From 4d6b228d84ba992ee13c90312c1ed539191c94b1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 7 Sep 2009 04:52:26 -0700 Subject: ath9k: use ath_hw for DPRINTF() and debug init/exit DPRINTF() is used in hw specific related code, as such ensure we don't rely on the private driver core ath_softc struct when calling it. Drivers can then implement their own DPRINTF() as they see fit. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 2 +- drivers/net/wireless/ath/ath9k/ani.c | 44 ++++---- drivers/net/wireless/ath/ath9k/beacon.c | 32 +++--- drivers/net/wireless/ath/ath9k/btcoex.c | 8 +- drivers/net/wireless/ath/ath9k/calib.c | 102 +++++++++--------- drivers/net/wireless/ath/ath9k/debug.c | 16 +-- drivers/net/wireless/ath/ath9k/debug.h | 15 +-- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 24 ++--- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 24 ++--- drivers/net/wireless/ath/ath9k/eeprom_def.c | 24 ++--- drivers/net/wireless/ath/ath9k/hw.c | 120 +++++++++++----------- drivers/net/wireless/ath/ath9k/mac.c | 48 ++++----- drivers/net/wireless/ath/ath9k/main.c | 148 ++++++++++++++------------- drivers/net/wireless/ath/ath9k/phy.c | 10 +- drivers/net/wireless/ath/ath9k/rc.c | 15 +-- drivers/net/wireless/ath/ath9k/recv.c | 18 ++-- drivers/net/wireless/ath/ath9k/xmit.c | 46 +++++---- 17 files changed, 356 insertions(+), 340 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 2ad7d0280f7a..41e16ed2f07d 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -40,7 +40,7 @@ static bool ath_ahb_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) pdata = (struct ath9k_platform_data *) pdev->dev.platform_data; if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "%s: flash read failed, offset %08x is out of range\n", __func__, off); return false; diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 2b493742ef10..e4f9559d25b6 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -31,7 +31,7 @@ static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, } } - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "No more channel states left. Using channel 0\n"); return 0; @@ -47,7 +47,7 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "level out of range (%u > %u)\n", level, (unsigned)ARRAY_SIZE(ah->totalSizeDesired)); @@ -152,7 +152,7 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(firstep)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "level out of range (%u > %u)\n", level, (unsigned) ARRAY_SIZE(firstep)); @@ -174,7 +174,7 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(cycpwrThr1)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "level out of range (%u > %u)\n", level, (unsigned) @@ -194,23 +194,23 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah, case ATH9K_ANI_PRESENT: break; default: - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "invalid cmd %u\n", cmd); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n"); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "ANI parameters:\n"); + DPRINTF(ah, ATH_DBG_ANI, "noiseImmunityLevel=%d, spurImmunityLevel=%d, " "ofdmWeakSigDetectOff=%d\n", aniState->noiseImmunityLevel, aniState->spurImmunityLevel, !aniState->ofdmWeakSigDetectOff); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "cckWeakSigThreshold=%d, " "firstepLevel=%d, listenTime=%d\n", aniState->cckWeakSigThreshold, aniState->firstepLevel, aniState->listenTime); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", aniState->cycleCount, aniState->ofdmPhyErrCount, aniState->cckPhyErrCount); @@ -240,7 +240,7 @@ static void ath9k_ani_restart(struct ath_hw *ah) if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { aniState->ofdmPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "OFDM Trigger is too high for hw counters\n"); } else { aniState->ofdmPhyErrBase = @@ -248,13 +248,13 @@ static void ath9k_ani_restart(struct ath_hw *ah) } if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { aniState->cckPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "CCK Trigger is too high for hw counters\n"); } else { aniState->cckPhyErrBase = AR_PHY_COUNTMAX - aniState->cckTrigHigh; } - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "Writing ofdmbase=%u cckbase=%u\n", aniState->ofdmPhyErrBase, aniState->cckPhyErrBase); @@ -475,7 +475,7 @@ void ath9k_ani_reset(struct ath_hw *ah) if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION && ah->opmode != NL80211_IFTYPE_ADHOC) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "Reset ANI state opmode %u\n", ah->opmode); ah->stats.ast_ani_reset++; @@ -569,7 +569,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, if (phyCnt1 < aniState->ofdmPhyErrBase || phyCnt2 < aniState->cckPhyErrBase) { if (phyCnt1 < aniState->ofdmPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "phyCnt1 0x%x, resetting " "counter value to 0x%x\n", phyCnt1, aniState->ofdmPhyErrBase); @@ -579,7 +579,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, AR_PHY_ERR_OFDM_TIMING); } if (phyCnt2 < aniState->cckPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "phyCnt2 0x%x, resetting " "counter value to 0x%x\n", phyCnt2, aniState->cckPhyErrBase); @@ -624,7 +624,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, void ath9k_enable_mib_counters(struct ath_hw *ah) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); + DPRINTF(ah, ATH_DBG_ANI, "Enable MIB counters\n"); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); @@ -640,7 +640,7 @@ void ath9k_enable_mib_counters(struct ath_hw *ah) /* Freeze the MIB counters, get the stats and then clear them */ void ath9k_hw_disable_mib_counters(struct ath_hw *ah) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n"); + DPRINTF(ah, ATH_DBG_ANI, "Disable MIB counters\n"); REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); @@ -662,7 +662,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 cc = REG_READ(ah, AR_CCCNT); if (cycles == 0 || cycles > cc) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "cycle counter wrap. ExtBusy = 0\n"); good = 0; } else { @@ -764,7 +764,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah) { int i; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Initialize ANI\n"); + DPRINTF(ah, ATH_DBG_ANI, "Initialize ANI\n"); memset(ah->ani, 0, sizeof(ah->ani)); for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { @@ -786,10 +786,10 @@ void ath9k_hw_ani_init(struct ath_hw *ah) AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; } - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "Setting OfdmErrBase = 0x%08x\n", ah->ani[0].ofdmPhyErrBase); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", + DPRINTF(ah, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", ah->ani[0].cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); @@ -803,7 +803,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah) void ath9k_hw_ani_disable(struct ath_hw *ah) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n"); + DPRINTF(ah, ATH_DBG_ANI, "Disabling ANI\n"); ath9k_hw_disable_mib_counters(ah); REG_WRITE(ah, AR_PHY_ERR_1, 0); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 45c4ea57616b..6e7a519d0a9c 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -42,7 +42,7 @@ static int ath_beaconq_config(struct ath_softc *sc) } if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unable to update h/w beacon queue parameters\n"); return 0; } else { @@ -172,7 +172,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error on beaconing\n"); + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "dma_mapping_error on beaconing\n"); return NULL; } @@ -192,7 +192,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, if (skb && cabq_depth) { if (sc->nvifs > 1) { - DPRINTF(sc, ATH_DBG_BEACON, + DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "Flushing previous cabq traffic\n"); ath_draintxq(sc, cabq, false); } @@ -233,7 +233,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, /* NB: caller is known to have already stopped tx dma */ ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); ath9k_hw_txstart(ah, sc->beacon.beaconq); - DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", + DPRINTF(ah, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); } @@ -309,7 +309,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) /* NB: the beacon data buffer must be 32-bit aligned. */ skb = ieee80211_beacon_get(sc->hw, vif); if (skb == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n"); + DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "cannot get skb\n"); return -ENOMEM; } @@ -333,7 +333,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) tsfadjust = intval * avp->av_bslot / ATH_BCBUF; avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); - DPRINTF(sc, ATH_DBG_BEACON, + DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "stagger beacons, bslot %d intval %u tsfadjust %llu\n", avp->av_bslot, intval, (unsigned long long)tsfadjust); @@ -349,7 +349,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "dma_mapping_error on beacon alloc\n"); return -ENOMEM; } @@ -405,11 +405,11 @@ void ath_beacon_tasklet(unsigned long data) sc->beacon.bmisscnt++; if (sc->beacon.bmisscnt < BSTUCK_THRESH) { - DPRINTF(sc, ATH_DBG_BEACON, + DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "missed %u consecutive beacons\n", sc->beacon.bmisscnt); } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { - DPRINTF(sc, ATH_DBG_BEACON, + DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "beacon is officially stuck\n"); sc->sc_flags |= SC_OP_TSF_RESET; ath_reset(sc, false); @@ -419,7 +419,7 @@ void ath_beacon_tasklet(unsigned long data) } if (sc->beacon.bmisscnt != 0) { - DPRINTF(sc, ATH_DBG_BEACON, + DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "resume beacon xmit after %u misses\n", sc->beacon.bmisscnt); sc->beacon.bmisscnt = 0; @@ -447,7 +447,7 @@ void ath_beacon_tasklet(unsigned long data) vif = sc->beacon.bslot[slot]; aphy = sc->beacon.bslot_aphy[slot]; - DPRINTF(sc, ATH_DBG_BEACON, + DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", slot, tsf, tsftu, intval, vif); @@ -490,7 +490,7 @@ void ath_beacon_tasklet(unsigned long data) * are still pending on the queue. */ if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "beacon queue %u did not stop?\n", sc->beacon.beaconq); } @@ -651,8 +651,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc, /* TSF out of range threshold fixed at 1 second */ bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); - DPRINTF(sc, ATH_DBG_BEACON, + DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); + DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", bs.bs_bmissthreshold, bs.bs_sleepduration, bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); @@ -689,7 +689,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, nexttbtt += intval; } while (nexttbtt < tsftu); - DPRINTF(sc, ATH_DBG_BEACON, + DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "IBSS nexttbtt %u intval %u (%u)\n", nexttbtt, intval, conf->beacon_interval); @@ -759,7 +759,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) ath_beacon_config_sta(sc, cur_conf); break; default: - DPRINTF(sc, ATH_DBG_CONFIG, + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Unsupported beaconing mode\n"); return; } diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 55f607b7699e..e19a9c99fb20 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -56,7 +56,7 @@ static void ath_detect_bt_priority(struct ath_softc *sc) if (time_after(jiffies, btinfo->bt_priority_time + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { if (btinfo->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { - DPRINTF(sc, ATH_DBG_BTCOEX, + DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "BT priority traffic detected"); sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; } else { @@ -90,7 +90,7 @@ static void ath_btcoex_bt_stomp(struct ath_softc *sc, AR_STOMP_NONE_WLAN_WGHT); break; default: - DPRINTF(sc, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); + DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); break; } @@ -142,7 +142,7 @@ static void ath_btcoex_no_stomp_timer(void *arg) struct ath_softc *sc = (struct ath_softc *)arg; struct ath_btcoex_info *btinfo = &sc->btcoex_info; - DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n"); + DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); spin_lock_bh(&btinfo->btcoex_lock); @@ -326,7 +326,7 @@ void ath_btcoex_timer_resume(struct ath_softc *sc, struct ath_btcoex_info *btinfo) { - DPRINTF(sc, ATH_DBG_BTCOEX, "Starting btcoex timers"); + DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "Starting btcoex timers"); /* make sure duty cycle timer is also stopped when resuming */ if (btinfo->hw_timer_enabled) diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 0ad6d0b76e9e..30106f49322a 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -26,7 +26,7 @@ static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf) { if (nf > ATH9K_NF_TOO_LOW) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "noise floor value detected (%d) is " "lower than what we think is a " "reasonable value (%d)\n", @@ -98,7 +98,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "NF calibrated [ctl] [chain 0] is %d\n", nf); nfarray[0] = nf; @@ -112,7 +112,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "NF calibrated [ctl] [chain 1] is %d\n", nf); nfarray[1] = nf; @@ -121,7 +121,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, AR_PHY_CH2_MINCCA_PWR); if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "NF calibrated [ctl] [chain 2] is %d\n", nf); nfarray[2] = nf; } @@ -136,7 +136,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "NF calibrated [ext] [chain 0] is %d\n", nf); nfarray[3] = nf; @@ -150,7 +150,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "NF calibrated [ext] [chain 1] is %d\n", nf); nfarray[4] = nf; @@ -159,7 +159,7 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, AR_PHY_CH2_EXT_MINCCA_PWR); if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "NF calibrated [ext] [chain 2] is %d\n", nf); nfarray[5] = nf; } @@ -195,22 +195,22 @@ static void ath9k_hw_setup_calibration(struct ath_hw *ah, switch (currCal->calData->calType) { case IQ_MISMATCH_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "starting IQ Mismatch Calibration\n"); break; case ADC_GAIN_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "starting ADC Gain Calibration\n"); break; case ADC_DC_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "starting ADC DC Calibration\n"); break; case ADC_DC_INIT_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "starting Init ADC DC Calibration\n"); break; } @@ -304,7 +304,7 @@ static void ath9k_hw_iqcal_collect(struct ath_hw *ah) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); ah->totalIqCorrMeas[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", ah->cal_samples, i, ah->totalPowerMeasI[i], ah->totalPowerMeasQ[i], @@ -326,7 +326,7 @@ static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah) ah->totalAdcQEvenPhase[i] += REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " "oddq=0x%08x; evenq=0x%08x;\n", ah->cal_samples, i, @@ -351,7 +351,7 @@ static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah) ah->totalAdcDcOffsetQEvenPhase[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " "oddq=0x%08x; evenq=0x%08x;\n", ah->cal_samples, i, @@ -374,11 +374,11 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) powerMeasQ = ah->totalPowerMeasQ[i]; iqCorrMeas = ah->totalIqCorrMeas[i]; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Starting IQ Cal and Correction for Chain %d\n", i); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Orignal: Chn %diq_corr_meas = 0x%08x\n", i, ah->totalIqCorrMeas[i]); @@ -389,11 +389,11 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) iqCorrNeg = 1; } - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", + DPRINTF(ah, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg); iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; @@ -402,13 +402,13 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) if (powerMeasQ != 0) { iCoff = iqCorrMeas / iCoffDenom; qCoff = powerMeasI / qCoffDenom - 64; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d iCoff = 0x%08x\n", i, iCoff); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d qCoff = 0x%08x\n", i, qCoff); iCoff = iCoff & 0x3f; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "New: Chn %d iCoff = 0x%08x\n", i, iCoff); if (iqCorrNeg == 0x0) iCoff = 0x40 - iCoff; @@ -418,7 +418,7 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) else if (qCoff <= -16) qCoff = 16; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", i, iCoff, qCoff); @@ -428,7 +428,7 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "IQ Cal and Correction done for Chain %d\n", i); } @@ -449,19 +449,19 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) qOddMeasOffset = ah->totalAdcQOddPhase[i]; qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Starting ADC Gain Cal for Chain %d\n", i); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d pwr_meas_odd_i = 0x%08x\n", i, iOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d pwr_meas_even_i = 0x%08x\n", i, iEvenMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d pwr_meas_odd_q = 0x%08x\n", i, qOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d pwr_meas_even_q = 0x%08x\n", i, qEvenMeasOffset); @@ -473,10 +473,10 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) ((qOddMeasOffset * 32) / qEvenMeasOffset) & 0x3f; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d gain_mismatch_i = 0x%08x\n", i, iGainMismatch); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d gain_mismatch_q = 0x%08x\n", i, qGainMismatch); @@ -485,7 +485,7 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) val |= (qGainMismatch) | (iGainMismatch << 6); REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "ADC Gain Cal done for Chain %d\n", i); } } @@ -510,19 +510,19 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Starting ADC DC Offset Cal for Chain %d\n", i); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d pwr_meas_odd_i = %d\n", i, iOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d pwr_meas_even_i = %d\n", i, iEvenMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d pwr_meas_odd_q = %d\n", i, qOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d pwr_meas_even_q = %d\n", i, qEvenMeasOffset); @@ -531,10 +531,10 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / numSamples) & 0x1ff; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, iDcMismatch); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, qDcMismatch); @@ -543,7 +543,7 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) val |= (qDcMismatch << 12) | (iDcMismatch << 21); REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "ADC DC Offset Cal done for Chain %d\n", i); } @@ -568,7 +568,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) return true; if (currCal->calState != CAL_DONE) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Calibration state incorrect, %d\n", currCal->calState); return true; @@ -577,7 +577,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType)) return true; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "Resetting Cal %d state for channel %u\n", currCal->calData->calType, conf->channel->center_freq); @@ -672,7 +672,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah, chan->channelFlags &= (~CHANNEL_CW_INT); if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "NF did not complete in calibration window\n"); nf = 0; chan->rawNoiseFloor = nf; @@ -682,7 +682,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah, nf = nfarray[0]; if (getNoiseFloorThresh(ah, c->band, &nfThresh) && nf > nfThresh) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "noise floor failed detected; " "detected %d, threshold %d\n", nf, nfThresh); @@ -889,7 +889,7 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) { 0x7838, 0 }, }; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); + DPRINTF(ah, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); /* PA CAL is not needed for high power solution */ if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == @@ -1049,7 +1049,7 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset " + DPRINTF(ah, ATH_DBG_CALIBRATE, "offset " "calibration failed to complete in " "1ms; noisy ??\n"); return false; @@ -1064,7 +1064,7 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset calibration " + DPRINTF(ah, ATH_DBG_CALIBRATE, "offset calibration " "failed to complete in 1ms; noisy ??\n"); return false; } @@ -1098,7 +1098,7 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) /* Poll for offset calibration complete */ if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "offset calibration failed to complete in 1ms; " "noisy environment?\n"); return false; @@ -1128,19 +1128,19 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) { INIT_CAL(&ah->adcgain_caldata); INSERT_CAL(ah, &ah->adcgain_caldata); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "enabling ADC Gain Calibration.\n"); } if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) { INIT_CAL(&ah->adcdc_caldata); INSERT_CAL(ah, &ah->adcdc_caldata); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "enabling ADC DC Calibration.\n"); } if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { INIT_CAL(&ah->iq_caldata); INSERT_CAL(ah, &ah->iq_caldata); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + DPRINTF(ah, ATH_DBG_CALIBRATE, "enabling IQ Calibration.\n"); } diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 2be4c2252047..babfd3780a9a 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -23,12 +23,12 @@ module_param_named(debug, ath9k_debug, uint, 0); static struct dentry *ath9k_debugfs_root; -void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) +void DPRINTF(struct ath_hw *ah, int dbg_mask, const char *fmt, ...) { - if (!sc) + if (!ah->ah_sc) return; - if (sc->debug.debug_mask & dbg_mask) { + if (ah->ah_sc->debug.debug_mask & dbg_mask) { va_list args; va_start(args, fmt); @@ -568,8 +568,10 @@ static const struct file_operations fops_xmit = { .owner = THIS_MODULE }; -int ath9k_init_debug(struct ath_softc *sc) +int ath9k_init_debug(struct ath_hw *ah) { + struct ath_softc *sc = ah->ah_sc; + sc->debug.debug_mask = ath9k_debug; if (!ath9k_debugfs_root) @@ -619,12 +621,14 @@ int ath9k_init_debug(struct ath_softc *sc) return 0; err: - ath9k_exit_debug(sc); + ath9k_exit_debug(ah); return -ENOMEM; } -void ath9k_exit_debug(struct ath_softc *sc) +void ath9k_exit_debug(struct ath_hw *ah) { + struct ath_softc *sc = ah->ah_sc; + debugfs_remove(sc->debug.debugfs_xmit); debugfs_remove(sc->debug.debugfs_wiphy); debugfs_remove(sc->debug.debugfs_rcstat); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 7241f4748338..c9c1aac95aef 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -17,6 +17,8 @@ #ifndef DEBUG_H #define DEBUG_H +#include "hw.h" + enum ATH_DEBUG { ATH_DBG_RESET = 0x00000001, ATH_DBG_QUEUE = 0x00000002, @@ -151,9 +153,10 @@ struct ath9k_debug { struct ath_stats stats; }; -void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); -int ath9k_init_debug(struct ath_softc *sc); -void ath9k_exit_debug(struct ath_softc *sc); +void DPRINTF(struct ath_hw *ah, int dbg_mask, const char *fmt, ...); +int ath9k_init_debug(struct ath_hw *ah); +void ath9k_exit_debug(struct ath_hw *ah); + int ath9k_debug_create_root(void); void ath9k_debug_remove_root(void); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); @@ -165,17 +168,17 @@ void ath_debug_stat_retries(struct ath_softc *sc, int rix, #else -static inline void DPRINTF(struct ath_softc *sc, int dbg_mask, +static inline void DPRINTF(struct ath_hw *ah, int dbg_mask, const char *fmt, ...) { } -static inline int ath9k_init_debug(struct ath_softc *sc) +static inline int ath9k_init_debug(struct ath_hw *ah) { return 0; } -static inline void ath9k_exit_debug(struct ath_softc *sc) +static inline void ath9k_exit_debug(struct ath_hw *ah) { } diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index b8eca7be5f3a..0675cd5edf0d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -35,13 +35,13 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) eep_start_loc = 64; if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "Reading from EEPROM, not flash\n"); } for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "Unable to read eeprom region \n"); return false; } @@ -66,12 +66,12 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) if (!ath9k_hw_use_flash(ah)) { if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Reading Magic # failed\n"); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { @@ -87,7 +87,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) eepdata++; } } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Invalid EEPROM Magic. " "endianness mismatch.\n"); return -EINVAL; @@ -95,7 +95,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) } } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + DPRINTF(ah, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? "True" : "False"); if (need_swap) @@ -117,7 +117,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) u32 integer; u16 word; - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "EEPROM Endianness is not native.. Changing\n"); word = swab16(eep->baseEepHeader.length); @@ -160,7 +160,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Bad EEPROM checksum 0x%x or revision 0x%04x\n", sum, ah->eep_ops->get_eeprom_ver(ah)); return -EINVAL; @@ -470,11 +470,11 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, ((pdadcValues[4 * j + 3] & 0xFF) << 24); REG_WRITE(ah, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "PDADC: Chain %d | " "PDADC %3d Value %3d | " "PDADC %3d Value %3d | " @@ -1151,7 +1151,7 @@ static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) u16 spur_val = AR_NO_SPUR; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "Getting spur idx %d is2Ghz. %d val %x\n", i, is2GHz, ah->config.spurchans[i][is2GHz]); @@ -1160,7 +1160,7 @@ static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) break; case SPUR_ENABLE_IOCTL: spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "Getting spur val from new loc. %d\n", spur_val); break; case SPUR_ENABLE_EEPROM: diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index c20c21a79b21..c6a4325019d5 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -34,14 +34,14 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) eep_data = (u16 *)eep; if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "Reading from EEPROM, not flash\n"); } for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); addr++) { if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "Unable to read eeprom region \n"); return false; } @@ -61,12 +61,12 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) if (!ath9k_hw_use_flash(ah)) { if (!ath9k_hw_nvram_read (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Reading Magic # failed\n"); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { magic2 = swab16(magic); @@ -83,14 +83,14 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) eepdata++; } } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Invalid EEPROM Magic. " "endianness mismatch.\n"); return -EINVAL; } } } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? + DPRINTF(ah, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? "True" : "False"); if (need_swap) @@ -148,7 +148,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Bad EEPROM checksum 0x%x or revision 0x%04x\n", sum, ah->eep_ops->get_eeprom_ver(ah)); return -EINVAL; @@ -564,12 +564,12 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, & 0xFF) << 24) ; REG_WRITE(ah, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "PDADC: Chain %d | " "PDADC %3d Value %3d | " "PDADC %3d Value %3d | " @@ -966,7 +966,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "Invalid chainmask configuration\n"); break; } @@ -1140,7 +1140,7 @@ static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) u16 spur_val = AR_NO_SPUR; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "Getting spur idx %d is2Ghz. %d val %x\n", i, is2GHz, ah->config.spurchans[i][is2GHz]); @@ -1149,7 +1149,7 @@ static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, break; case SPUR_ENABLE_IOCTL: spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "Getting spur val from new loc. %d\n", spur_val); break; case SPUR_ENABLE_EEPROM: diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 4071fc91da0a..8a7fc3962a16 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -95,7 +95,7 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unable to read eeprom region\n"); return false; } @@ -115,12 +115,12 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) int i, addr, size; if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); + DPRINTF(ah, ATH_DBG_FATAL, "Reading Magic # failed\n"); return false; } if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { @@ -137,7 +137,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) eepdata++; } } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Invalid EEPROM Magic. " "Endianness mismatch.\n"); return -EINVAL; @@ -145,7 +145,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) } } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + DPRINTF(ah, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? "True" : "False"); if (need_swap) @@ -167,7 +167,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) u32 integer, j; u16 word; - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "EEPROM Endianness is not native.. Changing.\n"); word = swab16(eep->baseEepHeader.length); @@ -214,7 +214,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Bad EEPROM checksum 0x%x or revision 0x%04x\n", sum, ah->eep_ops->get_eeprom_ver(ah)); return -EINVAL; @@ -870,11 +870,11 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, ((pdadcValues[4 * j + 3] & 0xFF) << 24); REG_WRITE(ah, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "PDADC (%d,%4x): %4.4x %8.8x\n", i, regChainOffset, regOffset, reg32); - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "PDADC: Chain %d | PDADC %3d " "Value %3d | PDADC %3d Value %3d | " "PDADC %3d Value %3d | PDADC %3d " @@ -1311,7 +1311,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "Invalid chainmask configuration\n"); break; } @@ -1352,7 +1352,7 @@ static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) u16 spur_val = AR_NO_SPUR; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "Getting spur idx %d is2Ghz. %d val %x\n", i, is2GHz, ah->config.spurchans[i][is2GHz]); @@ -1361,7 +1361,7 @@ static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) break; case SPUR_ENABLE_IOCTL: spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, + DPRINTF(ah, ATH_DBG_ANI, "Getting spur val from new loc. %d\n", spur_val); break; case SPUR_ENABLE_EEPROM: diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ca7694caf364..0342091dfe7d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -126,7 +126,7 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) udelay(AH_TIME_QUANTUM); } - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah, ATH_DBG_ANY, "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", timeout, reg, REG_READ(ah, reg), mask, val); @@ -210,7 +210,7 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, } break; default: - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unknown phy %u (rate ix %u)\n", rates->info[rateix].phy, rateix); txTime = 0; @@ -335,7 +335,7 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) REG_WRITE(ah, addr, wrData); rdData = REG_READ(ah, addr); if (rdData != wrData) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "address test failed " "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", addr, wrData, rdData); @@ -347,7 +347,7 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) REG_WRITE(ah, addr, wrData); rdData = REG_READ(ah, addr); if (wrData != rdData) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "address test failed " "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", addr, wrData, rdData); @@ -472,7 +472,7 @@ static int ath9k_hw_rfattach(struct ath_hw *ah) rfStatus = ath9k_hw_init_rf(ah, &ecode); if (!rfStatus) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "RF setup failed, status: %u\n", ecode); return ecode; } @@ -497,7 +497,7 @@ static int ath9k_hw_rf_claim(struct ath_hw *ah) case AR_RAD2122_SREV_MAJOR: break; default: - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Radio Chip Rev 0x%02X not supported\n", val & AR_RADIO_SREV_MAJOR); return -EOPNOTSUPP; @@ -590,7 +590,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah) if (ecode != 0) return ecode; - DPRINTF(ah->ah_sc, ATH_DBG_CONFIG, "Eeprom VER: %d, REV: %d\n", + DPRINTF(ah, ATH_DBG_CONFIG, "Eeprom VER: %d, REV: %d\n", ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah)); ecode = ath9k_hw_rfattach(ah); @@ -914,12 +914,12 @@ int ath9k_hw_init(struct ath_hw *ah) ath9k_hw_init_config(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n"); + DPRINTF(ah, ATH_DBG_FATAL, "Couldn't reset chip\n"); return -EIO; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); + DPRINTF(ah, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); return -EIO; } @@ -934,11 +934,11 @@ int ath9k_hw_init(struct ath_hw *ah) } } - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n", + DPRINTF(ah, ATH_DBG_RESET, "serialize_regmode is %d\n", ah->config.serialize_regmode); if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, ah->hw_version.macRev); @@ -979,7 +979,7 @@ int ath9k_hw_init(struct ath_hw *ah) r = ath9k_hw_init_macaddr(ah); if (r) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Failed to initialize MAC address\n"); return r; } @@ -1164,7 +1164,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) { if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us); + DPRINTF(ah, ATH_DBG_RESET, "bad ack timeout %u\n", us); ah->acktimeout = (u32) -1; return false; } else { @@ -1178,7 +1178,7 @@ static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) { if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us); + DPRINTF(ah, ATH_DBG_RESET, "bad cts timeout %u\n", us); ah->ctstimeout = (u32) -1; return false; } else { @@ -1192,7 +1192,7 @@ static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) { if (tu > 0xFFFF) { - DPRINTF(ah->ah_sc, ATH_DBG_XMIT, + DPRINTF(ah, ATH_DBG_XMIT, "bad global tx timeout %u\n", tu); ah->globaltxtimeout = (u32) -1; return false; @@ -1205,7 +1205,7 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) static void ath9k_hw_init_user_settings(struct ath_hw *ah) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ah->misc_mode 0x%x\n", + DPRINTF(ah, ATH_DBG_RESET, "ah->misc_mode 0x%x\n", ah->misc_mode); if (ah->misc_mode != 0) @@ -1302,23 +1302,23 @@ static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah, switch (ah->hw_version.devid) { case AR9280_DEVID_PCI: if (reg == 0x7894) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "ini VAL: %x EEPROM: %x\n", value, (pBase->version & 0xff)); if ((pBase->version & 0xff) > 0x0a) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "PWDCLKIND: %d\n", pBase->pwdclkind); value &= ~AR_AN_TOP2_PWDCLKIND; value |= AR_AN_TOP2_PWDCLKIND & (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); } else { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "PWDCLKIND Earlier Rev\n"); } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + DPRINTF(ah, ATH_DBG_EEPROM, "final ini VAL: %x\n", value); } break; @@ -1491,7 +1491,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, (u32) regulatory->power_limit)); if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "ar5416SetRfRegs failed\n"); return -EIO; } @@ -1697,7 +1697,7 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) REG_WRITE(ah, AR_RTC_RC, 0); if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, + DPRINTF(ah, ATH_DBG_RESET, "RTC stuck in MAC reset\n"); return false; } @@ -1734,7 +1734,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) AR_RTC_STATUS_M, AR_RTC_STATUS_ON, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n"); + DPRINTF(ah, ATH_DBG_RESET, "RTC not waking up\n"); return false; } @@ -1819,7 +1819,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + DPRINTF(ah, ATH_DBG_QUEUE, "Transmit frames pending on queue %d\n", qnum); return false; } @@ -1828,7 +1828,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Could not kill baseband RX\n"); return false; } @@ -1839,7 +1839,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ath9k_hw_ar9280_set_channel(ah, chan); } else { if (!(ath9k_hw_set_channel(ah, chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Failed to set channel\n"); return false; } @@ -2400,7 +2400,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, } if (!ath9k_hw_chip_reset(ah, chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n"); + DPRINTF(ah, ATH_DBG_FATAL, "Chip reset failed\n"); return -EINVAL; } @@ -2558,13 +2558,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u32 mask; mask = REG_READ(ah, AR_CFG); if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, + DPRINTF(ah, ATH_DBG_RESET, "CFG Byte Swap Set 0x%x\n", mask); } else { mask = INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB; REG_WRITE(ah, AR_CFG, mask); - DPRINTF(ah->ah_sc, ATH_DBG_RESET, + DPRINTF(ah, ATH_DBG_RESET, "Setting CFG 0x%x\n", REG_READ(ah, AR_CFG)); } } else { @@ -2592,7 +2592,7 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry) u32 keyType; if (entry >= ah->caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "keychache entry %u out of range\n", entry); return false; } @@ -2626,7 +2626,7 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) u32 macHi, macLo; if (entry >= ah->caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "keychache entry %u out of range\n", entry); return false; } @@ -2658,7 +2658,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, u32 keyType; if (entry >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "keycache entry %u out of range\n", entry); return false; } @@ -2669,7 +2669,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, break; case ATH9K_CIPHER_AES_CCM: if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah, ATH_DBG_ANY, "AES-CCM not supported by mac rev 0x%x\n", ah->hw_version.macRev); return false; @@ -2680,14 +2680,14 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, keyType = AR_KEYTABLE_TYPE_TKIP; if (ATH9K_IS_MIC_ENABLED(ah) && entry + 64 >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah, ATH_DBG_ANY, "entry %u inappropriate for TKIP\n", entry); return false; } break; case ATH9K_CIPHER_WEP: if (k->kv_len < WLAN_KEY_LEN_WEP40) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah, ATH_DBG_ANY, "WEP key length %u too small\n", k->kv_len); return false; } @@ -2702,7 +2702,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, keyType = AR_KEYTABLE_TYPE_CLR; break; default: - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "cipher %u not supported\n", k->kv_type); return false; } @@ -2920,7 +2920,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) AR_RTC_FORCE_WAKE_EN); } if (i == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Failed to wakeup in %uus\n", POWER_UP_TIME / 20); return false; } @@ -2945,7 +2945,7 @@ static bool ath9k_hw_setpower_nolock(struct ath_hw *ah, if (ah->power_mode == mode) return status; - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n", + DPRINTF(ah, ATH_DBG_RESET, "%s -> %s\n", modes[ah->power_mode], modes[mode]); switch (mode) { @@ -2960,7 +2960,7 @@ static bool ath9k_hw_setpower_nolock(struct ath_hw *ah, ath9k_set_power_network_sleep(ah, setChip); break; default: - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unknown power mode %u\n", mode); return false; } @@ -3249,7 +3249,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) } if (isr & AR_ISR_RXORN) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, + DPRINTF(ah, ATH_DBG_INTERRUPT, "receive FIFO overrun interrupt\n"); } @@ -3292,24 +3292,24 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) if (fatal_int) { if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah, ATH_DBG_ANY, "received PCI FATAL interrupt\n"); } if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, + DPRINTF(ah, ATH_DBG_ANY, "received PCI PERR interrupt\n"); } *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, + DPRINTF(ah, ATH_DBG_INTERRUPT, "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); REG_WRITE(ah, AR_RC, 0); *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, + DPRINTF(ah, ATH_DBG_INTERRUPT, "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); } @@ -3326,10 +3326,10 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->caps; - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); + DPRINTF(ah, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); if (omask & ATH9K_INT_GLOBAL) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "disable IER\n"); + DPRINTF(ah, ATH_DBG_INTERRUPT, "disable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_DISABLE); (void) REG_READ(ah, AR_IER); if (!AR_SREV_9100(ah)) { @@ -3386,7 +3386,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) mask2 |= AR_IMR_S2_CST; } - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); + DPRINTF(ah, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); REG_WRITE(ah, AR_IMR, mask); mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | @@ -3406,7 +3406,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) } if (ints & ATH9K_INT_GLOBAL) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "enable IER\n"); + DPRINTF(ah, ATH_DBG_INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, @@ -3419,7 +3419,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) REG_WRITE(ah, AR_INTR_SYNC_MASK, AR_INTR_SYNC_DEFAULT); } - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", + DPRINTF(ah, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); } @@ -3467,7 +3467,7 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; break; default: - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, + DPRINTF(ah, ATH_DBG_BEACON, "%s: unsupported opmode: %d\n", __func__, ah->opmode); return; @@ -3518,10 +3518,10 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, else nextTbtt = bs->bs_nexttbtt; - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "beacon period %d\n", beaconintval); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod); + DPRINTF(ah, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim); + DPRINTF(ah, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt); + DPRINTF(ah, ATH_DBG_BEACON, "beacon period %d\n", beaconintval); + DPRINTF(ah, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod); REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); @@ -3579,7 +3579,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) regulatory->current_rd += 5; else if (regulatory->current_rd == 0x41) regulatory->current_rd = 0x43; - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, + DPRINTF(ah, ATH_DBG_REGULATORY, "regdomain mapped to 0x%x\n", regulatory->current_rd); } @@ -4103,7 +4103,7 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) ath9k_ps_wakeup(ah->ah_sc); if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0, AH_TSF_WRITE_TIMEOUT)) - DPRINTF(ah->ah_sc, ATH_DBG_RESET, + DPRINTF(ah, ATH_DBG_RESET, "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); @@ -4121,7 +4121,7 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) { if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us); + DPRINTF(ah, ATH_DBG_RESET, "bad slot time %u\n", us); ah->slottime = (u32) -1; return false; } else { @@ -4234,7 +4234,7 @@ void ath_gen_timer_start(struct ath_hw *ah, tsf = ath9k_hw_gettsf32(ah); - DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, "curent tsf %x period %x" + DPRINTF(ah, ATH_DBG_HWTIMER, "curent tsf %x period %x" "timer_next %x\n", tsf, timer_period, timer_next); /* @@ -4324,7 +4324,7 @@ void ath_gen_timer_isr(struct ath_hw *ah) index = rightmost_index(timer_table, &thresh_mask); timer = timer_table->timers[index]; BUG_ON(!timer); - DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, + DPRINTF(ah, ATH_DBG_HWTIMER, "TSF overflow for Gen timer %d\n", index); timer->overflow(timer->arg); } @@ -4333,7 +4333,7 @@ void ath_gen_timer_isr(struct ath_hw *ah) index = rightmost_index(timer_table, &trigger_mask); timer = timer_table->timers[index]; BUG_ON(!timer); - DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, + DPRINTF(ah, ATH_DBG_HWTIMER, "Gen timer[%d] trigger\n", index); timer->trigger(timer->arg); } diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 800bfab94635..b4d2f207857d 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -19,7 +19,7 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, struct ath9k_tx_queue_info *qi) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, + DPRINTF(ah, ATH_DBG_INTERRUPT, "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", ah->txok_interrupt_mask, ah->txerr_interrupt_mask, ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask, @@ -47,7 +47,7 @@ void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) void ath9k_hw_txstart(struct ath_hw *ah, u32 q) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q); + DPRINTF(ah, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q); REG_WRITE(ah, AR_Q_TXE, 1 << q); } @@ -105,14 +105,14 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, " + DPRINTF(ah, ATH_DBG_QUEUE, "Stopping TX DMA, " "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, " + DPRINTF(ah, ATH_DBG_QUEUE, "Stopping TX DMA, " "inactive queue: %u\n", q); return false; } @@ -126,7 +126,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) } if (ath9k_hw_numtxpending(ah, q)) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + DPRINTF(ah, ATH_DBG_QUEUE, "%s: Num of pending TX Frames %d on Q %d\n", __func__, ath9k_hw_numtxpending(ah, q), q); @@ -142,7 +142,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10)) break; - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + DPRINTF(ah, ATH_DBG_QUEUE, "TSF has moved while trying to set " "quiet time TSF: 0x%08x\n", tsfLow); } @@ -155,7 +155,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) wait = wait_time; while (ath9k_hw_numtxpending(ah, q)) { if ((--wait) == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + DPRINTF(ah, ATH_DBG_QUEUE, "Failed to stop TX DMA in 100 " "msec after killing last frame\n"); break; @@ -449,19 +449,19 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, " + DPRINTF(ah, ATH_DBG_QUEUE, "Set TXQ properties, " "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, " + DPRINTF(ah, ATH_DBG_QUEUE, "Set TXQ properties, " "inactive queue: %u\n", q); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q); + DPRINTF(ah, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q); qi->tqi_ver = qinfo->tqi_ver; qi->tqi_subtype = qinfo->tqi_subtype; @@ -518,14 +518,14 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, " + DPRINTF(ah, ATH_DBG_QUEUE, "Get TXQ properties, " "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, " + DPRINTF(ah, ATH_DBG_QUEUE, "Get TXQ properties, " "inactive queue: %u\n", q); return false; } @@ -574,22 +574,22 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, ATH9K_TX_QUEUE_INACTIVE) break; if (q == pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "No available TX queue\n"); return -1; } break; default: - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid TX queue type: %u\n", + DPRINTF(ah, ATH_DBG_FATAL, "Invalid TX queue type: %u\n", type); return -1; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q); + DPRINTF(ah, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q); qi = &ah->txq[q]; if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "TX queue: %u already active\n", q); return -1; } @@ -620,18 +620,18 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, " + DPRINTF(ah, ATH_DBG_QUEUE, "Release TXQ, " "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, " + DPRINTF(ah, ATH_DBG_QUEUE, "Release TXQ, " "inactive queue: %u\n", q); return false; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TX queue: %u\n", q); + DPRINTF(ah, ATH_DBG_QUEUE, "Release TX queue: %u\n", q); qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; ah->txok_interrupt_mask &= ~(1 << q); @@ -652,19 +652,19 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) u32 cwMin, chanCwMin, value; if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, " + DPRINTF(ah, ATH_DBG_QUEUE, "Reset TXQ, " "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, " + DPRINTF(ah, ATH_DBG_QUEUE, "Reset TXQ, " "inactive queue: %u\n", q); return true; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q); + DPRINTF(ah, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q); if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { if (chan && IS_CHAN_B(chan)) @@ -911,7 +911,7 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) AR_DIAG_RX_ABORT)); reg = REG_READ(ah, AR_OBS_BUS_1); - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "RX failed to go idle in 10 ms RXSM=0x%x\n", reg); return false; @@ -967,7 +967,7 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah) } if (i == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "DMA failed to stop in %d ms " "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", AH_RX_STOP_DMA_TIMEOUT / 1000, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 52bed89063d4..68d8dd9602dc 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -224,7 +224,7 @@ static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) } sband->n_bitrates++; - DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n", rate[i].bitrate / 10, rate[i].hw_value); } } @@ -280,7 +280,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) fastcc = false; - DPRINTF(sc, ATH_DBG_CONFIG, + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "(%u MHz) -> (%u MHz), chanwidth: %d\n", sc->sc_ah->curchan->channel, channel->center_freq, sc->tx_chan_width); @@ -289,7 +289,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, r = ath9k_hw_reset(ah, hchan, fastcc); if (r) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to reset channel (%u Mhz) " "reset status %d\n", channel->center_freq, r); @@ -301,7 +301,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, sc->sc_flags &= ~SC_OP_FULL_RESET; if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to restart recv logic\n"); r = -EIO; goto ps_restore; @@ -353,7 +353,7 @@ static void ath_ani_calibrate(unsigned long data) /* Long calibration runs independently of short calibration. */ if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { longcal = true; - DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies); + DPRINTF(sc->sc_ah, ATH_DBG_ANI, "longcal @%lu\n", jiffies); sc->ani.longcal_timer = timestamp; } @@ -361,7 +361,7 @@ static void ath_ani_calibrate(unsigned long data) if (!sc->ani.caldone) { if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) { shortcal = true; - DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); + DPRINTF(sc->sc_ah, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); sc->ani.shortcal_timer = timestamp; sc->ani.resetcal_timer = timestamp; } @@ -395,7 +395,7 @@ static void ath_ani_calibrate(unsigned long data) sc->ani.noise_floor = ath9k_hw_getchan_noise(ah, ah->curchan); - DPRINTF(sc, ATH_DBG_ANI," calibrate chan %u/%x nf: %d\n", + DPRINTF(sc->sc_ah, ATH_DBG_ANI," calibrate chan %u/%x nf: %d\n", ah->curchan->channel, ah->curchan->channelFlags, sc->ani.noise_floor); } @@ -448,7 +448,7 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht) sc->rx_chainmask = 1; } - DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", sc->tx_chainmask, sc->rx_chainmask); } @@ -502,7 +502,7 @@ static void ath9k_tasklet(unsigned long data) * TSF sync does not look correct; remain awake to sync with * the next Beacon. */ - DPRINTF(sc, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); + DPRINTF(sc->sc_ah, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; } @@ -702,7 +702,7 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) { /* TX MIC entry failed. No need to proceed further */ - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Setting TX MIC Key Failed\n"); return 0; } @@ -907,7 +907,7 @@ static void setup_ht_cap(struct ath_softc *sc, rx_streams = !(sc->rx_chainmask & (sc->rx_chainmask - 1)) ? 1 : 2; if (tx_streams != rx_streams) { - DPRINTF(sc, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", tx_streams, rx_streams); ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; ht_info->mcs.tx_params |= ((tx_streams - 1) << @@ -927,7 +927,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, { if (bss_conf->assoc) { - DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", bss_conf->aid, sc->curbssid); /* New association, store aid */ @@ -949,7 +949,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_start_ani(sc); } else { - DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); sc->curaid = 0; /* Stop ANI */ del_timer_sync(&sc->ani.timer); @@ -1042,7 +1042,7 @@ static int ath_register_led(struct ath_softc *sc, struct ath_led *led, ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); if (ret) - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Failed to register led:%s", led->name); else led->registered = 1; @@ -1139,7 +1139,7 @@ void ath_radio_enable(struct ath_softc *sc) spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, ah->curchan, false); if (r) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to reset channel %u (%uMhz) ", "reset status %d\n", channel->center_freq, r); @@ -1148,7 +1148,7 @@ void ath_radio_enable(struct ath_softc *sc) ath_update_txpow(sc); if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to restart recv logic\n"); return; } @@ -1194,7 +1194,7 @@ void ath_radio_disable(struct ath_softc *sc) spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, ah->curchan, false); if (r) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to reset channel %u (%uMhz) " "reset status %d\n", channel->center_freq, r); @@ -1248,11 +1248,12 @@ void ath_cleanup(struct ath_softc *sc) void ath_detach(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; + struct ath_hw *ah = sc->sc_ah; int i = 0; ath9k_ps_wakeup(sc); - DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); + dev_dbg(sc->dev, "Detach ATH hw\n"); ath_deinit_leds(sc); wiphy_rfkill_stop_polling(sc->hw->wiphy); @@ -1273,7 +1274,7 @@ void ath_detach(struct ath_softc *sc) tasklet_kill(&sc->bcon_tasklet); if (!(sc->sc_flags & SC_OP_INVALID)) - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); + ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); /* cleanup tx queues */ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) @@ -1282,11 +1283,11 @@ void ath_detach(struct ath_softc *sc) if ((sc->btcoex_info.no_stomp_timer) && sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) - ath_gen_timer_free(sc->sc_ah, sc->btcoex_info.no_stomp_timer); + ath_gen_timer_free(ah, sc->btcoex_info.no_stomp_timer); - ath9k_hw_detach(sc->sc_ah); + ath9k_hw_detach(ah); + ath9k_exit_debug(sc->sc_ah); sc->sc_ah = NULL; - ath9k_exit_debug(sc); } static int ath9k_reg_notifier(struct wiphy *wiphy, @@ -1315,9 +1316,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) /* XXX: hardware will not be ready until ath_open() being called */ sc->sc_flags |= SC_OP_INVALID; - if (ath9k_init_debug(sc) < 0) - printk(KERN_ERR "Unable to create debugfs files\n"); - spin_lock_init(&sc->wiphy_lock); spin_lock_init(&sc->sc_resetlock); spin_lock_init(&sc->sc_serial_rw); @@ -1347,9 +1345,12 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) ah->hw_version.subsysid = subsysid; sc->sc_ah = ah; + if (ath9k_init_debug(ah) < 0) + dev_err(sc->dev, "Unable to create debugfs files\n"); + r = ath9k_hw_init(ah); if (r) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unable to initialize hardware; " "initialization status: %d\n", r); goto bad; @@ -1358,7 +1359,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) /* Get the hardware key cache size. */ sc->keymax = ah->caps.keycache_size; if (sc->keymax > ATH_KEYMAX) { - DPRINTF(sc, ATH_DBG_ANY, + DPRINTF(ah, ATH_DBG_ANY, "Warning, using only %u entries in %u key cache\n", ATH_KEYMAX, sc->keymax); sc->keymax = ATH_KEYMAX; @@ -1388,14 +1389,14 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) */ sc->beacon.beaconq = ath_beaconq_setup(ah); if (sc->beacon.beaconq == -1) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unable to setup a beacon xmit queue\n"); r = -EIO; goto bad2; } sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); if (sc->beacon.cabq == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unable to setup CAB xmit queue\n"); r = -EIO; goto bad2; @@ -1410,26 +1411,26 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) /* Setup data queues */ /* NB: ensure BK queue is the lowest priority h/w queue */ if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unable to setup xmit queue for BK traffic\n"); r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unable to setup xmit queue for BE traffic\n"); r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unable to setup xmit queue for VI traffic\n"); r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unable to setup xmit queue for VO traffic\n"); r = -EIO; goto bad2; @@ -1529,9 +1530,9 @@ bad2: ath_tx_cleanupq(sc, &sc->tx.txq[i]); bad: ath9k_hw_detach(ah); - sc->sc_ah = NULL; bad_no_ah: - ath9k_exit_debug(sc); + ath9k_exit_debug(sc->sc_ah); + sc->sc_ah = NULL; return r; } @@ -1577,18 +1578,21 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid) { struct ieee80211_hw *hw = sc->hw; + struct ath_hw *ah; int error = 0, i; struct ath_regulatory *reg; - DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); + dev_dbg(sc->dev, "Attach ATH hw\n"); error = ath_init_softc(devid, sc, subsysid); if (error != 0) return error; + ah = sc->sc_ah; + /* get mac address from hardware and set in mac80211 */ - SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr); + SET_IEEE80211_PERM_ADDR(hw, ah->macaddr); ath_set_hw_capab(sc, hw); @@ -1599,9 +1603,9 @@ int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid) reg = &sc->common.regulatory; - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) + if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); } @@ -1639,9 +1643,9 @@ error_attach: if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); - ath9k_hw_detach(sc->sc_ah); + ath9k_hw_detach(ah); + ath9k_exit_debug(ah); sc->sc_ah = NULL; - ath9k_exit_debug(sc); return error; } @@ -1660,12 +1664,12 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); if (r) - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d\n", r); spin_unlock_bh(&sc->sc_resetlock); if (ath_startrecv(sc) != 0) - DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); + DPRINTF(ah, ATH_DBG_FATAL, "Unable to start recv logic\n"); /* * We may be doing a reset in response to a request @@ -1713,13 +1717,13 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, struct ath_buf *bf; int i, bsize, error; - DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", name, nbuf, ndesc); INIT_LIST_HEAD(head); /* ath_desc must be a multiple of DWORDs */ if ((sizeof(struct ath_desc) % 4) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); ASSERT((sizeof(struct ath_desc) % 4) == 0); error = -ENOMEM; goto fail; @@ -1753,7 +1757,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, goto fail; } ds = dd->dd_desc; - DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", name, ds, (u32) dd->dd_desc_len, ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); @@ -1905,7 +1909,7 @@ static int ath9k_start(struct ieee80211_hw *hw) struct ath9k_channel *init_channel; int r; - DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with " + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Starting driver with " "initial channel: %d MHz\n", curchan->center_freq); mutex_lock(&sc->mutex); @@ -1950,7 +1954,7 @@ static int ath9k_start(struct ieee80211_hw *hw) spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(sc->sc_ah, init_channel, false); if (r) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d " "(freq %u MHz)\n", r, curchan->center_freq); @@ -1973,7 +1977,7 @@ static int ath9k_start(struct ieee80211_hw *hw) * here except setup the interrupt mask. */ if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to start recv logic\n"); r = -EIO; goto mutex_unlock; } @@ -2042,7 +2046,7 @@ static int ath9k_tx(struct ieee80211_hw *hw, if (ieee80211_is_data(hdr->frame_control) && !ieee80211_is_nullfunc(hdr->frame_control) && !ieee80211_has_pm(hdr->frame_control)) { - DPRINTF(sc, ATH_DBG_PS, "Add PM=1 for a TX frame " + DPRINTF(sc->sc_ah, ATH_DBG_PS, "Add PM=1 for a TX frame " "while in PS mode\n"); hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); } @@ -2058,11 +2062,11 @@ static int ath9k_tx(struct ieee80211_hw *hw, ath9k_ps_wakeup(sc); ath9k_hw_setrxabort(sc->sc_ah, 0); if (ieee80211_is_pspoll(hdr->frame_control)) { - DPRINTF(sc, ATH_DBG_PS, "Sending PS-Poll to pick a " + DPRINTF(sc->sc_ah, ATH_DBG_PS, "Sending PS-Poll to pick a " "buffered frame\n"); sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA; } else { - DPRINTF(sc, ATH_DBG_PS, "Wake up to complete TX\n"); + DPRINTF(sc->sc_ah, ATH_DBG_PS, "Wake up to complete TX\n"); sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK; } /* @@ -2104,10 +2108,10 @@ static int ath9k_tx(struct ieee80211_hw *hw, if (!txctl.txq) goto exit; - DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); + DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); if (ath_tx_start(hw, skb, &txctl) != 0) { - DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); + DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "TX failed\n"); goto exit; } @@ -2135,7 +2139,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) } if (sc->sc_flags & SC_OP_INVALID) { - DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); + DPRINTF(sc->sc_ah, ATH_DBG_ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; } @@ -2171,7 +2175,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) mutex_unlock(&sc->mutex); - DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n"); + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Driver halt\n"); } static int ath9k_add_interface(struct ieee80211_hw *hw, @@ -2205,13 +2209,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ic_opmode = conf->type; break; default: - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Interface type %d not yet supported\n", conf->type); ret = -EOPNOTSUPP; goto out; } - DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode); + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode); /* Set the VIF opmode */ avp->av_opmode = ic_opmode; @@ -2264,7 +2268,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ath_vif *avp = (void *)conf->vif->drv_priv; int i; - DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Detach Interface\n"); mutex_lock(&sc->mutex); @@ -2318,7 +2322,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } else if (all_wiphys_idle) { ath_radio_enable(sc); - DPRINTF(sc, ATH_DBG_CONFIG, + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "not-idle: enabling radio\n"); } } @@ -2372,7 +2376,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) goto skip_chan_change; } - DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Set channel: %d MHz\n", curchan->center_freq); /* XXX: remove me eventualy */ @@ -2381,7 +2385,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath_update_chainmask(sc, conf_is_ht(conf)); if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { - DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to set channel\n"); mutex_unlock(&sc->mutex); return -EINVAL; } @@ -2392,7 +2396,7 @@ skip_chan_change: sc->config.txpowlimit = 2 * conf->power_level; if (disable_radio) { - DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n"); + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "idle: disabling radio\n"); ath_radio_disable(sc); } @@ -2429,7 +2433,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, ath9k_hw_setrxfilter(sc->sc_ah, rfilt); ath9k_ps_restore(sc); - DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt); + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt); } static void ath9k_sta_notify(struct ieee80211_hw *hw, @@ -2473,7 +2477,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, qi.tqi_burstTime = params->txop; qnum = ath_get_hal_qnum(queue, sc); - DPRINTF(sc, ATH_DBG_CONFIG, + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Configure tx [queue/halq] [%d/%d], " "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", queue, qnum, params->aifs, params->cw_min, @@ -2481,7 +2485,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, ret = ath_txq_update(sc, qnum, &qi); if (ret) - DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n"); + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "TXQ Update failed\n"); mutex_unlock(&sc->mutex); @@ -2503,7 +2507,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - DPRINTF(sc, ATH_DBG_CONFIG, "Set HW Key\n"); + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Set HW Key\n"); switch (cmd) { case SET_KEY: @@ -2577,7 +2581,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, /* Set aggregation protection mode parameters */ sc->config.ath_aggr_prot = 0; - DPRINTF(sc, ATH_DBG_CONFIG, + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "RX filter 0x%x bssid %pM aid 0x%x\n", rfilt, sc->curbssid, sc->curaid); @@ -2626,7 +2630,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath_update_chainmask(sc, 0); if (changed & BSS_CHANGED_ERP_PREAMBLE) { - DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", bss_conf->use_short_preamble); if (bss_conf->use_short_preamble) sc->sc_flags |= SC_OP_PREAMBLE_SHORT; @@ -2635,7 +2639,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ERP_CTS_PROT) { - DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", bss_conf->use_cts_prot); if (bss_conf->use_cts_prot && hw->conf.channel->band != IEEE80211_BAND_5GHZ) @@ -2645,7 +2649,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", bss_conf->assoc); ath9k_bss_assoc_info(sc, vif, bss_conf); } @@ -2726,7 +2730,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ath_tx_aggr_resume(sc, sta, tid); break; default: - DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unknown AMPDU action\n"); } return ret; diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 63bf9a307c6a..1166f725f556 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -46,7 +46,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = ((freq - 704) * 2 - 3040) / 10; bModeSynth = 1; } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Invalid channel %u MHz\n", freq); return false; } @@ -79,7 +79,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8); aModeRefSel = ath9k_hw_reverse_bits(1, 2); } else { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Invalid channel %u MHz\n", freq); return false; } @@ -315,7 +315,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) || ah->analogBank6Data == NULL || ah->analogBank6TPCData == NULL || ah->analogBank7Data == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Cannot allocate RF banks\n"); *status = -ENOMEM; return false; @@ -326,7 +326,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) ah->iniAddac.ia_rows * ah->iniAddac.ia_columns), GFP_KERNEL); if (ah->addac5416_21 == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Cannot allocate addac5416_21\n"); *status = -ENOMEM; return false; @@ -336,7 +336,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) kzalloc((sizeof(u32) * ah->iniBank6.ia_rows), GFP_KERNEL); if (ah->bank6Temp == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Cannot allocate bank6Temp\n"); *status = -ENOMEM; return false; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 16a271787b85..cafe1ec7bdbb 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1177,13 +1177,14 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, mode = ATH9K_MODE_11NA_HT40PLUS; break; default: - DPRINTF(sc, ATH_DBG_CONFIG, "Invalid band\n"); + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Invalid band\n"); return NULL; } BUG_ON(mode >= ATH9K_MODE_MAX); - DPRINTF(sc, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode); + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, + "Choosing rate table for mode: %d\n", mode); return sc->hw_rate_table[mode]; } @@ -1198,7 +1199,8 @@ static void ath_rc_init(struct ath_softc *sc, u8 i, j, k, hi = 0, hthi = 0; if (!rate_table) { - DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n"); + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, + "Rate table not initialized\n"); return; } @@ -1261,7 +1263,8 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; sc->cur_rate_table = rate_table; - DPRINTF(sc, ATH_DBG_CONFIG, "RC Initialized with capabilities: 0x%x\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, + "RC Initialized with capabilities: 0x%x\n", ath_rc_priv->ht_cap); } @@ -1438,7 +1441,7 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, oper_cw40, oper_sgi40); ath_rc_init(sc, priv_sta, sband, sta, rate_table); - DPRINTF(sc, ATH_DBG_CONFIG, + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Operating HT Bandwidth changed to: %d\n", sc->hw->conf.channel_type); } @@ -1463,7 +1466,7 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp); if (!rate_priv) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to allocate private rc structure\n"); return NULL; } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index ec0abf823995..ee1e8b47496a 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -306,7 +306,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, min(sc->common.cachelsz, (u16)64)); - DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", + DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", sc->common.cachelsz, sc->rx.bufsize); /* Initialize rx descriptors */ @@ -314,7 +314,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, "rx", nbufs, 1); if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "failed to allocate rx descriptors: %d\n", error); goto err; } @@ -334,7 +334,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "dma_mapping_error() on RX init\n"); error = -ENOMEM; goto err; @@ -539,7 +539,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) if (sc->sc_flags & SC_OP_BEACON_SYNC) { sc->sc_flags &= ~SC_OP_BEACON_SYNC; - DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on " + DPRINTF(sc->sc_ah, ATH_DBG_PS, "Reconfigure Beacon timers based on " "timestamp from the AP\n"); ath_beacon_config(sc, NULL); } @@ -552,7 +552,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) * a backup trigger for returning into NETWORK SLEEP state, * so we are waiting for it as well. */ - DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating " + DPRINTF(sc->sc_ah, ATH_DBG_PS, "Received DTIM beacon indicating " "buffered broadcast/multicast frame(s)\n"); sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON; return; @@ -565,7 +565,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) * been delivered. */ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; - DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); + DPRINTF(sc->sc_ah, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); } } @@ -589,13 +589,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) * point. */ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; - DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to " + DPRINTF(sc->sc_ah, ATH_DBG_PS, "All PS CAB frames received, back to " "sleep\n"); } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && !is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_morefrags(hdr->frame_control)) { sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA; - DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having " + DPRINTF(sc->sc_ah, ATH_DBG_PS, "Going back to sleep after having " "received PS-Poll data (0x%x)\n", sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB | @@ -811,7 +811,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) bf->bf_buf_addr))) { dev_kfree_skb_any(requeue_skb); bf->bf_mpdu = NULL; - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "dma_mapping_error() on RX\n"); ath_rx_send_to_mac80211(sc, skb, &rx_status); break; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 42551a48c8ac..ddd3062186a7 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -854,7 +854,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) return NULL; } if (qnum >= ARRAY_SIZE(sc->tx.txq)) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "qnum %u out of range, max %u!\n", qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq)); ath9k_hw_releasetxqueue(ah, qnum); @@ -884,7 +884,7 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) switch (qtype) { case ATH9K_TX_QUEUE_DATA: if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "HAL AC %u out of range, max %zu!\n", haltype, ARRAY_SIZE(sc->tx.hwq_map)); return -1; @@ -914,7 +914,7 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) spin_lock_bh(&txq->axq_lock); if (txq->axq_depth >= (ATH_TXBUF - 20)) { - DPRINTF(sc, ATH_DBG_XMIT, + DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "TX queue: %d is full, depth: %d\n", qnum, txq->axq_depth); ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); @@ -955,7 +955,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, qi.tqi_readyTime = qinfo->tqi_readyTime; if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to update hardware queue %u!\n", qnum); error = -EIO; } else { @@ -1076,12 +1076,12 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) if (npend) { int r; - DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); + DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); if (r) - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d\n", r); spin_unlock_bh(&sc->sc_resetlock); @@ -1147,7 +1147,7 @@ int ath_tx_setup(struct ath_softc *sc, int haltype) struct ath_txq *txq; if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "HAL AC %u out of range, max %zu!\n", haltype, ARRAY_SIZE(sc->tx.hwq_map)); return 0; @@ -1188,17 +1188,17 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, txq->axq_depth++; txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); - DPRINTF(sc, ATH_DBG_QUEUE, + DPRINTF(sc->sc_ah, ATH_DBG_QUEUE, "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); if (txq->axq_link == NULL) { ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); - DPRINTF(sc, ATH_DBG_XMIT, + DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n", txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); } else { *txq->axq_link = bf->bf_daddr; - DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", + DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", txq->axq_qnum, txq->axq_link, ito64(bf->bf_daddr), bf->bf_desc); } @@ -1587,7 +1587,8 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_mpdu = NULL; kfree(tx_info_priv); tx_info->rate_driver_data[0] = NULL; - DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on TX\n"); + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, + "dma_mapping_error() on TX\n"); return -ENOMEM; } @@ -1674,7 +1675,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, bf = ath_tx_get_buffer(sc); if (!bf) { - DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n"); + DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "TX buffers are full\n"); return -1; } @@ -1682,7 +1683,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, if (unlikely(r)) { struct ath_txq *txq = txctl->txq; - DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n"); + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "TX mem alloc failure\n"); /* upon ath_tx_processq() this TX queue will be resumed, we * guarantee this will happen by knowing beforehand that @@ -1736,7 +1737,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) if (hdrlen & 3) { padsize = hdrlen % 4; if (skb_headroom(skb) < padsize) { - DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n"); + DPRINTF(sc->sc_ah, ATH_DBG_XMIT, + "TX CABQ padding failed\n"); dev_kfree_skb_any(skb); return; } @@ -1746,10 +1748,10 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) txctl.txq = sc->beacon.cabq; - DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); + DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); if (ath_tx_start(hw, skb, &txctl) != 0) { - DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n"); + DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "CABQ TX failed\n"); goto exit; } @@ -1771,7 +1773,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, int hdrlen, padsize; int frame_type = ATH9K_NOT_INTERNAL; - DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); + DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); if (tx_info_priv) { hw = tx_info_priv->aphy->hw; @@ -1805,7 +1807,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) { sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK; - DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having " + DPRINTF(sc->sc_ah, ATH_DBG_PS, "Going back to sleep after having " "received TX status (0x%x)\n", sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB | @@ -1942,7 +1944,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) int txok; int status; - DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", + DPRINTF(ah, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), txq->axq_link); @@ -2064,7 +2066,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work) } if (needreset) { - DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n"); + DPRINTF(sc->sc_ah, ATH_DBG_RESET, "tx hung, resetting the chip\n"); ath_reset(sc, false); } @@ -2100,7 +2102,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, "tx", nbufs, 1); if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Failed to allocate tx descriptors: %d\n", error); goto err; } @@ -2108,7 +2110,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, "beacon", ATH_BCBUF, 1); if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, + DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Failed to allocate beacon descriptors: %d\n", error); goto err; } -- cgit v1.2.3 From 2e20250a2ce1f4a7ba7c83ccb62d9b7b9b96c736 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 01:18:09 -0700 Subject: ath9k: move btcoex core driver info to its own struct There is some bluetooth coexistance data which is driver specific, stuff that into its own structure. Cc: Vasanthakumar Thiagarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 11 +++++ drivers/net/wireless/ath/ath9k/btcoex.c | 73 +++++++++++++++++---------------- drivers/net/wireless/ath/ath9k/btcoex.h | 16 ++------ drivers/net/wireless/ath/ath9k/main.c | 4 +- 4 files changed, 55 insertions(+), 49 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 1d59f10f68da..831874c621ec 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -451,6 +451,16 @@ struct ath_ani { struct timer_list timer; }; +struct ath_btcoex { + bool hw_timer_enabled; + spinlock_t btcoex_lock; + struct timer_list period_timer; /* Timer for BT period */ + u32 bt_priority_cnt; + unsigned long bt_priority_time; + u32 btcoex_no_stomp; /* in usec */ + u32 btcoex_period; /* in usec */ +}; + /********************/ /* LED Control */ /********************/ @@ -613,6 +623,7 @@ struct ath_softc { struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; struct ath_btcoex_info btcoex_info; + struct ath_btcoex btcoex; }; struct ath_wiphy { diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index e19a9c99fb20..e88a0a3f68f0 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -48,14 +48,14 @@ bool ath_btcoex_supported(u16 subsysid) */ static void ath_detect_bt_priority(struct ath_softc *sc) { - struct ath_btcoex_info *btinfo = &sc->btcoex_info; + struct ath_btcoex *btcoex = &sc->btcoex; - if (ath9k_hw_gpio_get(sc->sc_ah, btinfo->btpriority_gpio)) - btinfo->bt_priority_cnt++; + if (ath9k_hw_gpio_get(sc->sc_ah, sc->btcoex_info.btpriority_gpio)) + btcoex->bt_priority_cnt++; - if (time_after(jiffies, btinfo->bt_priority_time + + if (time_after(jiffies, btcoex->bt_priority_time + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { - if (btinfo->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { + if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "BT priority traffic detected"); sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; @@ -63,8 +63,8 @@ static void ath_detect_bt_priority(struct ath_softc *sc) sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; } - btinfo->bt_priority_cnt = 0; - btinfo->bt_priority_time = jiffies; + btcoex->bt_priority_cnt = 0; + btcoex->bt_priority_time = jiffies; } } @@ -106,29 +106,30 @@ static void ath_btcoex_bt_stomp(struct ath_softc *sc, static void ath_btcoex_period_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *) data; + struct ath_btcoex *btcoex = &sc->btcoex; struct ath_btcoex_info *btinfo = &sc->btcoex_info; ath_detect_bt_priority(sc); - spin_lock_bh(&btinfo->btcoex_lock); + spin_lock_bh(&btcoex->btcoex_lock); ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); - spin_unlock_bh(&btinfo->btcoex_lock); + spin_unlock_bh(&btcoex->btcoex_lock); - if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) { - if (btinfo->hw_timer_enabled) + if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { + if (btcoex->hw_timer_enabled) ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); ath_gen_timer_start(sc->sc_ah, btinfo->no_stomp_timer, (ath9k_hw_gettsf32(sc->sc_ah) + - btinfo->btcoex_no_stomp), - btinfo->btcoex_no_stomp * 10); - btinfo->hw_timer_enabled = true; + btcoex->btcoex_no_stomp), + btcoex->btcoex_no_stomp * 10); + btcoex->hw_timer_enabled = true; } - mod_timer(&btinfo->period_timer, jiffies + + mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); } @@ -140,23 +141,25 @@ static void ath_btcoex_period_timer(unsigned long data) static void ath_btcoex_no_stomp_timer(void *arg) { struct ath_softc *sc = (struct ath_softc *)arg; + struct ath_btcoex *btcoex = &sc->btcoex; struct ath_btcoex_info *btinfo = &sc->btcoex_info; DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); - spin_lock_bh(&btinfo->btcoex_lock); + spin_lock_bh(&btcoex->btcoex_lock); if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); - spin_unlock_bh(&btinfo->btcoex_lock); + spin_unlock_bh(&btcoex->btcoex_lock); } static int ath_init_btcoex_info(struct ath_hw *hw, struct ath_btcoex_info *btcoex_info) { + struct ath_btcoex *btcoex = &hw->ah_sc->btcoex; u32 i; int qnum; @@ -181,15 +184,15 @@ static int ath_init_btcoex_info(struct ath_hw *hw, btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - btcoex_info->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; + btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; - btcoex_info->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * - btcoex_info->btcoex_period / 100; + btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * + btcoex->btcoex_period / 100; for (i = 0; i < 32; i++) hw->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; - setup_timer(&btcoex_info->period_timer, ath_btcoex_period_timer, + setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, (unsigned long) hw->ah_sc); btcoex_info->no_stomp_timer = ath_gen_timer_alloc(hw, @@ -200,7 +203,7 @@ static int ath_init_btcoex_info(struct ath_hw *hw, if (btcoex_info->no_stomp_timer == NULL) return -ENOMEM; - spin_lock_init(&btcoex_info->btcoex_lock); + spin_lock_init(&btcoex->btcoex_lock); return 0; } @@ -307,34 +310,34 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) /* * Pause btcoex timer and bt duty cycle timer */ -void ath_btcoex_timer_pause(struct ath_softc *sc, - struct ath_btcoex_info *btinfo) +void ath_btcoex_timer_pause(struct ath_softc *sc) { + struct ath_btcoex *btcoex = &sc->btcoex; - del_timer_sync(&btinfo->period_timer); + del_timer_sync(&btcoex->period_timer); - if (btinfo->hw_timer_enabled) - ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); + if (btcoex->hw_timer_enabled) + ath_gen_timer_stop(sc->sc_ah, sc->btcoex_info.no_stomp_timer); - btinfo->hw_timer_enabled = false; + btcoex->hw_timer_enabled = false; } /* * (Re)start btcoex timers */ -void ath_btcoex_timer_resume(struct ath_softc *sc, - struct ath_btcoex_info *btinfo) +void ath_btcoex_timer_resume(struct ath_softc *sc) { + struct ath_btcoex *btcoex = &sc->btcoex; DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "Starting btcoex timers"); /* make sure duty cycle timer is also stopped when resuming */ - if (btinfo->hw_timer_enabled) - ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); + if (btcoex->hw_timer_enabled) + ath_gen_timer_stop(sc->sc_ah, sc->btcoex_info.no_stomp_timer); - btinfo->bt_priority_cnt = 0; - btinfo->bt_priority_time = jiffies; + btcoex->bt_priority_cnt = 0; + btcoex->bt_priority_time = jiffies; sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; - mod_timer(&btinfo->period_timer, jiffies); + mod_timer(&btcoex->period_timer, jiffies); } diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 297b027fd3c3..6cbbc14f9c39 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -70,13 +70,6 @@ struct ath_btcoex_info { u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */ u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */ u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ - u32 btcoex_no_stomp; /* in usec */ - u32 btcoex_period; /* in usec */ - u32 bt_priority_cnt; - unsigned long bt_priority_time; - bool hw_timer_enabled; - spinlock_t btcoex_lock; - struct timer_list period_timer; /* Timer for BT period */ struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/ }; @@ -84,16 +77,15 @@ bool ath_btcoex_supported(u16 subsysid); int ath9k_hw_btcoex_init(struct ath_hw *ah); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); -void ath_btcoex_timer_resume(struct ath_softc *sc, - struct ath_btcoex_info *btinfo); -void ath_btcoex_timer_pause(struct ath_softc *sc, - struct ath_btcoex_info *btinfo); + +void ath_btcoex_timer_resume(struct ath_softc *sc); +void ath_btcoex_timer_pause(struct ath_softc *sc); static inline void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info, u32 bt_weight, u32 wlan_weight) { - btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | + btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | SM(wlan_weight, AR_BTCOEX_WL_WGHT); } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 68d8dd9602dc..612e83678b23 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2013,7 +2013,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ath_pcie_aspm_disable(sc); if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) - ath_btcoex_timer_resume(sc, &sc->btcoex_info); + ath_btcoex_timer_resume(sc); } mutex_unlock: @@ -2152,7 +2152,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) { ath9k_hw_btcoex_disable(sc->sc_ah); if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) - ath_btcoex_timer_pause(sc, &sc->btcoex_info); + ath_btcoex_timer_pause(sc); } /* make sure h/w will not generate any interrupt -- cgit v1.2.3 From af03abecd8e3646736904431f3335dad5e28cb8d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 02:33:11 -0700 Subject: ath9k: move hw specific btcoex info to ath_hw Since we now access it via the ath_hw declare the ath_hw pointer at the header of some routines and se it. ath9k.h no longer needs to access btcoex.h and to adjust for this move ath_btcoex_set_weight() into btcoex.h and instead give main.c a helper for setting initial values upon drv_start() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 - drivers/net/wireless/ath/ath9k/btcoex.c | 57 ++++++++++++++++++--------- drivers/net/wireless/ath/ath9k/btcoex.h | 14 ++----- drivers/net/wireless/ath/ath9k/hw.c | 3 +- drivers/net/wireless/ath/ath9k/hw.h | 7 ++++ drivers/net/wireless/ath/ath9k/main.c | 70 ++++++++++++++++++--------------- 6 files changed, 88 insertions(+), 65 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 831874c621ec..e8a630ccfd96 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -26,7 +26,6 @@ #include "rc.h" #include "debug.h" #include "../ath.h" -#include "btcoex.h" struct ath_node; @@ -622,7 +621,6 @@ struct ath_softc { struct ath_bus_ops *bus_ops; struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; - struct ath_btcoex_info btcoex_info; struct ath_btcoex btcoex; }; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index e88a0a3f68f0..dfbcbd0969e6 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -43,14 +43,29 @@ bool ath_btcoex_supported(u16 subsysid) return false; } +static void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info, + u32 bt_weight, + u32 wlan_weight) +{ + btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | + SM(wlan_weight, AR_BTCOEX_WL_WGHT); +} + +void ath9k_hw_btcoex_init_weight(struct ath_hw *ah) +{ + ath_btcoex_set_weight(&ah->btcoex_info, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); +} + /* * Detects if there is any priority bt traffic */ static void ath_detect_bt_priority(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; - if (ath9k_hw_gpio_get(sc->sc_ah, sc->btcoex_info.btpriority_gpio)) + if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_info.btpriority_gpio)) btcoex->bt_priority_cnt++; if (time_after(jiffies, btcoex->bt_priority_time + @@ -106,8 +121,9 @@ static void ath_btcoex_bt_stomp(struct ath_softc *sc, static void ath_btcoex_period_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *) data; + struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_btcoex_info *btinfo = &sc->btcoex_info; + struct ath_btcoex_info *btinfo = &ah->btcoex_info; ath_detect_bt_priority(sc); @@ -119,9 +135,9 @@ static void ath_btcoex_period_timer(unsigned long data) if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { if (btcoex->hw_timer_enabled) - ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); + ath_gen_timer_stop(ah, btinfo->no_stomp_timer); - ath_gen_timer_start(sc->sc_ah, + ath_gen_timer_start(ah, btinfo->no_stomp_timer, (ath9k_hw_gettsf32(sc->sc_ah) + btcoex->btcoex_no_stomp), @@ -141,10 +157,11 @@ static void ath_btcoex_period_timer(unsigned long data) static void ath_btcoex_no_stomp_timer(void *arg) { struct ath_softc *sc = (struct ath_softc *)arg; + struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_btcoex_info *btinfo = &sc->btcoex_info; + struct ath_btcoex_info *btinfo = &ah->btcoex_info; - DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); + DPRINTF(ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); spin_lock_bh(&btcoex->btcoex_lock); @@ -156,14 +173,14 @@ static void ath_btcoex_no_stomp_timer(void *arg) spin_unlock_bh(&btcoex->btcoex_lock); } -static int ath_init_btcoex_info(struct ath_hw *hw, +static int ath_init_btcoex_info(struct ath_hw *ah, struct ath_btcoex_info *btcoex_info) { - struct ath_btcoex *btcoex = &hw->ah_sc->btcoex; + struct ath_btcoex *btcoex = &ah->ah_sc->btcoex; u32 i; int qnum; - qnum = ath_tx_get_qnum(hw->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); + qnum = ath_tx_get_qnum(ah->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); btcoex_info->bt_coex_mode = (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) | @@ -190,15 +207,15 @@ static int ath_init_btcoex_info(struct ath_hw *hw, btcoex->btcoex_period / 100; for (i = 0; i < 32; i++) - hw->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; + ah->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, - (unsigned long) hw->ah_sc); + (unsigned long) ah->ah_sc); - btcoex_info->no_stomp_timer = ath_gen_timer_alloc(hw, + btcoex_info->no_stomp_timer = ath_gen_timer_alloc(ah, ath_btcoex_no_stomp_timer, ath_btcoex_no_stomp_timer, - (void *)hw->ah_sc, AR_FIRST_NDP_TIMER); + (void *)ah->ah_sc, AR_FIRST_NDP_TIMER); if (btcoex_info->no_stomp_timer == NULL) return -ENOMEM; @@ -210,7 +227,7 @@ static int ath_init_btcoex_info(struct ath_hw *hw, int ath9k_hw_btcoex_init(struct ath_hw *ah) { - struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; int ret = 0; if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { @@ -258,7 +275,7 @@ int ath9k_hw_btcoex_init(struct ath_hw *ah) void ath9k_hw_btcoex_enable(struct ath_hw *ah) { - struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { /* Configure the desired GPIO port for TX_FRAME output */ @@ -291,7 +308,7 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) void ath9k_hw_btcoex_disable(struct ath_hw *ah) { - struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0); @@ -313,11 +330,12 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) void ath_btcoex_timer_pause(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; del_timer_sync(&btcoex->period_timer); if (btcoex->hw_timer_enabled) - ath_gen_timer_stop(sc->sc_ah, sc->btcoex_info.no_stomp_timer); + ath_gen_timer_stop(ah, ah->btcoex_info.no_stomp_timer); btcoex->hw_timer_enabled = false; } @@ -328,12 +346,13 @@ void ath_btcoex_timer_pause(struct ath_softc *sc) void ath_btcoex_timer_resume(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; - DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "Starting btcoex timers"); + DPRINTF(ah, ATH_DBG_BTCOEX, "Starting btcoex timers"); /* make sure duty cycle timer is also stopped when resuming */ if (btcoex->hw_timer_enabled) - ath_gen_timer_stop(sc->sc_ah, sc->btcoex_info.no_stomp_timer); + ath_gen_timer_stop(sc->sc_ah, ah->btcoex_info.no_stomp_timer); btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 6cbbc14f9c39..12e86b70d950 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -17,6 +17,8 @@ #ifndef BTCOEX_H #define BTCOEX_H +#include "hw.h" + #define ATH_WLANACTIVE_GPIO 5 #define ATH_BTACTIVE_GPIO 6 #define ATH_BTPRIORITY_GPIO 7 @@ -74,19 +76,9 @@ struct ath_btcoex_info { }; bool ath_btcoex_supported(u16 subsysid); +void ath9k_hw_btcoex_init_weight(struct ath_hw *ah); int ath9k_hw_btcoex_init(struct ath_hw *ah); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); -void ath_btcoex_timer_resume(struct ath_softc *sc); -void ath_btcoex_timer_pause(struct ath_softc *sc); - -static inline void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info, - u32 bt_weight, - u32 wlan_weight) -{ - btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | - SM(wlan_weight, AR_BTCOEX_WL_WGHT); -} - #endif diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0342091dfe7d..6e33aadc161c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -18,6 +18,7 @@ #include #include +#include "hw.h" #include "ath9k.h" #include "initvals.h" @@ -3558,7 +3559,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); - struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; + struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; u16 capField = 0, eeval; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index b89234571829..f2b3a601d6a9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -27,6 +27,7 @@ #include "calib.h" #include "reg.h" #include "phy.h" +#include "btcoex.h" #include "../regd.h" @@ -553,6 +554,9 @@ struct ath_hw { int firpwr[5]; enum ath9k_ani_cmd ani_function; + /* Bluetooth coexistance */ + struct ath_btcoex_info btcoex_info; + u32 intr_txqs; enum ath9k_ht_extprotspacing extprotspacing; u8 txchainmask; @@ -675,4 +679,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); #define ATH_PCIE_CAP_LINK_L1 2 void ath_pcie_aspm_disable(struct ath_softc *sc); + +void ath_btcoex_timer_resume(struct ath_softc *sc); +void ath_btcoex_timer_pause(struct ath_softc *sc); #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 612e83678b23..63e1f183b470 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -16,6 +16,7 @@ #include #include "ath9k.h" +#include "btcoex.h" static char *dev_info = "ath9k"; @@ -439,8 +440,10 @@ static void ath_start_ani(struct ath_softc *sc) */ void ath_update_chainmask(struct ath_softc *sc, int is_ht) { + struct ath_hw *ah = sc->sc_ah; + if ((sc->sc_flags & SC_OP_SCANNING) || is_ht || - (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE)) { + (ah->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE)) { sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask; } else { @@ -448,7 +451,7 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht) sc->rx_chainmask = 1; } - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", + DPRINTF(ah, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", sc->tx_chainmask, sc->rx_chainmask); } @@ -478,6 +481,8 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) static void ath9k_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; + struct ath_hw *ah = sc->sc_ah; + u32 status = sc->intrstatus; ath9k_ps_wakeup(sc); @@ -502,16 +507,16 @@ static void ath9k_tasklet(unsigned long data) * TSF sync does not look correct; remain awake to sync with * the next Beacon. */ - DPRINTF(sc->sc_ah, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); + DPRINTF(ah, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; } - if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) if (status & ATH9K_INT_GENTIMER) ath_gen_timer_isr(sc->sc_ah); /* re-enable hardware interrupt */ - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_hw_set_interrupts(ah, sc->imask); ath9k_ps_restore(sc); } @@ -1281,12 +1286,12 @@ void ath_detach(struct ath_softc *sc) if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); - if ((sc->btcoex_info.no_stomp_timer) && - sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) - ath_gen_timer_free(ah, sc->btcoex_info.no_stomp_timer); + if ((ah->btcoex_info.no_stomp_timer) && + ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + ath_gen_timer_free(ah, ah->btcoex_info.no_stomp_timer); ath9k_hw_detach(ah); - ath9k_exit_debug(sc->sc_ah); + ath9k_exit_debug(ah); sc->sc_ah = NULL; } @@ -1516,7 +1521,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) ARRAY_SIZE(ath9k_5ghz_chantable); } - if (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) { + if (ah->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) { r = ath9k_hw_btcoex_init(ah); if (r) goto bad2; @@ -1905,11 +1910,12 @@ static int ath9k_start(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_hw *ah = sc->sc_ah; struct ieee80211_channel *curchan = hw->conf.channel; struct ath9k_channel *init_channel; int r; - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Starting driver with " + DPRINTF(ah, ATH_DBG_CONFIG, "Starting driver with " "initial channel: %d MHz\n", curchan->center_freq); mutex_lock(&sc->mutex); @@ -1942,7 +1948,7 @@ static int ath9k_start(struct ieee80211_hw *hw) init_channel = ath_get_curchannel(sc, hw); /* Reset SERDES registers */ - ath9k_hw_configpcipowersave(sc->sc_ah, 0, 0); + ath9k_hw_configpcipowersave(ah, 0, 0); /* * The basic interface to setting the hardware in a good @@ -1952,9 +1958,9 @@ static int ath9k_start(struct ieee80211_hw *hw) * and then setup of the interrupt mask. */ spin_lock_bh(&sc->sc_resetlock); - r = ath9k_hw_reset(sc->sc_ah, init_channel, false); + r = ath9k_hw_reset(ah, init_channel, false); if (r) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, + DPRINTF(ah, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d " "(freq %u MHz)\n", r, curchan->center_freq); @@ -1977,7 +1983,7 @@ static int ath9k_start(struct ieee80211_hw *hw) * here except setup the interrupt mask. */ if (ath_startrecv(sc) != 0) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to start recv logic\n"); + DPRINTF(ah, ATH_DBG_FATAL, "Unable to start recv logic\n"); r = -EIO; goto mutex_unlock; } @@ -1987,10 +1993,10 @@ static int ath9k_start(struct ieee80211_hw *hw) | ATH9K_INT_RXEOL | ATH9K_INT_RXORN | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_GTT) + if (ah->caps.hw_caps & ATH9K_HW_CAP_GTT) sc->imask |= ATH9K_INT_GTT; - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) + if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) sc->imask |= ATH9K_INT_CST; ath_cache_conf_rate(sc, &hw->conf); @@ -1999,20 +2005,19 @@ static int ath9k_start(struct ieee80211_hw *hw) /* Disable BMISS interrupt when we're not associated */ sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_hw_set_interrupts(ah, sc->imask); ieee80211_wake_queues(hw); ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); - if ((sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) && + if ((ah->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) && !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) { - ath_btcoex_set_weight(&sc->btcoex_info, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); - ath9k_hw_btcoex_enable(sc->sc_ah); + ath9k_hw_btcoex_init_weight(ah); + ath9k_hw_btcoex_enable(ah); ath_pcie_aspm_disable(sc); - if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) ath_btcoex_timer_resume(sc); } @@ -2125,6 +2130,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_hw *ah = sc->sc_ah; mutex_lock(&sc->mutex); @@ -2139,7 +2145,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) } if (sc->sc_flags & SC_OP_INVALID) { - DPRINTF(sc->sc_ah, ATH_DBG_ANY, "Device not present\n"); + DPRINTF(ah, ATH_DBG_ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; } @@ -2150,32 +2156,32 @@ static void ath9k_stop(struct ieee80211_hw *hw) } if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) { - ath9k_hw_btcoex_disable(sc->sc_ah); - if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + ath9k_hw_btcoex_disable(ah); + if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) ath_btcoex_timer_pause(sc); } /* make sure h/w will not generate any interrupt * before setting the invalid flag. */ - ath9k_hw_set_interrupts(sc->sc_ah, 0); + ath9k_hw_set_interrupts(ah, 0); if (!(sc->sc_flags & SC_OP_INVALID)) { ath_drain_all_txq(sc, false); ath_stoprecv(sc); - ath9k_hw_phy_disable(sc->sc_ah); + ath9k_hw_phy_disable(ah); } else sc->rx.rxlink = NULL; /* disable HAL and put h/w to sleep */ - ath9k_hw_disable(sc->sc_ah); - ath9k_hw_configpcipowersave(sc->sc_ah, 1, 1); - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); + ath9k_hw_disable(ah); + ath9k_hw_configpcipowersave(ah, 1, 1); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); sc->sc_flags |= SC_OP_INVALID; mutex_unlock(&sc->mutex); - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Driver halt\n"); + DPRINTF(ah, ATH_DBG_CONFIG, "Driver halt\n"); } static int ath9k_add_interface(struct ieee80211_hw *hw, -- cgit v1.2.3 From 7a2f0f58c865be9217356528ab6cf73feb35cb07 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 02:54:40 -0700 Subject: ath9k: split bluetooth hardware coex init into two helpers Use a helper for 2-wire and another for 3-wire. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.c | 75 +++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index dfbcbd0969e6..be699241ca75 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -225,48 +225,61 @@ static int ath_init_btcoex_info(struct ath_hw *ah, return 0; } -int ath9k_hw_btcoex_init(struct ath_hw *ah) +static void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) { struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; - int ret = 0; - if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { - /* connect bt_active to baseband */ - REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, - (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | - AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); + /* connect bt_active to baseband */ + REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, + (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | + AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); - /* Set input mux for bt_active to gpio pin */ - REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, - AR_GPIO_INPUT_MUX1_BT_ACTIVE, - btcoex_info->btactive_gpio); + /* Set input mux for bt_active to gpio pin */ + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + btcoex_info->btactive_gpio); - /* Configure the desired gpio port for input */ - ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); - } else { - /* btcoex 3-wire */ - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB | - AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB)); + /* Configure the desired gpio port for input */ + ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); +} + +static void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) +{ + struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; - /* Set input mux for bt_prority_async and - * bt_active_async to GPIO pins */ - REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, - AR_GPIO_INPUT_MUX1_BT_ACTIVE, - btcoex_info->btactive_gpio); + /* btcoex 3-wire */ + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB | + AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB)); - REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, - AR_GPIO_INPUT_MUX1_BT_PRIORITY, - btcoex_info->btpriority_gpio); + /* Set input mux for bt_prority_async and + * bt_active_async to GPIO pins */ + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + btcoex_info->btactive_gpio); - /* Configure the desired GPIO ports for input */ + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, + AR_GPIO_INPUT_MUX1_BT_PRIORITY, + btcoex_info->btpriority_gpio); - ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); - ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio); + /* Configure the desired GPIO ports for input */ + + ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); + ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio); +} + +int ath9k_hw_btcoex_init(struct ath_hw *ah) +{ + struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; + int ret = 0; + if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) + ath9k_hw_btcoex_init_2wire(ah); + else { + ath9k_hw_btcoex_init_3wire(ah); ret = ath_init_btcoex_info(ah, btcoex_info); } -- cgit v1.2.3 From 75d7839f4c4ca472bcf0b71f6f682957e19f777a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 04:00:10 -0700 Subject: ath9k: move driver core helpers to main.c Keep on btcoex.c only hardware access helpers, move the driver core specific code to main.c. To accomplish this we had to split ath_init_btcoex_info() into two parts, the driver core part -- ath_init_btcoex_timer() and the hw specific part -- ath9k_hw_init_btcoex_hw_info(). This highlights how ath_gen_timer is part of the driver core, not hw related, so stuff that into ath_btcoex struct. The ath9k_hw_btcoex_init() code is now put inline on ath_init_softc() through a switch to it easier to follow, since we did that we can now call ath_tx_get_qnum() from the main.c instead of btcoex.c Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/btcoex.c | 214 +------------------------------ drivers/net/wireless/ath/ath9k/btcoex.h | 7 +- drivers/net/wireless/ath/ath9k/hw.h | 3 - drivers/net/wireless/ath/ath9k/main.c | 215 +++++++++++++++++++++++++++++++- 5 files changed, 218 insertions(+), 222 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e8a630ccfd96..f001cc262660 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -458,6 +458,7 @@ struct ath_btcoex { unsigned long bt_priority_time; u32 btcoex_no_stomp; /* in usec */ u32 btcoex_period; /* in usec */ + struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ }; /********************/ diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index be699241ca75..6209a56f7a9a 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -43,144 +43,10 @@ bool ath_btcoex_supported(u16 subsysid) return false; } -static void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info, - u32 bt_weight, - u32 wlan_weight) +void ath9k_hw_init_btcoex_hw_info(struct ath_hw *ah, int qnum) { - btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | - SM(wlan_weight, AR_BTCOEX_WL_WGHT); -} - -void ath9k_hw_btcoex_init_weight(struct ath_hw *ah) -{ - ath_btcoex_set_weight(&ah->btcoex_info, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); -} - -/* - * Detects if there is any priority bt traffic - */ -static void ath_detect_bt_priority(struct ath_softc *sc) -{ - struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_hw *ah = sc->sc_ah; - - if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_info.btpriority_gpio)) - btcoex->bt_priority_cnt++; - - if (time_after(jiffies, btcoex->bt_priority_time + - msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { - if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { - DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, - "BT priority traffic detected"); - sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; - } else { - sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; - } - - btcoex->bt_priority_cnt = 0; - btcoex->bt_priority_time = jiffies; - } -} - -/* - * Configures appropriate weight based on stomp type. - */ -static void ath_btcoex_bt_stomp(struct ath_softc *sc, - struct ath_btcoex_info *btinfo, - int stomp_type) -{ - - switch (stomp_type) { - case ATH_BTCOEX_STOMP_ALL: - ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, - AR_STOMP_ALL_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_LOW: - ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_NONE: - ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, - AR_STOMP_NONE_WLAN_WGHT); - break; - default: - DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); - break; - } - - ath9k_hw_btcoex_enable(sc->sc_ah); -} - -/* - * This is the master bt coex timer which runs for every - * 45ms, bt traffic will be given priority during 55% of this - * period while wlan gets remaining 45% - */ - -static void ath_btcoex_period_timer(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *) data; - struct ath_hw *ah = sc->sc_ah; - struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_btcoex_info *btinfo = &ah->btcoex_info; - - ath_detect_bt_priority(sc); - - spin_lock_bh(&btcoex->btcoex_lock); - - ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); - - spin_unlock_bh(&btcoex->btcoex_lock); - - if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { - if (btcoex->hw_timer_enabled) - ath_gen_timer_stop(ah, btinfo->no_stomp_timer); - - ath_gen_timer_start(ah, - btinfo->no_stomp_timer, - (ath9k_hw_gettsf32(sc->sc_ah) + - btcoex->btcoex_no_stomp), - btcoex->btcoex_no_stomp * 10); - btcoex->hw_timer_enabled = true; - } - - mod_timer(&btcoex->period_timer, jiffies + - msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); -} - -/* - * Generic tsf based hw timer which configures weight - * registers to time slice between wlan and bt traffic - */ - -static void ath_btcoex_no_stomp_timer(void *arg) -{ - struct ath_softc *sc = (struct ath_softc *)arg; - struct ath_hw *ah = sc->sc_ah; - struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_btcoex_info *btinfo = &ah->btcoex_info; - - DPRINTF(ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); - - spin_lock_bh(&btcoex->btcoex_lock); - - if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) - ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); - else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) - ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); - - spin_unlock_bh(&btcoex->btcoex_lock); -} - -static int ath_init_btcoex_info(struct ath_hw *ah, - struct ath_btcoex_info *btcoex_info) -{ - struct ath_btcoex *btcoex = &ah->ah_sc->btcoex; + struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; u32 i; - int qnum; - - qnum = ath_tx_get_qnum(ah->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); btcoex_info->bt_coex_mode = (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) | @@ -201,31 +67,11 @@ static int ath_init_btcoex_info(struct ath_hw *ah, btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; - - btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * - btcoex->btcoex_period / 100; - for (i = 0; i < 32; i++) ah->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; - - setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, - (unsigned long) ah->ah_sc); - - btcoex_info->no_stomp_timer = ath_gen_timer_alloc(ah, - ath_btcoex_no_stomp_timer, - ath_btcoex_no_stomp_timer, - (void *)ah->ah_sc, AR_FIRST_NDP_TIMER); - - if (btcoex_info->no_stomp_timer == NULL) - return -ENOMEM; - - spin_lock_init(&btcoex->btcoex_lock); - - return 0; } -static void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) +void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) { struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; @@ -246,7 +92,7 @@ static void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); } -static void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) +void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) { struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; @@ -271,21 +117,6 @@ static void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio); } -int ath9k_hw_btcoex_init(struct ath_hw *ah) -{ - struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; - int ret = 0; - - if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) - ath9k_hw_btcoex_init_2wire(ah); - else { - ath9k_hw_btcoex_init_3wire(ah); - ret = ath_init_btcoex_info(ah, btcoex_info); - } - - return ret; -} - void ath9k_hw_btcoex_enable(struct ath_hw *ah) { struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; @@ -336,40 +167,3 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; } - -/* - * Pause btcoex timer and bt duty cycle timer - */ -void ath_btcoex_timer_pause(struct ath_softc *sc) -{ - struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_hw *ah = sc->sc_ah; - - del_timer_sync(&btcoex->period_timer); - - if (btcoex->hw_timer_enabled) - ath_gen_timer_stop(ah, ah->btcoex_info.no_stomp_timer); - - btcoex->hw_timer_enabled = false; -} - -/* - * (Re)start btcoex timers - */ -void ath_btcoex_timer_resume(struct ath_softc *sc) -{ - struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_hw *ah = sc->sc_ah; - - DPRINTF(ah, ATH_DBG_BTCOEX, "Starting btcoex timers"); - - /* make sure duty cycle timer is also stopped when resuming */ - if (btcoex->hw_timer_enabled) - ath_gen_timer_stop(sc->sc_ah, ah->btcoex_info.no_stomp_timer); - - btcoex->bt_priority_cnt = 0; - btcoex->bt_priority_time = jiffies; - sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; - - mod_timer(&btcoex->period_timer, jiffies); -} diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 12e86b70d950..ed8d01d2f762 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -72,13 +72,14 @@ struct ath_btcoex_info { u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */ u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */ u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ - struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/ }; bool ath_btcoex_supported(u16 subsysid); -void ath9k_hw_btcoex_init_weight(struct ath_hw *ah); -int ath9k_hw_btcoex_init(struct ath_hw *ah); +void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah); +void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah); +void ath9k_hw_init_btcoex_hw_info(struct ath_hw *ah, int qnum); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); + #endif diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f2b3a601d6a9..b244225ca050 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -679,7 +679,4 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); #define ATH_PCIE_CAP_LINK_L1 2 void ath_pcie_aspm_disable(struct ath_softc *sc); - -void ath_btcoex_timer_resume(struct ath_softc *sc); -void ath_btcoex_timer_pause(struct ath_softc *sc); #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 63e1f183b470..9ac1ee0638f0 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1286,9 +1286,9 @@ void ath_detach(struct ath_softc *sc) if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); - if ((ah->btcoex_info.no_stomp_timer) && + if ((sc->btcoex.no_stomp_timer) && ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) - ath_gen_timer_free(ah, ah->btcoex_info.no_stomp_timer); + ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); ath9k_hw_detach(ah); ath9k_exit_debug(ah); @@ -1306,6 +1306,158 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, return ath_reg_notifier_apply(wiphy, request, reg); } +/* + * Detects if there is any priority bt traffic + */ +static void ath_detect_bt_priority(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; + + if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_info.btpriority_gpio)) + btcoex->bt_priority_cnt++; + + if (time_after(jiffies, btcoex->bt_priority_time + + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { + if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { + DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, + "BT priority traffic detected"); + sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; + } else { + sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; + } + + btcoex->bt_priority_cnt = 0; + btcoex->bt_priority_time = jiffies; + } +} + +static void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info, + u32 bt_weight, + u32 wlan_weight) +{ + btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | + SM(wlan_weight, AR_BTCOEX_WL_WGHT); +} + +static void ath9k_hw_btcoex_init_weight(struct ath_hw *ah) +{ + ath_btcoex_set_weight(&ah->btcoex_info, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); +} + +/* + * Configures appropriate weight based on stomp type. + */ +static void ath_btcoex_bt_stomp(struct ath_softc *sc, + struct ath_btcoex_info *btinfo, + int stomp_type) +{ + + switch (stomp_type) { + case ATH_BTCOEX_STOMP_ALL: + ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + AR_STOMP_ALL_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_LOW: + ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_NONE: + ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + AR_STOMP_NONE_WLAN_WGHT); + break; + default: + DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); + break; + } + + ath9k_hw_btcoex_enable(sc->sc_ah); +} + +/* + * This is the master bt coex timer which runs for every + * 45ms, bt traffic will be given priority during 55% of this + * period while wlan gets remaining 45% + */ +static void ath_btcoex_period_timer(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *) data; + struct ath_hw *ah = sc->sc_ah; + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_btcoex_info *btinfo = &ah->btcoex_info; + + ath_detect_bt_priority(sc); + + spin_lock_bh(&btcoex->btcoex_lock); + + ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); + + spin_unlock_bh(&btcoex->btcoex_lock); + + if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { + if (btcoex->hw_timer_enabled) + ath_gen_timer_stop(ah, btcoex->no_stomp_timer); + + ath_gen_timer_start(ah, + btcoex->no_stomp_timer, + (ath9k_hw_gettsf32(ah) + + btcoex->btcoex_no_stomp), + btcoex->btcoex_no_stomp * 10); + btcoex->hw_timer_enabled = true; + } + + mod_timer(&btcoex->period_timer, jiffies + + msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); +} + +/* + * Generic tsf based hw timer which configures weight + * registers to time slice between wlan and bt traffic + */ +static void ath_btcoex_no_stomp_timer(void *arg) +{ + struct ath_softc *sc = (struct ath_softc *)arg; + struct ath_hw *ah = sc->sc_ah; + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_btcoex_info *btinfo = &ah->btcoex_info; + + DPRINTF(ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); + + spin_lock_bh(&btcoex->btcoex_lock); + + if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) + ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); + else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) + ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); + + spin_unlock_bh(&btcoex->btcoex_lock); +} + +static int ath_init_btcoex_timer(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + + btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; + btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * + btcoex->btcoex_period / 100; + + setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, + (unsigned long) sc); + + spin_lock_init(&btcoex->btcoex_lock); + + btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah, + ath_btcoex_no_stomp_timer, + ath_btcoex_no_stomp_timer, + (void *) sc, AR_FIRST_NDP_TIMER); + + if (!btcoex->no_stomp_timer) + return -ENOMEM; + + return 0; +} + /* * Initialize and fill ath_softc, ath_sofct is the * "Software Carrier" struct. Historically it has existed @@ -1317,6 +1469,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) struct ath_hw *ah = NULL; int r = 0, i; int csz = 0; + int qnum; /* XXX: hardware will not be ready until ath_open() being called */ sc->sc_flags |= SC_OP_INVALID; @@ -1521,10 +1674,23 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) ARRAY_SIZE(ath9k_5ghz_chantable); } - if (ah->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) { - r = ath9k_hw_btcoex_init(ah); + switch (ah->btcoex_info.btcoex_scheme) { + case ATH_BTCOEX_CFG_NONE: + break; + case ATH_BTCOEX_CFG_2WIRE: + ath9k_hw_btcoex_init_2wire(ah); + break; + case ATH_BTCOEX_CFG_3WIRE: + ath9k_hw_btcoex_init_3wire(ah); + r = ath_init_btcoex_timer(sc); if (r) goto bad2; + qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); + ath9k_hw_init_btcoex_hw_info(ah, qnum); + break; + default: + WARN_ON(1); + break; } return 0; @@ -1906,6 +2072,27 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, /* mac80211 callbacks */ /**********************/ +/* + * (Re)start btcoex timers + */ +static void ath9k_btcoex_timer_resume(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; + + DPRINTF(ah, ATH_DBG_BTCOEX, "Starting btcoex timers"); + + /* make sure duty cycle timer is also stopped when resuming */ + if (btcoex->hw_timer_enabled) + ath_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); + + btcoex->bt_priority_cnt = 0; + btcoex->bt_priority_time = jiffies; + sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; + + mod_timer(&btcoex->period_timer, jiffies); +} + static int ath9k_start(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; @@ -2018,7 +2205,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ath_pcie_aspm_disable(sc); if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) - ath_btcoex_timer_resume(sc); + ath9k_btcoex_timer_resume(sc); } mutex_unlock: @@ -2126,6 +2313,22 @@ exit: return 0; } +/* + * Pause btcoex timer and bt duty cycle timer + */ +static void ath9k_btcoex_timer_pause(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + struct ath_hw *ah = sc->sc_ah; + + del_timer_sync(&btcoex->period_timer); + + if (btcoex->hw_timer_enabled) + ath_gen_timer_stop(ah, btcoex->no_stomp_timer); + + btcoex->hw_timer_enabled = false; +} + static void ath9k_stop(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; @@ -2158,7 +2361,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) { ath9k_hw_btcoex_disable(ah); if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) - ath_btcoex_timer_pause(sc); + ath9k_btcoex_timer_pause(sc); } /* make sure h/w will not generate any interrupt -- cgit v1.2.3 From bc74bf8fc382b30df24c4e280fb84f3b1303958f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 04:17:45 -0700 Subject: ath9k: split ath9k_hw_btcoex_enable() into two helpers One for 2-wire and another for 3-wire. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.c | 57 +++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 6209a56f7a9a..61a8e1d95bb9 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -117,30 +117,47 @@ void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio); } +static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah) +{ + struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; + + /* Configure the desired GPIO port for TX_FRAME output */ + ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); +} + +static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) +{ + struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; + + /* + * Program coex mode and weight registers to + * enable coex 3-wire + */ + REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode); + REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights); + REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2); + + REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); + REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); + + ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, + AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL); +} + void ath9k_hw_btcoex_enable(struct ath_hw *ah) { struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; - if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { - /* Configure the desired GPIO port for TX_FRAME output */ - ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); - } else { - /* - * Program coex mode and weight registers to - * enable coex 3-wire - */ - REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode); - REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights); - REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2); - - REG_RMW_FIELD(ah, AR_QUIET1, - AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); - REG_RMW_FIELD(ah, AR_PCU_MISC, - AR_PCU_BT_ANT_PREVENT_RX, 0); - - ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL); + switch (btcoex_info->btcoex_scheme) { + case ATH_BTCOEX_CFG_NONE: + break; + case ATH_BTCOEX_CFG_2WIRE: + ath9k_hw_btcoex_enable_2wire(ah); + break; + case ATH_BTCOEX_CFG_3WIRE: + ath9k_hw_btcoex_enable_3wire(ah); + break; } REG_RMW(ah, AR_GPIO_PDPU, -- cgit v1.2.3 From 8c1b39547e2562f9aa0cc00b1a7d4cc325a46a4c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 13:44:23 -0700 Subject: ath9k: replaces SC_OP_BTCOEX_ENABLED with a bool Whether or not bluetooth coex has been enabled is a hardware state and only the hardware helpers will be able to set this. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/btcoex.c | 4 ++-- drivers/net/wireless/ath/ath9k/btcoex.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index f001cc262660..891e71b10e5c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -532,7 +532,6 @@ struct ath_led { #define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17) #define SC_OP_WAIT_FOR_TX_ACK BIT(18) #define SC_OP_BEACON_SYNC BIT(19) -#define SC_OP_BTCOEX_ENABLED BIT(20) #define SC_OP_BT_PRIORITY_DETECTED BIT(21) struct ath_bus_ops { diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 61a8e1d95bb9..91befc78a15b 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -164,7 +164,7 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) (0x2 << (btcoex_info->btactive_gpio * 2)), (0x3 << (btcoex_info->btactive_gpio * 2))); - ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; + ah->btcoex_info.enabled = true; } void ath9k_hw_btcoex_disable(struct ath_hw *ah) @@ -182,5 +182,5 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) REG_WRITE(ah, AR_BT_COEX_MODE2, 0); } - ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; + ah->btcoex_info.enabled = false; } diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index ed8d01d2f762..b2c3f7669852 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -64,6 +64,7 @@ struct ath_btcoex_config { struct ath_btcoex_info { enum ath_btcoex_scheme btcoex_scheme; + bool enabled; u8 wlanactive_gpio; u8 btactive_gpio; u8 btpriority_gpio; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6e33aadc161c..bbbd454fffef 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2578,7 +2578,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, #endif } - if (ah->ah_sc->sc_flags & SC_OP_BTCOEX_ENABLED) + if (ah->btcoex_info.enabled) ath9k_hw_btcoex_enable(ah); return 0; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9ac1ee0638f0..cd1bc9c27527 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2199,7 +2199,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); if ((ah->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) && - !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) { + !ah->btcoex_info.enabled) { ath9k_hw_btcoex_init_weight(ah); ath9k_hw_btcoex_enable(ah); @@ -2358,7 +2358,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) return; /* another wiphy still in use */ } - if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) { + if (ah->btcoex_info.enabled) { ath9k_hw_btcoex_disable(ah); if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) ath9k_btcoex_timer_pause(sc); -- cgit v1.2.3 From e08a6ace7db089dc111c6d0abe9278226c39b7b0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 14:26:15 -0700 Subject: ath9k: move bt_stomp_type to driver core The bt_stomp_type defines the bt coex weight, it has a one-to-one mapping. In the future we may want to just use the weight directly. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 9 +++++++++ drivers/net/wireless/ath/ath9k/btcoex.c | 2 -- drivers/net/wireless/ath/ath9k/btcoex.h | 8 -------- drivers/net/wireless/ath/ath9k/main.c | 7 ++++--- 4 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 891e71b10e5c..d99c92d7b949 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -450,12 +450,21 @@ struct ath_ani { struct timer_list timer; }; +/* Defines the BT AR_BT_COEX_WGHT used */ +enum ath_stomp_type { + ATH_BTCOEX_NO_STOMP, + ATH_BTCOEX_STOMP_ALL, + ATH_BTCOEX_STOMP_LOW, + ATH_BTCOEX_STOMP_NONE +}; + struct ath_btcoex { bool hw_timer_enabled; spinlock_t btcoex_lock; struct timer_list period_timer; /* Timer for BT period */ u32 bt_priority_cnt; unsigned long bt_priority_time; + int bt_stomp_type; /* Types of BT stomping */ u32 btcoex_no_stomp; /* in usec */ u32 btcoex_period; /* in usec */ struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 91befc78a15b..ab19072493cb 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -65,8 +65,6 @@ void ath9k_hw_init_btcoex_hw_info(struct ath_hw *ah, int qnum) SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | AR_BT_DISABLE_BT_ANT; - btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - for (i = 0; i < 32; i++) ah->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; } diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index b2c3f7669852..d932f01f7731 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -36,13 +36,6 @@ enum ath_btcoex_scheme { ATH_BTCOEX_CFG_3WIRE, }; -enum ath_stomp_type { - ATH_BTCOEX_NO_STOMP, - ATH_BTCOEX_STOMP_ALL, - ATH_BTCOEX_STOMP_LOW, - ATH_BTCOEX_STOMP_NONE -}; - enum ath_bt_mode { ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */ ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */ @@ -69,7 +62,6 @@ struct ath_btcoex_info { u8 btactive_gpio; u8 btpriority_gpio; u8 bt_duty_cycle; /* BT duty cycle in percentage */ - int bt_stomp_type; /* Types of BT stomping */ u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */ u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */ u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cd1bc9c27527..7ca6e3aa7bc4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1391,7 +1391,7 @@ static void ath_btcoex_period_timer(unsigned long data) spin_lock_bh(&btcoex->btcoex_lock); - ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); + ath_btcoex_bt_stomp(sc, btinfo, btcoex->bt_stomp_type); spin_unlock_bh(&btcoex->btcoex_lock); @@ -1426,9 +1426,9 @@ static void ath_btcoex_no_stomp_timer(void *arg) spin_lock_bh(&btcoex->btcoex_lock); - if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) + if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); - else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) + else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); spin_unlock_bh(&btcoex->btcoex_lock); @@ -1687,6 +1687,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) goto bad2; qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); ath9k_hw_init_btcoex_hw_info(ah, qnum); + sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; break; default: WARN_ON(1); -- cgit v1.2.3 From 05a0b3c9200f4677097937efe634204044c4b4dc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 14:31:24 -0700 Subject: ath9k: remove unused bt_duty_cycle Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index d932f01f7731..72c613d9c53d 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -61,7 +61,6 @@ struct ath_btcoex_info { u8 wlanactive_gpio; u8 btactive_gpio; u8 btpriority_gpio; - u8 bt_duty_cycle; /* BT duty cycle in percentage */ u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */ u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */ u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ -- cgit v1.2.3 From 46289e1e5f2155ba1502b079e786e91755919823 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 14:34:22 -0700 Subject: ath9k: rename btcoex_scheme to just scheme btcoex_scheme is already part of a btcoex struct, its implied this is btcoex related. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.c | 4 ++-- drivers/net/wireless/ath/ath9k/btcoex.h | 2 +- drivers/net/wireless/ath/ath9k/hw.c | 6 +++--- drivers/net/wireless/ath/ath9k/main.c | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index ab19072493cb..aa0ec2c2f326 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -147,7 +147,7 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) { struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; - switch (btcoex_info->btcoex_scheme) { + switch (btcoex_info->scheme) { case ATH_BTCOEX_CFG_NONE: break; case ATH_BTCOEX_CFG_2WIRE: @@ -174,7 +174,7 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) { + if (btcoex_info->scheme == ATH_BTCOEX_CFG_3WIRE) { REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); REG_WRITE(ah, AR_BT_COEX_MODE2, 0); diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 72c613d9c53d..aea6d3fbb5b4 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -56,7 +56,7 @@ struct ath_btcoex_config { }; struct ath_btcoex_info { - enum ath_btcoex_scheme btcoex_scheme; + enum ath_btcoex_scheme scheme; bool enabled; u8 wlanactive_gpio; u8 btactive_gpio; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index bbbd454fffef..0b7e2859c1ef 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3733,13 +3733,13 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; if (AR_SREV_9285(ah)) { - btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE; + btcoex_info->scheme = ATH_BTCOEX_CFG_3WIRE; btcoex_info->btpriority_gpio = ATH_BTPRIORITY_GPIO; } else { - btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE; + btcoex_info->scheme = ATH_BTCOEX_CFG_2WIRE; } } else { - btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE; + btcoex_info->scheme = ATH_BTCOEX_CFG_NONE; } } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7ca6e3aa7bc4..3d0eb68c863c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -443,7 +443,7 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht) struct ath_hw *ah = sc->sc_ah; if ((sc->sc_flags & SC_OP_SCANNING) || is_ht || - (ah->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE)) { + (ah->btcoex_info.scheme != ATH_BTCOEX_CFG_NONE)) { sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask; } else { @@ -511,7 +511,7 @@ static void ath9k_tasklet(unsigned long data) sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; } - if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + if (ah->btcoex_info.scheme == ATH_BTCOEX_CFG_3WIRE) if (status & ATH9K_INT_GENTIMER) ath_gen_timer_isr(sc->sc_ah); @@ -1287,7 +1287,7 @@ void ath_detach(struct ath_softc *sc) ath_tx_cleanupq(sc, &sc->tx.txq[i]); if ((sc->btcoex.no_stomp_timer) && - ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + ah->btcoex_info.scheme == ATH_BTCOEX_CFG_3WIRE) ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); ath9k_hw_detach(ah); @@ -1674,7 +1674,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) ARRAY_SIZE(ath9k_5ghz_chantable); } - switch (ah->btcoex_info.btcoex_scheme) { + switch (ah->btcoex_info.scheme) { case ATH_BTCOEX_CFG_NONE: break; case ATH_BTCOEX_CFG_2WIRE: @@ -2199,13 +2199,13 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); - if ((ah->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) && + if ((ah->btcoex_info.scheme != ATH_BTCOEX_CFG_NONE) && !ah->btcoex_info.enabled) { ath9k_hw_btcoex_init_weight(ah); ath9k_hw_btcoex_enable(ah); ath_pcie_aspm_disable(sc); - if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + if (ah->btcoex_info.scheme == ATH_BTCOEX_CFG_3WIRE) ath9k_btcoex_timer_resume(sc); } @@ -2361,7 +2361,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) if (ah->btcoex_info.enabled) { ath9k_hw_btcoex_disable(ah); - if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) + if (ah->btcoex_info.scheme == ATH_BTCOEX_CFG_3WIRE) ath9k_btcoex_timer_pause(sc); } -- cgit v1.2.3 From 766ec4a9a813ae262b61842020f150f865c1b10a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 14:52:02 -0700 Subject: ath9k: rename ath_btcoex_info to ath_btcoex_hw Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.c | 60 ++++++++++++++++----------------- drivers/net/wireless/ath/ath9k/btcoex.h | 4 +-- drivers/net/wireless/ath/ath9k/hw.c | 16 ++++----- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 46 ++++++++++++------------- 5 files changed, 64 insertions(+), 64 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index aa0ec2c2f326..0b5a7d4a6d55 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -43,13 +43,13 @@ bool ath_btcoex_supported(u16 subsysid) return false; } -void ath9k_hw_init_btcoex_hw_info(struct ath_hw *ah, int qnum) +void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) { - struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; u32 i; - btcoex_info->bt_coex_mode = - (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) | + btcoex_hw->bt_coex_mode = + (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) | SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) | SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) | SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | @@ -60,7 +60,7 @@ void ath9k_hw_init_btcoex_hw_info(struct ath_hw *ah, int qnum) SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | SM(qnum, AR_BT_QCU_THRESH); - btcoex_info->bt_coex_mode2 = + btcoex_hw->bt_coex_mode2 = SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) | SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | AR_BT_DISABLE_BT_ANT; @@ -71,7 +71,7 @@ void ath9k_hw_init_btcoex_hw_info(struct ath_hw *ah, int qnum) void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) { - struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; /* connect bt_active to baseband */ REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, @@ -84,15 +84,15 @@ void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) /* Set input mux for bt_active to gpio pin */ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, AR_GPIO_INPUT_MUX1_BT_ACTIVE, - btcoex_info->btactive_gpio); + btcoex_hw->btactive_gpio); /* Configure the desired gpio port for input */ - ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); + ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio); } void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) { - struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; /* btcoex 3-wire */ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, @@ -103,51 +103,51 @@ void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) * bt_active_async to GPIO pins */ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, AR_GPIO_INPUT_MUX1_BT_ACTIVE, - btcoex_info->btactive_gpio); + btcoex_hw->btactive_gpio); REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, AR_GPIO_INPUT_MUX1_BT_PRIORITY, - btcoex_info->btpriority_gpio); + btcoex_hw->btpriority_gpio); /* Configure the desired GPIO ports for input */ - ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); - ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio); + ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio); + ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btpriority_gpio); } static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah) { - struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; /* Configure the desired GPIO port for TX_FRAME output */ - ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, + ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); } static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) { - struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; /* * Program coex mode and weight registers to * enable coex 3-wire */ - REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode); - REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights); - REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2); + REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode); + REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); + REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2); REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); - ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, + ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL); } void ath9k_hw_btcoex_enable(struct ath_hw *ah) { - struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - switch (btcoex_info->scheme) { + switch (btcoex_hw->scheme) { case ATH_BTCOEX_CFG_NONE: break; case ATH_BTCOEX_CFG_2WIRE: @@ -159,26 +159,26 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) } REG_RMW(ah, AR_GPIO_PDPU, - (0x2 << (btcoex_info->btactive_gpio * 2)), - (0x3 << (btcoex_info->btactive_gpio * 2))); + (0x2 << (btcoex_hw->btactive_gpio * 2)), + (0x3 << (btcoex_hw->btactive_gpio * 2))); - ah->btcoex_info.enabled = true; + ah->btcoex_hw.enabled = true; } void ath9k_hw_btcoex_disable(struct ath_hw *ah) { - struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0); + ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0); - ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, + ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - if (btcoex_info->scheme == ATH_BTCOEX_CFG_3WIRE) { + if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) { REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); REG_WRITE(ah, AR_BT_COEX_MODE2, 0); } - ah->btcoex_info.enabled = false; + ah->btcoex_hw.enabled = false; } diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index aea6d3fbb5b4..296ddd8ce813 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -55,7 +55,7 @@ struct ath_btcoex_config { bool bt_hold_rx_clear; }; -struct ath_btcoex_info { +struct ath_btcoex_hw { enum ath_btcoex_scheme scheme; bool enabled; u8 wlanactive_gpio; @@ -69,7 +69,7 @@ struct ath_btcoex_info { bool ath_btcoex_supported(u16 subsysid); void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah); void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah); -void ath9k_hw_init_btcoex_hw_info(struct ath_hw *ah, int qnum); +void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0b7e2859c1ef..93b3258190cb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2578,7 +2578,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, #endif } - if (ah->btcoex_info.enabled) + if (ah->btcoex_hw.enabled) ath9k_hw_btcoex_enable(ah); return 0; @@ -3559,7 +3559,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); - struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; u16 capField = 0, eeval; @@ -3729,17 +3729,17 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9280_10_OR_LATER(ah) && ath_btcoex_supported(ah->hw_version.subsysid)) { - btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO; - btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO; + btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO; + btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO; if (AR_SREV_9285(ah)) { - btcoex_info->scheme = ATH_BTCOEX_CFG_3WIRE; - btcoex_info->btpriority_gpio = ATH_BTPRIORITY_GPIO; + btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; + btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO; } else { - btcoex_info->scheme = ATH_BTCOEX_CFG_2WIRE; + btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; } } else { - btcoex_info->scheme = ATH_BTCOEX_CFG_NONE; + btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE; } } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index b244225ca050..4d187aa8b8d2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -555,7 +555,7 @@ struct ath_hw { enum ath9k_ani_cmd ani_function; /* Bluetooth coexistance */ - struct ath_btcoex_info btcoex_info; + struct ath_btcoex_hw btcoex_hw; u32 intr_txqs; enum ath9k_ht_extprotspacing extprotspacing; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3d0eb68c863c..a096e4c8e49a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -443,7 +443,7 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht) struct ath_hw *ah = sc->sc_ah; if ((sc->sc_flags & SC_OP_SCANNING) || is_ht || - (ah->btcoex_info.scheme != ATH_BTCOEX_CFG_NONE)) { + (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE)) { sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask; } else { @@ -511,7 +511,7 @@ static void ath9k_tasklet(unsigned long data) sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; } - if (ah->btcoex_info.scheme == ATH_BTCOEX_CFG_3WIRE) + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) if (status & ATH9K_INT_GENTIMER) ath_gen_timer_isr(sc->sc_ah); @@ -1287,7 +1287,7 @@ void ath_detach(struct ath_softc *sc) ath_tx_cleanupq(sc, &sc->tx.txq[i]); if ((sc->btcoex.no_stomp_timer) && - ah->btcoex_info.scheme == ATH_BTCOEX_CFG_3WIRE) + ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); ath9k_hw_detach(ah); @@ -1314,7 +1314,7 @@ static void ath_detect_bt_priority(struct ath_softc *sc) struct ath_btcoex *btcoex = &sc->btcoex; struct ath_hw *ah = sc->sc_ah; - if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_info.btpriority_gpio)) + if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio)) btcoex->bt_priority_cnt++; if (time_after(jiffies, btcoex->bt_priority_time + @@ -1332,17 +1332,17 @@ static void ath_detect_bt_priority(struct ath_softc *sc) } } -static void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info, +static void ath_btcoex_set_weight(struct ath_btcoex_hw *btcoex_hw, u32 bt_weight, u32 wlan_weight) { - btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | + btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | SM(wlan_weight, AR_BTCOEX_WL_WGHT); } static void ath9k_hw_btcoex_init_weight(struct ath_hw *ah) { - ath_btcoex_set_weight(&ah->btcoex_info, AR_BT_COEX_WGHT, + ath_btcoex_set_weight(&ah->btcoex_hw, AR_BT_COEX_WGHT, AR_STOMP_LOW_WLAN_WGHT); } @@ -1350,21 +1350,21 @@ static void ath9k_hw_btcoex_init_weight(struct ath_hw *ah) * Configures appropriate weight based on stomp type. */ static void ath_btcoex_bt_stomp(struct ath_softc *sc, - struct ath_btcoex_info *btinfo, + struct ath_btcoex_hw *btcoex_hw, int stomp_type) { switch (stomp_type) { case ATH_BTCOEX_STOMP_ALL: - ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + ath_btcoex_set_weight(btcoex_hw, AR_BT_COEX_WGHT, AR_STOMP_ALL_WLAN_WGHT); break; case ATH_BTCOEX_STOMP_LOW: - ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + ath_btcoex_set_weight(btcoex_hw, AR_BT_COEX_WGHT, AR_STOMP_LOW_WLAN_WGHT); break; case ATH_BTCOEX_STOMP_NONE: - ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, + ath_btcoex_set_weight(btcoex_hw, AR_BT_COEX_WGHT, AR_STOMP_NONE_WLAN_WGHT); break; default: @@ -1385,13 +1385,13 @@ static void ath_btcoex_period_timer(unsigned long data) struct ath_softc *sc = (struct ath_softc *) data; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_btcoex_info *btinfo = &ah->btcoex_info; + struct ath_btcoex_hw *btcoex_hw= &ah->btcoex_hw; ath_detect_bt_priority(sc); spin_lock_bh(&btcoex->btcoex_lock); - ath_btcoex_bt_stomp(sc, btinfo, btcoex->bt_stomp_type); + ath_btcoex_bt_stomp(sc, btcoex_hw, btcoex->bt_stomp_type); spin_unlock_bh(&btcoex->btcoex_lock); @@ -1420,16 +1420,16 @@ static void ath_btcoex_no_stomp_timer(void *arg) struct ath_softc *sc = (struct ath_softc *)arg; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_btcoex_info *btinfo = &ah->btcoex_info; + struct ath_btcoex_hw *btcoex_hw= &ah->btcoex_hw; DPRINTF(ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); spin_lock_bh(&btcoex->btcoex_lock); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) - ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); + ath_btcoex_bt_stomp(sc, btcoex_hw, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) - ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); + ath_btcoex_bt_stomp(sc, btcoex_hw, ATH_BTCOEX_STOMP_LOW); spin_unlock_bh(&btcoex->btcoex_lock); } @@ -1674,7 +1674,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) ARRAY_SIZE(ath9k_5ghz_chantable); } - switch (ah->btcoex_info.scheme) { + switch (ah->btcoex_hw.scheme) { case ATH_BTCOEX_CFG_NONE: break; case ATH_BTCOEX_CFG_2WIRE: @@ -1686,7 +1686,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) if (r) goto bad2; qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); - ath9k_hw_init_btcoex_hw_info(ah, qnum); + ath9k_hw_init_btcoex_hw(ah, qnum); sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; break; default: @@ -2199,13 +2199,13 @@ static int ath9k_start(struct ieee80211_hw *hw) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); - if ((ah->btcoex_info.scheme != ATH_BTCOEX_CFG_NONE) && - !ah->btcoex_info.enabled) { + if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) && + !ah->btcoex_hw.enabled) { ath9k_hw_btcoex_init_weight(ah); ath9k_hw_btcoex_enable(ah); ath_pcie_aspm_disable(sc); - if (ah->btcoex_info.scheme == ATH_BTCOEX_CFG_3WIRE) + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath9k_btcoex_timer_resume(sc); } @@ -2359,9 +2359,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) return; /* another wiphy still in use */ } - if (ah->btcoex_info.enabled) { + if (ah->btcoex_hw.enabled) { ath9k_hw_btcoex_disable(ah); - if (ah->btcoex_info.scheme == ATH_BTCOEX_CFG_3WIRE) + if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath9k_btcoex_timer_pause(sc); } -- cgit v1.2.3 From 269ad8120b2e1f01a7bcea4bdb175142a0e62171 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 15:05:00 -0700 Subject: ath9k: simplify ath_btcoex_bt_stomp() The second argument is always the hardware bt coex struct, so remove it, and rename the function on the path with a ath9k_ prefix. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 43 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a096e4c8e49a..0788a2724416 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1332,47 +1332,48 @@ static void ath_detect_bt_priority(struct ath_softc *sc) } } -static void ath_btcoex_set_weight(struct ath_btcoex_hw *btcoex_hw, - u32 bt_weight, - u32 wlan_weight) +static void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, + u32 bt_weight, + u32 wlan_weight) { + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | - SM(wlan_weight, AR_BTCOEX_WL_WGHT); + SM(wlan_weight, AR_BTCOEX_WL_WGHT); } static void ath9k_hw_btcoex_init_weight(struct ath_hw *ah) { - ath_btcoex_set_weight(&ah->btcoex_hw, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, AR_STOMP_LOW_WLAN_WGHT); } /* * Configures appropriate weight based on stomp type. */ -static void ath_btcoex_bt_stomp(struct ath_softc *sc, - struct ath_btcoex_hw *btcoex_hw, - int stomp_type) +static void ath9k_btcoex_bt_stomp(struct ath_softc *sc, + enum ath_stomp_type stomp_type) { + struct ath_hw *ah = sc->sc_ah; switch (stomp_type) { case ATH_BTCOEX_STOMP_ALL: - ath_btcoex_set_weight(btcoex_hw, AR_BT_COEX_WGHT, - AR_STOMP_ALL_WLAN_WGHT); + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_ALL_WLAN_WGHT); break; case ATH_BTCOEX_STOMP_LOW: - ath_btcoex_set_weight(btcoex_hw, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); break; case ATH_BTCOEX_STOMP_NONE: - ath_btcoex_set_weight(btcoex_hw, AR_BT_COEX_WGHT, - AR_STOMP_NONE_WLAN_WGHT); + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_NONE_WLAN_WGHT); break; default: - DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); + DPRINTF(ah, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); break; } - ath9k_hw_btcoex_enable(sc->sc_ah); + ath9k_hw_btcoex_enable(ah); } /* @@ -1385,13 +1386,12 @@ static void ath_btcoex_period_timer(unsigned long data) struct ath_softc *sc = (struct ath_softc *) data; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_btcoex_hw *btcoex_hw= &ah->btcoex_hw; ath_detect_bt_priority(sc); spin_lock_bh(&btcoex->btcoex_lock); - ath_btcoex_bt_stomp(sc, btcoex_hw, btcoex->bt_stomp_type); + ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type); spin_unlock_bh(&btcoex->btcoex_lock); @@ -1420,16 +1420,15 @@ static void ath_btcoex_no_stomp_timer(void *arg) struct ath_softc *sc = (struct ath_softc *)arg; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_btcoex_hw *btcoex_hw= &ah->btcoex_hw; DPRINTF(ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); spin_lock_bh(&btcoex->btcoex_lock); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) - ath_btcoex_bt_stomp(sc, btcoex_hw, ATH_BTCOEX_STOMP_NONE); + ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) - ath_btcoex_bt_stomp(sc, btcoex_hw, ATH_BTCOEX_STOMP_LOW); + ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW); spin_unlock_bh(&btcoex->btcoex_lock); } -- cgit v1.2.3 From 5e1972929532bfc3a26b1782c8551d3c56306ffd Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 15:15:55 -0700 Subject: ath9k: now move ath9k_hw_btcoex_set_weight() to btcoex.c After some necessary cleanups we now move ath9k_hw_btcoex_set_weight() to where it belongs. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.c | 10 ++++++++++ drivers/net/wireless/ath/ath9k/btcoex.h | 3 +++ drivers/net/wireless/ath/ath9k/main.c | 18 ++---------------- 3 files changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 0b5a7d4a6d55..4cca023647fd 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -124,6 +124,16 @@ static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah) AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); } +void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, + u32 bt_weight, + u32 wlan_weight) +{ + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + + btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | + SM(wlan_weight, AR_BTCOEX_WL_WGHT); +} + static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 296ddd8ce813..971d20065b45 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -70,6 +70,9 @@ bool ath_btcoex_supported(u16 subsysid); void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah); void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah); void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum); +void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, + u32 bt_weight, + u32 wlan_weight); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0788a2724416..42772d25491a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1332,21 +1332,6 @@ static void ath_detect_bt_priority(struct ath_softc *sc) } } -static void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, - u32 bt_weight, - u32 wlan_weight) -{ - struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - - btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | - SM(wlan_weight, AR_BTCOEX_WL_WGHT); -} - -static void ath9k_hw_btcoex_init_weight(struct ath_hw *ah) -{ - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, AR_STOMP_LOW_WLAN_WGHT); -} - /* * Configures appropriate weight based on stomp type. */ @@ -2200,7 +2185,8 @@ static int ath9k_start(struct ieee80211_hw *hw) if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) && !ah->btcoex_hw.enabled) { - ath9k_hw_btcoex_init_weight(ah); + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); ath9k_hw_btcoex_enable(ah); ath_pcie_aspm_disable(sc); -- cgit v1.2.3 From 8b4fc5ba896cd1b73c598d07fc51224abbfe8cdb Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 15:24:02 -0700 Subject: ath9k: move ath_btcoex_config and ath_bt_mode to btcoex.c These are only used by btcoex.c on one routine, so stuff them into that file. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.c | 31 +++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath9k/btcoex.h | 20 -------------------- 2 files changed, 29 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 4cca023647fd..ee2a83491235 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -16,8 +16,24 @@ #include "ath9k.h" -static const struct ath_btcoex_config ath_bt_config = { 0, true, true, - ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true }; +enum ath_bt_mode { + ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */ + ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */ + ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */ + ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */ +}; + +struct ath_btcoex_config { + u8 bt_time_extend; + bool bt_txstate_extend; + bool bt_txframe_extend; + enum ath_bt_mode bt_mode; /* coexistence mode */ + bool bt_quiet_collision; + bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/ + u8 bt_priority_time; + u8 bt_first_slot_time; + bool bt_hold_rx_clear; +}; static const u16 ath_subsysid_tbl[] = { AR9280_COEX2WIRE_SUBSYSID, @@ -46,6 +62,17 @@ bool ath_btcoex_supported(u16 subsysid) void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + const struct ath_btcoex_config ath_bt_config = { + .bt_time_extend = 0, + .bt_txstate_extend = true, + .bt_txframe_extend = true, + .bt_mode = ATH_BT_COEX_MODE_SLOTTED, + .bt_quiet_collision = true, + .bt_rxclear_polarity = true, + .bt_priority_time = 2, + .bt_first_slot_time = 5, + .bt_hold_rx_clear = true, + }; u32 i; btcoex_hw->bt_coex_mode = diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 971d20065b45..0dc51202d451 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -36,25 +36,6 @@ enum ath_btcoex_scheme { ATH_BTCOEX_CFG_3WIRE, }; -enum ath_bt_mode { - ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */ - ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */ - ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */ - ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */ -}; - -struct ath_btcoex_config { - u8 bt_time_extend; - bool bt_txstate_extend; - bool bt_txframe_extend; - enum ath_bt_mode bt_mode; /* coexistence mode */ - bool bt_quiet_collision; - bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/ - u8 bt_priority_time; - u8 bt_first_slot_time; - bool bt_hold_rx_clear; -}; - struct ath_btcoex_hw { enum ath_btcoex_scheme scheme; bool enabled; @@ -76,5 +57,4 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); - #endif -- cgit v1.2.3 From a36cfbca21d0acbab0840337f0b59ea58f415e50 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 16:05:32 -0700 Subject: ath9k: rename ath_btcoex_supported() to ath9k_hw_btcoex_supported() Also just pass the ath_hw as the parameter. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/btcoex.c | 6 +++--- drivers/net/wireless/ath/ath9k/btcoex.h | 2 +- drivers/net/wireless/ath/ath9k/hw.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index ee2a83491235..5d1095f18d77 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -45,15 +45,15 @@ static const u16 ath_subsysid_tbl[] = { * Checks the subsystem id of the device to see if it * supports btcoex */ -bool ath_btcoex_supported(u16 subsysid) +bool ath9k_hw_btcoex_supported(struct ath_hw *ah) { int i; - if (!subsysid) + if (!ah->hw_version.subsysid) return false; for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++) - if (subsysid == ath_subsysid_tbl[i]) + if (ah->hw_version.subsysid == ath_subsysid_tbl[i]) return true; return false; diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 0dc51202d451..1ba31a73317c 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -47,7 +47,7 @@ struct ath_btcoex_hw { u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ }; -bool ath_btcoex_supported(u16 subsysid); +bool ath9k_hw_btcoex_supported(struct ath_hw *ah); void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah); void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah); void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 93b3258190cb..de83d3c4b469 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3728,7 +3728,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); if (AR_SREV_9280_10_OR_LATER(ah) && - ath_btcoex_supported(ah->hw_version.subsysid)) { + ath9k_hw_btcoex_supported(ah)) { btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO; btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO; -- cgit v1.2.3 From 21526d57ad98635fe12dc8efe46a3d992439a443 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 20:05:39 -0700 Subject: ath9k: move ps helpers onto core driver when reseting tsf When the TSF is reset power save state is disabled and then restored. The helpers to disable power save and restore it use a lock provided by the driver core. Move the callers of the helpers outside of the hw code. We reset the TSF when mac80211 tells us and on the beacon.c helper ath9k_hw_beaconinit() when it is made explicitly required. Add a helper on beacon.c which will deal with ps awake/restore if we need to reset the TSF upon ath9k_hw_beaconinit(). Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 17 +++++++++++++++-- drivers/net/wireless/ath/ath9k/hw.c | 2 -- drivers/net/wireless/ath/ath9k/main.c | 4 ++++ 3 files changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 6e7a519d0a9c..fb4ff5512360 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -502,6 +502,19 @@ void ath_beacon_tasklet(unsigned long data) } } +static void ath9k_beacon_init(struct ath_softc *sc, + u32 next_beacon, + u32 beacon_period) +{ + if (beacon_period & ATH9K_BEACON_RESET_TSF) + ath9k_ps_wakeup(sc); + + ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); + + if (beacon_period & ATH9K_BEACON_RESET_TSF) + ath9k_ps_restore(sc); +} + /* * For multi-bss ap support beacons are either staggered evenly over N slots or * burst together. For the former arrange for the SWBA to be delivered for each @@ -534,7 +547,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc, /* Set the computed AP beacon timers */ ath9k_hw_set_interrupts(sc->sc_ah, 0); - ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval); + ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); @@ -707,7 +720,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, /* Set the computed ADHOC beacon timers */ ath9k_hw_set_interrupts(sc->sc_ah, 0); - ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval); + ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index de83d3c4b469..0893f23adaa8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4101,14 +4101,12 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64) void ath9k_hw_reset_tsf(struct ath_hw *ah) { - ath9k_ps_wakeup(ah->ah_sc); if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0, AH_TSF_WRITE_TIMEOUT)) DPRINTF(ah, ATH_DBG_RESET, "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); - ath9k_ps_restore(ah->ah_sc); } void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 42772d25491a..fe2888e4b8e9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2893,7 +2893,11 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw) struct ath_softc *sc = aphy->sc; mutex_lock(&sc->mutex); + + ath9k_ps_wakeup(sc); ath9k_hw_reset_tsf(sc->sc_ah); + ath9k_ps_restore(sc); + mutex_unlock(&sc->mutex); } -- cgit v1.2.3 From a91d75aec19d8d23c7c543dd4bc0e394e1d46867 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 20:29:18 -0700 Subject: ath9k: move ath9k_ps_wakeup() and ath9k_ps_restore() to main.c These are driver core helpers. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 36 +---------------------------------- drivers/net/wireless/ath/ath9k/hw.h | 6 ++++-- drivers/net/wireless/ath/ath9k/main.c | 33 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0893f23adaa8..82c91e5883d9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2932,8 +2932,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) return true; } -static bool ath9k_hw_setpower_nolock(struct ath_hw *ah, - enum ath9k_power_mode mode) +bool ath9k_hw_setpower_nolock(struct ath_hw *ah, enum ath9k_power_mode mode) { int status = true, setChip = true; static const char *modes[] = { @@ -2982,39 +2981,6 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) return ret; } -void ath9k_ps_wakeup(struct ath_softc *sc) -{ - unsigned long flags; - - spin_lock_irqsave(&sc->sc_pm_lock, flags); - if (++sc->ps_usecount != 1) - goto unlock; - - ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); - - unlock: - spin_unlock_irqrestore(&sc->sc_pm_lock, flags); -} - -void ath9k_ps_restore(struct ath_softc *sc) -{ - unsigned long flags; - - spin_lock_irqsave(&sc->sc_pm_lock, flags); - if (--sc->ps_usecount != 0) - goto unlock; - - if (sc->ps_enabled && - !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | - SC_OP_WAIT_FOR_CAB | - SC_OP_WAIT_FOR_PSPOLL_DATA | - SC_OP_WAIT_FOR_TX_ACK))) - ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); - - unlock: - spin_unlock_irqrestore(&sc->sc_pm_lock, flags); -} - /* * Helper for ASPM support. * diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 4d187aa8b8d2..01a127b01724 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -652,8 +652,10 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, const struct ath9k_beacon_state *bs); -bool ath9k_hw_setpower(struct ath_hw *ah, - enum ath9k_power_mode mode); + +bool ath9k_hw_setpower_nolock(struct ath_hw *ah, enum ath9k_power_mode mode); +bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); + void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off); /* Interrupt Handling */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index fe2888e4b8e9..9f9ac5b52acb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -243,6 +243,39 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc, return channel; } +void ath9k_ps_wakeup(struct ath_softc *sc) +{ + unsigned long flags; + + spin_lock_irqsave(&sc->sc_pm_lock, flags); + if (++sc->ps_usecount != 1) + goto unlock; + + ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); + + unlock: + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); +} + +void ath9k_ps_restore(struct ath_softc *sc) +{ + unsigned long flags; + + spin_lock_irqsave(&sc->sc_pm_lock, flags); + if (--sc->ps_usecount != 0) + goto unlock; + + if (sc->ps_enabled && + !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | + SC_OP_WAIT_FOR_CAB | + SC_OP_WAIT_FOR_PSPOLL_DATA | + SC_OP_WAIT_FOR_TX_ACK))) + ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); + + unlock: + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); +} + /* * Set/change channels. If the channel is really being changed, it's done * by reseting the chip. To accomplish this we must first cleanup any pending -- cgit v1.2.3 From 1adc93c832726c9de4a43445c008a7f17549390b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 20:54:36 -0700 Subject: ath9k: avoid usage of ath9k_hw_setpower() on hw.c ath9k_hw_setpower() is a core driver helper with locking protection. Locking protection should be left to the driver core, not the hw code. Hardware code no longer contends for locking when it needs to wake up the chip or put it to sleep. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 82c91e5883d9..910726203ec7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -919,7 +919,7 @@ int ath9k_hw_init(struct ath_hw *ah) return -EIO; } - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { + if (!ath9k_hw_setpower_nolock(ah, ATH9K_PM_AWAKE)) { DPRINTF(ah, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); return -EIO; } @@ -1234,7 +1234,7 @@ void ath9k_hw_detach(struct ath_hw *ah) ath9k_hw_ani_disable(ah); ath9k_hw_rf_free(ah); - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + ath9k_hw_setpower_nolock(ah, ATH9K_PM_FULL_SLEEP); kfree(ah); ah = NULL; } @@ -1800,7 +1800,7 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah, } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) return false; - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + if (!ath9k_hw_setpower_nolock(ah, ATH9K_PM_AWAKE)) return false; ah->chip_fullsleep = false; @@ -2355,7 +2355,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ah->txchainmask = sc->tx_chainmask; ah->rxchainmask = sc->rx_chainmask; - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + if (!ath9k_hw_setpower_nolock(ah, ATH9K_PM_AWAKE)) return -EIO; if (curchan && !ah->chip_fullsleep) @@ -3998,7 +3998,7 @@ bool ath9k_hw_phy_disable(struct ath_hw *ah) bool ath9k_hw_disable(struct ath_hw *ah) { - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + if (!ath9k_hw_setpower_nolock(ah, ATH9K_PM_AWAKE)) return false; return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); -- cgit v1.2.3 From 8c77a5694cd31eb2291948dd1bfe700a199be8e7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 21:02:34 -0700 Subject: ath9k: move ath9k_hw_setpower() to main.c And we make it static. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 12 ------------ drivers/net/wireless/ath/ath9k/hw.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 12 ++++++++++++ 3 files changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 910726203ec7..e71fe24cd3d8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2969,18 +2969,6 @@ bool ath9k_hw_setpower_nolock(struct ath_hw *ah, enum ath9k_power_mode mode) return status; } -bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) -{ - unsigned long flags; - bool ret; - - spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags); - ret = ath9k_hw_setpower_nolock(ah, mode); - spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags); - - return ret; -} - /* * Helper for ASPM support. * diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 01a127b01724..05e4f8bc566b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -654,7 +654,6 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, const struct ath9k_beacon_state *bs); bool ath9k_hw_setpower_nolock(struct ath_hw *ah, enum ath9k_power_mode mode); -bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9f9ac5b52acb..d0637a65f9a9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -243,6 +243,18 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc, return channel; } +static bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags); + ret = ath9k_hw_setpower_nolock(ah, mode); + spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags); + + return ret; +} + void ath9k_ps_wakeup(struct ath_softc *sc) { unsigned long flags; -- cgit v1.2.3 From 9ecdef4be864fede4e5964abc82c8d7451288539 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 21:10:09 -0700 Subject: ath9k: rename driver core and hw power save helpers ath9k_hw_setpower_nolock --> ath9k_hw_setpower() ath9k_hw_setpower() --> ath9k_setpower() Also change the param for ath9k_setpower() to pass the ath_softc. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 12 ++++++------ drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 22 +++++++++++----------- 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e71fe24cd3d8..cb352daf2dc7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -919,7 +919,7 @@ int ath9k_hw_init(struct ath_hw *ah) return -EIO; } - if (!ath9k_hw_setpower_nolock(ah, ATH9K_PM_AWAKE)) { + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { DPRINTF(ah, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); return -EIO; } @@ -1234,7 +1234,7 @@ void ath9k_hw_detach(struct ath_hw *ah) ath9k_hw_ani_disable(ah); ath9k_hw_rf_free(ah); - ath9k_hw_setpower_nolock(ah, ATH9K_PM_FULL_SLEEP); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); kfree(ah); ah = NULL; } @@ -1800,7 +1800,7 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah, } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) return false; - if (!ath9k_hw_setpower_nolock(ah, ATH9K_PM_AWAKE)) + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return false; ah->chip_fullsleep = false; @@ -2355,7 +2355,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ah->txchainmask = sc->tx_chainmask; ah->rxchainmask = sc->rx_chainmask; - if (!ath9k_hw_setpower_nolock(ah, ATH9K_PM_AWAKE)) + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; if (curchan && !ah->chip_fullsleep) @@ -2932,7 +2932,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) return true; } -bool ath9k_hw_setpower_nolock(struct ath_hw *ah, enum ath9k_power_mode mode) +bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) { int status = true, setChip = true; static const char *modes[] = { @@ -3986,7 +3986,7 @@ bool ath9k_hw_phy_disable(struct ath_hw *ah) bool ath9k_hw_disable(struct ath_hw *ah) { - if (!ath9k_hw_setpower_nolock(ah, ATH9K_PM_AWAKE)) + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return false; return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 05e4f8bc566b..2432edcabafb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -653,7 +653,7 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, const struct ath9k_beacon_state *bs); -bool ath9k_hw_setpower_nolock(struct ath_hw *ah, enum ath9k_power_mode mode); +bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d0637a65f9a9..216b72f9c85c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -243,14 +243,14 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc, return channel; } -static bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) +static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) { unsigned long flags; bool ret; - spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags); - ret = ath9k_hw_setpower_nolock(ah, mode); - spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags); + spin_lock_irqsave(&sc->sc_pm_lock, flags); + ret = ath9k_hw_setpower(sc->sc_ah, mode); + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); return ret; } @@ -263,7 +263,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc) if (++sc->ps_usecount != 1) goto unlock; - ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE); + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); @@ -282,7 +282,7 @@ void ath9k_ps_restore(struct ath_softc *sc) SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_PSPOLL_DATA | SC_OP_WAIT_FOR_TX_ACK))) - ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); @@ -652,7 +652,7 @@ irqreturn_t ath_isr(int irq, void *dev) if (status & ATH9K_INT_TIM_TIMER) { /* Clear RxAbort bit so that we can * receive frames */ - ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); + ath9k_setpower(sc, ATH9K_PM_AWAKE); ath9k_hw_setrxabort(sc->sc_ah, 0); sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; } @@ -1254,7 +1254,7 @@ void ath_radio_disable(struct ath_softc *sc) ath9k_hw_phy_disable(ah); ath9k_hw_configpcipowersave(ah, 1, 1); ath9k_ps_restore(sc); - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); } /*******************/ @@ -1324,7 +1324,7 @@ void ath_detach(struct ath_softc *sc) tasklet_kill(&sc->bcon_tasklet); if (!(sc->sc_flags & SC_OP_INVALID)) - ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); + ath9k_setpower(sc, ATH9K_PM_AWAKE); /* cleanup tx queues */ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) @@ -2409,7 +2409,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) /* disable HAL and put h/w to sleep */ ath9k_hw_disable(ah); ath9k_hw_configpcipowersave(ah, 1, 1); - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); sc->sc_flags |= SC_OP_INVALID; @@ -2581,7 +2581,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) sc->ps_enabled = true; } else { sc->ps_enabled = false; - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); + ath9k_setpower(sc, ATH9K_PM_AWAKE); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { ath9k_hw_setrxabort(sc->sc_ah, 0); -- cgit v1.2.3 From 17753748e15eaf29c8db15c5c05b8dde5db6e64d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 9 Sep 2009 22:19:26 -0700 Subject: ath: move ath_bcast_mac to common header This is used by both ath5k and ath9k to set the first bssid mask. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 2 ++ drivers/net/wireless/ath/ath5k/attach.c | 2 +- drivers/net/wireless/ath/ath5k/base.c | 2 +- drivers/net/wireless/ath/ath5k/pcu.c | 2 +- drivers/net/wireless/ath/ath9k/ath9k.h | 2 -- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index a63e90cbf9e5..59072e3820d0 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -19,6 +19,8 @@ #include +static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + struct reg_dmn_pair_mapping { u16 regDmnEnum; u16 reg_5ghz_ctl; diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 71a1bd254517..9a009a78a046 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -336,7 +336,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc) ath5k_hw_set_lladdr(ah, (u8[ETH_ALEN]){}); /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ - memset(ah->ah_bssid, 0xff, ETH_ALEN); + memcpy(ah->ah_bssid, ath_bcast_mac, ETH_ALEN); ath5k_hw_set_associd(ah, ah->ah_bssid, 0); ath5k_hw_set_opmode(ah); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 9c6ab5378f6e..a28d79555dfc 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -815,7 +815,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) SET_IEEE80211_PERM_ADDR(hw, mac); /* All MAC address bits matter for ACKs */ - memset(sc->bssidmask, 0xff, ETH_ALEN); + memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN); ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain; diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 2942f13c9c4a..43aa35806618 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -365,7 +365,7 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) * assuming only 4 bits for a mac address and for BSSIDs you can then have: * * \ - * MAC: 0001 | + * MAC: 0001 | * BSSID-01: 0100 | --> Belongs to us * BSSID-02: 1001 | * / diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index d99c92d7b949..e54fac322bd2 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -60,8 +60,6 @@ struct ath_node; #define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1< Date: Wed, 9 Sep 2009 22:43:17 -0700 Subject: atheros: use get_unaligned_le*() for bssid mask setting Historically some macro helpers have been users for this, AR5K_LOW_ID() and AR5K_HIGH_ID(), use upstream unaligned helpers instead. This applid to ath5k and ar9170. ath9k already uses this. Worth noting is ath5k uses an ah_sta_id but that is already the MAC address combined with the associaiton ID, ah_sta_id is really ETH_ALEN in size. Cc: Bob Copeland Cc: Nick Kossifidis Cc: Christian Lamparter Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/mac.c | 10 +++++----- drivers/net/wireless/ath/ath.h | 1 + drivers/net/wireless/ath/ath5k/ath5k.h | 7 ------- drivers/net/wireless/ath/ath5k/pcu.c | 36 ++++++++++++++++++++-------------- drivers/net/wireless/ath/ath5k/reset.c | 6 ++++-- 5 files changed, 31 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index 614e3218a2bc..0c6273a63d6b 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -35,6 +35,9 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + #include "ar9170.h" #include "cmd.h" @@ -227,11 +230,8 @@ static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) ar9170_regwrite_begin(ar); - ar9170_regwrite(reg, - (mac[3] << 24) | (mac[2] << 16) | - (mac[1] << 8) | mac[0]); - - ar9170_regwrite(reg + 4, (mac[5] << 8) | mac[4]); + ar9170_regwrite(reg, get_unaligned_le32(mac)); + ar9170_regwrite(reg + 4, get_unaligned_le16(mac + 4)); ar9170_regwrite_finish(); diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 59072e3820d0..44f885a37c11 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -18,6 +18,7 @@ #define ATH_H #include +#include static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 6cd5efcec417..93a9c1f93f69 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -165,13 +165,6 @@ #define AR5K_INI_VAL_XR 0 #define AR5K_INI_VAL_MAX 5 -/* Used for BSSID etc manipulation */ -#define AR5K_LOW_ID(_a)( \ -(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \ -) - -#define AR5K_HIGH_ID(_a) ((_a)[4] | (_a)[5] << 8) - /* * Some tuneable values (these should be changeable by the user) * TODO: Make use of them and add more options OR use debug/configfs diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 43aa35806618..7bbcfe4fe34b 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -24,6 +24,8 @@ * Protocol Control Unit Functions * \*********************************/ +#include + #include "ath5k.h" #include "reg.h" #include "debug.h" @@ -95,8 +97,8 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah) /* * Set PCU registers */ - low_id = AR5K_LOW_ID(ah->ah_sta_id); - high_id = AR5K_HIGH_ID(ah->ah_sta_id); + low_id = get_unaligned_le32(ah->ah_sta_id); + high_id = get_unaligned_le16(ah->ah_sta_id + 4); ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); @@ -279,8 +281,8 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; - low_id = AR5K_LOW_ID(mac); - high_id = AR5K_HIGH_ID(mac); + low_id = get_unaligned_le32(mac); + high_id = get_unaligned_le16(mac + 4); ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); @@ -306,17 +308,18 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) * Set simple BSSID mask on 5212 */ if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask), + ath5k_hw_reg_write(ah, get_unaligned_le32(ah->ah_bssid_mask), AR5K_BSS_IDM0); - ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask), - AR5K_BSS_IDM1); + ath5k_hw_reg_write(ah, + get_unaligned_le16(ah->ah_bssid_mask + 4), + AR5K_BSS_IDM1); } /* * Set BSSID which triggers the "SME Join" operation */ - low_id = AR5K_LOW_ID(bssid); - high_id = AR5K_HIGH_ID(bssid); + low_id = get_unaligned_le32(bssid); + high_id = get_unaligned_le16(bssid); ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); @@ -437,8 +440,8 @@ int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) * on reset */ memcpy(ah->ah_bssid_mask, mask, ETH_ALEN); if (ah->ah_version == AR5K_AR5212) { - low_id = AR5K_LOW_ID(mask); - high_id = AR5K_HIGH_ID(mask); + low_id = get_unaligned_le32(mask); + high_id = get_unaligned_le16(mask + 4); ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); @@ -1157,14 +1160,17 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) /* Invalid entry (key table overflow) */ AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); - /* MAC may be NULL if it's a broadcast key. In this case no need to - * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */ + /* + * MAC may be NULL if it's a broadcast key. In this case no need to + * to compute get_unaligned_le32 and get_unaligned_le16 as we + * already know it. + */ if (!mac) { low_id = 0xffffffff; high_id = 0xffff | AR5K_KEYTABLE_VALID; } else { - low_id = AR5K_LOW_ID(mac); - high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID; + low_id = get_unaligned_le32(mac); + high_id = get_unaligned_le16(mac + 4) | AR5K_KEYTABLE_VALID; } ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 34e13c700849..3454dacc2af8 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -25,6 +25,8 @@ Reset functions and helpers \*****************************/ +#include + #include /* To determine if a card is pci-e */ #include #include "ath5k.h" @@ -1171,9 +1173,9 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO); /* Restore sta_id flags and preserve our mac address*/ - ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_sta_id), + ath5k_hw_reg_write(ah, get_unaligned_le32(ah->ah_sta_id), AR5K_STA_ID0); - ath5k_hw_reg_write(ah, staid1_flags | AR5K_HIGH_ID(ah->ah_sta_id), + ath5k_hw_reg_write(ah, staid1_flags | get_unaligned_le16(ah->ah_sta_id), AR5K_STA_ID1); -- cgit v1.2.3 From f2b2143e60651228945f361c09de7ee752360cd1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 08:50:20 -0700 Subject: ath9k: make ath9k_hw_setbssidmask() and ath9k_hw_write_associd() use ath_hw Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 14 +++++++------- drivers/net/wireless/ath/ath9k/hw.h | 4 ++-- drivers/net/wireless/ath/ath9k/main.c | 11 ++++++----- drivers/net/wireless/ath/ath9k/recv.c | 2 +- drivers/net/wireless/ath/ath9k/virtual.c | 2 +- 5 files changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index cb352daf2dc7..721b0c9e3eab 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4024,17 +4024,17 @@ void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1) REG_WRITE(ah, AR_MCAST_FIL1, filter1); } -void ath9k_hw_setbssidmask(struct ath_softc *sc) +void ath9k_hw_setbssidmask(struct ath_hw *ah) { - REG_WRITE(sc->sc_ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask)); - REG_WRITE(sc->sc_ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4)); + REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ah->ah_sc->bssidmask)); + REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ah->ah_sc->bssidmask + 4)); } -void ath9k_hw_write_associd(struct ath_softc *sc) +void ath9k_hw_write_associd(struct ath_hw *ah) { - REG_WRITE(sc->sc_ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid)); - REG_WRITE(sc->sc_ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) | - ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); + REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ah->ah_sc->curbssid)); + REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ah->ah_sc->curbssid + 4) | + ((ah->ah_sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); } u64 ath9k_hw_gettsf64(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 2432edcabafb..c0c22dfd3065 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -641,8 +641,8 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit); void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac); void ath9k_hw_setopmode(struct ath_hw *ah); void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); -void ath9k_hw_setbssidmask(struct ath_softc *sc); -void ath9k_hw_write_associd(struct ath_softc *sc); +void ath9k_hw_setbssidmask(struct ath_hw *ah); +void ath9k_hw_write_associd(struct ath_hw *ah); u64 ath9k_hw_gettsf64(struct ath_hw *ah); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 216b72f9c85c..f2c1feb7d491 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -975,14 +975,15 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) { + struct ath_hw *ah = sc->sc_ah; if (bss_conf->assoc) { - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", + DPRINTF(ah, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", bss_conf->aid, sc->curbssid); /* New association, store aid */ sc->curaid = bss_conf->aid; - ath9k_hw_write_associd(sc); + ath9k_hw_write_associd(ah); /* * Request a re-configuration of Beacon related timers @@ -999,7 +1000,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_start_ani(sc); } else { - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); + DPRINTF(ah, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); sc->curaid = 0; /* Stop ANI */ del_timer_sync(&sc->ani.timer); @@ -2801,7 +2802,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_hw_setopmode(ah); memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN); sc->curaid = 0; - ath9k_hw_write_associd(sc); + ath9k_hw_write_associd(ah); /* Request full reset to get hw opmode changed properly */ sc->sc_flags |= SC_OP_FULL_RESET; } @@ -2816,7 +2817,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, memcpy(sc->curbssid, bss_conf->bssid, ETH_ALEN); memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); sc->curaid = 0; - ath9k_hw_write_associd(sc); + ath9k_hw_write_associd(ah); /* Set aggregation protection mode parameters */ sc->config.ath_aggr_prot = 0; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index ee1e8b47496a..529cab6bfe66 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -280,7 +280,7 @@ static void ath_opmode_init(struct ath_softc *sc) /* configure bssid mask */ if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) - ath9k_hw_setbssidmask(sc); + ath9k_hw_setbssidmask(ah); /* configure operational mode */ ath9k_hw_setopmode(ah); diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 19b88f8177fd..52becd32ad8c 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -93,7 +93,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) sc->bssidmask[4] = ~mask[4]; sc->bssidmask[5] = ~mask[5]; - ath9k_hw_setbssidmask(sc); + ath9k_hw_setbssidmask(sc->sc_ah); } int ath9k_wiphy_add(struct ath_softc *sc) -- cgit v1.2.3 From 7664072b7937d0bd5563800359e04ff4418572e0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 08:54:56 -0700 Subject: ath9k: Use ath9k_hw_setbssidmask() on reset The same code was being implemented on reset for setting the bssidmask, instead just use the already provided helper. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 721b0c9e3eab..227e40391b09 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2472,8 +2472,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | ah->sta_id1_defaults); ath9k_hw_set_operating_mode(ah, ah->opmode); - REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(sc->bssidmask)); - REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(sc->bssidmask + 4)); + ath9k_hw_setbssidmask(ah); REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); -- cgit v1.2.3 From 3453ad8839ca91e1c11211d4d87dc3657c5a2b44 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 08:57:00 -0700 Subject: ath9k: use ath9k_hw_write_associd() on reset Use the already provided helper instead of rewriting the code required in place. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 227e40391b09..20c1b3edbd0a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2476,9 +2476,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); - REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(sc->curbssid)); - REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(sc->curbssid + 4) | - ((sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); + ath9k_hw_write_associd(ah); REG_WRITE(ah, AR_ISR, ~0); -- cgit v1.2.3 From 1510718d0fd6e20803aac95fe1d8a44846098a34 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 09:22:37 -0700 Subject: atheros/ath9k: move macaddr, curaid, curbssid and bssidmask to common These are common amongst ath9k and ath5k, so put them into the common structure and make ath9k to use it. ar9170 can use macaddr, and curbssid. We'll change ath5k and ar9170 separately. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 4 ++++ drivers/net/wireless/ath/ath9k/ath9k.h | 3 --- drivers/net/wireless/ath/ath9k/hw.c | 26 +++++++++++++++---------- drivers/net/wireless/ath/ath9k/hw.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 33 +++++++++++++++++++------------- drivers/net/wireless/ath/ath9k/recv.c | 7 +++++-- drivers/net/wireless/ath/ath9k/virtual.c | 18 +++++++++-------- 7 files changed, 55 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 44f885a37c11..7589b2aa030b 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -41,6 +41,10 @@ struct ath_regulatory { struct ath_common { u16 cachelsz; + u16 curaid; + u8 macaddr[ETH_ALEN]; + u8 curbssid[ETH_ALEN]; + u8 bssidmask[ETH_ALEN]; struct ath_regulatory regulatory; }; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e54fac322bd2..757f17fddcfd 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -581,12 +581,9 @@ struct ath_softc { spinlock_t sc_pm_lock; struct mutex mutex; - u8 curbssid[ETH_ALEN]; - u8 bssidmask[ETH_ALEN]; u32 intrstatus; u32 sc_flags; /* SC_OP_* */ u16 curtxpow; - u16 curaid; u8 nbcnvifs; u16 nvifs; u8 tx_chainmask; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 20c1b3edbd0a..4e14c307b3da 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -511,6 +511,7 @@ static int ath9k_hw_rf_claim(struct ath_hw *ah) static int ath9k_hw_init_macaddr(struct ath_hw *ah) { + struct ath_common *common = ath9k_hw_common(ah); u32 sum; int i; u16 eeval; @@ -519,8 +520,8 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah) for (i = 0; i < 3; i++) { eeval = ah->eep_ops->get_eeprom(ah, AR_EEPROM_MAC(i)); sum += eeval; - ah->macaddr[2 * i] = eeval >> 8; - ah->macaddr[2 * i + 1] = eeval & 0xff; + common->macaddr[2 * i] = eeval >> 8; + common->macaddr[2 * i + 1] = eeval & 0xff; } if (sum == 0 || sum == 0xffff * 3) return -EADDRNOTAVAIL; @@ -2343,6 +2344,7 @@ static void ath9k_enable_rfkill(struct ath_hw *ah) int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange) { + struct ath_common *common = ath9k_hw_common(ah); u32 saveLedState; struct ath_softc *sc = ah->ah_sc; struct ath9k_channel *curchan = ah->curchan; @@ -2463,8 +2465,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_decrease_chain_power(ah, chan); - REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ah->macaddr)); - REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ah->macaddr + 4) + REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr)); + REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4) | macStaId1 | AR_STA_ID1_RTS_USE_DEF | (ah->config. @@ -4007,7 +4009,7 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac) { - memcpy(ah->macaddr, mac, ETH_ALEN); + memcpy(ath9k_hw_common(ah)->macaddr, mac, ETH_ALEN); } void ath9k_hw_setopmode(struct ath_hw *ah) @@ -4023,15 +4025,19 @@ void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1) void ath9k_hw_setbssidmask(struct ath_hw *ah) { - REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ah->ah_sc->bssidmask)); - REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ah->ah_sc->bssidmask + 4)); + struct ath_common *common = ath9k_hw_common(ah); + + REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(common->bssidmask)); + REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(common->bssidmask + 4)); } void ath9k_hw_write_associd(struct ath_hw *ah) { - REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ah->ah_sc->curbssid)); - REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ah->ah_sc->curbssid + 4) | - ((ah->ah_sc->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); + struct ath_common *common = ath9k_hw_common(ah); + + REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(common->curbssid)); + REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(common->curbssid + 4) | + ((common->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); } u64 ath9k_hw_gettsf64(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c0c22dfd3065..6aee01343d3a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -451,7 +451,6 @@ struct ath_hw { bool sw_mgmt_crypto; bool is_pciexpress; - u8 macaddr[ETH_ALEN]; u16 tx_trig_level; u16 rfsilent; u32 rfkill_gpio; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index f2c1feb7d491..a96350d2aace 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -976,13 +976,14 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ieee80211_bss_conf *bss_conf) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); if (bss_conf->assoc) { DPRINTF(ah, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, sc->curbssid); + bss_conf->aid, common->curbssid); /* New association, store aid */ - sc->curaid = bss_conf->aid; + common->curaid = bss_conf->aid; ath9k_hw_write_associd(ah); /* @@ -1001,7 +1002,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_start_ani(sc); } else { DPRINTF(ah, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); - sc->curaid = 0; + common->curaid = 0; /* Stop ANI */ del_timer_sync(&sc->ani.timer); } @@ -1497,6 +1498,7 @@ static int ath_init_btcoex_timer(struct ath_softc *sc) static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) { struct ath_hw *ah = NULL; + struct ath_common *common; int r = 0, i; int csz = 0; int qnum; @@ -1675,8 +1677,10 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); sc->rx.defant = ath9k_hw_getdefantenna(ah); + common = ath9k_hw_common(ah); + if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) - memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN); + memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ @@ -1780,6 +1784,7 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid) { struct ieee80211_hw *hw = sc->hw; + struct ath_common *common; struct ath_hw *ah; int error = 0, i; struct ath_regulatory *reg; @@ -1791,19 +1796,20 @@ int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid) return error; ah = sc->sc_ah; + common = ath9k_hw_common(ah); /* get mac address from hardware and set in mac80211 */ - SET_IEEE80211_PERM_ADDR(hw, ah->macaddr); + SET_IEEE80211_PERM_ADDR(hw, common->macaddr); ath_set_hw_capab(sc, hw); - error = ath_regd_init(&sc->common.regulatory, sc->hw->wiphy, + error = ath_regd_init(&common->regulatory, sc->hw->wiphy, ath9k_reg_notifier); if (error) return error; - reg = &sc->common.regulatory; + reg = &common->regulatory; if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); @@ -2785,6 +2791,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; u32 rfilt = 0; int error, i; @@ -2800,8 +2807,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ah->opmode != NL80211_IFTYPE_AP) { ah->opmode = NL80211_IFTYPE_STATION; ath9k_hw_setopmode(ah); - memcpy(sc->curbssid, sc->sc_ah->macaddr, ETH_ALEN); - sc->curaid = 0; + memcpy(common->curbssid, common->macaddr, ETH_ALEN); + common->curaid = 0; ath9k_hw_write_associd(ah); /* Request full reset to get hw opmode changed properly */ sc->sc_flags |= SC_OP_FULL_RESET; @@ -2814,9 +2821,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: /* Set BSSID */ - memcpy(sc->curbssid, bss_conf->bssid, ETH_ALEN); + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); - sc->curaid = 0; + common->curaid = 0; ath9k_hw_write_associd(ah); /* Set aggregation protection mode parameters */ @@ -2824,7 +2831,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "RX filter 0x%x bssid %pM aid 0x%x\n", - rfilt, sc->curbssid, sc->curaid); + rfilt, common->curbssid, common->curaid); /* need to reconfigure the beacon */ sc->sc_flags &= ~SC_OP_BEACONS ; @@ -2863,7 +2870,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) ath9k_hw_keysetmac(sc->sc_ah, (u16)i, - sc->curbssid); + common->curbssid); } /* Only legacy IBSS for now */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 529cab6bfe66..3bdd4e637219 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -272,6 +272,8 @@ rx_next: static void ath_opmode_init(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + u32 rfilt, mfilt[2]; /* configure rx filter */ @@ -286,7 +288,7 @@ static void ath_opmode_init(struct ath_softc *sc) ath9k_hw_setopmode(ah); /* Handle any link-level address change. */ - ath9k_hw_setmac(ah, sc->sc_ah->macaddr); + ath9k_hw_setmac(ah, common->macaddr); /* calculate and install multicast filter */ mfilt[0] = mfilt[1] = ~0; @@ -527,12 +529,13 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) { struct ieee80211_mgmt *mgmt; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); if (skb->len < 24 + 8 + 2 + 2) return; mgmt = (struct ieee80211_mgmt *)skb->data; - if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0) + if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) return; /* not from our current AP */ sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 52becd32ad8c..7b763b6555fd 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -40,6 +40,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_vif_iter_data iter_data; int i, j; u8 mask[ETH_ALEN]; @@ -51,7 +52,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) */ iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC); if (iter_data.addr) { - memcpy(iter_data.addr, sc->sc_ah->macaddr, ETH_ALEN); + memcpy(iter_data.addr, common->macaddr, ETH_ALEN); iter_data.count = 1; } else iter_data.count = 0; @@ -86,12 +87,12 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) kfree(iter_data.addr); /* Invert the mask and configure hardware */ - sc->bssidmask[0] = ~mask[0]; - sc->bssidmask[1] = ~mask[1]; - sc->bssidmask[2] = ~mask[2]; - sc->bssidmask[3] = ~mask[3]; - sc->bssidmask[4] = ~mask[4]; - sc->bssidmask[5] = ~mask[5]; + common->bssidmask[0] = ~mask[0]; + common->bssidmask[1] = ~mask[1]; + common->bssidmask[2] = ~mask[2]; + common->bssidmask[3] = ~mask[3]; + common->bssidmask[4] = ~mask[4]; + common->bssidmask[5] = ~mask[5]; ath9k_hw_setbssidmask(sc->sc_ah); } @@ -100,6 +101,7 @@ int ath9k_wiphy_add(struct ath_softc *sc) { int i, error; struct ath_wiphy *aphy; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_hw *hw; u8 addr[ETH_ALEN]; @@ -138,7 +140,7 @@ int ath9k_wiphy_add(struct ath_softc *sc) sc->sec_wiphy[i] = aphy; spin_unlock_bh(&sc->wiphy_lock); - memcpy(addr, sc->sc_ah->macaddr, ETH_ALEN); + memcpy(addr, common->macaddr, ETH_ALEN); addr[0] |= 0x02; /* Locally managed address */ /* * XOR virtual wiphy index into the least significant bits to generate -- cgit v1.2.3 From 8c727e70860dab0cf34a68591cd3f2043a9b9757 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 10:10:54 -0700 Subject: ar9170: make use of common macaddr and curbssid These are provided by ath_common. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 2 -- drivers/net/wireless/ath/ar9170/mac.c | 5 +++-- drivers/net/wireless/ath/ar9170/main.c | 6 ++++-- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index 914e4718a9a8..c5576eec12ae 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -172,8 +172,6 @@ struct ar9170 { /* interface mode settings */ struct ieee80211_vif *vif; - u8 mac_addr[ETH_ALEN]; - u8 bssid[ETH_ALEN]; /* beaconing */ struct sk_buff *beacon; diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c index 0c6273a63d6b..ddc8c09dc79e 100644 --- a/drivers/net/wireless/ath/ar9170/mac.c +++ b/drivers/net/wireless/ath/ar9170/mac.c @@ -311,13 +311,14 @@ static int ar9170_set_promiscouous(struct ar9170 *ar) int ar9170_set_operating_mode(struct ar9170 *ar) { + struct ath_common *common = &ar->common; u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS; u8 *mac_addr, *bssid; int err; if (ar->vif) { - mac_addr = ar->mac_addr; - bssid = ar->bssid; + mac_addr = common->macaddr; + bssid = common->curbssid; switch (ar->vif->type) { case NL80211_IFTYPE_MESH_POINT: diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index c1f8c69db165..81c6cf1135bc 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -1952,6 +1952,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ar9170 *ar = hw->priv; + struct ath_common *common = &ar->common; int err = 0; mutex_lock(&ar->mutex); @@ -1962,7 +1963,7 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw, } ar->vif = conf->vif; - memcpy(ar->mac_addr, conf->mac_addr, ETH_ALEN); + memcpy(common->macaddr, conf->mac_addr, ETH_ALEN); if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { ar->rx_software_decryption = true; @@ -2131,12 +2132,13 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { struct ar9170 *ar = hw->priv; + struct ath_common *common = &ar->common; int err = 0; mutex_lock(&ar->mutex); if (changed & BSS_CHANGED_BSSID) { - memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN); + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); err = ar9170_set_operating_mode(ar); if (err) goto out; -- cgit v1.2.3 From 954fecea5d1df4d1dc7bf9a822a2fad308e8588e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 10:51:33 -0700 Subject: ath5k: use common curbssid, bssidmask and macaddr The ah_sta_id was really being used as the macaddr. ath5k still does not use the association ID now passed up by mac80211, that can be fixed later. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 9 -------- drivers/net/wireless/ath/ath5k/attach.c | 7 ++++-- drivers/net/wireless/ath/ath5k/base.c | 8 ++++--- drivers/net/wireless/ath/ath5k/pcu.c | 38 +++++++++------------------------ drivers/net/wireless/ath/ath5k/reset.c | 13 ++++++----- 5 files changed, 28 insertions(+), 47 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 93a9c1f93f69..f46a92e78b32 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1060,14 +1060,6 @@ struct ath5k_hw { u8 ah_def_ant; bool ah_software_retry; - u8 ah_sta_id[ETH_ALEN]; - - /* Current BSSID we are trying to assoc to / create. - * This is passed by mac80211 on config_interface() and cached here for - * use in resets */ - u8 ah_bssid[ETH_ALEN]; - u8 ah_bssid_mask[ETH_ALEN]; - int ah_gpio_npins; struct ath5k_capabilities ah_capabilities; @@ -1196,7 +1188,6 @@ extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah); /* Protocol Control Unit Functions */ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); /* BSSID Functions */ -extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac); extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id); extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 9a009a78a046..2d262c7d9061 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -104,6 +104,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah) struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc) { struct ath5k_hw *ah; + struct ath_common *common; struct pci_dev *pdev = sc->pdev; struct ath5k_eeprom_info *ee; int ret; @@ -118,7 +119,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc) } ah->ah_sc = sc; + ah->ah_sc->ah = ah; ah->ah_iobase = sc->iobase; + common = ath5k_hw_common(ah); /* * HW information @@ -336,8 +339,8 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc) ath5k_hw_set_lladdr(ah, (u8[ETH_ALEN]){}); /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ - memcpy(ah->ah_bssid, ath_bcast_mac, ETH_ALEN); - ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN); + ath5k_hw_set_associd(ah, common->curbssid, 0); ath5k_hw_set_opmode(ah); ath5k_hw_rfgain_opt_init(ah); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index a28d79555dfc..efee68c8b1ab 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1685,13 +1685,14 @@ static void ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, struct ieee80211_rx_status *rxs) { + struct ath_common *common = ath5k_hw_common(sc->ah); u64 tsf, bc_tstamp; u32 hw_tu; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; if (ieee80211_is_beacon(mgmt->frame_control) && le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && - memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) { + memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) == 0) { /* * Received an IBSS beacon with the same BSSID. Hardware *must* * have updated the local TSF. We have to work around various @@ -3177,6 +3178,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); unsigned long flags; mutex_lock(&sc->lock); @@ -3185,10 +3187,10 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_BSSID) { /* Cache for later use during resets */ - memcpy(ah->ah_bssid, bss_conf->bssid, ETH_ALEN); + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); /* XXX: assoc id is set to 0 for now, mac80211 doesn't have * a clean way of letting us retrieve this yet. */ - ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + ath5k_hw_set_associd(ah, common->curbssid, 0); mmiowb(); } diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 7bbcfe4fe34b..f03c06d583e6 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -46,6 +46,7 @@ */ int ath5k_hw_set_opmode(struct ath5k_hw *ah) { + struct ath_common *common = ath5k_hw_common(ah); u32 pcu_reg, beacon_reg, low_id, high_id; @@ -97,8 +98,8 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah) /* * Set PCU registers */ - low_id = get_unaligned_le32(ah->ah_sta_id); - high_id = get_unaligned_le16(ah->ah_sta_id + 4); + low_id = get_unaligned_le32(common->macaddr); + high_id = get_unaligned_le16(common->macaddr + 4); ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); @@ -240,28 +241,6 @@ int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) return 0; } - -/****************\ -* BSSID handling * -\****************/ - -/** - * ath5k_hw_get_lladdr - Get station id - * - * @ah: The &struct ath5k_hw - * @mac: The card's mac address - * - * Initialize ah->ah_sta_id using the mac address provided - * (just a memcpy). - * - * TODO: Remove it once we merge ath5k_softc and ath5k_hw - */ -void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) -{ - ATH5K_TRACE(ah->ah_sc); - memcpy(mac, ah->ah_sta_id, ETH_ALEN); -} - /** * ath5k_hw_set_lladdr - Set station id * @@ -272,12 +251,13 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) */ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) { + struct ath_common *common = ath5k_hw_common(ah); u32 low_id, high_id; u32 pcu_reg; ATH5K_TRACE(ah->ah_sc); /* Set new station ID */ - memcpy(ah->ah_sta_id, mac, ETH_ALEN); + memcpy(common->macaddr, mac, ETH_ALEN); pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; @@ -301,6 +281,7 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) */ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) { + struct ath_common *common = ath5k_hw_common(ah); u32 low_id, high_id; u16 tim_offset = 0; @@ -308,10 +289,10 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) * Set simple BSSID mask on 5212 */ if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, get_unaligned_le32(ah->ah_bssid_mask), + ath5k_hw_reg_write(ah, get_unaligned_le32(common->bssidmask), AR5K_BSS_IDM0); ath5k_hw_reg_write(ah, - get_unaligned_le16(ah->ah_bssid_mask + 4), + get_unaligned_le16(common->curbssid + 4), AR5K_BSS_IDM1); } @@ -433,12 +414,13 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) */ int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) { + struct ath_common *common = ath5k_hw_common(ah); u32 low_id, high_id; ATH5K_TRACE(ah->ah_sc); /* Cache bssid mask so that we can restore it * on reset */ - memcpy(ah->ah_bssid_mask, mask, ETH_ALEN); + memcpy(common->bssidmask, mask, ETH_ALEN); if (ah->ah_version == AR5K_AR5212) { low_id = get_unaligned_le32(mask); high_id = get_unaligned_le16(mask + 4); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 3454dacc2af8..51aff7652c4b 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -872,6 +872,7 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel) { + struct ath_common *common = ath5k_hw_common(ah); u32 s_seq[10], s_ant, s_led[3], staid1_flags, tsf_up, tsf_lo; u32 phy_tst1; u8 mode, freq, ee_mode, ant[2]; @@ -1173,10 +1174,12 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO); /* Restore sta_id flags and preserve our mac address*/ - ath5k_hw_reg_write(ah, get_unaligned_le32(ah->ah_sta_id), - AR5K_STA_ID0); - ath5k_hw_reg_write(ah, staid1_flags | get_unaligned_le16(ah->ah_sta_id), - AR5K_STA_ID1); + ath5k_hw_reg_write(ah, + get_unaligned_le32(common->macaddr), + AR5K_STA_ID0); + ath5k_hw_reg_write(ah, + staid1_flags | get_unaligned_le16(common->macaddr), + AR5K_STA_ID1); /* @@ -1185,7 +1188,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Restore bssid and bssid mask */ /* XXX: add ah->aid once mac80211 gives this to us */ - ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + ath5k_hw_set_associd(ah, common->curbssid, 0); /* Set PCU config */ ath5k_hw_set_opmode(ah); -- cgit v1.2.3 From 394317fc793eb25dbbda4432d29d97cd80f3b561 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 10:57:00 -0700 Subject: ath5k: initialize eeprom struct early on attach This fixes this sparse warning: CHECK drivers/net/wireless/ath/ath5k/attach.c drivers/net/wireless/ath/ath5k/attach.c:288:42: warning: symbol 'ee' shadows an earlier one drivers/net/wireless/ath/ath5k/attach.c:109:34: originally declared here Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/attach.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 2d262c7d9061..123612a8a5c6 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -281,12 +281,12 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc) goto err_free; } + ee = &ah->ah_capabilities.cap_eeprom; + /* * Write PCI-E power save settings */ if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) { - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES); ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES); @@ -324,7 +324,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc) } /* Crypto settings */ - ee = &ah->ah_capabilities.cap_eeprom; ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 && (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && !AR5K_EEPROM_AES_DIS(ee->ee_misc5)); -- cgit v1.2.3 From 27c51f1a349f3e4eb9c1d6d3a548eafe1828cc7a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 11:08:14 -0700 Subject: ath9k: move ath_common to ath_hw This ensures that we can access common on hw related code independent of the driver core. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 +--- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 22 +++++++++++----------- drivers/net/wireless/ath/ath9k/recv.c | 10 ++++++---- 4 files changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 757f17fddcfd..0c64c801a150 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -553,8 +553,6 @@ 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 @@ -649,7 +647,7 @@ int ath_cabq_update(struct ath_softc *); static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) { - return &ah->ah_sc->common; + return &ah->common; } static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6aee01343d3a..f1dc98927c4a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -435,6 +435,7 @@ struct ath_gen_timer_table { struct ath_hw { struct ath_softc *ah_sc; + struct ath_common common; struct ath9k_hw_version hw_version; struct ath9k_ops_config config; struct ath9k_hw_capabilities caps; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a96350d2aace..dc8d47e4d0f5 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1348,7 +1348,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_regulatory *reg = &sc->common.regulatory; + struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); return ath_reg_notifier_apply(wiphy, request, reg); } @@ -1516,14 +1516,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, (unsigned long)sc); - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - ath_read_cachesize(sc, &csz); - /* XXX assert csz is non-zero */ - sc->common.cachelsz = csz << 2; /* convert to bytes */ - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); if (!ah) { r = -ENOMEM; @@ -1535,6 +1527,16 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) ah->hw_version.subsysid = subsysid; sc->sc_ah = ah; + common = ath9k_hw_common(ah); + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + ath_read_cachesize(sc, &csz); + /* XXX assert csz is non-zero */ + common->cachelsz = csz << 2; /* convert to bytes */ + if (ath9k_init_debug(ah) < 0) dev_err(sc->dev, "Unable to create debugfs files\n"); @@ -1677,8 +1679,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); sc->rx.defant = ath9k_hw_getdefantenna(ah); - common = ath9k_hw_common(ah); - if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 3bdd4e637219..97a5efe18d66 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -297,6 +297,7 @@ static void ath_opmode_init(struct ath_softc *sc) int ath_rx_init(struct ath_softc *sc, int nbufs) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct sk_buff *skb; struct ath_buf *bf; int error = 0; @@ -306,10 +307,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->common.cachelsz, (u16)64)); + min(common->cachelsz, (u16)64)); DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", - sc->common.cachelsz, sc->rx.bufsize); + common->cachelsz, sc->rx.bufsize); /* Initialize rx descriptors */ @@ -322,7 +323,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->common, sc->rx.bufsize, GFP_KERNEL); + skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_KERNEL); if (skb == NULL) { error = -ENOMEM; goto err; @@ -654,6 +655,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct sk_buff *skb = NULL, *requeue_skb; struct ieee80211_rx_status rx_status; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hdr *hdr; int hdrlen, padsize, retval; bool decrypt_error = false; @@ -752,7 +754,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->common, sc->rx.bufsize, GFP_ATOMIC); + requeue_skb = ath_rxbuf_alloc(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 -- cgit v1.2.3 From db7197184802578314d974e4b2bc961bdcec8f8c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 11:20:57 -0700 Subject: ath5k: move ath_common to ath5k_hw Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 2 ++ drivers/net/wireless/ath/ath5k/base.c | 21 +++++++++++++-------- drivers/net/wireless/ath/ath5k/base.h | 3 +-- 3 files changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index f46a92e78b32..fee16fdd9c5a 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -35,6 +35,7 @@ * TODO: Make a more generic struct (eg. add more stuff to ath5k_capabilities) * and clean up common bits, then introduce set/get functions in eeprom.c */ #include "eeprom.h" +#include "../ath.h" /* PCI IDs */ #define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */ @@ -1020,6 +1021,7 @@ struct ath5k_capabilities { /* TODO: Clean up and merge with ath5k_softc */ struct ath5k_hw { u32 ah_magic; + struct ath_common common; struct ath5k_softc *ah_sc; void __iomem *ah_iobase; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index efee68c8b1ab..06fc893723fa 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -444,6 +444,7 @@ ath5k_pci_probe(struct pci_dev *pdev, { void __iomem *mem; struct ath5k_softc *sc; + struct ath_common *common; struct ieee80211_hw *hw; int ret; u8 csz; @@ -547,7 +548,6 @@ 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 << 2; /* convert to bytes */ sc->opmode = NL80211_IFTYPE_STATION; sc->bintval = 1000; mutex_init(&sc->lock); @@ -572,6 +572,9 @@ ath5k_pci_probe(struct pci_dev *pdev, goto err_irq; } + common = ath5k_hw_common(sc->ah); + common->cachelsz = csz << 2; /* convert to bytes */ + /* set up multi-rate retry capabilities */ if (sc->ah->ah_version == AR5K_AR5212) { hw->max_rates = 4; @@ -718,7 +721,7 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath5k_softc *sc = hw->priv; - struct ath_regulatory *regulatory = &sc->common.regulatory; + struct ath_regulatory *regulatory = ath5k_hw_regulatory(sc->ah); return ath_reg_notifier_apply(wiphy, request, regulatory); } @@ -728,7 +731,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; - struct ath_regulatory *regulatory = &sc->common.regulatory; + struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah); u8 mac[ETH_ALEN] = {}; int ret; @@ -1153,19 +1156,20 @@ ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) static struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr) { + struct ath_common *common = ath5k_hw_common(sc->ah); struct sk_buff *skb; /* * Allocate buffer with headroom_needed space for the * fake physical layer header at the start. */ - skb = ath_rxbuf_alloc(&sc->common, - sc->rxbufsize + sc->common.cachelsz - 1, + skb = ath_rxbuf_alloc(common, + sc->rxbufsize + common->cachelsz - 1, GFP_ATOMIC); if (!skb) { ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", - sc->rxbufsize + sc->common.cachelsz - 1); + sc->rxbufsize + common->cachelsz - 1); return NULL; } @@ -1606,13 +1610,14 @@ static int ath5k_rx_start(struct ath5k_softc *sc) { struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); struct ath5k_buf *bf; int ret; - sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz); + sc->rxbufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz); ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", - sc->common.cachelsz, sc->rxbufsize); + 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 a28c42f32c9d..005d25f2e130 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -115,7 +115,6 @@ 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]; @@ -204,7 +203,7 @@ struct ath5k_softc { static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah) { - return &ah->ah_sc->common; + return &ah->common; } static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah) -- cgit v1.2.3 From 867633f026456ff71d4c4890f502c7a61b2adac0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 12:12:23 -0700 Subject: ath9k: Define bus agnostic bluetooth coex prep helper We disable ASPM when enabling bluetooth coexistance. Disabling ASPM is a bus specific operation. In the future other buses may support bluetooth coexistance, an example is USB. To this end move the current routine which disables ASPM into pci.c, and declare it the PCI bt_coex_prep() helper. Additionally, since ASPM is a PCI-Express primitive ensure we don't ever try to muck with ASPM registers on non PCI-express devices. This also cleans up hw.c to not include bus specific headers or utilities. Cc: Vasanthakumar Thiagarajan Cc: Stephen Chen Cc: Zhifeng Cai Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 14 -------------- drivers/net/wireless/ath/ath9k/hw.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 3 ++- drivers/net/wireless/ath/ath9k/pci.c | 17 +++++++++++++++++ 5 files changed, 20 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0c64c801a150..0962505430e2 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -545,6 +545,7 @@ struct ath_bus_ops { void (*read_cachesize)(struct ath_softc *sc, int *csz); void (*cleanup)(struct ath_softc *sc); bool (*eeprom_read)(struct ath_hw *ah, u32 off, u16 *data); + void (*bt_coex_prep)(struct ath_softc *sc); }; struct ath_wiphy; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4e14c307b3da..a3b1ce32cfcb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -16,7 +16,6 @@ #include #include -#include #include "hw.h" #include "ath9k.h" @@ -4294,16 +4293,3 @@ void ath_gen_timer_isr(struct ath_hw *ah) timer->trigger(timer->arg); } } - -/* - * Primitive to disable ASPM - */ -void ath_pcie_aspm_disable(struct ath_softc *sc) -{ - struct pci_dev *pdev = to_pci_dev(sc->dev); - u8 aspm; - - pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); - aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1); - pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); -} diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f1dc98927c4a..f460a06b86ac 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -679,5 +679,4 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); #define ATH_PCIE_CAP_LINK_L0S 1 #define ATH_PCIE_CAP_LINK_L1 2 -void ath_pcie_aspm_disable(struct ath_softc *sc); #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index dc8d47e4d0f5..27ab378ae535 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2241,7 +2241,8 @@ static int ath9k_start(struct ieee80211_hw *hw) AR_STOMP_LOW_WLAN_WGHT); ath9k_hw_btcoex_enable(ah); - ath_pcie_aspm_disable(sc); + if (sc->bus_ops->bt_coex_prep) + sc->bus_ops->bt_coex_prep(sc); if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath9k_btcoex_timer_resume(sc); } diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 903dd8ad9d43..f59d22491ced 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -75,10 +75,27 @@ static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) return true; } +/* + * Bluetooth coexistance requires disabling ASPM. + */ +static void ath_pci_bt_coex_prep(struct ath_softc *sc) +{ + struct pci_dev *pdev = to_pci_dev(sc->dev); + u8 aspm; + + if (!pdev->is_pcie) + return; + + pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); + aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1); + pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); +} + static struct ath_bus_ops ath_pci_bus_ops = { .read_cachesize = ath_pci_read_cachesize, .cleanup = ath_pci_cleanup, .eeprom_read = ath_pci_eeprom_read, + .bt_coex_prep = ath_pci_bt_coex_prep, }; static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -- cgit v1.2.3 From 9e4bffd233f27fe83fc48efb01935aee7d0685bf Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 16:11:21 -0700 Subject: atheros/ath9k: add common read/write ops and port ath9k to use it In an effort to make hw code driver core agnostic read and write operations are defined on the ath_common structure. This patch adds that and makes ath9k use it. This allows drivers like ath9k_htc to define its own read/write ops and still rely on the same hw code. This also paves the way for sharing code between ath9k/ath5k/ath9k_htc. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 6 +++++ drivers/net/wireless/ath/ath9k/ath9k.h | 13 ----------- drivers/net/wireless/ath/ath9k/hw.c | 32 -------------------------- drivers/net/wireless/ath/ath9k/hw.h | 17 ++++++++++++-- drivers/net/wireless/ath/ath9k/main.c | 42 ++++++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 47 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 7589b2aa030b..38be4279affc 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -39,6 +39,11 @@ struct ath_regulatory { struct reg_dmn_pair_mapping *regpair; }; +struct ath_ops { + unsigned int (*read)(void *, u32 reg_offset); + void (*write)(void *, u32 val, u32 reg_offset); +}; + struct ath_common { u16 cachelsz; u16 curaid; @@ -46,6 +51,7 @@ struct ath_common { u8 curbssid[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; struct ath_regulatory regulatory; + struct ath_ops *ops; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 0962505430e2..7c740cf50f7c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -646,16 +646,6 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); int ath_cabq_update(struct ath_softc *); -static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) -{ - return &ah->common; -} - -static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) -{ - return &(ath9k_hw_common(ah)->regulatory); -} - static inline void ath_read_cachesize(struct ath_softc *sc, int *csz) { sc->bus_ops->read_cachesize(sc, csz); @@ -718,8 +708,5 @@ bool ath9k_wiphy_scanning(struct ath_softc *sc); void ath9k_wiphy_work(struct work_struct *work); bool ath9k_all_wiphys_idle(struct ath_softc *sc); -void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val); -unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset); - int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index a3b1ce32cfcb..0ad25987d85c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -81,38 +81,6 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) return ath9k_hw_mac_clks(ah, usecs); } -/* - * Read and write, they both share the same lock. We do this to serialize - * reads and writes on Atheros 802.11n PCI devices only. This is required - * as the FIFO on these devices can only accept sanely 2 requests. After - * that the device goes bananas. Serializing the reads/writes prevents this - * from happening. - */ - -void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val) -{ - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - iowrite32(val, ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); - } else - iowrite32(val, ah->ah_sc->mem + reg_offset); -} - -unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset) -{ - u32 val; - if (ah->config.serialize_regmode == SER_REG_MODE_ON) { - unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - val = ioread32(ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); - } else - val = ioread32(ah->ah_sc->mem + reg_offset); - return val; -} - bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) { int i; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f460a06b86ac..ae351a183416 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -51,8 +51,11 @@ #define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab /* Register read/write primitives */ -#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val)) -#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg)) +#define REG_WRITE(_ah, _reg, _val) \ + ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) + +#define REG_READ(_ah, _reg) \ + ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) #define SM(_v, _f) (((_v) << _f##_S) & _f) #define MS(_v, _f) (((_v) & _f) >> _f##_S) @@ -588,6 +591,16 @@ struct ath_hw { struct ath_gen_timer_table hw_gen_timers; }; +static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) +{ + return &ah->common; +} + +static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) +{ + return &(ath9k_hw_common(ah)->regulatory); +} + /* Initialization, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 27ab378ae535..4a85f6ccb509 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1489,6 +1489,47 @@ static int ath_init_btcoex_timer(struct ath_softc *sc) return 0; } +/* + * Read and write, they both share the same lock. We do this to serialize + * reads and writes on Atheros 802.11n PCI devices only. This is required + * as the FIFO on these devices can only accept sanely 2 requests. After + * that the device goes bananas. Serializing the reads/writes prevents this + * from happening. + */ + +static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + iowrite32(val, ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + iowrite32(val, ah->ah_sc->mem + reg_offset); +} + +static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + u32 val; + + if (ah->config.serialize_regmode == SER_REG_MODE_ON) { + unsigned long flags; + spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); + val = ioread32(ah->ah_sc->mem + reg_offset); + spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + } else + val = ioread32(ah->ah_sc->mem + reg_offset); + return val; +} + +static struct ath_ops ath9k_common_ops = { + .read = ath9k_ioread32, + .write = ath9k_iowrite32, +}; + /* * Initialize and fill ath_softc, ath_sofct is the * "Software Carrier" struct. Historically it has existed @@ -1528,6 +1569,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) sc->sc_ah = ah; common = ath9k_hw_common(ah); + common->ops = &ath9k_common_ops; /* * Cache line size is used to size and align various -- cgit v1.2.3 From 9adca126dbf4bf099bc7051deb6b566725a046dc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 18:04:47 -0700 Subject: ath5k: allocate ath5k_hw prior to initializing hw We can propagate better errors upon failed hw initialization, and set up the ath_common structure for attach purposes. This will become important once we start using the ath_common for read/write ops. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 2 +- drivers/net/wireless/ath/ath5k/ath5k.h | 2 +- drivers/net/wireless/ath/ath5k/attach.c | 23 ++++------------------- drivers/net/wireless/ath/ath5k/base.c | 20 ++++++++++++++++---- 4 files changed, 22 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 38be4279affc..be68cb8cf705 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -51,7 +51,7 @@ struct ath_common { u8 curbssid[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; struct ath_regulatory regulatory; - struct ath_ops *ops; + const struct ath_ops *ops; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index fee16fdd9c5a..29ce868b1f1c 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1147,7 +1147,7 @@ struct ath5k_hw { */ /* Attach/Detach Functions */ -extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc); +extern int ath5k_hw_attach(struct ath5k_softc *sc); extern void ath5k_hw_detach(struct ath5k_hw *ah); /* LED functions */ diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 123612a8a5c6..c0840aba2715 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -101,28 +101,15 @@ static int ath5k_hw_post(struct ath5k_hw *ah) * -ENODEV if the device is not supported or prints an error msg if something * else went wrong. */ -struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc) +int ath5k_hw_attach(struct ath5k_softc *sc) { - struct ath5k_hw *ah; + struct ath5k_hw *ah = sc->ah; struct ath_common *common; struct pci_dev *pdev = sc->pdev; struct ath5k_eeprom_info *ee; int ret; u32 srev; - /*If we passed the test malloc a ath5k_hw struct*/ - ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); - if (ah == NULL) { - ret = -ENOMEM; - ATH5K_ERR(sc, "out of memory\n"); - goto err; - } - - ah->ah_sc = sc; - ah->ah_sc->ah = ah; - ah->ah_iobase = sc->iobase; - common = ath5k_hw_common(ah); - /* * HW information */ @@ -347,11 +334,10 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc) /* turn on HW LEDs */ ath5k_hw_set_ledstate(ah, AR5K_LED_INIT); - return ah; + return 0; err_free: kfree(ah); -err: - return ERR_PTR(ret); + return ret; } /** @@ -371,5 +357,4 @@ void ath5k_hw_detach(struct ath5k_hw *ah) ath5k_eeprom_detach(ah); /* assume interrupts are down */ - kfree(ah); } diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 06fc893723fa..3cb07520d47b 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -565,16 +565,25 @@ ath5k_pci_probe(struct pci_dev *pdev, goto err_free; } - /* Initialize device */ - sc->ah = ath5k_hw_attach(sc); - if (IS_ERR(sc->ah)) { - ret = PTR_ERR(sc->ah); + /*If we passed the test malloc a ath5k_hw struct*/ + sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); + if (!sc->ah) { + ret = -ENOMEM; + ATH5K_ERR(sc, "out of memory\n"); goto err_irq; } + sc->ah->ah_sc = sc; + sc->ah->ah_iobase = sc->iobase; common = ath5k_hw_common(sc->ah); common->cachelsz = csz << 2; /* convert to bytes */ + /* Initialize device */ + ret = ath5k_hw_attach(sc); + if (ret) { + goto err_free_ah; + } + /* set up multi-rate retry capabilities */ if (sc->ah->ah_version == AR5K_AR5212) { hw->max_rates = 4; @@ -643,6 +652,8 @@ err_ah: ath5k_hw_detach(sc->ah); err_irq: free_irq(pdev->irq, sc); +err_free_ah: + kfree(sc->ah); err_free: ieee80211_free_hw(hw); err_map: @@ -664,6 +675,7 @@ ath5k_pci_remove(struct pci_dev *pdev) ath5k_debug_finish_device(sc); ath5k_detach(pdev, hw); ath5k_hw_detach(sc->ah); + kfree(sc->ah); free_irq(pdev->irq, sc); pci_iounmap(pdev, sc->iobase); pci_release_region(pdev, 0); -- cgit v1.2.3 From e5aa847489e543e33a7c72898e72183871ce2916 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 16:55:11 -0700 Subject: ath5k: define ath_common ops Only common ath read/write ops go through the common ops. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 16 ++++++++++------ drivers/net/wireless/ath/ath5k/base.c | 17 +++++++++++++++++ drivers/net/wireless/ath/ath5k/base.h | 11 ----------- 3 files changed, 27 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 29ce868b1f1c..1416562e4d19 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1315,17 +1315,21 @@ static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo) return turbo ? (clock / 80) : (clock / 40); } -/* - * Read from a register - */ +static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah) +{ + return &ah->common; +} + +static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah) +{ + return &(ath5k_hw_common(ah)->regulatory); +} + static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg) { return ioread32(ah->ah_iobase + reg); } -/* - * Write to a register - */ static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg) { iowrite32(val, ah->ah_iobase + reg); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 3cb07520d47b..13bbf3dfc6c3 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -437,6 +437,22 @@ ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val) return name; } +static unsigned int ath5k_ioread32(void *hw_priv, u32 reg_offset) +{ + struct ath5k_hw *ah = (struct ath5k_hw *) hw_priv; + return ath5k_hw_reg_read(ah, reg_offset); +} + +static void ath5k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) +{ + struct ath5k_hw *ah = (struct ath5k_hw *) hw_priv; + ath5k_hw_reg_write(ah, val, reg_offset); +} + +static const struct ath_ops ath5k_common_ops = { + .read = ath5k_ioread32, + .write = ath5k_iowrite32, +}; static int __devinit ath5k_pci_probe(struct pci_dev *pdev, @@ -576,6 +592,7 @@ ath5k_pci_probe(struct pci_dev *pdev, sc->ah->ah_sc = sc; sc->ah->ah_iobase = sc->iobase; common = ath5k_hw_common(sc->ah); + common->ops = &ath5k_common_ops; common->cachelsz = csz << 2; /* convert to bytes */ /* Initialize device */ diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 005d25f2e130..b14ba07e9157 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -201,15 +201,4 @@ struct ath5k_softc { #define ath5k_hw_hasveol(_ah) \ (ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0) -static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah) -{ - return &ah->common; -} - -static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah) -{ - return &(ath5k_hw_common(ah)->regulatory); - -} - #endif -- cgit v1.2.3 From 13b81559200b8e54473e5b140323cbb5f2bb21c0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 10 Sep 2009 17:52:45 -0700 Subject: atheros: define shared bssidmask setting Also make ath5k and ath9k use it, and share register definitions. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/Makefile | 5 +- drivers/net/wireless/ath/ath.h | 3 + drivers/net/wireless/ath/ath5k/ath5k.h | 2 +- drivers/net/wireless/ath/ath5k/attach.c | 2 +- drivers/net/wireless/ath/ath5k/base.c | 1 + drivers/net/wireless/ath/ath5k/initvals.c | 4 +- drivers/net/wireless/ath/ath5k/pcu.c | 121 ++-------------------------- drivers/net/wireless/ath/ath5k/reg.h | 8 +- drivers/net/wireless/ath/ath9k/hw.c | 10 +-- drivers/net/wireless/ath/ath9k/main.c | 1 + drivers/net/wireless/ath/ath9k/recv.c | 2 +- drivers/net/wireless/ath/ath9k/reg.h | 5 +- drivers/net/wireless/ath/ath9k/virtual.c | 2 +- drivers/net/wireless/ath/hw.c | 126 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/reg.h | 27 +++++++ 15 files changed, 179 insertions(+), 140 deletions(-) create mode 100644 drivers/net/wireless/ath/hw.c create mode 100644 drivers/net/wireless/ath/reg.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 4bb0132ada37..6ebf2148167a 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -3,4 +3,7 @@ obj-$(CONFIG_ATH9K) += ath9k/ obj-$(CONFIG_AR9170_USB) += ar9170/ obj-$(CONFIG_ATH_COMMON) += ath.o -ath-objs := main.o regd.o + +ath-objs := main.o \ + regd.o \ + hw.o diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index be68cb8cf705..0582ee4a493e 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -45,6 +45,7 @@ struct ath_ops { }; struct ath_common { + void *ah; u16 cachelsz; u16 curaid; u8 macaddr[ETH_ALEN]; @@ -58,4 +59,6 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, u32 len, gfp_t gfp_mask); +void ath_hw_setbssidmask(struct ath_common *common); + #endif /* ATH_H */ diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 1416562e4d19..43585d54c270 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1192,7 +1192,7 @@ extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); /* BSSID Functions */ extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id); -extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); +extern void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); /* Receive start/stop functions */ extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah); extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index c0840aba2715..e230de8ad320 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -104,7 +104,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah) int ath5k_hw_attach(struct ath5k_softc *sc) { struct ath5k_hw *ah = sc->ah; - struct ath_common *common; + struct ath_common *common = ath5k_hw_common(ah); struct pci_dev *pdev = sc->pdev; struct ath5k_eeprom_info *ee; int ret; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 13bbf3dfc6c3..1abbebc2bd26 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -593,6 +593,7 @@ ath5k_pci_probe(struct pci_dev *pdev, sc->ah->ah_iobase = sc->iobase; common = ath5k_hw_common(sc->ah); common->ops = &ath5k_common_ops; + common->ah = sc->ah; common->cachelsz = csz << 2; /* convert to bytes */ /* Initialize device */ diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c index 18eb5190ce4b..8fa439308828 100644 --- a/drivers/net/wireless/ath/ath5k/initvals.c +++ b/drivers/net/wireless/ath/ath5k/initvals.c @@ -560,8 +560,8 @@ static const struct ath5k_ini ar5212_ini_common_start[] = { { AR5K_SLEEP0, 0x0002aaaa }, { AR5K_SLEEP1, 0x02005555 }, { AR5K_SLEEP2, 0x00000000 }, - { AR5K_BSS_IDM0, 0xffffffff }, - { AR5K_BSS_IDM1, 0x0000ffff }, + { AR_BSSMSKL, 0xffffffff }, + { AR_BSSMSKU, 0x0000ffff }, { AR5K_TXPC, 0x00000000 }, { AR5K_PROFCNT_TX, 0x00000000 }, { AR5K_PROFCNT_RX, 0x00000000 }, diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index f03c06d583e6..9ac763875a98 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -290,10 +290,10 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) */ if (ah->ah_version == AR5K_AR5212) { ath5k_hw_reg_write(ah, get_unaligned_le32(common->bssidmask), - AR5K_BSS_IDM0); + AR_BSSMSKL); ath5k_hw_reg_write(ah, get_unaligned_le16(common->curbssid + 4), - AR5K_BSS_IDM1); + AR_BSSMSKU); } /* @@ -301,9 +301,9 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) */ low_id = get_unaligned_le32(bssid); high_id = get_unaligned_le16(bssid); - ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); + ath5k_hw_reg_write(ah, low_id, AR_BSSMSKL); ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << - AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); + AR5K_BSS_ID1_AID_S), AR_BSSMSKU); if (assoc_id == 0) { ath5k_hw_disable_pspoll(ah); @@ -316,125 +316,18 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) ath5k_hw_enable_pspoll(ah, NULL, 0); } -/** - * ath5k_hw_set_bssid_mask - filter out bssids we listen - * - * @ah: the &struct ath5k_hw - * @mask: the bssid_mask, a u8 array of size ETH_ALEN - * - * BSSID masking is a method used by AR5212 and newer hardware to inform PCU - * which bits of the interface's MAC address should be looked at when trying - * to decide which packets to ACK. In station mode and AP mode with a single - * BSS every bit matters since we lock to only one BSS. In AP mode with - * multiple BSSes (virtual interfaces) not every bit matters because hw must - * accept frames for all BSSes and so we tweak some bits of our mac address - * in order to have multiple BSSes. - * - * NOTE: This is a simple filter and does *not* filter out all - * relevant frames. Some frames that are not for us might get ACKed from us - * by PCU because they just match the mask. - * - * When handling multiple BSSes you can get the BSSID mask by computing the - * set of ~ ( MAC XOR BSSID ) for all bssids we handle. - * - * When you do this you are essentially computing the common bits of all your - * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with - * the MAC address to obtain the relevant bits and compare the result with - * (frame's BSSID & mask) to see if they match. - */ -/* - * Simple example: on your card you have have two BSSes you have created with - * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. - * There is another BSSID-03 but you are not part of it. For simplicity's sake, - * assuming only 4 bits for a mac address and for BSSIDs you can then have: - * - * \ - * MAC: 0001 | - * BSSID-01: 0100 | --> Belongs to us - * BSSID-02: 1001 | - * / - * ------------------- - * BSSID-03: 0110 | --> External - * ------------------- - * - * Our bssid_mask would then be: - * - * On loop iteration for BSSID-01: - * ~(0001 ^ 0100) -> ~(0101) - * -> 1010 - * bssid_mask = 1010 - * - * On loop iteration for BSSID-02: - * bssid_mask &= ~(0001 ^ 1001) - * bssid_mask = (1010) & ~(0001 ^ 1001) - * bssid_mask = (1010) & ~(1001) - * bssid_mask = (1010) & (0110) - * bssid_mask = 0010 - * - * A bssid_mask of 0010 means "only pay attention to the second least - * significant bit". This is because its the only bit common - * amongst the MAC and all BSSIDs we support. To findout what the real - * common bit is we can simply "&" the bssid_mask now with any BSSID we have - * or our MAC address (we assume the hardware uses the MAC address). - * - * Now, suppose there's an incoming frame for BSSID-03: - * - * IFRAME-01: 0110 - * - * An easy eye-inspeciton of this already should tell you that this frame - * will not pass our check. This is beacuse the bssid_mask tells the - * hardware to only look at the second least significant bit and the - * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB - * as 1, which does not match 0. - * - * So with IFRAME-01 we *assume* the hardware will do: - * - * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; - * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; - * --> allow = (0010) == 0000 ? 1 : 0; - * --> allow = 0 - * - * Lets now test a frame that should work: - * - * IFRAME-02: 0001 (we should allow) - * - * allow = (0001 & 1010) == 1010 - * - * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; - * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; - * --> allow = (0010) == (0010) - * --> allow = 1 - * - * Other examples: - * - * IFRAME-03: 0100 --> allowed - * IFRAME-04: 1001 --> allowed - * IFRAME-05: 1101 --> allowed but its not for us!!! - * - */ -int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) +void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) { struct ath_common *common = ath5k_hw_common(ah); - u32 low_id, high_id; ATH5K_TRACE(ah->ah_sc); /* Cache bssid mask so that we can restore it * on reset */ memcpy(common->bssidmask, mask, ETH_ALEN); - if (ah->ah_version == AR5K_AR5212) { - low_id = get_unaligned_le32(mask); - high_id = get_unaligned_le16(mask + 4); - - ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); - ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); - - return 0; - } - - return -EIO; + if (ah->ah_version == AR5K_AR5212) + ath_hw_setbssidmask(common); } - /************\ * RX Control * \************/ diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index c63ea6afd96f..64227abe3c20 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -35,7 +35,7 @@ * released by Atheros and on various debug messages found on the net. */ - +#include "../reg.h" /*====MAC DMA REGISTERS====*/ @@ -1649,12 +1649,6 @@ #define AR5K_SLEEP2_DTIM_PER 0xffff0000 /* Mask for DTIM period (?) */ #define AR5K_SLEEP2_DTIM_PER_S 16 -/* - * BSSID mask registers - */ -#define AR5K_BSS_IDM0 0x80e0 /* Upper bits */ -#define AR5K_BSS_IDM1 0x80e4 /* Lower bits */ - /* * TX power control (TPC) register * diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0ad25987d85c..5fb94fa45ff9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2441,7 +2441,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | ah->sta_id1_defaults); ath9k_hw_set_operating_mode(ah, ah->opmode); - ath9k_hw_setbssidmask(ah); + ath_hw_setbssidmask(common); REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); @@ -3990,14 +3990,6 @@ void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1) REG_WRITE(ah, AR_MCAST_FIL1, filter1); } -void ath9k_hw_setbssidmask(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - - REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(common->bssidmask)); - REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(common->bssidmask + 4)); -} - void ath9k_hw_write_associd(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4a85f6ccb509..d752b167f5ad 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1570,6 +1570,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) common = ath9k_hw_common(ah); common->ops = &ath9k_common_ops; + common->ah = ah; /* * Cache line size is used to size and align various diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 97a5efe18d66..fb635a0a34e8 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -282,7 +282,7 @@ static void ath_opmode_init(struct ath_softc *sc) /* configure bssid mask */ if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) - ath9k_hw_setbssidmask(ah); + ath_hw_setbssidmask(common); /* configure operational mode */ ath9k_hw_setopmode(ah); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index d83b77f821e9..ceed0095efac 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -17,6 +17,8 @@ #ifndef REG_H #define REG_H +#include "../reg.h" + #define AR_CR 0x0008 #define AR_CR_RXE 0x00000004 #define AR_CR_RXD 0x00000020 @@ -1421,9 +1423,6 @@ enum { #define AR_SLEEP2_BEACON_TIMEOUT 0xFFE00000 #define AR_SLEEP2_BEACON_TIMEOUT_S 21 -#define AR_BSSMSKL 0x80e0 -#define AR_BSSMSKU 0x80e4 - #define AR_TPC 0x80e8 #define AR_TPC_ACK 0x0000003f #define AR_TPC_ACK_S 0x00 diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 7b763b6555fd..bc7d173b6fae 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -94,7 +94,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) common->bssidmask[4] = ~mask[4]; common->bssidmask[5] = ~mask[5]; - ath9k_hw_setbssidmask(sc->sc_ah); + ath_hw_setbssidmask(common); } int ath9k_wiphy_add(struct ath_softc *sc) diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c new file mode 100644 index 000000000000..ecc9eb01f4fa --- /dev/null +++ b/drivers/net/wireless/ath/hw.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 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. + */ + +#include + +#include "ath.h" +#include "reg.h" + +#define REG_READ common->ops->read +#define REG_WRITE common->ops->write + +/** + * ath_hw_set_bssid_mask - filter out bssids we listen + * + * @common: the ath_common struct for the device. + * + * BSSID masking is a method used by AR5212 and newer hardware to inform PCU + * which bits of the interface's MAC address should be looked at when trying + * to decide which packets to ACK. In station mode and AP mode with a single + * BSS every bit matters since we lock to only one BSS. In AP mode with + * multiple BSSes (virtual interfaces) not every bit matters because hw must + * accept frames for all BSSes and so we tweak some bits of our mac address + * in order to have multiple BSSes. + * + * NOTE: This is a simple filter and does *not* filter out all + * relevant frames. Some frames that are not for us might get ACKed from us + * by PCU because they just match the mask. + * + * When handling multiple BSSes you can get the BSSID mask by computing the + * set of ~ ( MAC XOR BSSID ) for all bssids we handle. + * + * When you do this you are essentially computing the common bits of all your + * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with + * the MAC address to obtain the relevant bits and compare the result with + * (frame's BSSID & mask) to see if they match. + * + * Simple example: on your card you have have two BSSes you have created with + * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. + * There is another BSSID-03 but you are not part of it. For simplicity's sake, + * assuming only 4 bits for a mac address and for BSSIDs you can then have: + * + * \ + * MAC: 0001 | + * BSSID-01: 0100 | --> Belongs to us + * BSSID-02: 1001 | + * / + * ------------------- + * BSSID-03: 0110 | --> External + * ------------------- + * + * Our bssid_mask would then be: + * + * On loop iteration for BSSID-01: + * ~(0001 ^ 0100) -> ~(0101) + * -> 1010 + * bssid_mask = 1010 + * + * On loop iteration for BSSID-02: + * bssid_mask &= ~(0001 ^ 1001) + * bssid_mask = (1010) & ~(0001 ^ 1001) + * bssid_mask = (1010) & ~(1001) + * bssid_mask = (1010) & (0110) + * bssid_mask = 0010 + * + * A bssid_mask of 0010 means "only pay attention to the second least + * significant bit". This is because its the only bit common + * amongst the MAC and all BSSIDs we support. To findout what the real + * common bit is we can simply "&" the bssid_mask now with any BSSID we have + * or our MAC address (we assume the hardware uses the MAC address). + * + * Now, suppose there's an incoming frame for BSSID-03: + * + * IFRAME-01: 0110 + * + * An easy eye-inspeciton of this already should tell you that this frame + * will not pass our check. This is beacuse the bssid_mask tells the + * hardware to only look at the second least significant bit and the + * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB + * as 1, which does not match 0. + * + * So with IFRAME-01 we *assume* the hardware will do: + * + * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; + * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; + * --> allow = (0010) == 0000 ? 1 : 0; + * --> allow = 0 + * + * Lets now test a frame that should work: + * + * IFRAME-02: 0001 (we should allow) + * + * allow = (0001 & 1010) == 1010 + * + * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; + * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; + * --> allow = (0010) == (0010) + * --> allow = 1 + * + * Other examples: + * + * IFRAME-03: 0100 --> allowed + * IFRAME-04: 1001 --> allowed + * IFRAME-05: 1101 --> allowed but its not for us!!! + * + */ +void ath_hw_setbssidmask(struct ath_common *common) +{ + void *ah = common->ah; + + REG_WRITE(ah, get_unaligned_le32(common->bssidmask), AR_BSSMSKL); + REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU); +} +EXPORT_SYMBOL(ath_hw_setbssidmask); diff --git a/drivers/net/wireless/ath/reg.h b/drivers/net/wireless/ath/reg.h new file mode 100644 index 000000000000..dfe1fbec24f5 --- /dev/null +++ b/drivers/net/wireless/ath/reg.h @@ -0,0 +1,27 @@ +/* + * 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_REGISTERS_H +#define ATH_REGISTERS_H + +/* + * BSSID mask registers. See ath_hw_set_bssid_mask() + * for detailed documentation about these registers. + */ +#define AR_BSSMSKL 0x80e0 +#define AR_BSSMSKU 0x80e4 + +#endif /* ATH_REGISTERS_H */ -- cgit v1.2.3 From b002a4a950e41326310795cf4a0c74d0e90fa70a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 13 Sep 2009 00:03:27 -0700 Subject: atheros: add ieee80211_hw to ath_common Make use of it on hw code in ath9k to avoid using the ath9k ath_softc. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 2 ++ drivers/net/wireless/ath/ath5k/base.c | 1 + drivers/net/wireless/ath/ath9k/ani.c | 4 ++-- drivers/net/wireless/ath/ath9k/calib.c | 4 ++-- drivers/net/wireless/ath/ath9k/hw.c | 8 ++++---- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 1 + 7 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 0582ee4a493e..88654138f999 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -19,6 +19,7 @@ #include #include +#include static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -46,6 +47,7 @@ struct ath_ops { struct ath_common { void *ah; + struct ieee80211_hw *hw; u16 cachelsz; u16 curaid; u8 macaddr[ETH_ALEN]; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 1abbebc2bd26..70831f1bcf04 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -594,6 +594,7 @@ ath5k_pci_probe(struct pci_dev *pdev, common = ath5k_hw_common(sc->ah); common->ops = &ath5k_common_ops; common->ah = sc->ah; + common->hw = hw; common->cachelsz = csz << 2; /* convert to bytes */ /* Initialize device */ diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index e4f9559d25b6..9682c49ab454 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -271,7 +271,7 @@ static void ath9k_ani_restart(struct ath_hw *ah) static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) { - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; struct ar5416AniState *aniState; int32_t rssi; @@ -343,7 +343,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) { - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; struct ar5416AniState *aniState; int32_t rssi; diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 30106f49322a..bdd4a19f32be 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -278,7 +278,7 @@ static bool ath9k_hw_per_calibration(struct ath_hw *ah, static bool ath9k_hw_iscal_supported(struct ath_hw *ah, enum ath9k_cal_types calType) { - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; switch (calType & ah->supp_cals) { case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */ @@ -555,7 +555,7 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) /* This is done for the currently configured channel */ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) { - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; struct ath9k_cal_list *currCal = ah->cal_list_curr; if (!ah->curchan) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 5fb94fa45ff9..177244b2b6b9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -40,7 +40,7 @@ static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks) { - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; if (!ah->curchan) /* should really check for CCK instead */ return clks / ATH9K_CLOCK_RATE_CCK; @@ -52,7 +52,7 @@ static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks) static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks) { - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; if (conf_is_ht40(conf)) return ath9k_hw_mac_usec(ah, clks) / 2; @@ -62,7 +62,7 @@ static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks) static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) { - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; if (!ah->curchan) /* should really check for CCK instead */ return usecs *ATH9K_CLOCK_RATE_CCK; @@ -73,7 +73,7 @@ static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) { - struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; if (conf_is_ht40(conf)) return ath9k_hw_mac_clks(ah, usecs) * 2; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ae351a183416..1f6dece9b007 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -437,6 +437,7 @@ struct ath_gen_timer_table { }; struct ath_hw { + struct ieee80211_hw *hw; struct ath_softc *ah_sc; struct ath_common common; struct ath9k_hw_version hw_version; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d752b167f5ad..693555728eab 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1571,6 +1571,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) common = ath9k_hw_common(ah); common->ops = &ath9k_common_ops; common->ah = ah; + common->hw = sc->hw; /* * Cache line size is used to size and align various -- cgit v1.2.3 From cd9bf689600e62d84449d65b3d25fb6d2757589e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 13 Sep 2009 02:08:34 -0700 Subject: ath9k: separate core driver and hw timer code Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 22 ++++-------------- drivers/net/wireless/ath/ath9k/hw.h | 9 ++++--- drivers/net/wireless/ath/ath9k/main.c | 44 ++++++++++++++++++++++++++++------- 3 files changed, 47 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 177244b2b6b9..e6ca3158759b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4136,9 +4136,10 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, return timer; } -void ath_gen_timer_start(struct ath_hw *ah, - struct ath_gen_timer *timer, - u32 timer_next, u32 timer_period) +void ath9k_hw_gen_timer_start(struct ath_hw *ah, + struct ath_gen_timer *timer, + u32 timer_next, + u32 timer_period) { struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; u32 tsf; @@ -4173,15 +4174,9 @@ void ath_gen_timer_start(struct ath_hw *ah, REG_SET_BIT(ah, AR_IMR_S5, (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); - - if ((ah->ah_sc->imask & ATH9K_INT_GENTIMER) == 0) { - ath9k_hw_set_interrupts(ah, 0); - ah->ah_sc->imask |= ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, ah->ah_sc->imask); - } } -void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) +void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) { struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; @@ -4200,13 +4195,6 @@ void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); clear_bit(timer->index, &timer_table->timer_mask.timer_bits); - - /* if no timer is enabled, turn off interrupt mask */ - if (timer_table->timer_mask.val == 0) { - ath9k_hw_set_interrupts(ah, 0); - ah->ah_sc->imask &= ~ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, ah->ah_sc->imask); - } } void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 1f6dece9b007..32401742751e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -682,9 +682,12 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, void (*overflow)(void *), void *arg, u8 timer_index); -void ath_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, - u32 timer_next, u32 timer_period); -void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer); +void ath9k_hw_gen_timer_start(struct ath_hw *ah, + struct ath_gen_timer *timer, + u32 timer_next, + u32 timer_period); +void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer); + void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_isr(struct ath_hw *hw); u32 ath9k_hw_gettsf32(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 693555728eab..571a0d9c8605 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1408,6 +1408,34 @@ static void ath9k_btcoex_bt_stomp(struct ath_softc *sc, ath9k_hw_btcoex_enable(ah); } +static void ath9k_gen_timer_start(struct ath_hw *ah, + struct ath_gen_timer *timer, + u32 timer_next, + u32 timer_period) +{ + ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); + + if ((ah->ah_sc->imask & ATH9K_INT_GENTIMER) == 0) { + ath9k_hw_set_interrupts(ah, 0); + ah->ah_sc->imask |= ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, ah->ah_sc->imask); + } +} + +static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + + ath9k_hw_gen_timer_stop(ah, timer); + + /* if no timer is enabled, turn off interrupt mask */ + if (timer_table->timer_mask.val == 0) { + ath9k_hw_set_interrupts(ah, 0); + ah->ah_sc->imask &= ~ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, ah->ah_sc->imask); + } +} + /* * This is the master bt coex timer which runs for every * 45ms, bt traffic will be given priority during 55% of this @@ -1429,13 +1457,13 @@ static void ath_btcoex_period_timer(unsigned long data) if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { if (btcoex->hw_timer_enabled) - ath_gen_timer_stop(ah, btcoex->no_stomp_timer); + ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); - ath_gen_timer_start(ah, - btcoex->no_stomp_timer, - (ath9k_hw_gettsf32(ah) + - btcoex->btcoex_no_stomp), - btcoex->btcoex_no_stomp * 10); + ath9k_gen_timer_start(ah, + btcoex->no_stomp_timer, + (ath9k_hw_gettsf32(ah) + + btcoex->btcoex_no_stomp), + btcoex->btcoex_no_stomp * 10); btcoex->hw_timer_enabled = true; } @@ -2165,7 +2193,7 @@ static void ath9k_btcoex_timer_resume(struct ath_softc *sc) /* make sure duty cycle timer is also stopped when resuming */ if (btcoex->hw_timer_enabled) - ath_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); + ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; @@ -2407,7 +2435,7 @@ static void ath9k_btcoex_timer_pause(struct ath_softc *sc) del_timer_sync(&btcoex->period_timer); if (btcoex->hw_timer_enabled) - ath_gen_timer_stop(ah, btcoex->no_stomp_timer); + ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); btcoex->hw_timer_enabled = false; } -- cgit v1.2.3 From c46917bb53a546f60c7d3103407fe953c418dd5b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 13 Sep 2009 02:42:02 -0700 Subject: atheros: add common debug printing ath9k uses this for now, ath9k_htc is expected to re-use this as well. We lave ath5k as is, but it certainly can also be converted later. The ath9k module parameter and debugfs entry is kept. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/Kconfig | 8 + drivers/net/wireless/ath/Makefile | 2 + drivers/net/wireless/ath/ath.h | 3 + drivers/net/wireless/ath/ath9k/Kconfig | 4 + drivers/net/wireless/ath/ath9k/ahb.c | 7 +- drivers/net/wireless/ath/ath9k/ani.c | 133 ++++++------ drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/beacon.c | 80 +++---- drivers/net/wireless/ath/ath9k/calib.c | 303 ++++++++++++++------------- drivers/net/wireless/ath/ath9k/calib.h | 2 + drivers/net/wireless/ath/ath9k/debug.c | 26 +-- drivers/net/wireless/ath/ath9k/debug.h | 27 --- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 81 +++---- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 89 ++++---- drivers/net/wireless/ath/ath9k/eeprom_def.c | 75 +++---- drivers/net/wireless/ath/ath9k/hw.c | 254 ++++++++++++---------- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/mac.c | 118 ++++++----- drivers/net/wireless/ath/ath9k/main.c | 266 +++++++++++++---------- drivers/net/wireless/ath/ath9k/phy.c | 23 +- drivers/net/wireless/ath/ath9k/rc.c | 28 +-- drivers/net/wireless/ath/ath9k/recv.c | 38 ++-- drivers/net/wireless/ath/ath9k/xmit.c | 100 +++++---- drivers/net/wireless/ath/debug.c | 32 +++ drivers/net/wireless/ath/debug.h | 77 +++++++ 25 files changed, 1005 insertions(+), 773 deletions(-) create mode 100644 drivers/net/wireless/ath/debug.c create mode 100644 drivers/net/wireless/ath/debug.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 11ded150b932..6ce86cb37654 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -16,7 +16,15 @@ menuconfig ATH_COMMON http://wireless.kernel.org/en/users/Drivers/Atheros if ATH_COMMON + +config ATH_DEBUG + bool "Atheros wireless debugging" + ---help--- + Say Y, if you want to debug atheros wireless drivers. + Right now only ath9k makes use of this. + source "drivers/net/wireless/ath/ath5k/Kconfig" source "drivers/net/wireless/ath/ath9k/Kconfig" source "drivers/net/wireless/ath/ar9170/Kconfig" + endif diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 6ebf2148167a..5c8e6b2bbaab 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -7,3 +7,5 @@ obj-$(CONFIG_ATH_COMMON) += ath.o ath-objs := main.o \ regd.o \ hw.o + +ath-$(CONFIG_ATH_DEBUG) += debug.o diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 88654138f999..2ca9701181ee 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -48,11 +48,14 @@ struct ath_ops { struct ath_common { void *ah; struct ieee80211_hw *hw; + int debug_mask; + u16 cachelsz; u16 curaid; u8 macaddr[ETH_ALEN]; u8 curbssid[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; + struct ath_regulatory regulatory; const struct ath_ops *ops; }; diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index ef5f59c4dd80..de4aeea8a005 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -16,6 +16,8 @@ config ATH9K If you choose to build a module, it'll be called ath9k. +if ATH_DEBUG + config ATH9K_DEBUG bool "Atheros ath9k debugging" depends on ATH9K @@ -26,3 +28,5 @@ config ATH9K_DEBUG modprobe ath9k debug=0x00000200 Look in ath9k/debug.h for possible debug masks + +endif # ATH_DEBUG diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 41e16ed2f07d..095973e8b232 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -40,9 +40,10 @@ static bool ath_ahb_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) pdata = (struct ath9k_platform_data *) pdev->dev.platform_data; if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { - DPRINTF(ah, ATH_DBG_FATAL, - "%s: flash read failed, offset %08x is out of range\n", - __func__, off); + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "%s: flash read failed, offset %08x " + "is out of range\n", + __func__, off); return false; } diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 9682c49ab454..bb0a6d985270 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -31,8 +31,8 @@ static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, } } - DPRINTF(ah, ATH_DBG_ANI, - "No more channel states left. Using channel 0\n"); + ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, + "No more channel states left. Using channel 0\n"); return 0; } @@ -41,16 +41,17 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah, enum ath9k_ani_cmd cmd, int param) { struct ar5416AniState *aniState = ah->curani; + struct ath_common *common = ath9k_hw_common(ah); switch (cmd & ah->ani_function) { case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ u32 level = param; if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { - DPRINTF(ah, ATH_DBG_ANI, - "level out of range (%u > %u)\n", - level, - (unsigned)ARRAY_SIZE(ah->totalSizeDesired)); + ath_print(common, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned)ARRAY_SIZE(ah->totalSizeDesired)); return false; } @@ -152,10 +153,10 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(firstep)) { - DPRINTF(ah, ATH_DBG_ANI, - "level out of range (%u > %u)\n", - level, - (unsigned) ARRAY_SIZE(firstep)); + ath_print(common, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) ARRAY_SIZE(firstep)); return false; } REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, @@ -174,11 +175,10 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah, u32 level = param; if (level >= ARRAY_SIZE(cycpwrThr1)) { - DPRINTF(ah, ATH_DBG_ANI, - "level out of range (%u > %u)\n", - level, - (unsigned) - ARRAY_SIZE(cycpwrThr1)); + ath_print(common, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) ARRAY_SIZE(cycpwrThr1)); return false; } REG_RMW_FIELD(ah, AR_PHY_TIMING5, @@ -194,25 +194,28 @@ static bool ath9k_hw_ani_control(struct ath_hw *ah, case ATH9K_ANI_PRESENT: break; default: - DPRINTF(ah, ATH_DBG_ANI, - "invalid cmd %u\n", cmd); + ath_print(common, ATH_DBG_ANI, + "invalid cmd %u\n", cmd); return false; } - DPRINTF(ah, ATH_DBG_ANI, "ANI parameters:\n"); - DPRINTF(ah, ATH_DBG_ANI, - "noiseImmunityLevel=%d, spurImmunityLevel=%d, " - "ofdmWeakSigDetectOff=%d\n", - aniState->noiseImmunityLevel, aniState->spurImmunityLevel, - !aniState->ofdmWeakSigDetectOff); - DPRINTF(ah, ATH_DBG_ANI, - "cckWeakSigThreshold=%d, " - "firstepLevel=%d, listenTime=%d\n", - aniState->cckWeakSigThreshold, aniState->firstepLevel, - aniState->listenTime); - DPRINTF(ah, ATH_DBG_ANI, + ath_print(common, ATH_DBG_ANI, "ANI parameters:\n"); + ath_print(common, ATH_DBG_ANI, + "noiseImmunityLevel=%d, spurImmunityLevel=%d, " + "ofdmWeakSigDetectOff=%d\n", + aniState->noiseImmunityLevel, + aniState->spurImmunityLevel, + !aniState->ofdmWeakSigDetectOff); + ath_print(common, ATH_DBG_ANI, + "cckWeakSigThreshold=%d, " + "firstepLevel=%d, listenTime=%d\n", + aniState->cckWeakSigThreshold, + aniState->firstepLevel, + aniState->listenTime); + ath_print(common, ATH_DBG_ANI, "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", - aniState->cycleCount, aniState->ofdmPhyErrCount, + aniState->cycleCount, + aniState->ofdmPhyErrCount, aniState->cckPhyErrCount); return true; @@ -231,6 +234,7 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah, static void ath9k_ani_restart(struct ath_hw *ah) { struct ar5416AniState *aniState; + struct ath_common *common = ath9k_hw_common(ah); if (!DO_ANI(ah)) return; @@ -240,24 +244,24 @@ static void ath9k_ani_restart(struct ath_hw *ah) if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { aniState->ofdmPhyErrBase = 0; - DPRINTF(ah, ATH_DBG_ANI, - "OFDM Trigger is too high for hw counters\n"); + ath_print(common, ATH_DBG_ANI, + "OFDM Trigger is too high for hw counters\n"); } else { aniState->ofdmPhyErrBase = AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; } if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { aniState->cckPhyErrBase = 0; - DPRINTF(ah, ATH_DBG_ANI, - "CCK Trigger is too high for hw counters\n"); + ath_print(common, ATH_DBG_ANI, + "CCK Trigger is too high for hw counters\n"); } else { aniState->cckPhyErrBase = AR_PHY_COUNTMAX - aniState->cckTrigHigh; } - DPRINTF(ah, ATH_DBG_ANI, - "Writing ofdmbase=%u cckbase=%u\n", - aniState->ofdmPhyErrBase, - aniState->cckPhyErrBase); + ath_print(common, ATH_DBG_ANI, + "Writing ofdmbase=%u cckbase=%u\n", + aniState->ofdmPhyErrBase, + aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); @@ -464,6 +468,7 @@ void ath9k_ani_reset(struct ath_hw *ah) { struct ar5416AniState *aniState; struct ath9k_channel *chan = ah->curchan; + struct ath_common *common = ath9k_hw_common(ah); int index; if (!DO_ANI(ah)) @@ -475,8 +480,8 @@ void ath9k_ani_reset(struct ath_hw *ah) if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION && ah->opmode != NL80211_IFTYPE_ADHOC) { - DPRINTF(ah, ATH_DBG_ANI, - "Reset ANI state opmode %u\n", ah->opmode); + ath_print(common, ATH_DBG_ANI, + "Reset ANI state opmode %u\n", ah->opmode); ah->stats.ast_ani_reset++; if (ah->opmode == NL80211_IFTYPE_AP) { @@ -543,6 +548,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) { struct ar5416AniState *aniState; + struct ath_common *common = ath9k_hw_common(ah); int32_t listenTime; u32 phyCnt1, phyCnt2; u32 ofdmPhyErrCnt, cckPhyErrCnt; @@ -569,20 +575,22 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, if (phyCnt1 < aniState->ofdmPhyErrBase || phyCnt2 < aniState->cckPhyErrBase) { if (phyCnt1 < aniState->ofdmPhyErrBase) { - DPRINTF(ah, ATH_DBG_ANI, - "phyCnt1 0x%x, resetting " - "counter value to 0x%x\n", - phyCnt1, aniState->ofdmPhyErrBase); + ath_print(common, ATH_DBG_ANI, + "phyCnt1 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt1, + aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); } if (phyCnt2 < aniState->cckPhyErrBase) { - DPRINTF(ah, ATH_DBG_ANI, - "phyCnt2 0x%x, resetting " - "counter value to 0x%x\n", - phyCnt2, aniState->cckPhyErrBase); + ath_print(common, ATH_DBG_ANI, + "phyCnt2 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt2, + aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_MASK_2, @@ -624,7 +632,9 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, void ath9k_enable_mib_counters(struct ath_hw *ah) { - DPRINTF(ah, ATH_DBG_ANI, "Enable MIB counters\n"); + struct ath_common *common = ath9k_hw_common(ah); + + ath_print(common, ATH_DBG_ANI, "Enable MIB counters\n"); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); @@ -640,7 +650,10 @@ void ath9k_enable_mib_counters(struct ath_hw *ah) /* Freeze the MIB counters, get the stats and then clear them */ void ath9k_hw_disable_mib_counters(struct ath_hw *ah) { - DPRINTF(ah, ATH_DBG_ANI, "Disable MIB counters\n"); + struct ath_common *common = ath9k_hw_common(ah); + + ath_print(common, ATH_DBG_ANI, "Disable MIB counters\n"); + REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); @@ -653,6 +666,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxf_pcnt, u32 *txf_pcnt) { + struct ath_common *common = ath9k_hw_common(ah); static u32 cycles, rx_clear, rx_frame, tx_frame; u32 good = 1; @@ -662,8 +676,8 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 cc = REG_READ(ah, AR_CCCNT); if (cycles == 0 || cycles > cc) { - DPRINTF(ah, ATH_DBG_ANI, - "cycle counter wrap. ExtBusy = 0\n"); + ath_print(common, ATH_DBG_ANI, + "cycle counter wrap. ExtBusy = 0\n"); good = 0; } else { u32 cc_d = cc - cycles; @@ -762,9 +776,10 @@ void ath9k_hw_ani_setup(struct ath_hw *ah) void ath9k_hw_ani_init(struct ath_hw *ah) { + struct ath_common *common = ath9k_hw_common(ah); int i; - DPRINTF(ah, ATH_DBG_ANI, "Initialize ANI\n"); + ath_print(common, ATH_DBG_ANI, "Initialize ANI\n"); memset(ah->ani, 0, sizeof(ah->ani)); for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { @@ -786,11 +801,11 @@ void ath9k_hw_ani_init(struct ath_hw *ah) AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; } - DPRINTF(ah, ATH_DBG_ANI, - "Setting OfdmErrBase = 0x%08x\n", - ah->ani[0].ofdmPhyErrBase); - DPRINTF(ah, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", - ah->ani[0].cckPhyErrBase); + ath_print(common, ATH_DBG_ANI, + "Setting OfdmErrBase = 0x%08x\n", + ah->ani[0].ofdmPhyErrBase); + ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", + ah->ani[0].cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); @@ -803,7 +818,7 @@ void ath9k_hw_ani_init(struct ath_hw *ah) void ath9k_hw_ani_disable(struct ath_hw *ah) { - DPRINTF(ah, ATH_DBG_ANI, "Disabling ANI\n"); + ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n"); ath9k_hw_disable_mib_counters(ah); REG_WRITE(ah, AR_PHY_ERR_1, 0); diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7c740cf50f7c..9864461ecb53 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -26,6 +26,7 @@ #include "rc.h" #include "debug.h" #include "../ath.h" +#include "../debug.h" struct ath_node; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index fb4ff5512360..2f003132463b 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -26,6 +26,7 @@ static int ath_beaconq_config(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info qi; ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); @@ -42,8 +43,8 @@ static int ath_beaconq_config(struct ath_softc *sc) } if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { - DPRINTF(ah, ATH_DBG_FATAL, - "Unable to update h/w beacon queue parameters\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to update h/w beacon queue parameters\n"); return 0; } else { ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); @@ -119,6 +120,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_buf *bf; struct ath_vif *avp; struct sk_buff *skb; @@ -172,7 +174,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "dma_mapping_error on beaconing\n"); + ath_print(common, ATH_DBG_FATAL, + "dma_mapping_error on beaconing\n"); return NULL; } @@ -192,8 +195,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, if (skb && cabq_depth) { if (sc->nvifs > 1) { - DPRINTF(sc->sc_ah, ATH_DBG_BEACON, - "Flushing previous cabq traffic\n"); + ath_print(common, ATH_DBG_BEACON, + "Flushing previous cabq traffic\n"); ath_draintxq(sc, cabq, false); } } @@ -216,6 +219,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, struct ieee80211_vif *vif) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf; struct ath_vif *avp; struct sk_buff *skb; @@ -233,8 +237,8 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, /* NB: caller is known to have already stopped tx dma */ ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); ath9k_hw_txstart(ah, sc->beacon.beaconq); - DPRINTF(ah, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", - sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); + ath_print(common, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", + sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); } int ath_beaconq_setup(struct ath_hw *ah) @@ -252,6 +256,7 @@ int ath_beaconq_setup(struct ath_hw *ah) int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) { struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp; struct ath_buf *bf; struct sk_buff *skb; @@ -309,7 +314,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) /* NB: the beacon data buffer must be 32-bit aligned. */ skb = ieee80211_beacon_get(sc->hw, vif); if (skb == NULL) { - DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "cannot get skb\n"); + ath_print(common, ATH_DBG_BEACON, "cannot get skb\n"); return -ENOMEM; } @@ -333,9 +338,10 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) tsfadjust = intval * avp->av_bslot / ATH_BCBUF; avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); - DPRINTF(sc->sc_ah, ATH_DBG_BEACON, - "stagger beacons, bslot %d intval %u tsfadjust %llu\n", - avp->av_bslot, intval, (unsigned long long)tsfadjust); + ath_print(common, ATH_DBG_BEACON, + "stagger beacons, bslot %d intval " + "%u tsfadjust %llu\n", + avp->av_bslot, intval, (unsigned long long)tsfadjust); ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = avp->tsf_adjust; @@ -349,8 +355,8 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "dma_mapping_error on beacon alloc\n"); + ath_print(common, ATH_DBG_FATAL, + "dma_mapping_error on beacon alloc\n"); return -ENOMEM; } @@ -386,6 +392,7 @@ void ath_beacon_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf = NULL; struct ieee80211_vif *vif; struct ath_wiphy *aphy; @@ -405,12 +412,12 @@ void ath_beacon_tasklet(unsigned long data) sc->beacon.bmisscnt++; if (sc->beacon.bmisscnt < BSTUCK_THRESH) { - DPRINTF(sc->sc_ah, ATH_DBG_BEACON, - "missed %u consecutive beacons\n", - sc->beacon.bmisscnt); + ath_print(common, ATH_DBG_BEACON, + "missed %u consecutive beacons\n", + sc->beacon.bmisscnt); } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { - DPRINTF(sc->sc_ah, ATH_DBG_BEACON, - "beacon is officially stuck\n"); + ath_print(common, ATH_DBG_BEACON, + "beacon is officially stuck\n"); sc->sc_flags |= SC_OP_TSF_RESET; ath_reset(sc, false); } @@ -419,9 +426,9 @@ void ath_beacon_tasklet(unsigned long data) } if (sc->beacon.bmisscnt != 0) { - DPRINTF(sc->sc_ah, ATH_DBG_BEACON, - "resume beacon xmit after %u misses\n", - sc->beacon.bmisscnt); + ath_print(common, ATH_DBG_BEACON, + "resume beacon xmit after %u misses\n", + sc->beacon.bmisscnt); sc->beacon.bmisscnt = 0; } @@ -447,9 +454,9 @@ void ath_beacon_tasklet(unsigned long data) vif = sc->beacon.bslot[slot]; aphy = sc->beacon.bslot_aphy[slot]; - DPRINTF(sc->sc_ah, ATH_DBG_BEACON, - "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", - slot, tsf, tsftu, intval, vif); + ath_print(common, ATH_DBG_BEACON, + "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", + slot, tsf, tsftu, intval, vif); bfaddr = 0; if (vif) { @@ -490,7 +497,7 @@ void ath_beacon_tasklet(unsigned long data) * are still pending on the queue. */ if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, + ath_print(common, ATH_DBG_FATAL, "beacon queue %u did not stop?\n", sc->beacon.beaconq); } @@ -568,6 +575,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc, static void ath_beacon_config_sta(struct ath_softc *sc, struct ath_beacon_config *conf) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_beacon_state bs; int dtimperiod, dtimcount, sleepduration; int cfpperiod, cfpcount; @@ -664,11 +672,11 @@ static void ath_beacon_config_sta(struct ath_softc *sc, /* TSF out of range threshold fixed at 1 second */ bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - DPRINTF(sc->sc_ah, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); - DPRINTF(sc->sc_ah, ATH_DBG_BEACON, - "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", - bs.bs_bmissthreshold, bs.bs_sleepduration, - bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); + ath_print(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); + ath_print(common, ATH_DBG_BEACON, + "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", + bs.bs_bmissthreshold, bs.bs_sleepduration, + bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); /* Set the computed STA beacon timers */ @@ -682,6 +690,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, struct ath_beacon_config *conf, struct ieee80211_vif *vif) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); u64 tsf; u32 tsftu, intval, nexttbtt; @@ -702,9 +711,9 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, nexttbtt += intval; } while (nexttbtt < tsftu); - DPRINTF(sc->sc_ah, ATH_DBG_BEACON, - "IBSS nexttbtt %u intval %u (%u)\n", - nexttbtt, intval, conf->beacon_interval); + ath_print(common, ATH_DBG_BEACON, + "IBSS nexttbtt %u intval %u (%u)\n", + nexttbtt, intval, conf->beacon_interval); /* * In IBSS mode enable the beacon timers but only enable SWBA interrupts @@ -732,6 +741,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) { struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); enum nl80211_iftype iftype; /* Setup the beacon configuration parameters */ @@ -772,8 +782,8 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) ath_beacon_config_sta(sc, cur_conf); break; default: - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, - "Unsupported beaconing mode\n"); + ath_print(common, ATH_DBG_CONFIG, + "Unsupported beaconing mode\n"); return; } diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index bdd4a19f32be..2a2212465ea3 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -15,6 +15,7 @@ */ #include "ath9k.h" +#include "hw.h" /* We can tune this as we go by monitoring really low values */ #define ATH9K_NF_TOO_LOW -60 @@ -26,11 +27,11 @@ static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf) { if (nf > ATH9K_NF_TOO_LOW) { - DPRINTF(ah, ATH_DBG_CALIBRATE, - "noise floor value detected (%d) is " - "lower than what we think is a " - "reasonable value (%d)\n", - nf, ATH9K_NF_TOO_LOW); + ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "noise floor value detected (%d) is " + "lower than what we think is a " + "reasonable value (%d)\n", + nf, ATH9K_NF_TOO_LOW); return false; } return true; @@ -89,6 +90,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, static void ath9k_hw_do_getnf(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]) { + struct ath_common *common = ath9k_hw_common(ah); int16_t nf; if (AR_SREV_9280_10_OR_LATER(ah)) @@ -98,8 +100,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 0] is %d\n", nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 0] is %d\n", nf); nfarray[0] = nf; if (!AR_SREV_9285(ah)) { @@ -112,8 +114,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 1] is %d\n", nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 1] is %d\n", nf); nfarray[1] = nf; if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) { @@ -121,8 +123,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, AR_PHY_CH2_MINCCA_PWR); if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 2] is %d\n", nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 2] is %d\n", nf); nfarray[2] = nf; } } @@ -136,8 +138,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 0] is %d\n", nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 0] is %d\n", nf); nfarray[3] = nf; if (!AR_SREV_9285(ah)) { @@ -150,8 +152,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 1] is %d\n", nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 1] is %d\n", nf); nfarray[4] = nf; if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) { @@ -159,8 +161,8 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, AR_PHY_CH2_EXT_MINCCA_PWR); if (nf & 0x100) nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 2] is %d\n", nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 2] is %d\n", nf); nfarray[5] = nf; } } @@ -188,6 +190,8 @@ static bool getNoiseFloorThresh(struct ath_hw *ah, static void ath9k_hw_setup_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal) { + struct ath_common *common = ath9k_hw_common(ah); + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, currCal->calData->calCountMax); @@ -195,23 +199,23 @@ static void ath9k_hw_setup_calibration(struct ath_hw *ah, switch (currCal->calData->calType) { case IQ_MISMATCH_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "starting IQ Mismatch Calibration\n"); + ath_print(common, ATH_DBG_CALIBRATE, + "starting IQ Mismatch Calibration\n"); break; case ADC_GAIN_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "starting ADC Gain Calibration\n"); + ath_print(common, ATH_DBG_CALIBRATE, + "starting ADC Gain Calibration\n"); break; case ADC_DC_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "starting ADC DC Calibration\n"); + ath_print(common, ATH_DBG_CALIBRATE, + "starting ADC DC Calibration\n"); break; case ADC_DC_INIT_CAL: REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "starting Init ADC DC Calibration\n"); + ath_print(common, ATH_DBG_CALIBRATE, + "starting Init ADC DC Calibration\n"); break; } @@ -304,11 +308,11 @@ static void ath9k_hw_iqcal_collect(struct ath_hw *ah) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); ah->totalIqCorrMeas[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", - ah->cal_samples, i, ah->totalPowerMeasI[i], - ah->totalPowerMeasQ[i], - ah->totalIqCorrMeas[i]); + ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + ah->cal_samples, i, ah->totalPowerMeasI[i], + ah->totalPowerMeasQ[i], + ah->totalIqCorrMeas[i]); } } @@ -326,14 +330,14 @@ static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah) ah->totalAdcQEvenPhase[i] += REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ah->cal_samples, i, - ah->totalAdcIOddPhase[i], - ah->totalAdcIEvenPhase[i], - ah->totalAdcQOddPhase[i], - ah->totalAdcQEvenPhase[i]); + ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ah->cal_samples, i, + ah->totalAdcIOddPhase[i], + ah->totalAdcIEvenPhase[i], + ah->totalAdcQOddPhase[i], + ah->totalAdcQEvenPhase[i]); } } @@ -351,19 +355,20 @@ static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah) ah->totalAdcDcOffsetQEvenPhase[i] += (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ah->cal_samples, i, - ah->totalAdcDcOffsetIOddPhase[i], - ah->totalAdcDcOffsetIEvenPhase[i], - ah->totalAdcDcOffsetQOddPhase[i], - ah->totalAdcDcOffsetQEvenPhase[i]); + ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ah->cal_samples, i, + ah->totalAdcDcOffsetIOddPhase[i], + ah->totalAdcDcOffsetIEvenPhase[i], + ah->totalAdcDcOffsetQOddPhase[i], + ah->totalAdcDcOffsetQEvenPhase[i]); } } static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) { + struct ath_common *common = ath9k_hw_common(ah); u32 powerMeasQ, powerMeasI, iqCorrMeas; u32 qCoffDenom, iCoffDenom; int32_t qCoff, iCoff; @@ -374,13 +379,13 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) powerMeasQ = ah->totalPowerMeasQ[i]; iqCorrMeas = ah->totalIqCorrMeas[i]; - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Starting IQ Cal and Correction for Chain %d\n", - i); + ath_print(common, ATH_DBG_CALIBRATE, + "Starting IQ Cal and Correction for Chain %d\n", + i); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Orignal: Chn %diq_corr_meas = 0x%08x\n", - i, ah->totalIqCorrMeas[i]); + ath_print(common, ATH_DBG_CALIBRATE, + "Orignal: Chn %diq_corr_meas = 0x%08x\n", + i, ah->totalIqCorrMeas[i]); iqCorrNeg = 0; @@ -389,12 +394,12 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) iqCorrNeg = 1; } - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); - DPRINTF(ah, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", - iqCorrNeg); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); + ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", + iqCorrNeg); iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; qCoffDenom = powerMeasQ / 64; @@ -402,14 +407,14 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) if (powerMeasQ != 0) { iCoff = iqCorrMeas / iCoffDenom; qCoff = powerMeasI / qCoffDenom - 64; - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d iCoff = 0x%08x\n", i, iCoff); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d qCoff = 0x%08x\n", i, qCoff); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d iCoff = 0x%08x\n", i, iCoff); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d qCoff = 0x%08x\n", i, qCoff); iCoff = iCoff & 0x3f; - DPRINTF(ah, ATH_DBG_CALIBRATE, - "New: Chn %d iCoff = 0x%08x\n", i, iCoff); + ath_print(common, ATH_DBG_CALIBRATE, + "New: Chn %d iCoff = 0x%08x\n", i, iCoff); if (iqCorrNeg == 0x0) iCoff = 0x40 - iCoff; @@ -418,9 +423,9 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) else if (qCoff <= -16) qCoff = 16; - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", - i, iCoff, qCoff); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", + i, iCoff, qCoff); REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, @@ -428,9 +433,9 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, qCoff); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "IQ Cal and Correction done for Chain %d\n", - i); + ath_print(common, ATH_DBG_CALIBRATE, + "IQ Cal and Correction done for Chain %d\n", + i); } } @@ -440,6 +445,7 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) { + struct ath_common *common = ath9k_hw_common(ah); u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; u32 qGainMismatch, iGainMismatch, val, i; @@ -449,21 +455,21 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) qOddMeasOffset = ah->totalAdcQOddPhase[i]; qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Starting ADC Gain Cal for Chain %d\n", i); - - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = 0x%08x\n", i, - iOddMeasOffset); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = 0x%08x\n", i, - iEvenMeasOffset); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = 0x%08x\n", i, - qOddMeasOffset); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = 0x%08x\n", i, - qEvenMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Starting ADC Gain Cal for Chain %d\n", i); + + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = 0x%08x\n", i, + iOddMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = 0x%08x\n", i, + iEvenMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = 0x%08x\n", i, + qOddMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = 0x%08x\n", i, + qEvenMeasOffset); if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { iGainMismatch = @@ -473,20 +479,20 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) ((qOddMeasOffset * 32) / qEvenMeasOffset) & 0x3f; - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_i = 0x%08x\n", i, - iGainMismatch); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_q = 0x%08x\n", i, - qGainMismatch); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_i = 0x%08x\n", i, + iGainMismatch); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_q = 0x%08x\n", i, + qGainMismatch); val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); val &= 0xfffff000; val |= (qGainMismatch) | (iGainMismatch << 6); REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "ADC Gain Cal done for Chain %d\n", i); + ath_print(common, ATH_DBG_CALIBRATE, + "ADC Gain Cal done for Chain %d\n", i); } } @@ -497,6 +503,7 @@ static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) { + struct ath_common *common = ath9k_hw_common(ah); u32 iOddMeasOffset, iEvenMeasOffset, val, i; int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; const struct ath9k_percal_data *calData = @@ -510,41 +517,41 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Starting ADC DC Offset Cal for Chain %d\n", i); - - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = %d\n", i, - iOddMeasOffset); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = %d\n", i, - iEvenMeasOffset); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = %d\n", i, - qOddMeasOffset); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = %d\n", i, - qEvenMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Starting ADC DC Offset Cal for Chain %d\n", i); + + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = %d\n", i, + iOddMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = %d\n", i, + iEvenMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = %d\n", i, + qOddMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = %d\n", i, + qEvenMeasOffset); iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / numSamples) & 0x1ff; qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / numSamples) & 0x1ff; - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, - iDcMismatch); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, - qDcMismatch); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, + iDcMismatch); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, + qDcMismatch); val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); val &= 0xc0000fff; val |= (qDcMismatch << 12) | (iDcMismatch << 21); REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "ADC DC Offset Cal done for Chain %d\n", i); + ath_print(common, ATH_DBG_CALIBRATE, + "ADC DC Offset Cal done for Chain %d\n", i); } REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), @@ -555,7 +562,8 @@ static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) /* This is done for the currently configured channel */ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) { - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &common->hw->conf; struct ath9k_cal_list *currCal = ah->cal_list_curr; if (!ah->curchan) @@ -568,18 +576,18 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) return true; if (currCal->calState != CAL_DONE) { - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Calibration state incorrect, %d\n", - currCal->calState); + ath_print(common, ATH_DBG_CALIBRATE, + "Calibration state incorrect, %d\n", + currCal->calState); return true; } if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType)) return true; - DPRINTF(ah, ATH_DBG_CALIBRATE, - "Resetting Cal %d state for channel %u\n", - currCal->calData->calType, conf->channel->center_freq); + ath_print(common, ATH_DBG_CALIBRATE, + "Resetting Cal %d state for channel %u\n", + currCal->calData->calType, conf->channel->center_freq); ah->curchan->CalValid &= ~currCal->calData->calType; currCal->calState = CAL_WAITING; @@ -665,6 +673,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) int16_t ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) { + struct ath_common *common = ath9k_hw_common(ah); int16_t nf, nfThresh; int16_t nfarray[NUM_NF_READINGS] = { 0 }; struct ath9k_nfcal_hist *h; @@ -672,8 +681,8 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah, chan->channelFlags &= (~CHANNEL_CW_INT); if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { - DPRINTF(ah, ATH_DBG_CALIBRATE, - "NF did not complete in calibration window\n"); + ath_print(common, ATH_DBG_CALIBRATE, + "NF did not complete in calibration window\n"); nf = 0; chan->rawNoiseFloor = nf; return chan->rawNoiseFloor; @@ -682,10 +691,10 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah, nf = nfarray[0]; if (getNoiseFloorThresh(ah, c->band, &nfThresh) && nf > nfThresh) { - DPRINTF(ah, ATH_DBG_CALIBRATE, - "noise floor failed detected; " - "detected %d, threshold %d\n", - nf, nfThresh); + ath_print(common, ATH_DBG_CALIBRATE, + "noise floor failed detected; " + "detected %d, threshold %d\n", + nf, nfThresh); chan->channelFlags |= CHANNEL_CW_INT; } } @@ -875,7 +884,7 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah) static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) { - + struct ath_common *common = ath9k_hw_common(ah); u32 regVal; int i, offset, offs_6_1, offs_0; u32 ccomp_org, reg_field; @@ -889,7 +898,7 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) { 0x7838, 0 }, }; - DPRINTF(ah, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); + ath_print(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); /* PA CAL is not needed for high power solution */ if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == @@ -1039,6 +1048,8 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) { + struct ath_common *common = ath9k_hw_common(ah); + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); if (IS_CHAN_HT20(chan)) { REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); @@ -1049,9 +1060,9 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah, ATH_DBG_CALIBRATE, "offset " - "calibration failed to complete in " - "1ms; noisy ??\n"); + ath_print(common, ATH_DBG_CALIBRATE, "offset " + "calibration failed to complete in " + "1ms; noisy ??\n"); return false; } REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); @@ -1064,8 +1075,8 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah, ATH_DBG_CALIBRATE, "offset calibration " - "failed to complete in 1ms; noisy ??\n"); + ath_print(common, ATH_DBG_CALIBRATE, "offset calibration " + "failed to complete in 1ms; noisy ??\n"); return false; } @@ -1078,6 +1089,8 @@ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { + struct ath_common *common = ath9k_hw_common(ah); + if (AR_SREV_9285_12_OR_LATER(ah)) { if (!ar9285_clc(ah, chan)) return false; @@ -1098,9 +1111,9 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) /* Poll for offset calibration complete */ if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah, ATH_DBG_CALIBRATE, - "offset calibration failed to complete in 1ms; " - "noisy environment?\n"); + ath_print(common, ATH_DBG_CALIBRATE, + "offset calibration failed to " + "complete in 1ms; noisy environment?\n"); return false; } @@ -1128,20 +1141,20 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) { INIT_CAL(&ah->adcgain_caldata); INSERT_CAL(ah, &ah->adcgain_caldata); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "enabling ADC Gain Calibration.\n"); + ath_print(common, ATH_DBG_CALIBRATE, + "enabling ADC Gain Calibration.\n"); } if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) { INIT_CAL(&ah->adcdc_caldata); INSERT_CAL(ah, &ah->adcdc_caldata); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "enabling ADC DC Calibration.\n"); + ath_print(common, ATH_DBG_CALIBRATE, + "enabling ADC DC Calibration.\n"); } if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { INIT_CAL(&ah->iq_caldata); INSERT_CAL(ah, &ah->iq_caldata); - DPRINTF(ah, ATH_DBG_CALIBRATE, - "enabling IQ Calibration.\n"); + ath_print(common, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); } ah->cal_list_curr = ah->cal_list; diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 9028ab193e42..b2c873e97485 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -17,6 +17,8 @@ #ifndef CALIB_H #define CALIB_H +#include "hw.h" + extern const struct ath9k_percal_data iq_cal_multi_sample; extern const struct ath9k_percal_data iq_cal_single_sample; extern const struct ath9k_percal_data adc_gain_cal_multi_sample; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index babfd3780a9a..5dfc0e97d96d 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -18,26 +18,11 @@ #include "ath9k.h" -static unsigned int ath9k_debug = DBG_DEFAULT; +static unsigned int ath9k_debug = ATH_DBG_DEFAULT; module_param_named(debug, ath9k_debug, uint, 0); static struct dentry *ath9k_debugfs_root; -void DPRINTF(struct ath_hw *ah, int dbg_mask, const char *fmt, ...) -{ - if (!ah->ah_sc) - return; - - if (ah->ah_sc->debug.debug_mask & dbg_mask) { - va_list args; - - va_start(args, fmt); - printk(KERN_DEBUG "ath9k: "); - vprintk(fmt, args); - va_end(args); - } -} - static int ath9k_debugfs_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; @@ -48,10 +33,11 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); char buf[32]; unsigned int len; - len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask); + len = snprintf(buf, sizeof(buf), "0x%08x\n", common->debug_mask); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -59,6 +45,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); unsigned long mask; char buf[32]; ssize_t len; @@ -71,7 +58,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf, if (strict_strtoul(buf, 0, &mask)) return -EINVAL; - sc->debug.debug_mask = mask; + common->debug_mask = mask; return count; } @@ -571,8 +558,9 @@ static const struct file_operations fops_xmit = { int ath9k_init_debug(struct ath_hw *ah) { struct ath_softc *sc = ah->ah_sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - sc->debug.debug_mask = ath9k_debug; + common->debug_mask = ath9k_debug; if (!ath9k_debugfs_root) return -ENOENT; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index c9c1aac95aef..749e85d57551 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -19,26 +19,6 @@ #include "hw.h" -enum ATH_DEBUG { - ATH_DBG_RESET = 0x00000001, - ATH_DBG_QUEUE = 0x00000002, - ATH_DBG_EEPROM = 0x00000004, - ATH_DBG_CALIBRATE = 0x00000008, - ATH_DBG_INTERRUPT = 0x00000010, - ATH_DBG_REGULATORY = 0x00000020, - ATH_DBG_ANI = 0x00000040, - ATH_DBG_XMIT = 0x00000080, - ATH_DBG_BEACON = 0x00000100, - ATH_DBG_CONFIG = 0x00000200, - ATH_DBG_FATAL = 0x00000400, - ATH_DBG_PS = 0x00000800, - ATH_DBG_HWTIMER = 0x00001000, - ATH_DBG_BTCOEX = 0x00002000, - ATH_DBG_ANY = 0xffffffff -}; - -#define DBG_DEFAULT (ATH_DBG_FATAL) - struct ath_txq; struct ath_buf; @@ -142,7 +122,6 @@ struct ath_stats { }; struct ath9k_debug { - int debug_mask; struct dentry *debugfs_phy; struct dentry *debugfs_debug; struct dentry *debugfs_dma; @@ -153,7 +132,6 @@ struct ath9k_debug { struct ath_stats stats; }; -void DPRINTF(struct ath_hw *ah, int dbg_mask, const char *fmt, ...); int ath9k_init_debug(struct ath_hw *ah); void ath9k_exit_debug(struct ath_hw *ah); @@ -168,11 +146,6 @@ void ath_debug_stat_retries(struct ath_softc *sc, int rix, #else -static inline void DPRINTF(struct ath_hw *ah, int dbg_mask, - const char *fmt, ...) -{ -} - static inline int ath9k_init_debug(struct ath_hw *ah) { return 0; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 0675cd5edf0d..079dd201a2d8 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -15,6 +15,7 @@ */ #include "ath9k.h" +#include "hw.h" static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) { @@ -29,20 +30,21 @@ static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) { #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data = (u16 *)&ah->eeprom.map4k; int addr, eep_start_loc = 0; eep_start_loc = 64; if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); + ath_print(common, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); } for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { - DPRINTF(ah, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); + ath_print(common, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); return false; } eep_data++; @@ -55,6 +57,7 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) { #define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + struct ath_common *common = ath9k_hw_common(ah); struct ar5416_eeprom_4k *eep = (struct ar5416_eeprom_4k *) &ah->eeprom.map4k; u16 *eepdata, temp, magic, magic2; @@ -66,13 +69,13 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) if (!ath9k_hw_use_flash(ah)) { if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah, ATH_DBG_FATAL, - "Reading Magic # failed\n"); + ath_print(common, ATH_DBG_FATAL, + "Reading Magic # failed\n"); return false; } - DPRINTF(ah, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); + ath_print(common, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { magic2 = swab16(magic); @@ -87,16 +90,16 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) eepdata++; } } else { - DPRINTF(ah, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "endianness mismatch.\n"); + ath_print(common, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); return -EINVAL; } } } - DPRINTF(ah, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); + ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); if (need_swap) el = swab16(ah->eeprom.map4k.baseEepHeader.length); @@ -117,8 +120,8 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) u32 integer; u16 word; - DPRINTF(ah, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing\n"); + ath_print(common, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing\n"); word = swab16(eep->baseEepHeader.length); eep->baseEepHeader.length = word; @@ -160,9 +163,9 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah, ATH_DBG_FATAL, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); + ath_print(common, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); return -EINVAL; } @@ -385,6 +388,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) { + struct ath_common *common = ath9k_hw_common(ah); struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; struct cal_data_per_freq_4k *pRawDataset; u8 *pCalBChans = NULL; @@ -470,21 +474,21 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, ((pdadcValues[4 * j + 3] & 0xFF) << 24); REG_WRITE(ah, regOffset, reg32); - DPRINTF(ah, ATH_DBG_EEPROM, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah, ATH_DBG_EEPROM, - "PDADC: Chain %d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); + ath_print(common, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + ath_print(common, ATH_DBG_EEPROM, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); regOffset += 4; } @@ -1148,20 +1152,21 @@ static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) { #define EEP_MAP4K_SPURCHAN \ (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) + struct ath_common *common = ath9k_hw_common(ah); u16 spur_val = AR_NO_SPUR; - DPRINTF(ah, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); + ath_print(common, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); switch (ah->config.spurmode) { case SPUR_DISABLE: break; case SPUR_ENABLE_IOCTL: spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); + ath_print(common, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); break; case SPUR_ENABLE_EEPROM: spur_val = EEP_MAP4K_SPURCHAN; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index c6a4325019d5..6ffe85de75c1 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -15,6 +15,7 @@ */ #include "ath9k.h" +#include "hw.h" static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) { @@ -29,20 +30,21 @@ static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah) static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) { struct ar9287_eeprom *eep = &ah->eeprom.map9287; + struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data; int addr, eep_start_loc = AR9287_EEP_START_LOC; eep_data = (u16 *)eep; if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah, ATH_DBG_EEPROM, - "Reading from EEPROM, not flash\n"); + ath_print(common, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); } for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); addr++) { if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { - DPRINTF(ah, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); + ath_print(common, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); return false; } eep_data++; @@ -57,17 +59,18 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) int i, addr; bool need_swap = false; struct ar9287_eeprom *eep = &ah->eeprom.map9287; + struct ath_common *common = ath9k_hw_common(ah); if (!ath9k_hw_use_flash(ah)) { if (!ath9k_hw_nvram_read (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah, ATH_DBG_FATAL, - "Reading Magic # failed\n"); + ath_print(common, ATH_DBG_FATAL, + "Reading Magic # failed\n"); return false; } - DPRINTF(ah, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); + ath_print(common, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { magic2 = swab16(magic); @@ -83,15 +86,15 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) eepdata++; } } else { - DPRINTF(ah, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "endianness mismatch.\n"); + ath_print(common, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); return -EINVAL; } } } - DPRINTF(ah, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? - "True" : "False"); + ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ? + "True" : "False"); if (need_swap) el = swab16(ah->eeprom.map9287.baseEepHeader.length); @@ -148,9 +151,9 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah, ATH_DBG_FATAL, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); + ath_print(common, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ah->eep_ops->get_eeprom_ver(ah)); return -EINVAL; } @@ -436,6 +439,7 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) { + struct ath_common *common = ath9k_hw_common(ah); struct cal_data_per_freq_ar9287 *pRawDataset; struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; u8 *pCalBChans = NULL; @@ -564,24 +568,25 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah, & 0xFF) << 24) ; REG_WRITE(ah, regOffset, reg32); - DPRINTF(ah, ATH_DBG_EEPROM, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - - DPRINTF(ah, ATH_DBG_EEPROM, - "PDADC: Chain %d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d | " - "PDADC %3d Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, - pdadcValues[4 * j + 1], - 4 * j + 2, - pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); + ath_print(common, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x " + "%8.8x\n", + i, regChainOffset, regOffset, + reg32); + + ath_print(common, ATH_DBG_EEPROM, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, + pdadcValues[4 * j + 1], + 4 * j + 2, + pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); regOffset += 4; } @@ -831,6 +836,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, { #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 + struct ath_common *common = ath9k_hw_common(ah); struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; @@ -966,8 +972,8 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah, INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: - DPRINTF(ah, ATH_DBG_EEPROM, - "Invalid chainmask configuration\n"); + ath_print(common, ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); break; } } @@ -1138,19 +1144,20 @@ static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, { #define EEP_MAP9287_SPURCHAN \ (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) + struct ath_common *common = ath9k_hw_common(ah); u16 spur_val = AR_NO_SPUR; - DPRINTF(ah, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); + ath_print(common, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); switch (ah->config.spurmode) { case SPUR_DISABLE: break; case SPUR_ENABLE_IOCTL: spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); + ath_print(common, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); break; case SPUR_ENABLE_EEPROM: spur_val = EEP_MAP9287_SPURCHAN; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 8a7fc3962a16..b0687e5bdc1d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -15,6 +15,7 @@ */ #include "ath9k.h" +#include "hw.h" static void ath9k_get_txgain_index(struct ath_hw *ah, struct ath9k_channel *chan, @@ -95,8 +96,8 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, eep_data)) { - DPRINTF(ah, ATH_DBG_FATAL, - "Unable to read eeprom region\n"); + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "Unable to read eeprom region\n"); return false; } eep_data++; @@ -109,19 +110,20 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) { struct ar5416_eeprom_def *eep = (struct ar5416_eeprom_def *) &ah->eeprom.def; + struct ath_common *common = ath9k_hw_common(ah); u16 *eepdata, temp, magic, magic2; u32 sum = 0, el; bool need_swap = false; int i, addr, size; if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - DPRINTF(ah, ATH_DBG_FATAL, "Reading Magic # failed\n"); + ath_print(common, ATH_DBG_FATAL, "Reading Magic # failed\n"); return false; } if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah, ATH_DBG_EEPROM, - "Read Magic = 0x%04X\n", magic); + ath_print(common, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); if (magic != AR5416_EEPROM_MAGIC) { magic2 = swab16(magic); @@ -137,16 +139,16 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) eepdata++; } } else { - DPRINTF(ah, ATH_DBG_FATAL, - "Invalid EEPROM Magic. " - "Endianness mismatch.\n"); + ath_print(common, ATH_DBG_FATAL, + "Invalid EEPROM Magic. " + "Endianness mismatch.\n"); return -EINVAL; } } } - DPRINTF(ah, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); + ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); if (need_swap) el = swab16(ah->eeprom.def.baseEepHeader.length); @@ -167,8 +169,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) u32 integer, j; u16 word; - DPRINTF(ah, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing.\n"); + ath_print(common, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing.\n"); word = swab16(eep->baseEepHeader.length); eep->baseEepHeader.length = word; @@ -214,8 +216,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah, ATH_DBG_FATAL, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + ath_print(common, ATH_DBG_FATAL, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", sum, ah->eep_ops->get_eeprom_ver(ah)); return -EINVAL; } @@ -746,7 +748,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, #define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) #define SM_PDGAIN_B(x, y) \ SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) - + struct ath_common *common = ath9k_hw_common(ah); struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; struct cal_data_per_freq *pRawDataset; u8 *pCalBChans = NULL; @@ -870,20 +872,20 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, ((pdadcValues[4 * j + 3] & 0xFF) << 24); REG_WRITE(ah, regOffset, reg32); - DPRINTF(ah, ATH_DBG_EEPROM, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah, ATH_DBG_EEPROM, - "PDADC: Chain %d | PDADC %3d " - "Value %3d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d | PDADC %3d " - "Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); + ath_print(common, ATH_DBG_EEPROM, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + ath_print(common, ATH_DBG_EEPROM, + "PDADC: Chain %d | PDADC %3d " + "Value %3d | PDADC %3d Value %3d | " + "PDADC %3d Value %3d | PDADC %3d " + "Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); regOffset += 4; } @@ -1311,8 +1313,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; break; default: - DPRINTF(ah, ATH_DBG_EEPROM, - "Invalid chainmask configuration\n"); + ath_print(ath9k_hw_common(ah), ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); break; } } @@ -1349,20 +1351,21 @@ static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) { #define EEP_DEF_SPURCHAN \ (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) + struct ath_common *common = ath9k_hw_common(ah); u16 spur_val = AR_NO_SPUR; - DPRINTF(ah, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); + ath_print(common, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->config.spurchans[i][is2GHz]); switch (ah->config.spurmode) { case SPUR_DISABLE: break; case SPUR_ENABLE_IOCTL: spur_val = ah->config.spurchans[i][is2GHz]; - DPRINTF(ah, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); + ath_print(common, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); break; case SPUR_ENABLE_EEPROM: spur_val = EEP_DEF_SPURCHAN; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index e6ca3158759b..8ecd1b0bdf8f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -94,9 +94,9 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) udelay(AH_TIME_QUANTUM); } - DPRINTF(ah, ATH_DBG_ANY, - "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", - timeout, reg, REG_READ(ah, reg), mask, val); + ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, + "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", + timeout, reg, REG_READ(ah, reg), mask, val); return false; } @@ -178,9 +178,9 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, } break; default: - DPRINTF(ah, ATH_DBG_FATAL, - "Unknown phy %u (rate ix %u)\n", - rates->info[rateix].phy, rateix); + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "Unknown phy %u (rate ix %u)\n", + rates->info[rateix].phy, rateix); txTime = 0; break; } @@ -285,6 +285,7 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah) static bool ath9k_hw_chip_test(struct ath_hw *ah) { + struct ath_common *common = ath9k_hw_common(ah); u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) }; u32 regHold[2]; u32 patternData[4] = { 0x55555555, @@ -303,10 +304,11 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) REG_WRITE(ah, addr, wrData); rdData = REG_READ(ah, addr); if (rdData != wrData) { - DPRINTF(ah, ATH_DBG_FATAL, - "address test failed " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - addr, wrData, rdData); + ath_print(common, ATH_DBG_FATAL, + "address test failed " + "addr: 0x%08x - wr:0x%08x != " + "rd:0x%08x\n", + addr, wrData, rdData); return false; } } @@ -315,10 +317,11 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) REG_WRITE(ah, addr, wrData); rdData = REG_READ(ah, addr); if (wrData != rdData) { - DPRINTF(ah, ATH_DBG_FATAL, - "address test failed " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - addr, wrData, rdData); + ath_print(common, ATH_DBG_FATAL, + "address test failed " + "addr: 0x%08x - wr:0x%08x != " + "rd:0x%08x\n", + addr, wrData, rdData); return false; } } @@ -440,8 +443,8 @@ static int ath9k_hw_rfattach(struct ath_hw *ah) rfStatus = ath9k_hw_init_rf(ah, &ecode); if (!rfStatus) { - DPRINTF(ah, ATH_DBG_FATAL, - "RF setup failed, status: %u\n", ecode); + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "RF setup failed, status: %u\n", ecode); return ecode; } @@ -465,9 +468,9 @@ static int ath9k_hw_rf_claim(struct ath_hw *ah) case AR_RAD2122_SREV_MAJOR: break; default: - DPRINTF(ah, ATH_DBG_FATAL, - "Radio Chip Rev 0x%02X not supported\n", - val & AR_RADIO_SREV_MAJOR); + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "Radio Chip Rev 0x%02X not supported\n", + val & AR_RADIO_SREV_MAJOR); return -EOPNOTSUPP; } @@ -559,8 +562,10 @@ static int ath9k_hw_post_init(struct ath_hw *ah) if (ecode != 0) return ecode; - DPRINTF(ah, ATH_DBG_CONFIG, "Eeprom VER: %d, REV: %d\n", - ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah)); + ath_print(ath9k_hw_common(ah), ATH_DBG_CONFIG, + "Eeprom VER: %d, REV: %d\n", + ah->eep_ops->get_eeprom_ver(ah), + ah->eep_ops->get_eeprom_rev(ah)); ecode = ath9k_hw_rfattach(ah); if (ecode != 0) @@ -874,6 +879,7 @@ static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah) int ath9k_hw_init(struct ath_hw *ah) { + struct ath_common *common = ath9k_hw_common(ah); int r = 0; if (!ath9k_hw_devid_supported(ah->hw_version.devid)) @@ -883,12 +889,13 @@ int ath9k_hw_init(struct ath_hw *ah) ath9k_hw_init_config(ah); if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(ah, ATH_DBG_FATAL, "Couldn't reset chip\n"); + ath_print(common, ATH_DBG_FATAL, + "Couldn't reset chip\n"); return -EIO; } if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(ah, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); + ath_print(common, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); return -EIO; } @@ -903,14 +910,14 @@ int ath9k_hw_init(struct ath_hw *ah) } } - DPRINTF(ah, ATH_DBG_RESET, "serialize_regmode is %d\n", + ath_print(common, ATH_DBG_RESET, "serialize_regmode is %d\n", ah->config.serialize_regmode); if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { - DPRINTF(ah, ATH_DBG_FATAL, - "Mac Chip Rev 0x%02x.%x is not supported by " - "this driver\n", ah->hw_version.macVersion, - ah->hw_version.macRev); + ath_print(common, ATH_DBG_FATAL, + "Mac Chip Rev 0x%02x.%x is not supported by " + "this driver\n", ah->hw_version.macVersion, + ah->hw_version.macRev); return -EOPNOTSUPP; } @@ -948,8 +955,8 @@ int ath9k_hw_init(struct ath_hw *ah) r = ath9k_hw_init_macaddr(ah); if (r) { - DPRINTF(ah, ATH_DBG_FATAL, - "Failed to initialize MAC address\n"); + ath_print(common, ATH_DBG_FATAL, + "Failed to initialize MAC address\n"); return r; } @@ -1133,7 +1140,8 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) { if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { - DPRINTF(ah, ATH_DBG_RESET, "bad ack timeout %u\n", us); + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, + "bad ack timeout %u\n", us); ah->acktimeout = (u32) -1; return false; } else { @@ -1147,7 +1155,8 @@ static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) { if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { - DPRINTF(ah, ATH_DBG_RESET, "bad cts timeout %u\n", us); + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, + "bad cts timeout %u\n", us); ah->ctstimeout = (u32) -1; return false; } else { @@ -1161,8 +1170,8 @@ static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) { if (tu > 0xFFFF) { - DPRINTF(ah, ATH_DBG_XMIT, - "bad global tx timeout %u\n", tu); + ath_print(ath9k_hw_common(ah), ATH_DBG_XMIT, + "bad global tx timeout %u\n", tu); ah->globaltxtimeout = (u32) -1; return false; } else { @@ -1174,8 +1183,8 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) static void ath9k_hw_init_user_settings(struct ath_hw *ah) { - DPRINTF(ah, ATH_DBG_RESET, "ah->misc_mode 0x%x\n", - ah->misc_mode); + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n", + ah->misc_mode); if (ah->misc_mode != 0) REG_WRITE(ah, AR_PCU_MISC, @@ -1267,28 +1276,29 @@ static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah, u32 reg, u32 value) { struct base_eep_header *pBase = &(pEepData->baseEepHeader); + struct ath_common *common = ath9k_hw_common(ah); switch (ah->hw_version.devid) { case AR9280_DEVID_PCI: if (reg == 0x7894) { - DPRINTF(ah, ATH_DBG_EEPROM, + ath_print(common, ATH_DBG_EEPROM, "ini VAL: %x EEPROM: %x\n", value, (pBase->version & 0xff)); if ((pBase->version & 0xff) > 0x0a) { - DPRINTF(ah, ATH_DBG_EEPROM, - "PWDCLKIND: %d\n", - pBase->pwdclkind); + ath_print(common, ATH_DBG_EEPROM, + "PWDCLKIND: %d\n", + pBase->pwdclkind); value &= ~AR_AN_TOP2_PWDCLKIND; value |= AR_AN_TOP2_PWDCLKIND & (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); } else { - DPRINTF(ah, ATH_DBG_EEPROM, - "PWDCLKIND Earlier Rev\n"); + ath_print(common, ATH_DBG_EEPROM, + "PWDCLKIND Earlier Rev\n"); } - DPRINTF(ah, ATH_DBG_EEPROM, - "final ini VAL: %x\n", value); + ath_print(common, ATH_DBG_EEPROM, + "final ini VAL: %x\n", value); } break; } @@ -1460,8 +1470,8 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, (u32) regulatory->power_limit)); if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { - DPRINTF(ah, ATH_DBG_FATAL, - "ar5416SetRfRegs failed\n"); + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "ar5416SetRfRegs failed\n"); return -EIO; } @@ -1666,8 +1676,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) REG_WRITE(ah, AR_RTC_RC, 0); if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) { - DPRINTF(ah, ATH_DBG_RESET, - "RTC stuck in MAC reset\n"); + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, + "RTC stuck in MAC reset\n"); return false; } @@ -1703,7 +1713,8 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) AR_RTC_STATUS_M, AR_RTC_STATUS_ON, AH_WAIT_TIMEOUT)) { - DPRINTF(ah, ATH_DBG_RESET, "RTC not waking up\n"); + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, + "RTC not waking up\n"); return false; } @@ -1783,13 +1794,15 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, enum ath9k_ht_macmode macmode) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *channel = chan->chan; u32 synthDelay, qnum; for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { - DPRINTF(ah, ATH_DBG_QUEUE, - "Transmit frames pending on queue %d\n", qnum); + ath_print(common, ATH_DBG_QUEUE, + "Transmit frames pending on " + "queue %d\n", qnum); return false; } } @@ -1797,8 +1810,8 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) { - DPRINTF(ah, ATH_DBG_FATAL, - "Could not kill baseband RX\n"); + ath_print(common, ATH_DBG_FATAL, + "Could not kill baseband RX\n"); return false; } @@ -1808,8 +1821,8 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ath9k_hw_ar9280_set_channel(ah, chan); } else { if (!(ath9k_hw_set_channel(ah, chan))) { - DPRINTF(ah, ATH_DBG_FATAL, - "Failed to set channel\n"); + ath_print(common, ATH_DBG_FATAL, + "Failed to set channel\n"); return false; } } @@ -2370,7 +2383,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, } if (!ath9k_hw_chip_reset(ah, chan)) { - DPRINTF(ah, ATH_DBG_FATAL, "Chip reset failed\n"); + ath_print(common, ATH_DBG_FATAL, "Chip reset failed\n"); return -EINVAL; } @@ -2525,13 +2538,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u32 mask; mask = REG_READ(ah, AR_CFG); if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) { - DPRINTF(ah, ATH_DBG_RESET, + ath_print(common, ATH_DBG_RESET, "CFG Byte Swap Set 0x%x\n", mask); } else { mask = INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB; REG_WRITE(ah, AR_CFG, mask); - DPRINTF(ah, ATH_DBG_RESET, + ath_print(common, ATH_DBG_RESET, "Setting CFG 0x%x\n", REG_READ(ah, AR_CFG)); } } else { @@ -2559,8 +2572,8 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry) u32 keyType; if (entry >= ah->caps.keycache_size) { - DPRINTF(ah, ATH_DBG_FATAL, - "keychache entry %u out of range\n", entry); + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "keychache entry %u out of range\n", entry); return false; } @@ -2593,8 +2606,8 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) u32 macHi, macLo; if (entry >= ah->caps.keycache_size) { - DPRINTF(ah, ATH_DBG_FATAL, - "keychache entry %u out of range\n", entry); + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "keychache entry %u out of range\n", entry); return false; } @@ -2621,12 +2634,13 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, const u8 *mac) { const struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_common *common = ath9k_hw_common(ah); u32 key0, key1, key2, key3, key4; u32 keyType; if (entry >= pCap->keycache_size) { - DPRINTF(ah, ATH_DBG_FATAL, - "keycache entry %u out of range\n", entry); + ath_print(common, ATH_DBG_FATAL, + "keycache entry %u out of range\n", entry); return false; } @@ -2636,9 +2650,9 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, break; case ATH9K_CIPHER_AES_CCM: if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { - DPRINTF(ah, ATH_DBG_ANY, - "AES-CCM not supported by mac rev 0x%x\n", - ah->hw_version.macRev); + ath_print(common, ATH_DBG_ANY, + "AES-CCM not supported by mac rev 0x%x\n", + ah->hw_version.macRev); return false; } keyType = AR_KEYTABLE_TYPE_CCM; @@ -2647,15 +2661,15 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, keyType = AR_KEYTABLE_TYPE_TKIP; if (ATH9K_IS_MIC_ENABLED(ah) && entry + 64 >= pCap->keycache_size) { - DPRINTF(ah, ATH_DBG_ANY, - "entry %u inappropriate for TKIP\n", entry); + ath_print(common, ATH_DBG_ANY, + "entry %u inappropriate for TKIP\n", entry); return false; } break; case ATH9K_CIPHER_WEP: if (k->kv_len < WLAN_KEY_LEN_WEP40) { - DPRINTF(ah, ATH_DBG_ANY, - "WEP key length %u too small\n", k->kv_len); + ath_print(common, ATH_DBG_ANY, + "WEP key length %u too small\n", k->kv_len); return false; } if (k->kv_len <= WLAN_KEY_LEN_WEP40) @@ -2669,8 +2683,8 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, keyType = AR_KEYTABLE_TYPE_CLR; break; default: - DPRINTF(ah, ATH_DBG_FATAL, - "cipher %u not supported\n", k->kv_type); + ath_print(common, ATH_DBG_FATAL, + "cipher %u not supported\n", k->kv_type); return false; } @@ -2887,8 +2901,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) AR_RTC_FORCE_WAKE_EN); } if (i == 0) { - DPRINTF(ah, ATH_DBG_FATAL, - "Failed to wakeup in %uus\n", POWER_UP_TIME / 20); + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "Failed to wakeup in %uus\n", + POWER_UP_TIME / 20); return false; } } @@ -2900,6 +2915,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) { + struct ath_common *common = ath9k_hw_common(ah); int status = true, setChip = true; static const char *modes[] = { "AWAKE", @@ -2911,8 +2927,8 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) if (ah->power_mode == mode) return status; - DPRINTF(ah, ATH_DBG_RESET, "%s -> %s\n", - modes[ah->power_mode], modes[mode]); + ath_print(common, ATH_DBG_RESET, "%s -> %s\n", + modes[ah->power_mode], modes[mode]); switch (mode) { case ATH9K_PM_AWAKE: @@ -2926,8 +2942,8 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) ath9k_set_power_network_sleep(ah, setChip); break; default: - DPRINTF(ah, ATH_DBG_FATAL, - "Unknown power mode %u\n", mode); + ath_print(common, ATH_DBG_FATAL, + "Unknown power mode %u\n", mode); return false; } ah->power_mode = mode; @@ -3097,6 +3113,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) struct ath9k_hw_capabilities *pCap = &ah->caps; u32 sync_cause = 0; bool fatal_int = false; + struct ath_common *common = ath9k_hw_common(ah); if (!AR_SREV_9100(ah)) { if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { @@ -3170,8 +3187,8 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) } if (isr & AR_ISR_RXORN) { - DPRINTF(ah, ATH_DBG_INTERRUPT, - "receive FIFO overrun interrupt\n"); + ath_print(common, ATH_DBG_INTERRUPT, + "receive FIFO overrun interrupt\n"); } if (!AR_SREV_9100(ah)) { @@ -3213,25 +3230,25 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) if (fatal_int) { if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { - DPRINTF(ah, ATH_DBG_ANY, - "received PCI FATAL interrupt\n"); + ath_print(common, ATH_DBG_ANY, + "received PCI FATAL interrupt\n"); } if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { - DPRINTF(ah, ATH_DBG_ANY, - "received PCI PERR interrupt\n"); + ath_print(common, ATH_DBG_ANY, + "received PCI PERR interrupt\n"); } *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { - DPRINTF(ah, ATH_DBG_INTERRUPT, - "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); + ath_print(common, ATH_DBG_INTERRUPT, + "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); REG_WRITE(ah, AR_RC, 0); *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { - DPRINTF(ah, ATH_DBG_INTERRUPT, - "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); + ath_print(common, ATH_DBG_INTERRUPT, + "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); } REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); @@ -3246,11 +3263,12 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) u32 omask = ah->mask_reg; u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_common *common = ath9k_hw_common(ah); - DPRINTF(ah, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); + ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); if (omask & ATH9K_INT_GLOBAL) { - DPRINTF(ah, ATH_DBG_INTERRUPT, "disable IER\n"); + ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_DISABLE); (void) REG_READ(ah, AR_IER); if (!AR_SREV_9100(ah)) { @@ -3307,7 +3325,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) mask2 |= AR_IMR_S2_CST; } - DPRINTF(ah, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); + ath_print(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); REG_WRITE(ah, AR_IMR, mask); mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | @@ -3327,7 +3345,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) } if (ints & ATH9K_INT_GLOBAL) { - DPRINTF(ah, ATH_DBG_INTERRUPT, "enable IER\n"); + ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, @@ -3340,8 +3358,8 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) REG_WRITE(ah, AR_INTR_SYNC_MASK, AR_INTR_SYNC_DEFAULT); } - DPRINTF(ah, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", - REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); + ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", + REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); } return omask; @@ -3388,9 +3406,9 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; break; default: - DPRINTF(ah, ATH_DBG_BEACON, - "%s: unsupported opmode: %d\n", - __func__, ah->opmode); + ath_print(ath9k_hw_common(ah), ATH_DBG_BEACON, + "%s: unsupported opmode: %d\n", + __func__, ah->opmode); return; break; } @@ -3414,6 +3432,7 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, { u32 nextTbtt, beaconintval, dtimperiod, beacontimeout; struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_common *common = ath9k_hw_common(ah); REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt)); @@ -3439,10 +3458,10 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, else nextTbtt = bs->bs_nexttbtt; - DPRINTF(ah, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim); - DPRINTF(ah, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt); - DPRINTF(ah, ATH_DBG_BEACON, "beacon period %d\n", beaconintval); - DPRINTF(ah, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod); + ath_print(common, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim); + ath_print(common, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt); + ath_print(common, ATH_DBG_BEACON, "beacon period %d\n", beaconintval); + ath_print(common, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod); REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); @@ -3479,6 +3498,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + struct ath_common *common = ath9k_hw_common(ah); struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; u16 capField = 0, eeval; @@ -3500,8 +3520,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) regulatory->current_rd += 5; else if (regulatory->current_rd == 0x41) regulatory->current_rd = 0x43; - DPRINTF(ah, ATH_DBG_REGULATORY, - "regdomain mapped to 0x%x\n", regulatory->current_rd); + ath_print(common, ATH_DBG_REGULATORY, + "regdomain mapped to 0x%x\n", regulatory->current_rd); } eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE); @@ -4019,8 +4039,8 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) { if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0, AH_TSF_WRITE_TIMEOUT)) - DPRINTF(ah, ATH_DBG_RESET, - "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, + "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); } @@ -4036,7 +4056,8 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) { if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { - DPRINTF(ah, ATH_DBG_RESET, "bad slot time %u\n", us); + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, + "bad slot time %u\n", us); ah->slottime = (u32) -1; return false; } else { @@ -4121,8 +4142,9 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL); if (timer == NULL) { - printk(KERN_DEBUG "Failed to allocate memory" - "for hw timer[%d]\n", timer_index); + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "Failed to allocate memory" + "for hw timer[%d]\n", timer_index); return NULL; } @@ -4150,8 +4172,9 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, tsf = ath9k_hw_gettsf32(ah); - DPRINTF(ah, ATH_DBG_HWTIMER, "curent tsf %x period %x" - "timer_next %x\n", tsf, timer_period, timer_next); + ath_print(ath9k_hw_common(ah), ATH_DBG_HWTIMER, + "curent tsf %x period %x" + "timer_next %x\n", tsf, timer_period, timer_next); /* * Pull timer_next forward if the current TSF already passed it @@ -4213,6 +4236,7 @@ void ath_gen_timer_isr(struct ath_hw *ah) { struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; struct ath_gen_timer *timer; + struct ath_common *common = ath9k_hw_common(ah); u32 trigger_mask, thresh_mask, index; /* get hardware generic timer interrupt status */ @@ -4227,8 +4251,8 @@ void ath_gen_timer_isr(struct ath_hw *ah) index = rightmost_index(timer_table, &thresh_mask); timer = timer_table->timers[index]; BUG_ON(!timer); - DPRINTF(ah, ATH_DBG_HWTIMER, - "TSF overflow for Gen timer %d\n", index); + ath_print(common, ATH_DBG_HWTIMER, + "TSF overflow for Gen timer %d\n", index); timer->overflow(timer->arg); } @@ -4236,8 +4260,8 @@ void ath_gen_timer_isr(struct ath_hw *ah) index = rightmost_index(timer_table, &trigger_mask); timer = timer_table->timers[index]; BUG_ON(!timer); - DPRINTF(ah, ATH_DBG_HWTIMER, - "Gen timer[%d] trigger\n", index); + ath_print(common, ATH_DBG_HWTIMER, + "Gen timer[%d] trigger\n", index); timer->trigger(timer->arg); } } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 32401742751e..1c73f81a5957 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -30,6 +30,7 @@ #include "btcoex.h" #include "../regd.h" +#include "../debug.h" #define ATHEROS_VENDOR_ID 0x168c #define AR5416_DEVID_PCI 0x0023 diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index b4d2f207857d..926f201ce4fa 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -15,15 +15,16 @@ */ #include "ath9k.h" +#include "hw.h" static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, struct ath9k_tx_queue_info *qi) { - DPRINTF(ah, ATH_DBG_INTERRUPT, - "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", - ah->txok_interrupt_mask, ah->txerr_interrupt_mask, - ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask, - ah->txurn_interrupt_mask); + ath_print(ath9k_hw_common(ah), ATH_DBG_INTERRUPT, + "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", + ah->txok_interrupt_mask, ah->txerr_interrupt_mask, + ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask, + ah->txurn_interrupt_mask); REG_WRITE(ah, AR_IMR_S0, SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK) @@ -47,7 +48,8 @@ void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) void ath9k_hw_txstart(struct ath_hw *ah, u32 q) { - DPRINTF(ah, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q); + ath_print(ath9k_hw_common(ah), ATH_DBG_QUEUE, + "Enable TXE on queue: %u\n", q); REG_WRITE(ah, AR_Q_TXE, 1 << q); } @@ -98,22 +100,22 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) { #define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */ #define ATH9K_TIME_QUANTUM 100 /* usec */ - + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; u32 tsfLow, j, wait; u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM; if (q >= pCap->total_queues) { - DPRINTF(ah, ATH_DBG_QUEUE, "Stopping TX DMA, " - "invalid queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah, ATH_DBG_QUEUE, "Stopping TX DMA, " - "inactive queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, " + "inactive queue: %u\n", q); return false; } @@ -126,9 +128,9 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) } if (ath9k_hw_numtxpending(ah, q)) { - DPRINTF(ah, ATH_DBG_QUEUE, - "%s: Num of pending TX Frames %d on Q %d\n", - __func__, ath9k_hw_numtxpending(ah, q), q); + ath_print(common, ATH_DBG_QUEUE, + "%s: Num of pending TX Frames %d on Q %d\n", + __func__, ath9k_hw_numtxpending(ah, q), q); for (j = 0; j < 2; j++) { tsfLow = REG_READ(ah, AR_TSF_L32); @@ -142,9 +144,9 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10)) break; - DPRINTF(ah, ATH_DBG_QUEUE, - "TSF has moved while trying to set " - "quiet time TSF: 0x%08x\n", tsfLow); + ath_print(common, ATH_DBG_QUEUE, + "TSF has moved while trying to set " + "quiet time TSF: 0x%08x\n", tsfLow); } REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); @@ -155,9 +157,9 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) wait = wait_time; while (ath9k_hw_numtxpending(ah, q)) { if ((--wait) == 0) { - DPRINTF(ah, ATH_DBG_QUEUE, - "Failed to stop TX DMA in 100 " - "msec after killing last frame\n"); + ath_print(common, ATH_DBG_QUEUE, + "Failed to stop TX DMA in 100 " + "msec after killing last frame\n"); break; } udelay(ATH9K_TIME_QUANTUM); @@ -445,23 +447,24 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, const struct ath9k_tx_queue_info *qinfo) { u32 cw; + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah, ATH_DBG_QUEUE, "Set TXQ properties, " - "invalid queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah, ATH_DBG_QUEUE, "Set TXQ properties, " - "inactive queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, " + "inactive queue: %u\n", q); return false; } - DPRINTF(ah, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q); qi->tqi_ver = qinfo->tqi_ver; qi->tqi_subtype = qinfo->tqi_subtype; @@ -514,19 +517,20 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qinfo) { + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah, ATH_DBG_QUEUE, "Get TXQ properties, " - "invalid queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah, ATH_DBG_QUEUE, "Get TXQ properties, " - "inactive queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, " + "inactive queue: %u\n", q); return false; } @@ -551,6 +555,7 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, const struct ath9k_tx_queue_info *qinfo) { + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info *qi; struct ath9k_hw_capabilities *pCap = &ah->caps; int q; @@ -574,23 +579,23 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, ATH9K_TX_QUEUE_INACTIVE) break; if (q == pCap->total_queues) { - DPRINTF(ah, ATH_DBG_FATAL, - "No available TX queue\n"); + ath_print(common, ATH_DBG_FATAL, + "No available TX queue\n"); return -1; } break; default: - DPRINTF(ah, ATH_DBG_FATAL, "Invalid TX queue type: %u\n", - type); + ath_print(common, ATH_DBG_FATAL, + "Invalid TX queue type: %u\n", type); return -1; } - DPRINTF(ah, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q); qi = &ah->txq[q]; if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah, ATH_DBG_FATAL, - "TX queue: %u already active\n", q); + ath_print(common, ATH_DBG_FATAL, + "TX queue: %u already active\n", q); return -1; } memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); @@ -617,21 +622,22 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) { struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info *qi; if (q >= pCap->total_queues) { - DPRINTF(ah, ATH_DBG_QUEUE, "Release TXQ, " - "invalid queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Release TXQ, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah, ATH_DBG_QUEUE, "Release TXQ, " - "inactive queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Release TXQ, " + "inactive queue: %u\n", q); return false; } - DPRINTF(ah, ATH_DBG_QUEUE, "Release TX queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q); qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; ah->txok_interrupt_mask &= ~(1 << q); @@ -647,24 +653,25 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) { struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ath9k_tx_queue_info *qi; u32 cwMin, chanCwMin, value; if (q >= pCap->total_queues) { - DPRINTF(ah, ATH_DBG_QUEUE, "Reset TXQ, " - "invalid queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, " + "invalid queue: %u\n", q); return false; } qi = &ah->txq[q]; if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah, ATH_DBG_QUEUE, "Reset TXQ, " - "inactive queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, " + "inactive queue: %u\n", q); return true; } - DPRINTF(ah, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q); + ath_print(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q); if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { if (chan && IS_CHAN_B(chan)) @@ -911,8 +918,9 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) AR_DIAG_RX_ABORT)); reg = REG_READ(ah, AR_OBS_BUS_1); - DPRINTF(ah, ATH_DBG_FATAL, - "RX failed to go idle in 10 ms RXSM=0x%x\n", reg); + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "RX failed to go idle in 10 ms RXSM=0x%x\n", + reg); return false; } @@ -954,7 +962,7 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah) { #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ #define AH_RX_TIME_QUANTUM 100 /* usec */ - + struct ath_common *common = ath9k_hw_common(ah); int i; REG_WRITE(ah, AR_CR, AR_CR_RXD); @@ -967,12 +975,12 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah) } if (i == 0) { - DPRINTF(ah, ATH_DBG_FATAL, - "DMA failed to stop in %d ms " - "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", - AH_RX_STOP_DMA_TIMEOUT / 1000, - REG_READ(ah, AR_CR), - REG_READ(ah, AR_DIAG_SW)); + ath_print(common, ATH_DBG_FATAL, + "DMA failed to stop in %d ms " + "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", + AH_RX_STOP_DMA_TIMEOUT / 1000, + REG_READ(ah, AR_CR), + REG_READ(ah, AR_DIAG_SW)); return false; } else { return true; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 571a0d9c8605..f409bbc30535 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -225,8 +225,9 @@ static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) } sband->n_bitrates++; - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n", - rate[i].bitrate / 10, rate[i].hw_value); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, + "Rate: %2dMbps, ratecode: %2d\n", + rate[i].bitrate / 10, rate[i].hw_value); } } @@ -297,6 +298,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, struct ath9k_channel *hchan) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); bool fastcc = true, stopped; struct ieee80211_channel *channel = hw->conf.channel; int r; @@ -326,19 +328,19 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) fastcc = false; - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, - "(%u MHz) -> (%u MHz), chanwidth: %d\n", - sc->sc_ah->curchan->channel, - channel->center_freq, sc->tx_chan_width); + ath_print(common, ATH_DBG_CONFIG, + "(%u MHz) -> (%u MHz), chanwidth: %d\n", + sc->sc_ah->curchan->channel, + channel->center_freq, sc->tx_chan_width); spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, hchan, fastcc); if (r) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Unable to reset channel (%u Mhz) " - "reset status %d\n", - channel->center_freq, r); + ath_print(common, ATH_DBG_FATAL, + "Unable to reset channel (%u Mhz) " + "reset status %d\n", + channel->center_freq, r); spin_unlock_bh(&sc->sc_resetlock); goto ps_restore; } @@ -347,8 +349,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, sc->sc_flags &= ~SC_OP_FULL_RESET; if (ath_startrecv(sc) != 0) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Unable to restart recv logic\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to restart recv logic\n"); r = -EIO; goto ps_restore; } @@ -373,6 +375,7 @@ static void ath_ani_calibrate(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); bool longcal = false; bool shortcal = false; bool aniflag = false; @@ -399,7 +402,7 @@ static void ath_ani_calibrate(unsigned long data) /* Long calibration runs independently of short calibration. */ if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { longcal = true; - DPRINTF(sc->sc_ah, ATH_DBG_ANI, "longcal @%lu\n", jiffies); + ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); sc->ani.longcal_timer = timestamp; } @@ -407,7 +410,8 @@ static void ath_ani_calibrate(unsigned long data) if (!sc->ani.caldone) { if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) { shortcal = true; - DPRINTF(sc->sc_ah, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); + ath_print(common, ATH_DBG_ANI, + "shortcal @%lu\n", jiffies); sc->ani.shortcal_timer = timestamp; sc->ani.resetcal_timer = timestamp; } @@ -441,9 +445,11 @@ static void ath_ani_calibrate(unsigned long data) sc->ani.noise_floor = ath9k_hw_getchan_noise(ah, ah->curchan); - DPRINTF(sc->sc_ah, ATH_DBG_ANI," calibrate chan %u/%x nf: %d\n", - ah->curchan->channel, ah->curchan->channelFlags, - sc->ani.noise_floor); + ath_print(common, ATH_DBG_ANI, + " calibrate chan %u/%x nf: %d\n", + ah->curchan->channel, + ah->curchan->channelFlags, + sc->ani.noise_floor); } } @@ -496,8 +502,9 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht) sc->rx_chainmask = 1; } - DPRINTF(ah, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", - sc->tx_chainmask, sc->rx_chainmask); + ath_print(ath9k_hw_common(ah), ATH_DBG_CONFIG, + "tx chmask: %d, rx chmask: %d\n", + sc->tx_chainmask, sc->rx_chainmask); } static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) @@ -527,6 +534,7 @@ static void ath9k_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); u32 status = sc->intrstatus; @@ -552,7 +560,8 @@ static void ath9k_tasklet(unsigned long data) * TSF sync does not look correct; remain awake to sync with * the next Beacon. */ - DPRINTF(ah, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); + ath_print(common, ATH_DBG_PS, + "TSFOOR - Sync with next Beacon\n"); sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; } @@ -752,8 +761,8 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) { /* TX MIC entry failed. No need to proceed further */ - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Setting TX MIC Key Failed\n"); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + "Setting TX MIC Key Failed\n"); return 0; } @@ -957,8 +966,9 @@ static void setup_ht_cap(struct ath_softc *sc, rx_streams = !(sc->rx_chainmask & (sc->rx_chainmask - 1)) ? 1 : 2; if (tx_streams != rx_streams) { - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, + "TX streams %d, RX streams: %d\n", + tx_streams, rx_streams); ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; ht_info->mcs.tx_params |= ((tx_streams - 1) << IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); @@ -979,8 +989,9 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, struct ath_common *common = ath9k_hw_common(ah); if (bss_conf->assoc) { - DPRINTF(ah, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, common->curbssid); + ath_print(common, ATH_DBG_CONFIG, + "Bss Info ASSOC %d, bssid: %pM\n", + bss_conf->aid, common->curbssid); /* New association, store aid */ common->curaid = bss_conf->aid; @@ -1001,7 +1012,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_start_ani(sc); } else { - DPRINTF(ah, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); + ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); common->curaid = 0; /* Stop ANI */ del_timer_sync(&sc->ani.timer); @@ -1094,8 +1105,8 @@ static int ath_register_led(struct ath_softc *sc, struct ath_led *led, ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); if (ret) - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Failed to register led:%s", led->name); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + "Failed to register led:%s", led->name); else led->registered = 1; return ret; @@ -1179,6 +1190,7 @@ fail: void ath_radio_enable(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *channel = sc->hw->conf.channel; int r; @@ -1191,17 +1203,17 @@ void ath_radio_enable(struct ath_softc *sc) spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, ah->curchan, false); if (r) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Unable to reset channel %u (%uMhz) ", - "reset status %d\n", - channel->center_freq, r); + ath_print(common, ATH_DBG_FATAL, + "Unable to reset channel %u (%uMhz) ", + "reset status %d\n", + channel->center_freq, r); } spin_unlock_bh(&sc->sc_resetlock); ath_update_txpow(sc); if (ath_startrecv(sc) != 0) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Unable to restart recv logic\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to restart recv logic\n"); return; } @@ -1246,10 +1258,10 @@ void ath_radio_disable(struct ath_softc *sc) spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, ah->curchan, false); if (r) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Unable to reset channel %u (%uMhz) " - "reset status %d\n", - channel->center_freq, r); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + "Unable to reset channel %u (%uMhz) " + "reset status %d\n", + channel->center_freq, r); } spin_unlock_bh(&sc->sc_resetlock); @@ -1367,8 +1379,8 @@ static void ath_detect_bt_priority(struct ath_softc *sc) if (time_after(jiffies, btcoex->bt_priority_time + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { - DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, - "BT priority traffic detected"); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, + "BT priority traffic detected"); sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; } else { sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; @@ -1401,7 +1413,8 @@ static void ath9k_btcoex_bt_stomp(struct ath_softc *sc, AR_STOMP_NONE_WLAN_WGHT); break; default: - DPRINTF(ah, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); + ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Invalid Stomptype\n"); break; } @@ -1481,7 +1494,8 @@ static void ath_btcoex_no_stomp_timer(void *arg) struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - DPRINTF(ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); + ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "no stomp timer running \n"); spin_lock_bh(&btcoex->btcoex_lock); @@ -1614,18 +1628,18 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) r = ath9k_hw_init(ah); if (r) { - DPRINTF(ah, ATH_DBG_FATAL, - "Unable to initialize hardware; " - "initialization status: %d\n", r); + ath_print(common, ATH_DBG_FATAL, + "Unable to initialize hardware; " + "initialization status: %d\n", r); goto bad; } /* Get the hardware key cache size. */ sc->keymax = ah->caps.keycache_size; if (sc->keymax > ATH_KEYMAX) { - DPRINTF(ah, ATH_DBG_ANY, - "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, sc->keymax); + ath_print(common, ATH_DBG_ANY, + "Warning, using only %u entries in %u key cache\n", + ATH_KEYMAX, sc->keymax); sc->keymax = ATH_KEYMAX; } @@ -1653,15 +1667,15 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) */ sc->beacon.beaconq = ath_beaconq_setup(ah); if (sc->beacon.beaconq == -1) { - DPRINTF(ah, ATH_DBG_FATAL, - "Unable to setup a beacon xmit queue\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to setup a beacon xmit queue\n"); r = -EIO; goto bad2; } sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); if (sc->beacon.cabq == NULL) { - DPRINTF(ah, ATH_DBG_FATAL, - "Unable to setup CAB xmit queue\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to setup CAB xmit queue\n"); r = -EIO; goto bad2; } @@ -1675,27 +1689,27 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) /* Setup data queues */ /* NB: ensure BK queue is the lowest priority h/w queue */ if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { - DPRINTF(ah, ATH_DBG_FATAL, - "Unable to setup xmit queue for BK traffic\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for BK traffic\n"); r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { - DPRINTF(ah, ATH_DBG_FATAL, - "Unable to setup xmit queue for BE traffic\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for BE traffic\n"); r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { - DPRINTF(ah, ATH_DBG_FATAL, - "Unable to setup xmit queue for VI traffic\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for VI traffic\n"); r = -EIO; goto bad2; } if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { - DPRINTF(ah, ATH_DBG_FATAL, - "Unable to setup xmit queue for VO traffic\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for VO traffic\n"); r = -EIO; goto bad2; } @@ -1933,6 +1947,7 @@ error_attach: int ath_reset(struct ath_softc *sc, bool retry_tx) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hw *hw = sc->hw; int r; @@ -1944,12 +1959,13 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); if (r) - DPRINTF(ah, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %d\n", r); + ath_print(common, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %d\n", r); spin_unlock_bh(&sc->sc_resetlock); if (ath_startrecv(sc) != 0) - DPRINTF(ah, ATH_DBG_FATAL, "Unable to start recv logic\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to start recv logic\n"); /* * We may be doing a reset in response to a request @@ -1992,18 +2008,19 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) #define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) #define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) - + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_desc *ds; struct ath_buf *bf; int i, bsize, error; - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", - name, nbuf, ndesc); + ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", + name, nbuf, ndesc); INIT_LIST_HEAD(head); /* ath_desc must be a multiple of DWORDs */ if ((sizeof(struct ath_desc) % 4) != 0) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); + ath_print(common, ATH_DBG_FATAL, + "ath_desc not DWORD aligned\n"); ASSERT((sizeof(struct ath_desc) % 4) == 0); error = -ENOMEM; goto fail; @@ -2037,9 +2054,9 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, goto fail; } ds = dd->dd_desc; - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", - name, ds, (u32) dd->dd_desc_len, - ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); + ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", + name, ds, (u32) dd->dd_desc_len, + ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); /* allocate buffers */ bsize = sizeof(struct ath_buf) * nbuf; @@ -2189,7 +2206,8 @@ static void ath9k_btcoex_timer_resume(struct ath_softc *sc) struct ath_btcoex *btcoex = &sc->btcoex; struct ath_hw *ah = sc->sc_ah; - DPRINTF(ah, ATH_DBG_BTCOEX, "Starting btcoex timers"); + ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Starting btcoex timers"); /* make sure duty cycle timer is also stopped when resuming */ if (btcoex->hw_timer_enabled) @@ -2207,12 +2225,14 @@ static int ath9k_start(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *curchan = hw->conf.channel; struct ath9k_channel *init_channel; int r; - DPRINTF(ah, ATH_DBG_CONFIG, "Starting driver with " - "initial channel: %d MHz\n", curchan->center_freq); + ath_print(common, ATH_DBG_CONFIG, + "Starting driver with initial channel: %d MHz\n", + curchan->center_freq); mutex_lock(&sc->mutex); @@ -2256,10 +2276,10 @@ static int ath9k_start(struct ieee80211_hw *hw) spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, init_channel, false); if (r) { - DPRINTF(ah, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %d " - "(freq %u MHz)\n", r, - curchan->center_freq); + ath_print(common, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %d " + "(freq %u MHz)\n", r, + curchan->center_freq); spin_unlock_bh(&sc->sc_resetlock); goto mutex_unlock; } @@ -2279,7 +2299,8 @@ static int ath9k_start(struct ieee80211_hw *hw) * here except setup the interrupt mask. */ if (ath_startrecv(sc) != 0) { - DPRINTF(ah, ATH_DBG_FATAL, "Unable to start recv logic\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to start recv logic\n"); r = -EIO; goto mutex_unlock; } @@ -2331,12 +2352,14 @@ static int ath9k_tx(struct ieee80211_hw *hw, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_tx_control txctl; int hdrlen, padsize; if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) { - printk(KERN_DEBUG "ath9k: %s: TX in unexpected wiphy state " - "%d\n", wiphy_name(hw->wiphy), aphy->state); + ath_print(common, ATH_DBG_XMIT, + "ath9k: %s: TX in unexpected wiphy state " + "%d\n", wiphy_name(hw->wiphy), aphy->state); goto exit; } @@ -2349,8 +2372,8 @@ static int ath9k_tx(struct ieee80211_hw *hw, if (ieee80211_is_data(hdr->frame_control) && !ieee80211_is_nullfunc(hdr->frame_control) && !ieee80211_has_pm(hdr->frame_control)) { - DPRINTF(sc->sc_ah, ATH_DBG_PS, "Add PM=1 for a TX frame " - "while in PS mode\n"); + ath_print(common, ATH_DBG_PS, "Add PM=1 for a TX frame " + "while in PS mode\n"); hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); } } @@ -2365,11 +2388,12 @@ static int ath9k_tx(struct ieee80211_hw *hw, ath9k_ps_wakeup(sc); ath9k_hw_setrxabort(sc->sc_ah, 0); if (ieee80211_is_pspoll(hdr->frame_control)) { - DPRINTF(sc->sc_ah, ATH_DBG_PS, "Sending PS-Poll to pick a " - "buffered frame\n"); + ath_print(common, ATH_DBG_PS, + "Sending PS-Poll to pick a buffered frame\n"); sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA; } else { - DPRINTF(sc->sc_ah, ATH_DBG_PS, "Wake up to complete TX\n"); + ath_print(common, ATH_DBG_PS, + "Wake up to complete TX\n"); sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK; } /* @@ -2411,10 +2435,10 @@ static int ath9k_tx(struct ieee80211_hw *hw, if (!txctl.txq) goto exit; - DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); + ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); if (ath_tx_start(hw, skb, &txctl) != 0) { - DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "TX failed\n"); + ath_print(common, ATH_DBG_XMIT, "TX failed\n"); goto exit; } @@ -2445,6 +2469,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); mutex_lock(&sc->mutex); @@ -2459,7 +2484,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) } if (sc->sc_flags & SC_OP_INVALID) { - DPRINTF(ah, ATH_DBG_ANY, "Device not present\n"); + ath_print(common, ATH_DBG_ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; } @@ -2495,7 +2520,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) mutex_unlock(&sc->mutex); - DPRINTF(ah, ATH_DBG_CONFIG, "Driver halt\n"); + ath_print(common, ATH_DBG_CONFIG, "Driver halt\n"); } static int ath9k_add_interface(struct ieee80211_hw *hw, @@ -2503,6 +2528,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp = (void *)conf->vif->drv_priv; enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; int ret = 0; @@ -2529,13 +2555,14 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ic_opmode = conf->type; break; default: - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, + ath_print(common, ATH_DBG_FATAL, "Interface type %d not yet supported\n", conf->type); ret = -EOPNOTSUPP; goto out; } - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode); + ath_print(common, ATH_DBG_CONFIG, + "Attach a VIF of type: %d\n", ic_opmode); /* Set the VIF opmode */ avp->av_opmode = ic_opmode; @@ -2585,10 +2612,11 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp = (void *)conf->vif->drv_priv; int i; - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Detach Interface\n"); + ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); mutex_lock(&sc->mutex); @@ -2623,6 +2651,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_conf *conf = &hw->conf; struct ath_hw *ah = sc->sc_ah; bool all_wiphys_idle = false, disable_radio = false; @@ -2642,8 +2671,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } else if (all_wiphys_idle) { ath_radio_enable(sc); - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, - "not-idle: enabling radio\n"); + ath_print(common, ATH_DBG_CONFIG, + "not-idle: enabling radio\n"); } } @@ -2696,8 +2725,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) goto skip_chan_change; } - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Set channel: %d MHz\n", - curchan->center_freq); + ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n", + curchan->center_freq); /* XXX: remove me eventualy */ ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]); @@ -2705,7 +2734,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath_update_chainmask(sc, conf_is_ht(conf)); if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unable to set channel\n"); + ath_print(common, ATH_DBG_FATAL, + "Unable to set channel\n"); mutex_unlock(&sc->mutex); return -EINVAL; } @@ -2716,7 +2746,7 @@ skip_chan_change: sc->config.txpowlimit = 2 * conf->power_level; if (disable_radio) { - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "idle: disabling radio\n"); + ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); ath_radio_disable(sc); } @@ -2753,7 +2783,8 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, ath9k_hw_setrxfilter(sc->sc_ah, rfilt); ath9k_ps_restore(sc); - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", rfilt); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, + "Set HW RX filter: 0x%x\n", rfilt); } static void ath9k_sta_notify(struct ieee80211_hw *hw, @@ -2781,6 +2812,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_tx_queue_info qi; int ret = 0, qnum; @@ -2797,15 +2829,15 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, qi.tqi_burstTime = params->txop; qnum = ath_get_hal_qnum(queue, sc); - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, - "Configure tx [queue/halq] [%d/%d], " - "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", - queue, qnum, params->aifs, params->cw_min, - params->cw_max, params->txop); + ath_print(common, ATH_DBG_CONFIG, + "Configure tx [queue/halq] [%d/%d], " + "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", + queue, qnum, params->aifs, params->cw_min, + params->cw_max, params->txop); ret = ath_txq_update(sc, qnum, &qi); if (ret) - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "TXQ Update failed\n"); + ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n"); mutex_unlock(&sc->mutex); @@ -2820,6 +2852,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); int ret = 0; if (modparam_nohwcrypt) @@ -2827,7 +2860,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Set HW Key\n"); + ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n"); switch (cmd) { case SET_KEY: @@ -2902,9 +2935,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, /* Set aggregation protection mode parameters */ sc->config.ath_aggr_prot = 0; - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, - "RX filter 0x%x bssid %pM aid 0x%x\n", - rfilt, common->curbssid, common->curaid); + ath_print(common, ATH_DBG_CONFIG, + "RX filter 0x%x bssid %pM aid 0x%x\n", + rfilt, common->curbssid, common->curaid); /* need to reconfigure the beacon */ sc->sc_flags &= ~SC_OP_BEACONS ; @@ -2951,8 +2984,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath_update_chainmask(sc, 0); if (changed & BSS_CHANGED_ERP_PREAMBLE) { - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", - bss_conf->use_short_preamble); + ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", + bss_conf->use_short_preamble); if (bss_conf->use_short_preamble) sc->sc_flags |= SC_OP_PREAMBLE_SHORT; else @@ -2960,8 +2993,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ERP_CTS_PROT) { - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", - bss_conf->use_cts_prot); + ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", + bss_conf->use_cts_prot); if (bss_conf->use_cts_prot && hw->conf.channel->band != IEEE80211_BAND_5GHZ) sc->sc_flags |= SC_OP_PROTECT_ENABLE; @@ -2970,7 +3003,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", + ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", bss_conf->assoc); ath9k_bss_assoc_info(sc, vif, bss_conf); } @@ -3055,7 +3088,8 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ath_tx_aggr_resume(sc, sta, tid); break; default: - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "Unknown AMPDU action\n"); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + "Unknown AMPDU action\n"); } return ret; diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 1166f725f556..b26302599765 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -26,6 +26,7 @@ ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, bool ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) { + struct ath_common *common = ath9k_hw_common(ah); u32 channelSel = 0; u32 bModeSynth = 0; u32 aModeRefSel = 0; @@ -46,8 +47,8 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = ((freq - 704) * 2 - 3040) / 10; bModeSynth = 1; } else { - DPRINTF(ah, ATH_DBG_FATAL, - "Invalid channel %u MHz\n", freq); + ath_print(common, ATH_DBG_FATAL, + "Invalid channel %u MHz\n", freq); return false; } @@ -79,8 +80,8 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8); aModeRefSel = ath9k_hw_reverse_bits(1, 2); } else { - DPRINTF(ah, ATH_DBG_FATAL, - "Invalid channel %u MHz\n", freq); + ath_print(common, ATH_DBG_FATAL, + "Invalid channel %u MHz\n", freq); return false; } @@ -285,6 +286,8 @@ ath9k_hw_rf_free(struct ath_hw *ah) bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) { + struct ath_common *common = ath9k_hw_common(ah); + if (!AR_SREV_9280_10_OR_LATER(ah)) { ah->analogBank0Data = kzalloc((sizeof(u32) * @@ -315,8 +318,8 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) || ah->analogBank6Data == NULL || ah->analogBank6TPCData == NULL || ah->analogBank7Data == NULL) { - DPRINTF(ah, ATH_DBG_FATAL, - "Cannot allocate RF banks\n"); + ath_print(common, ATH_DBG_FATAL, + "Cannot allocate RF banks\n"); *status = -ENOMEM; return false; } @@ -326,8 +329,8 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) ah->iniAddac.ia_rows * ah->iniAddac.ia_columns), GFP_KERNEL); if (ah->addac5416_21 == NULL) { - DPRINTF(ah, ATH_DBG_FATAL, - "Cannot allocate addac5416_21\n"); + ath_print(common, ATH_DBG_FATAL, + "Cannot allocate addac5416_21\n"); *status = -ENOMEM; return false; } @@ -336,8 +339,8 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) kzalloc((sizeof(u32) * ah->iniBank6.ia_rows), GFP_KERNEL); if (ah->bank6Temp == NULL) { - DPRINTF(ah, ATH_DBG_FATAL, - "Cannot allocate bank6Temp\n"); + ath_print(common, ATH_DBG_FATAL, + "Cannot allocate bank6Temp\n"); *status = -ENOMEM; return false; } diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index cafe1ec7bdbb..7346649af2d7 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1160,6 +1160,7 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, bool is_cw_40) { int mode = 0; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); switch(band) { case IEEE80211_BAND_2GHZ: @@ -1177,14 +1178,14 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, mode = ATH9K_MODE_11NA_HT40PLUS; break; default: - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "Invalid band\n"); + ath_print(common, ATH_DBG_CONFIG, "Invalid band\n"); return NULL; } BUG_ON(mode >= ATH9K_MODE_MAX); - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, - "Choosing rate table for mode: %d\n", mode); + ath_print(common, ATH_DBG_CONFIG, + "Choosing rate table for mode: %d\n", mode); return sc->hw_rate_table[mode]; } @@ -1195,12 +1196,13 @@ static void ath_rc_init(struct ath_softc *sc, const struct ath_rate_table *rate_table) { struct ath_rateset *rateset = &ath_rc_priv->neg_rates; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; u8 i, j, k, hi = 0, hthi = 0; if (!rate_table) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Rate table not initialized\n"); + ath_print(common, ATH_DBG_FATAL, + "Rate table not initialized\n"); return; } @@ -1263,9 +1265,9 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; sc->cur_rate_table = rate_table; - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, - "RC Initialized with capabilities: 0x%x\n", - ath_rc_priv->ht_cap); + ath_print(common, ATH_DBG_CONFIG, + "RC Initialized with capabilities: 0x%x\n", + ath_rc_priv->ht_cap); } static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta, @@ -1441,9 +1443,9 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, oper_cw40, oper_sgi40); ath_rc_init(sc, priv_sta, sband, sta, rate_table); - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, - "Operating HT Bandwidth changed to: %d\n", - sc->hw->conf.channel_type); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, + "Operating HT Bandwidth changed to: %d\n", + sc->hw->conf.channel_type); } } } @@ -1466,8 +1468,8 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp); if (!rate_priv) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Unable to allocate private rc structure\n"); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + "Unable to allocate private rc structure\n"); return NULL; } diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index fb635a0a34e8..6caef1b5dfe2 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -309,16 +309,16 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, min(common->cachelsz, (u16)64)); - DPRINTF(sc->sc_ah, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", - common->cachelsz, sc->rx.bufsize); + ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", + common->cachelsz, sc->rx.bufsize); /* Initialize rx descriptors */ error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, "rx", nbufs, 1); if (error != 0) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "failed to allocate rx descriptors: %d\n", error); + ath_print(common, ATH_DBG_FATAL, + "failed to allocate rx descriptors: %d\n", error); goto err; } @@ -337,8 +337,8 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "dma_mapping_error() on RX init\n"); + ath_print(common, ATH_DBG_FATAL, + "dma_mapping_error() on RX init\n"); error = -ENOMEM; goto err; } @@ -543,8 +543,9 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) if (sc->sc_flags & SC_OP_BEACON_SYNC) { sc->sc_flags &= ~SC_OP_BEACON_SYNC; - DPRINTF(sc->sc_ah, ATH_DBG_PS, "Reconfigure Beacon timers based on " - "timestamp from the AP\n"); + ath_print(common, ATH_DBG_PS, + "Reconfigure Beacon timers based on " + "timestamp from the AP\n"); ath_beacon_config(sc, NULL); } @@ -556,8 +557,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) * a backup trigger for returning into NETWORK SLEEP state, * so we are waiting for it as well. */ - DPRINTF(sc->sc_ah, ATH_DBG_PS, "Received DTIM beacon indicating " - "buffered broadcast/multicast frame(s)\n"); + ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating " + "buffered broadcast/multicast frame(s)\n"); sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON; return; } @@ -569,13 +570,15 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) * been delivered. */ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; - DPRINTF(sc->sc_ah, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); + ath_print(common, ATH_DBG_PS, + "PS wait for CAB frames timed out\n"); } } static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) { struct ieee80211_hdr *hdr; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); hdr = (struct ieee80211_hdr *)skb->data; @@ -593,14 +596,15 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) * point. */ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; - DPRINTF(sc->sc_ah, ATH_DBG_PS, "All PS CAB frames received, back to " - "sleep\n"); + ath_print(common, ATH_DBG_PS, + "All PS CAB frames received, back to sleep\n"); } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && !is_multicast_ether_addr(hdr->addr1) && !ieee80211_has_morefrags(hdr->frame_control)) { sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA; - DPRINTF(sc->sc_ah, ATH_DBG_PS, "Going back to sleep after having " - "received PS-Poll data (0x%x)\n", + ath_print(common, ATH_DBG_PS, + "Going back to sleep after having received " + "PS-Poll data (0x%x)\n", sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_PSPOLL_DATA | @@ -816,8 +820,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) bf->bf_buf_addr))) { dev_kfree_skb_any(requeue_skb); bf->bf_mpdu = NULL; - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "dma_mapping_error() on RX\n"); + ath_print(common, ATH_DBG_FATAL, + "dma_mapping_error() on RX\n"); ath_rx_send_to_mac80211(sc, skb, &rx_status); break; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index ddd3062186a7..36650505d2f1 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -815,6 +815,7 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc, struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info qi; int qnum; @@ -854,9 +855,9 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) return NULL; } if (qnum >= ARRAY_SIZE(sc->tx.txq)) { - DPRINTF(ah, ATH_DBG_FATAL, - "qnum %u out of range, max %u!\n", - qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq)); + ath_print(common, ATH_DBG_FATAL, + "qnum %u out of range, max %u!\n", + qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq)); ath9k_hw_releasetxqueue(ah, qnum); return NULL; } @@ -884,9 +885,9 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) switch (qtype) { case ATH9K_TX_QUEUE_DATA: if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "HAL AC %u out of range, max %zu!\n", - haltype, ARRAY_SIZE(sc->tx.hwq_map)); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + "HAL AC %u out of range, max %zu!\n", + haltype, ARRAY_SIZE(sc->tx.hwq_map)); return -1; } qnum = sc->tx.hwq_map[haltype]; @@ -914,9 +915,9 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) spin_lock_bh(&txq->axq_lock); if (txq->axq_depth >= (ATH_TXBUF - 20)) { - DPRINTF(sc->sc_ah, ATH_DBG_XMIT, - "TX queue: %d is full, depth: %d\n", - qnum, txq->axq_depth); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT, + "TX queue: %d is full, depth: %d\n", + qnum, txq->axq_depth); ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); txq->stopped = 1; spin_unlock_bh(&txq->axq_lock); @@ -955,8 +956,8 @@ int ath_txq_update(struct ath_softc *sc, int qnum, qi.tqi_readyTime = qinfo->tqi_readyTime; if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Unable to update hardware queue %u!\n", qnum); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + "Unable to update hardware queue %u!\n", qnum); error = -EIO; } else { ath9k_hw_resettxqueue(ah, qnum); @@ -1055,6 +1056,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_txq *txq; int i, npend = 0; @@ -1076,14 +1078,15 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) if (npend) { int r; - DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); + ath_print(common, ATH_DBG_XMIT, + "Unable to stop TxDMA. Reset HAL!\n"); spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); if (r) - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %d\n", - r); + ath_print(common, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %d\n", + r); spin_unlock_bh(&sc->sc_resetlock); } @@ -1147,8 +1150,8 @@ int ath_tx_setup(struct ath_softc *sc, int haltype) struct ath_txq *txq; if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "HAL AC %u out of range, max %zu!\n", + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + "HAL AC %u out of range, max %zu!\n", haltype, ARRAY_SIZE(sc->tx.hwq_map)); return 0; } @@ -1172,6 +1175,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, struct list_head *head) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf; /* @@ -1188,19 +1192,19 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, txq->axq_depth++; txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); - DPRINTF(sc->sc_ah, ATH_DBG_QUEUE, - "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); + ath_print(common, ATH_DBG_QUEUE, + "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); if (txq->axq_link == NULL) { ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); - DPRINTF(sc->sc_ah, ATH_DBG_XMIT, - "TXDP[%u] = %llx (%p)\n", - txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); + ath_print(common, ATH_DBG_XMIT, + "TXDP[%u] = %llx (%p)\n", + txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); } else { *txq->axq_link = bf->bf_daddr; - DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", - txq->axq_qnum, txq->axq_link, - ito64(bf->bf_daddr), bf->bf_desc); + ath_print(common, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", + txq->axq_qnum, txq->axq_link, + ito64(bf->bf_daddr), bf->bf_desc); } txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link); ath9k_hw_txstart(ah, txq->axq_qnum); @@ -1587,8 +1591,8 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_mpdu = NULL; kfree(tx_info_priv); tx_info->rate_driver_data[0] = NULL; - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "dma_mapping_error() on TX\n"); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + "dma_mapping_error() on TX\n"); return -ENOMEM; } @@ -1670,12 +1674,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_buf *bf; int r; bf = ath_tx_get_buffer(sc); if (!bf) { - DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "TX buffers are full\n"); + ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n"); return -1; } @@ -1683,7 +1688,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, if (unlikely(r)) { struct ath_txq *txq = txctl->txq; - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, "TX mem alloc failure\n"); + ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n"); /* upon ath_tx_processq() this TX queue will be resumed, we * guarantee this will happen by knowing beforehand that @@ -1713,6 +1718,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); int hdrlen, padsize; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_tx_control txctl; @@ -1737,8 +1743,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) if (hdrlen & 3) { padsize = hdrlen % 4; if (skb_headroom(skb) < padsize) { - DPRINTF(sc->sc_ah, ATH_DBG_XMIT, - "TX CABQ padding failed\n"); + ath_print(common, ATH_DBG_XMIT, + "TX CABQ padding failed\n"); dev_kfree_skb_any(skb); return; } @@ -1748,10 +1754,11 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) txctl.txq = sc->beacon.cabq; - DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); + ath_print(common, ATH_DBG_XMIT, + "transmitting CABQ packet, skb: %p\n", skb); if (ath_tx_start(hw, skb, &txctl) != 0) { - DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "CABQ TX failed\n"); + ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n"); goto exit; } @@ -1770,10 +1777,11 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); int hdrlen, padsize; int frame_type = ATH9K_NOT_INTERNAL; - DPRINTF(sc->sc_ah, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); + ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); if (tx_info_priv) { hw = tx_info_priv->aphy->hw; @@ -1807,8 +1815,9 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) { sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK; - DPRINTF(sc->sc_ah, ATH_DBG_PS, "Going back to sleep after having " - "received TX status (0x%x)\n", + ath_print(common, ATH_DBG_PS, + "Going back to sleep after having " + "received TX status (0x%x)\n", sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_PSPOLL_DATA | @@ -1938,15 +1947,16 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf, *lastbf, *bf_held = NULL; struct list_head bf_head; struct ath_desc *ds; int txok; int status; - DPRINTF(ah, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", - txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), - txq->axq_link); + ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", + txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), + txq->axq_link); for (;;) { spin_lock_bh(&txq->axq_lock); @@ -2066,7 +2076,8 @@ static void ath_tx_complete_poll_work(struct work_struct *work) } if (needreset) { - DPRINTF(sc->sc_ah, ATH_DBG_RESET, "tx hung, resetting the chip\n"); + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, + "tx hung, resetting the chip\n"); ath_reset(sc, false); } @@ -2095,6 +2106,7 @@ void ath_tx_tasklet(struct ath_softc *sc) int ath_tx_init(struct ath_softc *sc, int nbufs) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); int error = 0; spin_lock_init(&sc->tx.txbuflock); @@ -2102,16 +2114,16 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, "tx", nbufs, 1); if (error != 0) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Failed to allocate tx descriptors: %d\n", error); + ath_print(common, ATH_DBG_FATAL, + "Failed to allocate tx descriptors: %d\n", error); goto err; } error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, "beacon", ATH_BCBUF, 1); if (error != 0) { - DPRINTF(sc->sc_ah, ATH_DBG_FATAL, - "Failed to allocate beacon descriptors: %d\n", error); + ath_print(common, ATH_DBG_FATAL, + "Failed to allocate beacon descriptors: %d\n", error); goto err; } diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c new file mode 100644 index 000000000000..53e77bd131b9 --- /dev/null +++ b/drivers/net/wireless/ath/debug.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 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. + */ + +#include "ath.h" +#include "debug.h" + +void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) +{ + va_list args; + + if (likely(!(common->debug_mask & dbg_mask))) + return; + + va_start(args, fmt); + printk(KERN_DEBUG "ath: "); + vprintk(fmt, args); + va_end(args); +} +EXPORT_SYMBOL(ath_print); diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h new file mode 100644 index 000000000000..d6b685a06c5e --- /dev/null +++ b/drivers/net/wireless/ath/debug.h @@ -0,0 +1,77 @@ +/* + * 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_DEBUG_H +#define ATH_DEBUG_H + +#include "ath.h" + +/** + * enum ath_debug_level - atheros wireless debug level + * + * @ATH_DBG_RESET: reset processing + * @ATH_DBG_QUEUE: hardware queue management + * @ATH_DBG_EEPROM: eeprom processing + * @ATH_DBG_CALIBRATE: periodic calibration + * @ATH_DBG_INTERRUPT: interrupt processing + * @ATH_DBG_REGULATORY: regulatory processing + * @ATH_DBG_ANI: adaptive noise immunitive processing + * @ATH_DBG_XMIT: basic xmit operation + * @ATH_DBG_BEACON: beacon handling + * @ATH_DBG_CONFIG: configuration of the hardware + * @ATH_DBG_FATAL: fatal errors, this is the default, DBG_DEFAULT + * @ATH_DBG_PS: power save processing + * @ATH_DBG_HWTIMER: hardware timer handling + * @ATH_DBG_BTCOEX: bluetooth coexistance + * @ATH_DBG_ANY: enable all debugging + * + * The debug level is used to control the amount and type of debugging output + * we want to see. Each driver has its own method for enabling debugging and + * modifying debug level states -- but this is typically done through a + * module parameter 'debug' along with a respective 'debug' debugfs file + * entry. + */ +enum ATH_DEBUG { + ATH_DBG_RESET = 0x00000001, + ATH_DBG_QUEUE = 0x00000002, + ATH_DBG_EEPROM = 0x00000004, + ATH_DBG_CALIBRATE = 0x00000008, + ATH_DBG_INTERRUPT = 0x00000010, + ATH_DBG_REGULATORY = 0x00000020, + ATH_DBG_ANI = 0x00000040, + ATH_DBG_XMIT = 0x00000080, + ATH_DBG_BEACON = 0x00000100, + ATH_DBG_CONFIG = 0x00000200, + ATH_DBG_FATAL = 0x00000400, + ATH_DBG_PS = 0x00000800, + ATH_DBG_HWTIMER = 0x00001000, + ATH_DBG_BTCOEX = 0x00002000, + ATH_DBG_ANY = 0xffffffff +}; + +#define ATH_DBG_DEFAULT (ATH_DBG_FATAL) + +#ifdef CONFIG_ATH_DEBUG +void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...); +#else +static inline void ath_print(struct ath_common *common, + int dbg_mask, + const char *fmt, ...) +{ +} +#endif /* CONFIG_ATH_DEBUG */ + +#endif /* ATH_DEBUG_H */ -- cgit v1.2.3 From 43c2761364b77cd7fd20eb1f14cfee4cd1462abd Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 13 Sep 2009 21:07:07 -0700 Subject: atheros: move tx/rx chainmask to ath_common Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 3 +++ drivers/net/wireless/ath/ath9k/ath9k.h | 2 -- drivers/net/wireless/ath/ath9k/beacon.c | 3 ++- drivers/net/wireless/ath/ath9k/hw.c | 4 ++-- drivers/net/wireless/ath/ath9k/main.c | 34 ++++++++++++++++++++------------- drivers/net/wireless/ath/ath9k/xmit.c | 3 ++- 6 files changed, 30 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 2ca9701181ee..38ca68ee09c0 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -56,6 +56,9 @@ struct ath_common { u8 curbssid[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; + u8 tx_chainmask; + u8 rx_chainmask; + struct ath_regulatory regulatory; const struct ath_ops *ops; }; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9864461ecb53..46d19e863d3f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -586,8 +586,6 @@ struct ath_softc { u16 curtxpow; u8 nbcnvifs; u16 nvifs; - u8 tx_chainmask; - u8 rx_chainmask; u32 keymax; DECLARE_BITMAP(keymap, ATH_KEYMAX); u8 splitmic; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 2f003132463b..54be876639a0 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -62,6 +62,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, { struct sk_buff *skb = bf->bf_mpdu; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_desc *ds; struct ath9k_11n_rate_series series[4]; const struct ath_rate_table *rt; @@ -109,7 +110,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); series[0].Tries = 1; series[0].Rate = rate; - series[0].ChSel = sc->tx_chainmask; + series[0].ChSel = common->tx_chainmask; series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration, series, 4, 0); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8ecd1b0bdf8f..edf91d0fbb1a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2334,8 +2334,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, int i, rx_chainmask, r; ah->extprotspacing = sc->ht_extprotspacing; - ah->txchainmask = sc->tx_chainmask; - ah->rxchainmask = sc->rx_chainmask; + ah->txchainmask = common->tx_chainmask; + ah->rxchainmask = common->rx_chainmask; if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index f409bbc30535..7906b796dea9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -438,8 +438,11 @@ static void ath_ani_calibrate(unsigned long data) /* Perform calibration if necessary */ if (longcal || shortcal) { - sc->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan, - sc->rx_chainmask, longcal); + sc->ani.caldone = + ath9k_hw_calibrate(ah, + ah->curchan, + common->rx_chainmask, + longcal); if (longcal) sc->ani.noise_floor = ath9k_hw_getchan_noise(ah, @@ -492,19 +495,21 @@ static void ath_start_ani(struct ath_softc *sc) void ath_update_chainmask(struct ath_softc *sc, int is_ht) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); if ((sc->sc_flags & SC_OP_SCANNING) || is_ht || (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE)) { - sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask; - sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask; + common->tx_chainmask = ah->caps.tx_chainmask; + common->rx_chainmask = ah->caps.rx_chainmask; } else { - sc->tx_chainmask = 1; - sc->rx_chainmask = 1; + common->tx_chainmask = 1; + common->rx_chainmask = 1; } - ath_print(ath9k_hw_common(ah), ATH_DBG_CONFIG, + ath_print(common, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", - sc->tx_chainmask, sc->rx_chainmask); + common->tx_chainmask, + common->rx_chainmask); } static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) @@ -949,6 +954,7 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) static void setup_ht_cap(struct ath_softc *sc, struct ieee80211_sta_ht_cap *ht_info) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); u8 tx_streams, rx_streams; ht_info->ht_supported = true; @@ -962,11 +968,13 @@ static void setup_ht_cap(struct ath_softc *sc, /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - tx_streams = !(sc->tx_chainmask & (sc->tx_chainmask - 1)) ? 1 : 2; - rx_streams = !(sc->rx_chainmask & (sc->rx_chainmask - 1)) ? 1 : 2; + tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ? + 1 : 2; + rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ? + 1 : 2; if (tx_streams != rx_streams) { - ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, + ath_print(common, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", tx_streams, rx_streams); ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; @@ -1759,8 +1767,8 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) sc->sc_flags |= SC_OP_RXAGGR; } - sc->tx_chainmask = ah->caps.tx_chainmask; - sc->rx_chainmask = ah->caps.rx_chainmask; + common->tx_chainmask = ah->caps.tx_chainmask; + common->rx_chainmask = ah->caps.rx_chainmask; ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); sc->rx.defant = ath9k_hw_getdefantenna(ah); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 36650505d2f1..f302652af396 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1456,6 +1456,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); const struct ath_rate_table *rt = sc->cur_rate_table; struct ath9k_11n_rate_series series[4]; struct sk_buff *skb; @@ -1511,7 +1512,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) rix = rates[i].idx; series[i].Tries = rates[i].count; - series[i].ChSel = sc->tx_chainmask; + series[i].ChSel = common->tx_chainmask; if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) series[i].Rate = rt->info[rix].ratecode | -- cgit v1.2.3 From 6420014ca4a6b0e853c9a19a8649d93682a5bdac Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 13 Sep 2009 22:05:04 -0700 Subject: ath9k: remove ath9k 25 MHz HT40 spacing stuff This was for supporting 25 MHz spacing for HT40, this is not used as we use 20 MHz spacing instead for HT40 as per 802.11n. The hardware is capable of it though so we leave the phymode definition and EEPROM parsing for it. If some experimenter wants to work on this stuff stuff you can add an extension enabling bool on ath_common and perhaps some debugfs knob to enable it. Keep in mind you'll also need to update the phymode with the AR_PHY_FC_DYN2040_EXT_CH which has been left on the driver. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/hw.c | 8 ++------ drivers/net/wireless/ath/ath9k/hw.h | 1 - drivers/net/wireless/ath/ath9k/mac.h | 5 ----- drivers/net/wireless/ath/ath9k/phy.h | 1 + 5 files changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 46d19e863d3f..e93ab631a091 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -592,7 +592,6 @@ struct ath_softc { bool ps_enabled; unsigned long ps_usecount; enum ath9k_int imask; - enum ath9k_ht_extprotspacing ht_extprotspacing; enum ath9k_ht_macmode tx_chan_width; struct ath_config config; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index edf91d0fbb1a..6d2ac33a2764 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -213,10 +213,9 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah, centers->ctl_center = centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT); + /* 25 MHz spacing is supported by hw but not on upper layers */ centers->ext_center = - centers->synth_center + (extoff * - ((ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ? - HT40_CHANNEL_CENTER_SHIFT : 15)); + centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT); } /******************/ @@ -1759,8 +1758,6 @@ static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan, (chan->chanmode == CHANNEL_G_HT40PLUS)) phymode |= AR_PHY_FC_DYN2040_PRI_CH; - if (ah->extprotspacing == ATH9K_HT_EXTPROTSPACING_25) - phymode |= AR_PHY_FC_DYN2040_EXT_CH; } REG_WRITE(ah, AR_PHY_TURBO, phymode); @@ -2333,7 +2330,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u64 tsf = 0; int i, rx_chainmask, r; - ah->extprotspacing = sc->ht_extprotspacing; ah->txchainmask = common->tx_chainmask; ah->rxchainmask = common->rx_chainmask; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 1c73f81a5957..53ffe2a9e225 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -563,7 +563,6 @@ struct ath_hw { struct ath_btcoex_hw btcoex_hw; u32 intr_txqs; - enum ath9k_ht_extprotspacing extprotspacing; u8 txchainmask; u8 rxchainmask; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index f56e77da6c3e..767256dccb46 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -619,11 +619,6 @@ enum ath9k_ht_macmode { ATH9K_HT_MACMODE_2040 = 1, }; -enum ath9k_ht_extprotspacing { - ATH9K_HT_EXTPROTSPACING_20 = 0, - ATH9K_HT_EXTPROTSPACING_25 = 1, -}; - struct ath_hw; struct ath9k_channel; struct ath_rate_table; diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index dfda6f444648..140fef74c666 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -45,6 +45,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_FC_DYN2040_EN 0x00000004 #define AR_PHY_FC_DYN2040_PRI_ONLY 0x00000008 #define AR_PHY_FC_DYN2040_PRI_CH 0x00000010 +/* For 25 MHz channel spacing -- not used but supported by hw */ #define AR_PHY_FC_DYN2040_EXT_CH 0x00000020 #define AR_PHY_FC_HT_EN 0x00000040 #define AR_PHY_FC_SHORT_GI_40 0x00000080 -- cgit v1.2.3 From 25c56eec92b15fdec5be96fa1303dac3443200ae Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 13 Sep 2009 23:04:44 -0700 Subject: ath9k: remove ath9k_ht_macmode This is used just to determine how to program the MAC, either for 20 MHz operation of 40 MHz so just use conf_is_ht40() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/hw.c | 29 ++++++++++++----------------- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/mac.h | 5 ----- drivers/net/wireless/ath/ath9k/main.c | 13 ++++--------- 5 files changed, 17 insertions(+), 33 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e93ab631a091..73c2ac55937b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -592,7 +592,6 @@ struct ath_softc { bool ps_enabled; unsigned long ps_usecount; enum ath9k_int imask; - enum ath9k_ht_macmode tx_chan_width; struct ath_config config; struct ath_rx rx; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6d2ac33a2764..9d03d27a7dcb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -26,8 +26,7 @@ #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); -static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode); +static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan); static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, struct ar5416_eeprom_def *pEepData, u32 reg, u32 value); @@ -1352,8 +1351,7 @@ static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, } static int ath9k_hw_process_ini(struct ath_hw *ah, - struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) + struct ath9k_channel *chan) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); int i, regWrites = 0; @@ -1455,7 +1453,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, } ath9k_hw_override_ini(ah, chan); - ath9k_hw_set_regs(ah, chan, macmode); + ath9k_hw_set_regs(ah, chan); ath9k_hw_init_chain_masks(ah); if (OLC_FOR_AR9280_20_LATER) @@ -1738,8 +1736,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) } } -static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) +static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan) { u32 phymode; u32 enableDacFifo = 0; @@ -1761,7 +1758,7 @@ static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan, } REG_WRITE(ah, AR_PHY_TURBO, phymode); - ath9k_hw_set11nmac2040(ah, macmode); + ath9k_hw_set11nmac2040(ah); REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); @@ -1787,8 +1784,7 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah, } static bool ath9k_hw_channel_change(struct ath_hw *ah, - struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) + struct ath9k_channel *chan) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); @@ -1812,7 +1808,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, return false; } - ath9k_hw_set_regs(ah, chan, macmode); + ath9k_hw_set_regs(ah, chan); if (AR_SREV_9280_10_OR_LATER(ah)) { ath9k_hw_ar9280_set_channel(ah, chan); @@ -2323,7 +2319,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, { struct ath_common *common = ath9k_hw_common(ah); u32 saveLedState; - struct ath_softc *sc = ah->ah_sc; struct ath9k_channel *curchan = ah->curchan; u32 saveDefAntenna; u32 macStaId1; @@ -2348,7 +2343,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, !(AR_SREV_9280(ah) || IS_CHAN_A_5MHZ_SPACED(chan) || IS_CHAN_A_5MHZ_SPACED(ah->curchan))) { - if (ath9k_hw_channel_change(ah, chan, sc->tx_chan_width)) { + if (ath9k_hw_channel_change(ah, chan)) { ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_start_nfcal(ah); return 0; @@ -2408,7 +2403,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET); } - r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width); + r = ath9k_hw_process_ini(ah, chan); if (r) return r; @@ -4063,12 +4058,12 @@ bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) } } -void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode) +void ath9k_hw_set11nmac2040(struct ath_hw *ah) { + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; u32 macmode; - if (mode == ATH9K_HT_MACMODE_2040 && - !ah->config.cwm_ignore_extcca) + if (conf_is_ht40(conf) && !ah->config.cwm_ignore_extcca) macmode = AR_2040_JOINED_RX_CLEAR; else macmode = 0; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 53ffe2a9e225..92770cbc7444 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -662,7 +662,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); -void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode); +void ath9k_hw_set11nmac2040(struct ath_hw *ah); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, const struct ath9k_beacon_state *bs); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 767256dccb46..9ab343151be4 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -614,11 +614,6 @@ enum ath9k_cipher { ATH9K_CIPHER_MIC = 127 }; -enum ath9k_ht_macmode { - ATH9K_HT_MACMODE_20 = 0, - ATH9K_HT_MACMODE_2040 = 1, -}; - struct ath_hw; struct ath9k_channel; struct ath_rate_table; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7906b796dea9..e9aac3cbd4de 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -299,6 +299,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &common->hw->conf; bool fastcc = true, stopped; struct ieee80211_channel *channel = hw->conf.channel; int r; @@ -329,9 +330,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, fastcc = false; ath_print(common, ATH_DBG_CONFIG, - "(%u MHz) -> (%u MHz), chanwidth: %d\n", + "(%u MHz) -> (%u MHz), conf_is_ht40: %d\n", sc->sc_ah->curchan->channel, - channel->center_freq, sc->tx_chan_width); + channel->center_freq, conf_is_ht40(conf)); spin_lock_bh(&sc->sc_resetlock); @@ -2191,15 +2192,9 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; } - sc->tx_chan_width = ATH9K_HT_MACMODE_20; - - if (conf_is_ht(conf)) { - if (conf_is_ht40(conf)) - sc->tx_chan_width = ATH9K_HT_MACMODE_2040; - + if (conf_is_ht(conf)) ichan->chanmode = ath_get_extchanmode(sc, chan, conf->channel_type); - } } /**********************/ -- cgit v1.2.3 From e3d01bfc3ea4f17c9e91bb930f10062efb0c86eb Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 13 Sep 2009 23:11:13 -0700 Subject: ath9k: move ATH_AMPDU_LIMIT_MAX to hw.h This is used by hw code. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/hw.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 73c2ac55937b..f3b5a609554e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -189,7 +189,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, /* minimum h/w qdepth to be sustained to maximize aggregation */ #define ATH_AGGR_MIN_QDEPTH 2 #define ATH_AMPDU_SUBFRAME_DEFAULT 32 -#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_MAX 4096 diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 92770cbc7444..35a3224b56fe 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -51,6 +51,8 @@ #define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa #define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab +#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) + /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) \ ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) -- cgit v1.2.3 From 9680e8a391078a2bfa099b2c59542a6916a023ed Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 13 Sep 2009 23:28:00 -0700 Subject: ath9k: remove driver ASSERT, just use BUG_ON() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 -- drivers/net/wireless/ath/ath9k/hw.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- drivers/net/wireless/ath/ath9k/rc.c | 8 ++++---- drivers/net/wireless/ath/ath9k/recv.c | 2 +- drivers/net/wireless/ath/ath9k/xmit.c | 12 ++++++------ 6 files changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index f3b5a609554e..e512d519c596 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -54,8 +54,6 @@ struct ath_node; #define A_MAX(a, b) ((a) > (b) ? (a) : (b)) -#define ASSERT(exp) BUG_ON(!(exp)) - #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9d03d27a7dcb..93da19cbff10 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3814,7 +3814,7 @@ void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio) { u32 gpio_shift; - ASSERT(gpio < ah->caps.num_gpio_pins); + BUG_ON(gpio >= ah->caps.num_gpio_pins); gpio_shift = gpio << 1; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e9aac3cbd4de..0d8977341b2c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2030,7 +2030,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, if ((sizeof(struct ath_desc) % 4) != 0) { ath_print(common, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); - ASSERT((sizeof(struct ath_desc) % 4) == 0); + BUG_ON((sizeof(struct ath_desc) % 4) != 0); error = -ENOMEM; goto fail; } @@ -2088,7 +2088,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, * descriptor fetch. */ while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { - ASSERT((caddr_t) bf->bf_desc < + BUG_ON((caddr_t) bf->bf_desc >= ((caddr_t) dd->dd_desc + dd->dd_desc_len)); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 7346649af2d7..063936423d86 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -425,7 +425,7 @@ static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv) static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv, u8 index, int valid_tx_rate) { - ASSERT(index <= ath_rc_priv->rate_table_size); + BUG_ON(index > ath_rc_priv->rate_table_size); ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0; } @@ -1243,7 +1243,7 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->rate_table_size = hi + 1; ath_rc_priv->rate_max_phy = 0; - ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); + BUG_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE); for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) { for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) { @@ -1257,8 +1257,8 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1]; } - ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); - ASSERT(k <= RATE_TABLE_SIZE); + BUG_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE); + BUG_ON(k > RATE_TABLE_SIZE); ath_rc_priv->max_valid_rate = k; ath_rc_sort_validrates(rate_table, ath_rc_priv); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6caef1b5dfe2..3a2204d84702 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -59,7 +59,7 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) /* virtual addr of the beginning of the buffer. */ skb = bf->bf_mpdu; - ASSERT(skb != NULL); + BUG_ON(skb == NULL); ds->ds_vdata = skb->data; /* setup rx descriptors. The rx.bufsize here tells the harware diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f302652af396..a8620b1d091b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -107,7 +107,7 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; - ASSERT(tid->paused > 0); + BUG_ON(tid->paused <= 0); spin_lock_bh(&txq->axq_lock); tid->paused--; @@ -131,7 +131,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) struct list_head bf_head; INIT_LIST_HEAD(&bf_head); - ASSERT(tid->paused > 0); + BUG_ON(tid->paused <= 0); spin_lock_bh(&txq->axq_lock); tid->paused--; @@ -143,7 +143,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) while (!list_empty(&tid->buf_q)) { bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - ASSERT(!bf_isretried(bf)); + BUG_ON(bf_isretried(bf)); list_move_tail(&bf->list, &bf_head); ath_tx_send_ht_normal(sc, txq, tid, &bf_head); } @@ -178,7 +178,7 @@ static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno); cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - ASSERT(tid->tx_buf[cindex] == NULL); + BUG_ON(tid->tx_buf[cindex] != NULL); tid->tx_buf[cindex] = bf; if (index >= ((tid->baw_tail - tid->baw_head) & @@ -358,7 +358,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, else INIT_LIST_HEAD(&bf_head); } else { - ASSERT(!list_empty(bf_q)); + BUG_ON(list_empty(bf_q)); list_move_tail(&bf->list, &bf_head); } @@ -946,7 +946,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, return 0; } - ASSERT(sc->tx.txq[qnum].axq_qnum == qnum); + BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum); ath9k_hw_get_txq_props(ah, qnum, &qi); qi.tqi_aifs = qinfo->tqi_aifs; -- cgit v1.2.3 From cfe8cba982cda73d4970dab712411bebdcc3b9cd Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 13 Sep 2009 23:39:31 -0700 Subject: ath9k: clarify what hw code is and remove ath9k.h from a few files hw code will be shared between ath9k and ath9k_htc. Just a few more files are left to clean up, mark them as well. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Makefile | 14 +++++++++----- drivers/net/wireless/ath/ath9k/ani.c | 2 +- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/btcoex.c | 2 +- drivers/net/wireless/ath/ath9k/calib.c | 1 - drivers/net/wireless/ath/ath9k/eeprom_4k.c | 1 - drivers/net/wireless/ath/ath9k/eeprom_9287.c | 1 - drivers/net/wireless/ath/ath9k/eeprom_def.c | 1 - drivers/net/wireless/ath/ath9k/hw.c | 2 +- drivers/net/wireless/ath/ath9k/hw.h | 2 ++ drivers/net/wireless/ath/ath9k/mac.c | 1 - drivers/net/wireless/ath/ath9k/phy.c | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index ff2c9a26c10c..f85dc8235774 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -1,19 +1,23 @@ -ath9k-y += hw.o \ - eeprom.o \ +ATH9K_HW_FIX += eeprom.o \ + mac.o \ + +ATH9K_HW += hw.o \ eeprom_def.o \ eeprom_4k.o \ eeprom_9287.o \ - mac.o \ calib.o \ ani.o \ phy.o \ + btcoex.o + +ath9k-y += $(ATH9K_HW) \ + $(ATH9K_HW_FIX) \ beacon.o \ main.o \ recv.o \ xmit.o \ virtual.o \ - rc.o \ - btcoex.o + rc.o ath9k-$(CONFIG_PCI) += pci.o ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index bb0a6d985270..ecb23f302c3d 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "ath9k.h" +#include "hw.h" static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, struct ath9k_channel *chan) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e512d519c596..9aff11da3796 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -499,7 +499,6 @@ struct ath_led { * Used when PCI device not fully initialized by bootrom/BIOS */ #define DEFAULT_CACHELINE 32 -#define ATH_DEFAULT_NOISE_FLOOR -95 #define ATH_REGCLASSIDS_MAX 10 #define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ #define ATH_MAX_SW_RETRIES 10 diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 5d1095f18d77..0c54489ca443 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "ath9k.h" +#include "hw.h" enum ath_bt_mode { ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */ diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 2a2212465ea3..36c5f89e2fc7 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -14,7 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "ath9k.h" #include "hw.h" /* We can tune this as we go by monitoring really low values */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 079dd201a2d8..c2ac85c2aab7 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -14,7 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "ath9k.h" #include "hw.h" static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 6ffe85de75c1..839eed89179d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -14,7 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "ath9k.h" #include "hw.h" static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index b0687e5bdc1d..56e90baf6949 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -14,7 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "ath9k.h" #include "hw.h" static void ath9k_get_txgain_index(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 93da19cbff10..b120c2127e9a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -18,7 +18,7 @@ #include #include "hw.h" -#include "ath9k.h" +#include "rc.h" #include "initvals.h" #define ATH9K_CLOCK_RATE_CCK 22 diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 35a3224b56fe..874fb11cbac2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -53,6 +53,8 @@ #define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) +#define ATH_DEFAULT_NOISE_FLOOR -95 + /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) \ ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 926f201ce4fa..1796ac773f91 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -15,7 +15,6 @@ */ #include "ath9k.h" -#include "hw.h" static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, struct ath9k_tx_queue_info *qi) diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index b26302599765..eec4f1064a68 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "ath9k.h" +#include "hw.h" void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, -- cgit v1.2.3 From 990b70ab24cbce585a3436c8c88cb48b888d48b4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sun, 13 Sep 2009 23:55:05 -0700 Subject: ath9k: move ATH9K_RSSI_BAD to hw.h mac.c is now core driver independent. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Makefile | 7 +++---- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/hw.h | 2 ++ drivers/net/wireless/ath/ath9k/mac.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index f85dc8235774..2f21c67d86c8 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -1,6 +1,4 @@ -ATH9K_HW_FIX += eeprom.o \ - mac.o \ - +ATH9K_HW_FIX += eeprom.o ATH9K_HW += hw.o \ eeprom_def.o \ eeprom_4k.o \ @@ -8,7 +6,8 @@ ATH9K_HW += hw.o \ calib.o \ ani.o \ phy.o \ - btcoex.o + btcoex.o \ + mac.o \ ath9k-y += $(ATH9K_HW) \ $(ATH9K_HW_FIX) \ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9aff11da3796..8768e603eb72 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -288,7 +288,6 @@ struct ath_tx_control { #define ATH_RSSI_LPF_LEN 10 #define RSSI_LPF_THRESHOLD -20 -#define ATH9K_RSSI_BAD 0x80 #define ATH_RSSI_EP_MULTIPLIER (1<<7) #define ATH_EP_MUL(x, mul) ((x) * (mul)) #define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER)) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 874fb11cbac2..d854c17b8688 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -55,6 +55,8 @@ #define ATH_DEFAULT_NOISE_FLOOR -95 +#define ATH9K_RSSI_BAD 0x80 + /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) \ ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 1796ac773f91..3be658d42a53 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "ath9k.h" +#include "hw.h" static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, struct ath9k_tx_queue_info *qi) -- cgit v1.2.3 From 5bb127913299b37fceecf66ce86ee8ede70e7d13 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 14 Sep 2009 00:55:09 -0700 Subject: atheros: move bus ops to ath_common This is the last part to make ath9k hw code core driver agnostic. I believe ath9k_htc can now use use the hw code unmodified. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 10 ++++++++++ drivers/net/wireless/ath/ath9k/Makefile | 3 +-- drivers/net/wireless/ath/ath9k/ahb.c | 14 ++++++++------ drivers/net/wireless/ath/ath9k/ath9k.h | 19 ++++++------------- drivers/net/wireless/ath/ath9k/eeprom.c | 8 +++----- drivers/net/wireless/ath/ath9k/eeprom.h | 3 ++- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 4 ++-- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 7 ++++--- drivers/net/wireless/ath/ath9k/eeprom_def.c | 5 +++-- drivers/net/wireless/ath/ath9k/main.c | 20 +++++++++++++------- drivers/net/wireless/ath/ath9k/pci.c | 21 ++++++++++++++------- 11 files changed, 66 insertions(+), 48 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 38ca68ee09c0..e0341fefc921 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -45,6 +45,15 @@ struct ath_ops { void (*write)(void *, u32 val, u32 reg_offset); }; +struct ath_common; + +struct ath_bus_ops { + void (*read_cachesize)(struct ath_common *common, int *csz); + void (*cleanup)(struct ath_common *common); + bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); + void (*bt_coex_prep)(struct ath_common *common); +}; + struct ath_common { void *ah; struct ieee80211_hw *hw; @@ -61,6 +70,7 @@ struct ath_common { struct ath_regulatory regulatory; const struct ath_ops *ops; + const struct ath_bus_ops *bus_ops; }; struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 2f21c67d86c8..f3221af73eb7 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -1,5 +1,5 @@ -ATH9K_HW_FIX += eeprom.o ATH9K_HW += hw.o \ + eeprom.o \ eeprom_def.o \ eeprom_4k.o \ eeprom_9287.o \ @@ -10,7 +10,6 @@ ATH9K_HW += hw.o \ mac.o \ ath9k-y += $(ATH9K_HW) \ - $(ATH9K_HW_FIX) \ beacon.o \ main.o \ recv.o \ diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 095973e8b232..33c9e8167185 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -22,25 +22,28 @@ #include "ath9k.h" /* return bus cachesize in 4B word units */ -static void ath_ahb_read_cachesize(struct ath_softc *sc, int *csz) +static void ath_ahb_read_cachesize(struct ath_common *common, int *csz) { *csz = L1_CACHE_BYTES >> 2; } -static void ath_ahb_cleanup(struct ath_softc *sc) +static void ath_ahb_cleanup(struct ath_common *common) { + struct ath_hw *ah = (struct ath_hw *) common->ah; + struct ath_softc *sc = ah->ah_sc; iounmap(sc->mem); } -static bool ath_ahb_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) +static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) { + struct ath_hw *ah = (struct ath_hw *) common->ah; struct ath_softc *sc = ah->ah_sc; struct platform_device *pdev = to_platform_device(sc->dev); struct ath9k_platform_data *pdata; pdata = (struct ath9k_platform_data *) pdev->dev.platform_data; if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { - ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + ath_print(common, ATH_DBG_FATAL, "%s: flash read failed, offset %08x " "is out of range\n", __func__, off); @@ -117,10 +120,9 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->hw = hw; sc->dev = &pdev->dev; sc->mem = mem; - sc->bus_ops = &ath_ahb_bus_ops; sc->irq = irq; - ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0); + ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto err_free_hw; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8768e603eb72..14ff38d1f67c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -537,13 +537,6 @@ struct ath_led { #define SC_OP_BEACON_SYNC BIT(19) #define SC_OP_BT_PRIORITY_DETECTED BIT(21) -struct ath_bus_ops { - void (*read_cachesize)(struct ath_softc *sc, int *csz); - void (*cleanup)(struct ath_softc *sc); - bool (*eeprom_read)(struct ath_hw *ah, u32 off, u16 *data); - void (*bt_coex_prep)(struct ath_softc *sc); -}; - struct ath_wiphy; struct ath_softc { @@ -613,7 +606,6 @@ struct ath_softc { #ifdef CONFIG_ATH9K_DEBUG struct ath9k_debug debug; #endif - struct ath_bus_ops *bus_ops; struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; struct ath_btcoex btcoex; @@ -638,21 +630,22 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); int ath_cabq_update(struct ath_softc *); -static inline void ath_read_cachesize(struct ath_softc *sc, int *csz) +static inline void ath_read_cachesize(struct ath_common *common, int *csz) { - sc->bus_ops->read_cachesize(sc, csz); + common->bus_ops->read_cachesize(common, csz); } -static inline void ath_bus_cleanup(struct ath_softc *sc) +static inline void ath_bus_cleanup(struct ath_common *common) { - sc->bus_ops->cleanup(sc); + common->bus_ops->cleanup(common); } extern struct ieee80211_ops ath9k_ops; irqreturn_t ath_isr(int irq, void *dev); void ath_cleanup(struct ath_softc *sc); -int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid); +int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, + const struct ath_bus_ops *bus_ops); void ath_detach(struct ath_softc *sc); const char *ath_mac_bb_name(u32 mac_bb_version); const char *ath_rf_name(u16 rf_version); diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index b6e52d0f8c48..dacaae934148 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "ath9k.h" +#include "hw.h" static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) { @@ -83,11 +83,9 @@ bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, return false; } -bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) +bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_softc *sc = ah->ah_sc; - - return sc->bus_ops->eeprom_read(ah, off, data); + return common->bus_ops->eeprom_read(common, off, data); } void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 4fe33f7eee9d..8463ba09c12c 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -17,6 +17,7 @@ #ifndef EEPROM_H #define EEPROM_H +#include "../ath.h" #include #define AH_USE_EEPROM 0x1 @@ -684,7 +685,7 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, int16_t targetRight); bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, u16 *indexL, u16 *indexR); -bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data); +bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data); void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, u8 *pVpdList, u16 numIntercepts, u8 *pRetVpdList); diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index c2ac85c2aab7..2a27b1d51a1b 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -41,7 +41,7 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) } for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { - if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { ath_print(common, ATH_DBG_EEPROM, "Unable to read eeprom region \n"); return false; @@ -66,7 +66,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, + if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { ath_print(common, ATH_DBG_FATAL, "Reading Magic # failed\n"); diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 839eed89179d..839d05a1df29 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -41,7 +41,8 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16); addr++) { - if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + if (!ath9k_hw_nvram_read(common, + addr + eep_start_loc, eep_data)) { ath_print(common, ATH_DBG_EEPROM, "Unable to read eeprom region \n"); return false; @@ -61,8 +62,8 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read - (ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + if (!ath9k_hw_nvram_read(common, + AR5416_EEPROM_MAGIC_OFFSET, &magic)) { ath_print(common, ATH_DBG_FATAL, "Reading Magic # failed\n"); return false; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 56e90baf6949..8f04b644e2e6 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -89,11 +89,12 @@ static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) { #define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) + struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data = (u16 *)&ah->eeprom.def; int addr, ar5416_eep_start_loc = 0x100; for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { - if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, + if (!ath9k_hw_nvram_read(common, addr + ar5416_eep_start_loc, eep_data)) { ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, "Unable to read eeprom region\n"); @@ -115,7 +116,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) bool need_swap = false; int i, addr, size; - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { ath_print(common, ATH_DBG_FATAL, "Reading Magic # failed\n"); return false; } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0d8977341b2c..ab9b7eaecd81 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1311,9 +1311,12 @@ static void ath_start_rfkill_poll(struct ath_softc *sc) void ath_cleanup(struct ath_softc *sc) { + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + ath_detach(sc); free_irq(sc->irq, sc); - ath_bus_cleanup(sc); + ath_bus_cleanup(common); kfree(sc->sec_wiphy); ieee80211_free_hw(sc->hw); } @@ -1587,7 +1590,8 @@ static struct ath_ops ath9k_common_ops = { * to allow the separation between hardware specific * variables (now in ath_hw) and driver specific variables. */ -static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) +static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, + const struct ath_bus_ops *bus_ops) { struct ath_hw *ah = NULL; struct ath_common *common; @@ -1621,6 +1625,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) common = ath9k_hw_common(ah); common->ops = &ath9k_common_ops; + common->bus_ops = bus_ops; common->ah = ah; common->hw = sc->hw; @@ -1628,7 +1633,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) * Cache line size is used to size and align various * structures used to communicate with the hardware. */ - ath_read_cachesize(sc, &csz); + ath_read_cachesize(common, &csz); /* XXX assert csz is non-zero */ common->cachelsz = csz << 2; /* convert to bytes */ @@ -1876,7 +1881,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) } /* Device driver core initialization */ -int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid) +int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, + const struct ath_bus_ops *bus_ops) { struct ieee80211_hw *hw = sc->hw; struct ath_common *common; @@ -1886,7 +1892,7 @@ int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid) dev_dbg(sc->dev, "Attach ATH hw\n"); - error = ath_init_softc(devid, sc, subsysid); + error = ath_init_softc(devid, sc, subsysid, bus_ops); if (error != 0) return error; @@ -2337,8 +2343,8 @@ static int ath9k_start(struct ieee80211_hw *hw) AR_STOMP_LOW_WLAN_WGHT); ath9k_hw_btcoex_enable(ah); - if (sc->bus_ops->bt_coex_prep) - sc->bus_ops->bt_coex_prep(sc); + if (common->bus_ops->bt_coex_prep) + common->bus_ops->bt_coex_prep(common); if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath9k_btcoex_timer_resume(sc); } diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index f59d22491ced..a1001ffdd389 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -31,8 +31,10 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { }; /* return bus cachesize in 4B word units */ -static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz) +static void ath_pci_read_cachesize(struct ath_common *common, int *csz) { + struct ath_hw *ah = (struct ath_hw *) common->ah; + struct ath_softc *sc = ah->ah_sc; u8 u8tmp; pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp); @@ -48,8 +50,10 @@ static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz) *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ } -static void ath_pci_cleanup(struct ath_softc *sc) +static void ath_pci_cleanup(struct ath_common *common) { + struct ath_hw *ah = (struct ath_hw *) common->ah; + struct ath_softc *sc = ah->ah_sc; struct pci_dev *pdev = to_pci_dev(sc->dev); pci_iounmap(pdev, sc->mem); @@ -57,8 +61,10 @@ static void ath_pci_cleanup(struct ath_softc *sc) pci_release_region(pdev, 0); } -static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) +static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) { + struct ath_hw *ah = (struct ath_hw *) common->ah; + (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); if (!ath9k_hw_wait(ah, @@ -78,8 +84,10 @@ static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) /* * Bluetooth coexistance requires disabling ASPM. */ -static void ath_pci_bt_coex_prep(struct ath_softc *sc) +static void ath_pci_bt_coex_prep(struct ath_common *common) { + struct ath_hw *ah = (struct ath_hw *) common->ah; + struct ath_softc *sc = ah->ah_sc; struct pci_dev *pdev = to_pci_dev(sc->dev); u8 aspm; @@ -91,7 +99,7 @@ static void ath_pci_bt_coex_prep(struct ath_softc *sc) pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); } -static struct ath_bus_ops ath_pci_bus_ops = { +const static struct ath_bus_ops ath_pci_bus_ops = { .read_cachesize = ath_pci_read_cachesize, .cleanup = ath_pci_cleanup, .eeprom_read = ath_pci_eeprom_read, @@ -194,10 +202,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->hw = hw; sc->dev = &pdev->dev; sc->mem = mem; - sc->bus_ops = &ath_pci_bus_ops; pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); - ret = ath_init_device(id->device, sc, subsysid); + ret = ath_init_device(id->device, sc, subsysid, &ath_pci_bus_ops); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto bad3; -- cgit v1.2.3 From 2ddb5c8b8739ec054d22ef8efd9bf04cac12a36c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 14 Sep 2009 02:09:38 -0700 Subject: ath9k: make ath9k_common_ops const As noted by Jiri. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ab9b7eaecd81..2278dcbeee16 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1579,7 +1579,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) return val; } -static struct ath_ops ath9k_common_ops = { +static const struct ath_ops ath9k_common_ops = { .read = ath9k_ioread32, .write = ath9k_iowrite32, }; -- cgit v1.2.3 From 85fecff155ed2ba0cccd618ab92d5b4e7d69cd5d Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:07 -0700 Subject: iwlwifi: modify LED blink index table Modify LED blink index table to include 1Mbps. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-led.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index f420c99e7240..41addd1c7261 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -65,9 +65,9 @@ static const struct { {70, 65, 65}, {50, 75, 75}, {20, 85, 85}, - {15, 95, 95 }, - {10, 110, 110}, - {5, 130, 130}, + {10, 95, 95}, + {5, 110, 110}, + {1, 130, 130}, {0, 167, 167}, /* SOLID_ON */ {-1, IWL_LED_SOLID, 0} -- cgit v1.2.3 From 1b07a1307250e55fe00c076b33d0ab5ac088a489 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:09 -0700 Subject: iwlwifi: remove un-supported eeprom parameters Remove few of the parameters not used and no longer valid in EEPROM. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 6b68db7b1b81..90e2b4ea2606 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -370,12 +370,10 @@ struct iwl_eeprom_calib_info { #define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ #define EEPROM_VERSION (2*0x44) /* 2 bytes */ #define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ -#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ #define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ #define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ #define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */ #define EEPROM_3945_M_VERSION (2*0x4A) /* 1 bytes */ -#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ /* The following masks are to be applied on EEPROM_RADIO_CONFIG */ #define EEPROM_RF_CFG_TYPE_MSK(x) (x & 0x3) /* bits 0-1 */ -- cgit v1.2.3 From 9371d4ed79c1c2efefa00226f7f6b95e0e0b8f2b Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:10 -0700 Subject: iwlwifi: separate nic_config for different NIC Different NIC has different requirements for configuration. Currently all 5000 series hardware and later share the same configuration function even though they do not need the same configurations. Fix this by separating the needed configuration actions for each hardware model. .5000 series: L1-ASPM H/W bug work-around configure radio write CSR_HW_IF_CONFIG_REG for uCode use work-around for NIC get stuck after early PCIe power off .1000 series: write CSR_HW_IF_CONFIG_REG for uCode use setting digital SVR for 1000 card to 1.32V .6000 series: configure radio write CSR_HW_IF_CONFIG_REG for uCode use write CSR_GP_DRIVER_REG to indicate radio sku Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 5 ++++- drivers/net/wireless/iwlwifi/iwl-5000.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 16 +++++++++++++++- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 7 ++++++- 4 files changed, 27 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 2716b91ba9fa..89f360befc30 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -76,7 +76,10 @@ static void iwl1000_set_ct_threshold(struct iwl_priv *priv) /* NIC configuration for 1000 series */ static void iwl1000_nic_config(struct iwl_priv *priv) { - iwl5000_nic_config(priv); + /* set CSR_HW_CONFIG_REG for uCode use */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); /* Setting digital SVR for 1000 card to 1.32V */ /* locking is acquired in iwl_set_bits_mask_prph() function */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index eb08f4411000..d312ef03245f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -198,7 +198,7 @@ out: } -/* NIC configuration for 5000 series and up */ +/* NIC configuration for 5000 series */ void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; @@ -221,7 +221,7 @@ void iwl5000_nic_config(struct iwl_priv *priv) radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); /* write radio config values to register */ - if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_5000_RF_CFG_TYPE_MAX) + if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_RF_CONFIG_TYPE_MAX) iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | EEPROM_RF_CFG_STEP_MSK(radio_cfg) | diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index c295b8ee9228..37b3e2086633 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -71,7 +71,21 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) /* NIC configuration for 6000 series */ static void iwl6000_nic_config(struct iwl_priv *priv) { - iwl5000_nic_config(priv); + u16 radio_cfg; + + radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); + + /* write radio config values to register */ + if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | + EEPROM_RF_CFG_STEP_MSK(radio_cfg) | + EEPROM_RF_CFG_DASH_MSK(radio_cfg)); + + /* set CSR_HW_CONFIG_REG for uCode use */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); /* no locking required for register write */ if (priv->cfg->pa_type == IWL_PA_HYBRID) { diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 90e2b4ea2606..61794eb3d689 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -385,7 +385,12 @@ struct iwl_eeprom_calib_info { #define EEPROM_3945_RF_CFG_TYPE_MAX 0x0 #define EEPROM_4965_RF_CFG_TYPE_MAX 0x1 -#define EEPROM_5000_RF_CFG_TYPE_MAX 0x3 + +/* Radio Config for 5000 and up */ +#define EEPROM_RF_CONFIG_TYPE_R3x3 0x0 +#define EEPROM_RF_CONFIG_TYPE_R2x2 0x1 +#define EEPROM_RF_CONFIG_TYPE_R1x2 0x2 +#define EEPROM_RF_CONFIG_TYPE_MAX 0x3 /* * Per-channel regulatory data. -- cgit v1.2.3 From f3a2a42470c1c362b9a7b4e933a15a274d4b090e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:11 -0700 Subject: iwlwifi: separate set_hw_params function for 6000 series Separate set_hw_params() function for 6000 series from 5000/1000 series because: 1) 6000 series use different set of sensitivity range table 2) 6000 series has different uCode image size Also include the new sensitivity parameters needed by sensitivity algorithm. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 12 +----- drivers/net/wireless/iwlwifi/iwl-6000.c | 71 +++++++++++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-calib.c | 2 +- 3 files changed, 73 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d312ef03245f..e1b378528c72 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -833,16 +833,8 @@ int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { - case CSR_HW_REV_TYPE_6x00: - case CSR_HW_REV_TYPE_6x50: - priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; - priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; - break; - default: - priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; - priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE; - } + priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE; priv->hw_params.max_bsm_size = 0; priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 37b3e2086633..4b3fb4095678 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -44,6 +44,7 @@ #include "iwl-sta.h" #include "iwl-helpers.h" #include "iwl-5000-hw.h" +#include "iwl-6000-hw.h" /* Highest firmware API version supported */ #define IWL6000_UCODE_API_MAX 4 @@ -100,8 +101,76 @@ static void iwl6000_nic_config(struct iwl_priv *priv) /* else do nothing, uCode configured */ } +static struct iwl_sensitivity_ranges iwl6000_sensitivity = { + .min_nrg_cck = 97, + .max_nrg_cck = 0, /* not used, set to 0 */ + .auto_corr_min_ofdm = 80, + .auto_corr_min_ofdm_mrc = 128, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 192, + + .auto_corr_max_ofdm = 145, + .auto_corr_max_ofdm_mrc = 232, + .auto_corr_max_ofdm_x1 = 145, + .auto_corr_max_ofdm_mrc_x1 = 232, + + .auto_corr_min_cck = 125, + .auto_corr_max_cck = 175, + .auto_corr_min_cck_mrc = 160, + .auto_corr_max_cck_mrc = 310, + .nrg_th_cck = 97, + .nrg_th_ofdm = 100, +}; + +static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) +{ + if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || + (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { + IWL_ERR(priv, + "invalid queues_num, should be between %d and %d\n", + IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES); + return -EINVAL; + } + + priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; + priv->hw_params.scd_bc_tbls_size = + IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); + priv->hw_params.tfd_size = sizeof(struct iwl_tfd); + priv->hw_params.max_stations = IWL5000_STATION_COUNT; + priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; + + priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; + priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; + + priv->hw_params.max_bsm_size = 0; + priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + BIT(IEEE80211_BAND_5GHZ); + priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; + + priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); + priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; + priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; + + if (priv->cfg->ops->lib->temp_ops.set_ct_kill) + priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); + + /* Set initial sensitivity parameters */ + /* Set initial calibration set */ + priv->hw_params.sens = &iwl6000_sensitivity; + priv->hw_params.calib_init_cfg = + BIT(IWL_CALIB_XTAL) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_TX_IQ_PERD) | + BIT(IWL_CALIB_BASE_BAND); + + return 0; +} + static struct iwl_lib_ops iwl6000_lib = { - .set_hw_params = iwl5000_hw_set_hw_params, + .set_hw_params = iwl6000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, .txq_set_sched = iwl5000_txq_set_sched, diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index c4b565a2de94..6e73317c3b40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -516,7 +516,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv) for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) data->nrg_silence_rssi[i] = 0; - data->auto_corr_ofdm = 90; + data->auto_corr_ofdm = ranges->auto_corr_min_ofdm; data->auto_corr_ofdm_mrc = ranges->auto_corr_min_ofdm_mrc; data->auto_corr_ofdm_x1 = ranges->auto_corr_min_ofdm_x1; data->auto_corr_ofdm_mrc_x1 = ranges->auto_corr_min_ofdm_mrc_x1; -- cgit v1.2.3 From c812ee24855e20f43cf211e51e3eb53fe6dc6f1d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 11 Sep 2009 10:38:13 -0700 Subject: iwlwifi: clean up ht config a little is_ht can be bool instead of u8, and there's no need to use IWL_CHANNEL_WIDTH_* constants in supported_chan_width when that could just be named is_40mhz instead. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 14 +++++--------- drivers/net/wireless/iwlwifi/iwl-dev.h | 7 ++----- 2 files changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 484d5c1a7312..c09475105c52 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -636,8 +636,7 @@ u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, { struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; - if ((!iwl_ht_conf->is_ht) || - (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ)) + if (!iwl_ht_conf->is_ht || !iwl_ht_conf->is_40mhz) return 0; /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 @@ -2619,21 +2618,18 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) if (conf_is_ht40_minus(conf)) { ht_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ht_conf->supported_chan_width = - IWL_CHANNEL_WIDTH_40MHZ; + ht_conf->is_40mhz = true; } else if (conf_is_ht40_plus(conf)) { ht_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ht_conf->supported_chan_width = - IWL_CHANNEL_WIDTH_40MHZ; + ht_conf->is_40mhz = true; } else { ht_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; - ht_conf->supported_chan_width = - IWL_CHANNEL_WIDTH_20MHZ; + ht_conf->is_40mhz = false; } } else - ht_conf->supported_chan_width = IWL_CHANNEL_WIDTH_20MHZ; + ht_conf->is_40mhz = false; /* Default to no protection. Protection mode will later be set * from BSS config in iwl_ht_conf */ ht_conf->ht_protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 028d50599550..961d53440034 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -504,8 +504,8 @@ union iwl_ht_rate_supp { struct iwl_ht_info { /* self configuration data */ - u8 is_ht; - u8 supported_chan_width; + bool is_ht; + bool is_40mhz; u8 sm_ps; struct ieee80211_mcs_info mcs; /* BSS related data */ @@ -726,9 +726,6 @@ struct iwl_dma_ptr { size_t size; }; -#define IWL_CHANNEL_WIDTH_20MHZ 0 -#define IWL_CHANNEL_WIDTH_40MHZ 1 - #define IWL_OPERATION_MODE_AUTO 0 #define IWL_OPERATION_MODE_HT_ONLY 1 #define IWL_OPERATION_MODE_MIXED 2 -- cgit v1.2.3 From f2d0d0e2bab7a325071dbaba3bef51c90868e1e6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:14 -0700 Subject: iwlwifi: Adjust blink rate to compensate Clock difference Adjust led blink rate to compensate on a MAC Clock difference on every HW. Led blink rate analysis showed an average deviation of 0% on 3945, 5% on 4965 HW and 20% on 5000 series and up. Need to compensate on the led on/off time per HW according to the deviation to achieve the desired led frequency The calculation is: (100-averageDeviation)/100 * blinkTime For code efficiency the calculation will be: compensation = (100 - averageDeviation) * 64 / 100 NewBlinkTime = (compensation * BlinkTime) / 64 Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + drivers/net/wireless/iwlwifi/iwl-3945.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 6 ++++++ drivers/net/wireless/iwlwifi/iwl-6000.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl-core.h | 4 ++++ drivers/net/wireless/iwlwifi/iwl-led.c | 33 +++++++++++++++++++++++++++++++-- 7 files changed, 50 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 89f360befc30..1dd8db2f6f23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -164,5 +164,6 @@ struct iwl_cfg iwl1000_bgn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, .ht_greenfield_support = true, + .led_compensation = 51, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e70c5b0af364..33e40c21eb72 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2894,6 +2894,7 @@ static struct iwl_cfg iwl3945_bg_cfg = { .mod_params = &iwl3945_mod_params, .use_isr_legacy = true, .ht_greenfield_support = false, + .led_compensation = 64, }; static struct iwl_cfg iwl3945_abg_cfg = { @@ -2908,6 +2909,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { .mod_params = &iwl3945_mod_params, .use_isr_legacy = true, .ht_greenfield_support = false, + .led_compensation = 64, }; struct pci_device_id iwl3945_hw_card_ids[] = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a22a0501c190..2500ab2e1d91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2355,6 +2355,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .use_isr_legacy = true, .ht_greenfield_support = false, .broken_powersave = true, + .led_compensation = 61, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index e1b378528c72..c81fd4bc32b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1656,6 +1656,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl5100_bg_cfg = { @@ -1673,6 +1674,7 @@ struct iwl_cfg iwl5100_bg_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -1690,6 +1692,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -1707,6 +1710,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1724,6 +1728,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1741,6 +1746,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = true, .ht_greenfield_support = true, + .led_compensation = 51, }; MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 4b3fb4095678..48b2b7d2170c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -258,6 +258,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .ht_greenfield_support = true, + .led_compensation = 51, }; /* @@ -281,6 +282,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -301,6 +303,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -321,6 +324,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .ht_greenfield_support = true, + .led_compensation = 51, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -341,6 +345,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .ht_greenfield_support = true, + .led_compensation = 51, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index e50103a956b1..79ea42531e28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -213,6 +213,9 @@ struct iwl_mod_params { * @pa_type: used by 6000 series only to identify the type of Power Amplifier * @max_ll_items: max number of OTP blocks * @shadow_ram_support: shadow support for OTP memory + * @led_compensation: compensate on the led on/off time per HW according + * to the deviation to achieve the desired led frequency. + * The detail algorithm is described in iwl-led.c * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -255,6 +258,7 @@ struct iwl_cfg { const bool shadow_ram_support; const bool ht_greenfield_support; const bool broken_powersave; + u16 led_compensation; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 41addd1c7261..f547233c5b79 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -78,6 +78,29 @@ static const struct { #define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */ #define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) +/* + * Adjust led blink rate to compensate on a MAC Clock difference on every HW + * Led blink rate analysis showed an average deviation of 0% on 3945, + * 5% on 4965 HW and 20% on 5000 series and up. + * Need to compensate on the led on/off time per HW according to the deviation + * to achieve the desired led frequency + * The calculation is: (100-averageDeviation)/100 * blinkTime + * For code efficiency the calculation will be: + * compensation = (100 - averageDeviation) * 64 / 100 + * NewBlinkTime = (compensation * BlinkTime) / 64 + */ +static inline u8 iwl_blink_compensation(struct iwl_priv *priv, + u8 time, u16 compensation) +{ + if (!compensation) { + IWL_ERR(priv, "undefined blink compensation: " + "use pre-defined blinking time\n"); + return time; + } + + return (u8)((time * compensation) >> 6); +} + /* [0-256] -> [0..8] FIXME: we need [0..10] */ static inline int iwl_brightness_to_idx(enum led_brightness brightness) { @@ -114,8 +137,14 @@ static int iwl_led_pattern(struct iwl_priv *priv, int led_id, BUG_ON(idx > IWL_MAX_BLINK_TBL); - led_cmd.on = blink_tbl[idx].on_time; - led_cmd.off = blink_tbl[idx].off_time; + IWL_DEBUG_LED(priv, "Led blink time compensation= %u\n", + priv->cfg->led_compensation); + led_cmd.on = + iwl_blink_compensation(priv, blink_tbl[idx].on_time, + priv->cfg->led_compensation); + led_cmd.off = + iwl_blink_compensation(priv, blink_tbl[idx].off_time, + priv->cfg->led_compensation); return iwl_send_led_cmd(priv, &led_cmd); } -- cgit v1.2.3 From fad95bf59bf14f72e7d45d3887044e88b8584637 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 11 Sep 2009 10:38:15 -0700 Subject: iwlwifi: clean up ht config naming Daniel Halperin pointed out that the naming here is rather inconsistent with at least 3 different names being used for one thing in different contexts. Rename the struct to iwl_ht_config (rather than iwl_ht_info) and use ht_conf as a variable for it. Signed-off-by: Johannes Berg Acked-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 48 +++++++++++++++---------------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +-- 4 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 346dc06fa7b7..18af37c964cb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -662,7 +662,7 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, * there are no non-GF stations present in the BSS. */ static inline u8 rs_use_green(struct ieee80211_sta *sta, - struct iwl_ht_info *ht_conf) + struct iwl_ht_config *ht_conf) { return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && !(ht_conf->non_GF_STA_present); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c09475105c52..9d01fde92cc6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -634,9 +634,9 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, struct ieee80211_sta_ht_cap *sta_ht_inf) { - struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; + struct iwl_ht_config *ht_conf = &priv->current_ht_config; - if (!iwl_ht_conf->is_ht || !iwl_ht_conf->is_40mhz) + if (!ht_conf->is_ht || !ht_conf->is_40mhz) return 0; /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 @@ -652,7 +652,7 @@ u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, #endif return iwl_is_channel_extension(priv, priv->band, le16_to_cpu(priv->staging_rxon.channel), - iwl_ht_conf->extension_chan_offset); + ht_conf->extension_chan_offset); } EXPORT_SYMBOL(iwl_is_ht40_tx_allowed); @@ -876,11 +876,11 @@ u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rate_get_lowest_plcp); -void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) +void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - if (!ht_info->is_ht) { + if (!ht_conf->is_ht) { rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | RXON_FLG_HT40_PROT_MSK | @@ -891,7 +891,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) /* FIXME: if the definition of ht_protection changed, the "translation" * will be needed for rxon->flags */ - rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); + rxon->flags |= cpu_to_le32(ht_conf->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); /* Set up channel bandwidth: * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ @@ -900,10 +900,10 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); if (iwl_is_ht40_tx_allowed(priv, NULL)) { /* pure ht40 */ - if (ht_info->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { + if (ht_conf->ht_protection == IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; /* Note: control channel is opposite of extension channel */ - switch (ht_info->extension_chan_offset) { + switch (ht_conf->extension_chan_offset) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: rxon->flags &= ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; break; @@ -913,7 +913,7 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) } } else { /* Note: control channel is opposite of extension channel */ - switch (ht_info->extension_chan_offset) { + switch (ht_conf->extension_chan_offset) { case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; @@ -939,11 +939,11 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) IWL_DEBUG_ASSOC(priv, "supported HT rate 0x%X 0x%X 0x%X " "rxon flags 0x%X operation mode :0x%X " "extension channel offset 0x%x\n", - ht_info->mcs.rx_mask[0], - ht_info->mcs.rx_mask[1], - ht_info->mcs.rx_mask[2], - le32_to_cpu(rxon->flags), ht_info->ht_protection, - ht_info->extension_chan_offset); + ht_conf->mcs.rx_mask[0], + ht_conf->mcs.rx_mask[1], + ht_conf->mcs.rx_mask[2], + le32_to_cpu(rxon->flags), ht_conf->ht_protection, + ht_conf->extension_chan_offset); return; } EXPORT_SYMBOL(iwl_set_rxon_ht); @@ -2228,13 +2228,13 @@ EXPORT_SYMBOL(iwl_mac_conf_tx); static void iwl_ht_conf(struct iwl_priv *priv, struct ieee80211_bss_conf *bss_conf) { - struct ieee80211_sta_ht_cap *ht_conf; - struct iwl_ht_info *iwl_conf = &priv->current_ht_config; + struct iwl_ht_config *ht_conf = &priv->current_ht_config; + struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta *sta; IWL_DEBUG_MAC80211(priv, "enter: \n"); - if (!iwl_conf->is_ht) + if (!ht_conf->is_ht) return; @@ -2250,15 +2250,15 @@ static void iwl_ht_conf(struct iwl_priv *priv, rcu_read_unlock(); return; } - ht_conf = &sta->ht_cap; + ht_cap = &sta->ht_cap; - iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); + ht_conf->sm_ps = (u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS) >> 2); - memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); + memcpy(&ht_conf->mcs, &ht_cap->mcs, 16); - iwl_conf->ht_protection = + ht_conf->ht_protection = bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; - iwl_conf->non_GF_STA_present = + ht_conf->non_GF_STA_present = !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); rcu_read_unlock(); @@ -2568,7 +2568,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; struct ieee80211_conf *conf = &hw->conf; - struct iwl_ht_info *ht_conf = &priv->current_ht_config; + struct iwl_ht_config *ht_conf = &priv->current_ht_config; unsigned long flags = 0; int ret = 0; u16 ch; @@ -2735,7 +2735,7 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "enter\n"); spin_lock_irqsave(&priv->lock, flags); - memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); + memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config)); spin_unlock_irqrestore(&priv->lock, flags); iwl_reset_qos(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 79ea42531e28..a2ee95028c6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -277,7 +277,7 @@ int iwl_check_rxon_cmd(struct iwl_priv *priv); int iwl_full_rxon_required(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); -void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); +void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf); u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, struct ieee80211_sta_ht_cap *sta_ht_inf); void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 961d53440034..e161f8d1766e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -502,7 +502,7 @@ union iwl_ht_rate_supp { #define CFG_HT_MPDU_DENSITY_4USEC (0x5) #define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_4USEC -struct iwl_ht_info { +struct iwl_ht_config { /* self configuration data */ bool is_ht; bool is_40mhz; @@ -1077,7 +1077,7 @@ struct iwl_priv { struct iwl_chain_noise_data chain_noise_data; __le16 sensitivity_tbl[HD_TABLE_SIZE]; - struct iwl_ht_info current_ht_config; + struct iwl_ht_config current_ht_config; u8 last_phy_res[100]; /* Rate scaling data */ -- cgit v1.2.3 From e307ddce394ee7bcec41fb74330ac89eafaea1d9 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 11 Sep 2009 10:38:16 -0700 Subject: iwlwifi: show NVM version in debugfs Show version number along with dumping NVM data, the version information being removed from sysfs, add it back to debugfs to help debugging. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index a198bcf61022..037b75ca77f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -383,6 +383,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, int pos = 0, ofs = 0, buf_size = 0; const u8 *ptr; char *buf; + u16 eeprom_ver; size_t eeprom_len = priv->cfg->eeprom_size; buf_size = 4 * eeprom_len + 256; @@ -403,9 +404,11 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, IWL_ERR(priv, "Can not allocate Buffer\n"); return -ENOMEM; } - pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n", + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, " + "version: 0x%x\n", (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) - ? "OTP" : "EEPROM"); + ? "OTP" : "EEPROM", eeprom_ver); for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos, -- cgit v1.2.3 From 02bb1bea85e6570b4e64825026382556970b9296 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 11 Sep 2009 10:38:17 -0700 Subject: iwlwifi: clarify and clean up chain settings The chain settings we currently use in iwlwifi are rather confusing -- and we also go by the wrong settings entirely under certain circumstances. To clean it up, create a new variable in the current HT config -- single_chain_sufficient -- that tells us whether we need more than one chain. Calculate that based on the AP and operating mode (no IBSS HT implemented -- so no need for multiple chains, for station mode we use the AP's capabilities). Additionally, since APs always send disabled SM PS mode, keeping track of their sm_ps mode isn't very useful -- doubly not so for our _own_ RX config since that should depend on our, not the AP's, SM PS mode. Finally, document that our configuration of the number of RX chains used is currently wrong when in powersave (by adding a comment). All together this removes the two remaining items in struct iwl_ht_config that were done wrong there. For the future, the number of RX chains and some SM PS handshaking needs to be added to mac80211, which then needs to tell us, and the new variable current_ht_config.single_chain_sufficient should also be calculated by mac80211. Signed-off-by: Johannes Berg Acked-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 105 +++++++++++++++----------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 +- 2 files changed, 51 insertions(+), 57 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 9d01fde92cc6..2908bff49a3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -607,8 +607,7 @@ EXPORT_SYMBOL(iwlcore_free_geos); static bool is_single_rx_stream(struct iwl_priv *priv) { return !priv->current_ht_config.is_ht || - ((priv->current_ht_config.mcs.rx_mask[1] == 0) && - (priv->current_ht_config.mcs.rx_mask[2] == 0)); + priv->current_ht_config.single_chain_sufficient; } static u8 iwl_is_channel_extension(struct iwl_priv *priv, @@ -936,12 +935,8 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf) if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv); - IWL_DEBUG_ASSOC(priv, "supported HT rate 0x%X 0x%X 0x%X " - "rxon flags 0x%X operation mode :0x%X " + IWL_DEBUG_ASSOC(priv, "rxon flags 0x%X operation mode :0x%X " "extension channel offset 0x%x\n", - ht_conf->mcs.rx_mask[0], - ht_conf->mcs.rx_mask[1], - ht_conf->mcs.rx_mask[2], le32_to_cpu(rxon->flags), ht_conf->ht_protection, ht_conf->extension_chan_offset); return; @@ -960,12 +955,8 @@ EXPORT_SYMBOL(iwl_set_rxon_ht); */ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) { - bool is_single = is_single_rx_stream(priv); - bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); - /* # of Rx chains to use when expecting MIMO. */ - if (is_single || (!is_cam && (priv->current_ht_config.sm_ps == - WLAN_HT_CAP_SM_PS_STATIC))) + if (is_single_rx_stream(priv)) return IWL_NUM_RX_CHAINS_SINGLE; else return IWL_NUM_RX_CHAINS_MULTIPLE; @@ -973,27 +964,17 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) { - int idle_cnt; bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); + /* # Rx chains when idling and maybe trying to save power */ - switch (priv->current_ht_config.sm_ps) { - case WLAN_HT_CAP_SM_PS_STATIC: - case WLAN_HT_CAP_SM_PS_DYNAMIC: - idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : - IWL_NUM_IDLE_CHAINS_SINGLE; - break; - case WLAN_HT_CAP_SM_PS_DISABLED: - idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; - break; - case WLAN_HT_CAP_SM_PS_INVALID: - default: - IWL_ERR(priv, "invalid mimo ps mode %d\n", - priv->current_ht_config.sm_ps); - WARN_ON(1); - idle_cnt = -1; - break; - } - return idle_cnt; + + /* + * XXX: this is incorrect!! + * we always indicate to the AP that + * our SM PS mode is "disabled" + */ + + return is_cam ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; } /* up to 4 chains */ @@ -1493,8 +1474,6 @@ int iwl_init_drv(struct iwl_priv *priv) priv->iw_mode = NL80211_IFTYPE_STATION; - priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; - /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv); @@ -2226,10 +2205,9 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, EXPORT_SYMBOL(iwl_mac_conf_tx); static void iwl_ht_conf(struct iwl_priv *priv, - struct ieee80211_bss_conf *bss_conf) + struct ieee80211_bss_conf *bss_conf) { struct iwl_ht_config *ht_conf = &priv->current_ht_config; - struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta *sta; IWL_DEBUG_MAC80211(priv, "enter: \n"); @@ -2237,31 +2215,48 @@ static void iwl_ht_conf(struct iwl_priv *priv, if (!ht_conf->is_ht) return; - - /* - * It is totally wrong to base global information on something - * that is valid only when associated, alas, this driver works - * that way and I don't know how to fix it. - */ - - rcu_read_lock(); - sta = ieee80211_find_sta(priv->hw, priv->bssid); - if (!sta) { - rcu_read_unlock(); - return; - } - ht_cap = &sta->ht_cap; - - ht_conf->sm_ps = (u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS) >> 2); - - memcpy(&ht_conf->mcs, &ht_cap->mcs, 16); - ht_conf->ht_protection = bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; ht_conf->non_GF_STA_present = !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); - rcu_read_unlock(); + ht_conf->single_chain_sufficient = false; + + switch (priv->iw_mode) { + case NL80211_IFTYPE_STATION: + rcu_read_lock(); + sta = ieee80211_find_sta(priv->hw, priv->bssid); + if (sta) { + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; + int maxstreams; + + maxstreams = (ht_cap->mcs.tx_params & + IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) + >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; + maxstreams += 1; + + if ((ht_cap->mcs.rx_mask[1] == 0) && + (ht_cap->mcs.rx_mask[2] == 0)) + ht_conf->single_chain_sufficient = true; + if (maxstreams <= 1) + ht_conf->single_chain_sufficient = true; + } else { + /* + * If at all, this can only happen through a race + * when the AP disconnects us while we're still + * setting up the connection, in that case mac80211 + * will soon tell us about that. + */ + ht_conf->single_chain_sufficient = true; + } + rcu_read_unlock(); + break; + case NL80211_IFTYPE_ADHOC: + ht_conf->single_chain_sufficient = true; + break; + default: + break; + } IWL_DEBUG_MAC80211(priv, "leave\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e161f8d1766e..0c80692f934b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -506,8 +506,7 @@ struct iwl_ht_config { /* self configuration data */ bool is_ht; bool is_40mhz; - u8 sm_ps; - struct ieee80211_mcs_info mcs; + bool single_chain_sufficient; /* BSS related data */ u8 extension_chan_offset; u8 ht_protection; -- cgit v1.2.3 From 47eef9bd1079edbc3e6606309c733a2316ca5a72 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:44 -0700 Subject: iwlwifi: Use RTS/CTS as the preferred protection mechanism for 6000 series When 802.11g was introduced, we had RTS/CTS and CTS-to-Self protection mechanisms. In an HT Beacon, HT stations use the "Operating Mode" field in the HT Information Element to determine whether or not to use protection. The Operating Mode field has 4 possible settings: 0-3: Mode 0: If all stations in the BSS are 20/40 MHz HT capable, or if the BSS is 20/40 MHz capable, or if all stations in the BSS are 20 MHz HT stations in a 20 MHz BSS Mode 1: used if there are non-HT stations or APs using the primary or secondary channels Mode 2: if only HT stations are associated in the BSS and at least one 20 MHz HT station is associated. Mode 3: used if one or more non-HT stations are associated in the BSS. When in operating modes 1 or 3, and the Use_Protection field is 1 in the Beacon's ERP IE, all HT transmissions must be protected using RTS/CTS or CTS-to-Self. By default, CTS-to-self is the preferred protection mechanism for less overhead and higher throughput; but using the full RTS/CTS will better protect the inner exchange from interference, especially in highly-congested environment. For 6000 series WIFI NIC, RTS/CTS protection mechanism is the recommended choice for HT traffic based on the HW design. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 9 +++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 10 +++++++--- drivers/net/wireless/iwlwifi/iwl-core.h | 4 +++- 4 files changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 48b2b7d2170c..a9665ce1d658 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -259,6 +259,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ }; /* @@ -283,6 +284,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -304,6 +306,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -325,6 +328,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -346,6 +350,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 18af37c964cb..469d56321d88 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -418,6 +418,15 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid, else if (tid == IWL_AGG_ALL_TID) for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta); + if (priv->cfg->use_rts_for_ht) { + /* + * switch to RTS/CTS if it is the prefer protection method + * for HT traffic + */ + IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n"); + priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN; + iwlcore_commit_rxon(priv); + } } static inline int get_num_of_ant_from_rate(u32 rate_n_flags) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index cdc07c477457..a3739628c1d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -115,9 +115,6 @@ int iwl_commit_rxon(struct iwl_priv *priv) /* always get timestamp with Rx frame */ priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; - /* allow CTS-to-self if possible. this is relevant only for - * 5000, but will not damage 4965 */ - priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; ret = iwl_check_rxon_cmd(priv); if (ret) { @@ -217,6 +214,13 @@ int iwl_commit_rxon(struct iwl_priv *priv) "Could not send WEP static key.\n"); } + /* + * allow CTS-to-self if possible for new association. + * this is relevant only for 5000 series and up, + * but will not damage 4965 + */ + priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; + /* Apply the new configuration * RXON assoc doesn't clear the station table in uCode, */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a2ee95028c6e..c7675c387140 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -216,6 +216,7 @@ struct iwl_mod_params { * @led_compensation: compensate on the led on/off time per HW according * to the deviation to achieve the desired led frequency. * The detail algorithm is described in iwl-led.c + * @use_rts_for_ht: use rts/cts protection for HT traffic * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -257,8 +258,9 @@ struct iwl_cfg { const u16 max_ll_items; const bool shadow_ram_support; const bool ht_greenfield_support; - const bool broken_powersave; u16 led_compensation; + const bool broken_powersave; + bool use_rts_for_ht; }; /*************************** -- cgit v1.2.3 From 01abfbb282482d01e2ac2e6b00e75b248bf517c8 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:45 -0700 Subject: iwlwifi: allow user change protection mechanism for HT Allow user to change protection mechanism for HT between RTS/CTS and CTS-to-self through sysfs: Show current protection mechanism for HT cat /sys/class/net/wlan0/device/rts_ht_protection Change protection mechanism for HT (only allowed while not-associated) CTS-to-self: echo 0 > /sys/class/net/wlan0/device/rts_ht_protection RTS/CTS: echo 1 > /sys/class/net/wlan0/device/rts_ht_protection Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a3739628c1d6..2a7cc4bdf3fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2798,6 +2798,40 @@ static ssize_t show_statistics(struct device *d, static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); +static ssize_t show_rts_ht_protection(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + + return sprintf(buf, "%s\n", + priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self"); +} + +static ssize_t store_rts_ht_protection(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iwl_priv *priv = dev_get_drvdata(d); + unsigned long val; + int ret; + + ret = strict_strtoul(buf, 10, &val); + if (ret) + IWL_INFO(priv, "Input is not in decimal form.\n"); + else { + if (!iwl_is_associated(priv)) + priv->cfg->use_rts_for_ht = val ? true : false; + else + IWL_ERR(priv, "Sta associated with AP - " + "Change protection mechanism is not allowed\n"); + ret = count; + } + return ret; +} + +static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO, + show_rts_ht_protection, store_rts_ht_protection); + /***************************************************************************** * @@ -2854,6 +2888,7 @@ static struct attribute *iwl_sysfs_entries[] = { &dev_attr_statistics.attr, &dev_attr_temperature.attr, &dev_attr_tx_power.attr, + &dev_attr_rts_ht_protection.attr, #ifdef CONFIG_IWLWIFI_DEBUG &dev_attr_debug_level.attr, #endif -- cgit v1.2.3 From 1f4b9665032c4a1d60efd9ceaad2781cae6c7e92 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:46 -0700 Subject: iwlwifi: EEPROM version for 1000 and 6000 series Update EEPROM version requirement for 1000 and 6000 series of NIC for EEPROM version verification. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-6000.c | 10 +++++----- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 6 ++++++ 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 1dd8db2f6f23..879b3753a3bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -155,7 +155,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .sku = IWL_SKU_G|IWL_SKU_N, .ops = &iwl1000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_1000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a9665ce1d658..0d2cbab1f7d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -248,7 +248,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, @@ -273,7 +273,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, @@ -295,7 +295,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, @@ -317,7 +317,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, @@ -339,7 +339,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 61794eb3d689..75fe02282998 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -256,6 +256,12 @@ struct iwl_eeprom_enhanced_txpwr { #define EEPROM_5050_TX_POWER_VERSION (4) #define EEPROM_5050_EEPROM_VERSION (0x21E) +/* 1000 Specific */ +#define EEPROM_1000_EEPROM_VERSION (0x15D) + +/* 60x0 Specific */ +#define EEPROM_6000_EEPROM_VERSION (0x434) + /* OTP */ /* lower blocks contain EEPROM image and calibration data */ #define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ -- cgit v1.2.3 From 4e30cb691b9ba62642cc1594ef08f7439deb5a02 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:47 -0700 Subject: iwlwifi: use S_IRUGO and S_IWUSR in module parameters Instead of hardcode module parameter's permissions, use pre-defined. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 15 ++++++++------- drivers/net/wireless/iwlwifi/iwl-5000.c | 11 ++++++----- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 11 ++++++----- 4 files changed, 22 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 2500ab2e1d91..b5111702856a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2361,21 +2361,22 @@ struct iwl_cfg iwl4965_agn_cfg = { /* Module firmware */ MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX)); -module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444); +module_param_named(antenna, iwl4965_mod_params.antenna, int, S_IRUGO); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); +module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, S_IRUGO); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); module_param_named( - disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444); + disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, S_IRUGO); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); -module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444); +module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, S_IRUGO); MODULE_PARM_DESC(queues_num, "number of hw queues."); /* 11n */ -module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, 0444); +module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, S_IRUGO); MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); -module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, int, 0444); +module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, + int, S_IRUGO); MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); -module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, 0444); +module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart4965, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c81fd4bc32b4..75fa55db330e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1752,14 +1752,15 @@ struct iwl_cfg iwl5150_agn_cfg = { MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); -module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); +module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, S_IRUGO); MODULE_PARM_DESC(swcrypto50, "using software crypto engine (default 0 [hardware])\n"); -module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); +module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, S_IRUGO); MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); -module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444); +module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, S_IRUGO); MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality"); -module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444); +module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, + int, S_IRUGO); MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series"); -module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444); +module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error"); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2a7cc4bdf3fd..cf2b481dca6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3322,9 +3322,9 @@ module_exit(iwl_exit); module_init(iwl_init); #ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug50, iwl_debug_level, uint, 0444); +module_param_named(debug50, iwl_debug_level, uint, S_IRUGO); MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)"); -module_param_named(debug, iwl_debug_level, uint, 0644); +module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c390dbd877e4..4a4af0f782f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4225,18 +4225,19 @@ static void __exit iwl3945_exit(void) MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX)); -module_param_named(antenna, iwl3945_mod_params.antenna, int, 0444); +module_param_named(antenna, iwl3945_mod_params.antenna, int, S_IRUGO); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444); +module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, S_IRUGO); MODULE_PARM_DESC(swcrypto, "using software crypto (default 1 [software])\n"); #ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug, iwl_debug_level, uint, 0644); +module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); #endif -module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444); +module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, + int, S_IRUGO); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); -module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444); +module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error"); module_exit(iwl3945_exit); -- cgit v1.2.3 From 95407aa4d48a8b3a2adf6a110853b544342913bd Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 17 Sep 2009 10:43:48 -0700 Subject: iwlwifi: clean up rs_tx_status Cut down on redundant code, reorganize structure, and add/improve comments. Should contain no functional changes. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 230 ++++++++++++++---------------- 1 file changed, 108 insertions(+), 122 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 469d56321d88..cd24763d5fde 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -820,6 +820,26 @@ out: return rate_n_flags_from_tbl(lq_sta->drv, tbl, low, is_green); } +/* + * Simple function to compare two rate scale table types + */ +static bool table_type_matches(struct iwl_scale_tbl_info *a, + struct iwl_scale_tbl_info *b) +{ + return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) && + (a->is_SGI == b->is_SGI); +} +/* + * Static function to get the expected throughput from an iwl_scale_tbl_info + * that wraps a NULL pointer check + */ +static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) +{ + if (tbl->expected_tpt) + return tbl->expected_tpt[rs_index]; + return 0; +} + /* * mac80211 sends us Tx status */ @@ -827,21 +847,19 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { - int status; - u8 retries; - int rs_index, mac_index, index = 0; + int legacy_success; + int retries; + int rs_index, mac_index, i; struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_link_quality_cmd *table; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_rate_scale_data *window = NULL; - struct iwl_rate_scale_data *search_win = NULL; enum mac80211_rate_control_flags mac_flags; u32 tx_rate; struct iwl_scale_tbl_info tbl_type; - struct iwl_scale_tbl_info *curr_tbl, *search_tbl; - u8 active_index = 0; + struct iwl_scale_tbl_info *curr_tbl, *other_tbl; s32 tpt = 0; IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n"); @@ -855,25 +873,10 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - if (info->flags & IEEE80211_TX_STAT_AMPDU) - retries = 0; - else - retries = info->status.rates[0].count - 1; - - if (retries > 15) - retries = 15; if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) - goto out; - - table = &lq_sta->lq; - active_index = lq_sta->active_tbl; - - curr_tbl = &(lq_sta->lq_info[active_index]); - search_tbl = &(lq_sta->lq_info[(1 - active_index)]); - window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]); - search_win = (struct iwl_rate_scale_data *)&(search_tbl->win[0]); + return; /* * Ignore this Tx frame response if its initial rate doesn't match @@ -883,6 +886,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, * to check "search" mode, or a prior "search" mode after we've moved * to a new "search" mode (which might become the new "active" mode). */ + table = &lq_sta->lq; tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags); rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); if (priv->band == IEEE80211_BAND_5GHZ) @@ -901,7 +905,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, if (priv->band == IEEE80211_BAND_2GHZ) mac_index += IWL_FIRST_OFDM_RATE; } - + /* Here we actually compare this rate to the latest LQ command */ if ((mac_index < 0) || (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || (tbl_type.is_ht40 != !!(mac_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || @@ -911,124 +915,106 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, (!!(tx_rate & RATE_MCS_GF_MSK) != !!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) || (rs_index != mac_index)) { IWL_DEBUG_RATE(priv, "initial rate %d does not match %d (0x%x)\n", mac_index, rs_index, tx_rate); - /* the last LQ command could failed so the LQ in ucode not - * the same in driver sync up + /* + * Since rates mis-match, the last LQ command may have failed. + * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with + * ... driver. */ lq_sta->missed_rate_counter++; if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { lq_sta->missed_rate_counter = 0; iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } - goto out; + /* Regardless, ignore this status info for outdated rate */ + return; + } else + /* Rate did match, so reset the missed_rate_counter */ + lq_sta->missed_rate_counter = 0; + + /* Figure out if rate scale algorithm is in active or search table */ + if (table_type_matches(&tbl_type, + &(lq_sta->lq_info[lq_sta->active_tbl]))) { + curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); + } else if (table_type_matches(&tbl_type, + &lq_sta->lq_info[1 - lq_sta->active_tbl])) { + curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]); + other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); + } else { + IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n"); + return; } + window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]); - lq_sta->missed_rate_counter = 0; - /* Update frame history window with "failure" for each Tx retry. */ - while (retries) { - /* Look up the rate and other info used for each tx attempt. - * Each tx attempt steps one entry deeper in the rate table. */ - tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); - rs_get_tbl_info_from_mcs(tx_rate, priv->band, - &tbl_type, &rs_index); - - /* If type matches "search" table, - * add failure to "search" history */ - if ((tbl_type.lq_type == search_tbl->lq_type) && - (tbl_type.ant_type == search_tbl->ant_type) && - (tbl_type.is_SGI == search_tbl->is_SGI)) { - if (search_tbl->expected_tpt) - tpt = search_tbl->expected_tpt[rs_index]; - else - tpt = 0; - rs_collect_tx_data(search_win, rs_index, tpt, 1, 0); - - /* Else if type matches "current/active" table, - * add failure to "current/active" history */ - } else if ((tbl_type.lq_type == curr_tbl->lq_type) && - (tbl_type.ant_type == curr_tbl->ant_type) && - (tbl_type.is_SGI == curr_tbl->is_SGI)) { - if (curr_tbl->expected_tpt) - tpt = curr_tbl->expected_tpt[rs_index]; - else - tpt = 0; - rs_collect_tx_data(window, rs_index, tpt, 1, 0); + /* + * Updating the frame history depends on whether packets were + * aggregated. + * + * For aggregation, all packets were transmitted at the same rate, the + * first index into rate scale table. + */ + if (info->flags & IEEE80211_TX_STAT_AMPDU) { + tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, + &rs_index); + tpt = get_expected_tpt(curr_tbl, rs_index); + rs_collect_tx_data(window, rs_index, tpt, + info->status.ampdu_ack_len, + info->status.ampdu_ack_map); + + /* Update success/fail counts if not searching for new mode */ + if (lq_sta->stay_in_tbl) { + lq_sta->total_success += info->status.ampdu_ack_map; + lq_sta->total_failed += (info->status.ampdu_ack_len - + info->status.ampdu_ack_map); } - - /* If not searching for a new mode, increment failed counter - * ... this helps determine when to start searching again */ - if (lq_sta->stay_in_tbl) - lq_sta->total_failed++; - --retries; - index++; - - } - + } else { /* - * Find (by rate) the history window to update with final Tx attempt; - * if Tx was successful first try, use original rate, - * else look up the rate that was, finally, successful. + * For legacy, update frame history with for each Tx retry. */ - tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags); - lq_sta->last_rate_n_flags = tx_rate; - rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); - - /* Update frame history window with "success" if Tx got ACKed ... */ - status = !!(info->flags & IEEE80211_TX_STAT_ACK); - - /* If type matches "search" table, - * add final tx status to "search" history */ - if ((tbl_type.lq_type == search_tbl->lq_type) && - (tbl_type.ant_type == search_tbl->ant_type) && - (tbl_type.is_SGI == search_tbl->is_SGI)) { - if (search_tbl->expected_tpt) - tpt = search_tbl->expected_tpt[rs_index]; - else - tpt = 0; - if (info->flags & IEEE80211_TX_STAT_AMPDU) - rs_collect_tx_data(search_win, rs_index, tpt, - info->status.ampdu_ack_len, - info->status.ampdu_ack_map); - else - rs_collect_tx_data(search_win, rs_index, tpt, - 1, status); - /* Else if type matches "current/active" table, - * add final tx status to "current/active" history */ - } else if ((tbl_type.lq_type == curr_tbl->lq_type) && - (tbl_type.ant_type == curr_tbl->ant_type) && - (tbl_type.is_SGI == curr_tbl->is_SGI)) { - if (curr_tbl->expected_tpt) - tpt = curr_tbl->expected_tpt[rs_index]; - else - tpt = 0; - if (info->flags & IEEE80211_TX_STAT_AMPDU) - rs_collect_tx_data(window, rs_index, tpt, - info->status.ampdu_ack_len, - info->status.ampdu_ack_map); - else - rs_collect_tx_data(window, rs_index, tpt, - 1, status); - } + retries = info->status.rates[0].count - 1; + /* HW doesn't send more than 15 retries */ + retries = min(retries, 15); + + /* The last transmission may have been successful */ + legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); + /* Collect data for each rate used during failed TX attempts */ + for (i = 0; i <= retries; ++i) { + tx_rate = le32_to_cpu(table->rs_table[i].rate_n_flags); + rs_get_tbl_info_from_mcs(tx_rate, priv->band, + &tbl_type, &rs_index); + /* + * Only collect stats if retried rate is in the same RS + * table as active/search. + */ + if (table_type_matches(&tbl_type, curr_tbl)) + tpt = get_expected_tpt(curr_tbl, rs_index); + else if (table_type_matches(&tbl_type, other_tbl)) + tpt = get_expected_tpt(other_tbl, rs_index); + else + continue; - /* If not searching for new mode, increment success/failed counter - * ... these help determine when to start searching again */ - if (lq_sta->stay_in_tbl) { - if (info->flags & IEEE80211_TX_STAT_AMPDU) { - lq_sta->total_success += info->status.ampdu_ack_map; - lq_sta->total_failed += - (info->status.ampdu_ack_len - info->status.ampdu_ack_map); - } else { - if (status) - lq_sta->total_success++; + /* Constants mean 1 transmission, 0 successes */ + if (i < retries) + rs_collect_tx_data(window, rs_index, tpt, 1, + 0); else - lq_sta->total_failed++; + rs_collect_tx_data(window, rs_index, tpt, 1, + legacy_success); + } + + /* Update success/fail counts if not searching for new mode */ + if (lq_sta->stay_in_tbl) { + lq_sta->total_success += legacy_success; + lq_sta->total_failed += retries + (1 - legacy_success); } } + /* The last TX rate is cached in lq_sta; it's set in if/else above */ + lq_sta->last_rate_n_flags = tx_rate; /* See if there's a better rate or modulation mode to try. */ if (sta && sta->supp_rates[sband->band]) rs_rate_scale_perform(priv, skb, sta, lq_sta); -out: - return; } /* -- cgit v1.2.3 From 91a55ae60168847c3c8ab348f10d517407052b71 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 17 Sep 2009 10:43:49 -0700 Subject: iwlwifi: do not clear TX info flags when receiving BlockAckResponse OR-in AMPDU flags rather than assigning them. This lets the TX status for aggregated packets be processed by rs_tx_status. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index c18907544701..ad69479376a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1400,7 +1400,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]); memset(&info->status, 0, sizeof(info->status)); - info->flags = IEEE80211_TX_STAT_ACK; + info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_AMPDU; info->status.ampdu_ack_map = successes; info->status.ampdu_ack_len = agg->frame_count; -- cgit v1.2.3 From e3949d62861b3fdef19e80080d670aa1153a23c4 Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Thu, 17 Sep 2009 10:43:50 -0700 Subject: iwlwifi: add aggregation tables to the rate scaling algorithm Current rate scale algorithm fluctuates between different MIMO modes fairly rapidly, causing widely varying performance. These fluctuations occur because in the rate_scale tables for expected throughput the values are not very different for different modes. However, when aggregation is turned on and MAC overhead is reduced, the expected throughput for different MIMO modes grows and different modes have vastly different performance. Add expected throughput tables for this case. We also need to keep track of aggregation status per-station, so we add the "is_agg" field to struct lq_sta. Also includes cleanup of comments and variable names in/around the affected code. Signed-off-by: Daniel C Halperin Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 223 +++++++++++++++--------------- 1 file changed, 115 insertions(+), 108 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index cd24763d5fde..e6c35e07f41b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -171,6 +171,8 @@ struct iwl_lq_sta { int last_txrate_idx; /* last tx rate_n_flags */ u32 last_rate_n_flags; + /* packets destined for this STA are aggregated */ + u8 is_agg; }; static void rs_rate_scale_perform(struct iwl_priv *priv, @@ -190,84 +192,78 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, {} #endif -/* - * Expected throughput metrics for following rates: - * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits - * "G" is the only table that supports CCK (the first 4 rates). +/** + * The following tables contain the expected throughput metrics for all rates + * + * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits + * + * where invalid entries are zeros. + * + * CCK rates are only valid in legacy table and will only be used in G + * (2.4 GHz) band. */ -static s32 expected_tpt_A[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 -}; - -static s32 expected_tpt_G[IWL_RATE_COUNT] = { - 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186 -}; - -static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202 -}; - -static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211 -}; - -static s32 expected_tpt_mimo2_20MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251 -}; - -static s32 expected_tpt_mimo2_20MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257 +static s32 expected_tpt_legacy[IWL_RATE_COUNT] = { + 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0 }; -static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257 +static s32 expected_tpt_siso20MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 42, 0, 76, 102, 124, 158, 183, 193, 202}, /* Norm */ + {0, 0, 0, 0, 46, 0, 82, 110, 132, 167, 192, 202, 210}, /* SGI */ + {0, 0, 0, 0, 48, 0, 93, 135, 176, 251, 319, 351, 381}, /* AGG */ + {0, 0, 0, 0, 53, 0, 102, 149, 193, 275, 348, 381, 413}, /* AGG+SGI */ }; -static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264 +static s32 expected_tpt_siso40MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257}, /* Norm */ + {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264}, /* SGI */ + {0, 0, 0, 0, 96, 0, 182, 259, 328, 451, 553, 598, 640}, /* AGG */ + {0, 0, 0, 0, 106, 0, 199, 282, 357, 487, 593, 640, 683}, /* AGG+SGI */ }; -static s32 expected_tpt_mimo2_40MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289 +static s32 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250}, /* Norm */ + {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256}, /* SGI */ + {0, 0, 0, 0, 92, 0, 175, 250, 317, 436, 534, 578, 619}, /* AGG */ + {0, 0, 0, 0, 102, 0, 192, 273, 344, 470, 573, 619, 660}, /* AGG+SGI*/ }; -static s32 expected_tpt_mimo2_40MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 +static s32 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289}, /* Norm */ + {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293}, /* SGI */ + {0, 0, 0, 0, 180, 0, 327, 446, 545, 708, 828, 878, 922}, /* AGG */ + {0, 0, 0, 0, 197, 0, 355, 481, 584, 752, 872, 922, 966}, /* AGG+SGI */ }; -/* Expected throughput metric MIMO3 */ -static s32 expected_tpt_mimo3_20MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 99, 99, 153, 186, 208, 239, 256, 263, 268 +static s32 expected_tpt_mimo3_20MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 99, 0, 153, 186, 208, 239, 256, 263, 268}, /* Norm */ + {0, 0, 0, 0, 106, 0, 162, 194, 215, 246, 262, 268, 273}, /* SGI */ + {0, 0, 0, 0, 134, 0, 249, 346, 431, 574, 685, 732, 775}, /* AGG */ + {0, 0, 0, 0, 148, 0, 272, 376, 465, 614, 727, 775, 818}, /* AGG+SGI */ }; -static s32 expected_tpt_mimo3_20MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 106, 106, 162, 194, 215, 246, 262, 268, 273 -}; - -static s32 expected_tpt_mimo3_40MHz[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 152, 152, 211, 239, 255, 279, 290, 294, 297 -}; - -static s32 expected_tpt_mimo3_40MHzSGI[IWL_RATE_COUNT] = { - 0, 0, 0, 0, 160, 160, 219, 245, 261, 284, 294, 297, 300 +static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { + {0, 0, 0, 0, 152, 0, 211, 239, 255, 279, 290, 294, 297}, /* Norm */ + {0, 0, 0, 0, 160, 0, 219, 245, 261, 284, 294, 297, 300}, /* SGI */ + {0, 0, 0, 0, 254, 0, 443, 584, 695, 868, 984, 1030, 1070}, /* AGG */ + {0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */ }; /* mbps, mcs */ const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { - {"1", ""}, - {"2", ""}, - {"5.5", ""}, - {"11", ""}, - {"6", "BPSK 1/2"}, - {"9", "BPSK 1/2"}, - {"12", "QPSK 1/2"}, - {"18", "QPSK 3/4"}, - {"24", "16QAM 1/2"}, - {"36", "16QAM 3/4"}, - {"48", "64QAM 2/3"}, - {"54", "64QAM 3/4"}, - {"60", "64QAM 5/6"} + { "1", "BPSK DSSS"}, + { "2", "QPSK DSSS"}, + {"5.5", "BPSK CCK"}, + { "11", "QPSK CCK"}, + { "6", "BPSK 1/2"}, + { "9", "BPSK 1/2"}, + { "12", "QPSK 1/2"}, + { "18", "QPSK 3/4"}, + { "24", "16QAM 1/2"}, + { "36", "16QAM 3/4"}, + { "48", "64QAM 2/3"}, + { "54", "64QAM 3/4"}, + { "60", "64QAM 5/6"}, }; #define MCS_INDEX_PER_STREAM (8) @@ -444,7 +440,7 @@ static inline int get_num_of_ant_from_rate(u32 rate_n_flags) * packets. */ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, - int scale_index, s32 tpt, int retries, + int scale_index, s32 tpt, int attempts, int successes) { struct iwl_rate_scale_data *window = NULL; @@ -454,7 +450,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) return -EINVAL; - /* Select data for current tx bit rate */ + /* Select window for current tx bit rate */ window = &(windows[scale_index]); /* @@ -465,7 +461,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, * subtract "1" from the success counter (this is the main reason * we keep these bitmaps!). */ - while (retries > 0) { + while (attempts > 0) { if (window->counter >= IWL_RATE_MAX_WINDOW) { /* remove earliest */ @@ -480,17 +476,17 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, /* Increment frames-attempted counter */ window->counter++; - /* Shift bitmap by one frame (throw away oldest history), - * OR in "1", and increment "success" if this - * frame was successful. */ + /* Shift bitmap by one frame to throw away oldest history */ window->data <<= 1; + + /* Mark the most recent #successes attempts as successful */ if (successes > 0) { window->success_counter++; window->data |= 0x1; successes--; } - retries--; + attempts--; } /* Calculate current success ratio, avoid divide-by-0! */ @@ -868,12 +864,11 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, info->flags & IEEE80211_TX_CTL_NO_ACK) return; - /* This packet was aggregated but doesn't carry rate scale info */ + /* This packet was aggregated but doesn't carry status info */ if ((info->flags & IEEE80211_TX_CTL_AMPDU) && !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) return; @@ -1052,43 +1047,45 @@ static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy, static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl) { + /* Used to choose among HT tables */ + s32 (*ht_tbl_pointer)[IWL_RATE_COUNT]; + + /* Check for invalid LQ type */ + if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_Ht(tbl->lq_type))) { + tbl->expected_tpt = expected_tpt_legacy; + return; + } + + /* Legacy rates have only one table */ if (is_legacy(tbl->lq_type)) { - if (!is_a_band(tbl->lq_type)) - tbl->expected_tpt = expected_tpt_G; - else - tbl->expected_tpt = expected_tpt_A; - } else if (is_siso(tbl->lq_type)) { - if (tbl->is_ht40 && !lq_sta->is_dup) - if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_siso40MHzSGI; - else - tbl->expected_tpt = expected_tpt_siso40MHz; - else if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_siso20MHzSGI; - else - tbl->expected_tpt = expected_tpt_siso20MHz; - } else if (is_mimo2(tbl->lq_type)) { - if (tbl->is_ht40 && !lq_sta->is_dup) - if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo2_40MHzSGI; - else - tbl->expected_tpt = expected_tpt_mimo2_40MHz; - else if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo2_20MHzSGI; - else - tbl->expected_tpt = expected_tpt_mimo2_20MHz; - } else if (is_mimo3(tbl->lq_type)) { - if (tbl->is_ht40 && !lq_sta->is_dup) - if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo3_40MHzSGI; - else - tbl->expected_tpt = expected_tpt_mimo3_40MHz; - else if (tbl->is_SGI) - tbl->expected_tpt = expected_tpt_mimo3_20MHzSGI; - else - tbl->expected_tpt = expected_tpt_mimo3_20MHz; - } else - tbl->expected_tpt = expected_tpt_G; + tbl->expected_tpt = expected_tpt_legacy; + return; + } + + /* Choose among many HT tables depending on number of streams + * (SISO/MIMO2/MIMO3), channel width (20/40), SGI, and aggregation + * status */ + if (is_siso(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup)) + ht_tbl_pointer = expected_tpt_siso20MHz; + else if (is_siso(tbl->lq_type)) + ht_tbl_pointer = expected_tpt_siso40MHz; + else if (is_mimo2(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup)) + ht_tbl_pointer = expected_tpt_mimo2_20MHz; + else if (is_mimo2(tbl->lq_type)) + ht_tbl_pointer = expected_tpt_mimo2_40MHz; + else if (is_mimo3(tbl->lq_type) && (!tbl->is_ht40 || lq_sta->is_dup)) + ht_tbl_pointer = expected_tpt_mimo3_20MHz; + else /* if (is_mimo3(tbl->lq_type)) <-- must be true */ + ht_tbl_pointer = expected_tpt_mimo3_40MHz; + + if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */ + tbl->expected_tpt = ht_tbl_pointer[0]; + else if (tbl->is_SGI && !lq_sta->is_agg) /* SGI */ + tbl->expected_tpt = ht_tbl_pointer[1]; + else if (!tbl->is_SGI && lq_sta->is_agg) /* AGG */ + tbl->expected_tpt = ht_tbl_pointer[2]; + else /* AGG+SGI */ + tbl->expected_tpt = ht_tbl_pointer[3]; } /* @@ -2063,6 +2060,14 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; tid = rs_tl_add_packet(lq_sta, hdr); + if ((tid != MAX_TID_COUNT) && (lq_sta->tx_agg_tid_en & (1 << tid))) { + tid_data = &priv->stations[lq_sta->lq.sta_id].tid[tid]; + if (tid_data->agg.state == IWL_AGG_OFF) + lq_sta->is_agg = 0; + else + lq_sta->is_agg = 1; + } else + lq_sta->is_agg = 0; /* * Select rate-scale / modulation-mode table to work with in @@ -2163,10 +2168,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, goto out; } - /* Else we have enough samples; calculate estimate of * actual average throughput */ + /* Sanity-check TPT calculations */ BUG_ON(window->average_tpt != ((window->success_ratio * tbl->expected_tpt[index] + 64) / 128)); @@ -2676,6 +2681,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->last_txrate_idx = rate_lowest_index(sband, sta); if (sband->band == IEEE80211_BAND_5GHZ) lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + lq_sta->is_agg = 0; rs_initialize_lq(priv, conf, sta, lq_sta); } @@ -2928,8 +2934,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); desc += sprintf(buff+desc, " %s", (tbl->is_ht40) ? "40MHz" : "20MHz"); - desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "", - (lq_sta->is_green) ? "GF enabled" : ""); + desc += sprintf(buff+desc, " %s %s %s\n", (tbl->is_SGI) ? "SGI" : "", + (lq_sta->is_green) ? "GF enabled" : "", + (lq_sta->is_agg) ? "AGG on" : ""); } desc += sprintf(buff+desc, "last tx rate=0x%X\n", lq_sta->last_rate_n_flags); -- cgit v1.2.3 From 2f748deceee10bac563df0e859830cc628d1a841 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:51 -0700 Subject: iwlwifi: send cmd to uCode to configure valid tx antenna In order for uCode to select the valid antennas for transmit, driver need to configure the allowed tx antennas through host command. The TX_ANT_CONFIGURATION_CMD should be used for 5000 series and up Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 19 +++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-commands.h | 12 +++++++++++- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 75fa55db330e..68d97f50fd00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1450,6 +1450,24 @@ int iwl5000_calc_rssi(struct iwl_priv *priv, return max_rssi - agc - IWL49_RSSI_OFFSET; } +static int iwl5000_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) +{ + struct iwl_tx_ant_config_cmd tx_ant_cmd = { + .valid = cpu_to_le32(valid_tx_ant), + }; + + if (IWL_UCODE_API(priv->ucode_ver) > 1) { + IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant); + return iwl_send_cmd_pdu(priv, TX_ANT_CONFIGURATION_CMD, + sizeof(struct iwl_tx_ant_config_cmd), + &tx_ant_cmd); + } else { + IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n"); + return -EOPNOTSUPP; + } +} + + #define IWL5000_UCODE_GET(item) \ static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\ u32 api_ver) \ @@ -1492,6 +1510,7 @@ struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, .set_rxon_chain = iwl_set_rxon_chain, + .set_tx_ant = iwl5000_send_tx_ant_config, }; struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index cf2b481dca6d..5505878dcaf7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1762,6 +1762,10 @@ static void iwl_alive_start(struct iwl_priv *priv) priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + /* Configure Tx antenna selection based on H/W config */ + if (priv->cfg->ops->hcmd->set_tx_ant) + priv->cfg->ops->hcmd->set_tx_ant(priv, priv->cfg->valid_tx_ant); + if (iwl_is_associated(priv)) { struct iwl_rxon_cmd *active_rxon = (struct iwl_rxon_cmd *)&priv->active_rxon; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 2c5c88fc38f5..e5f40f35dc3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -148,7 +148,7 @@ enum { QUIET_NOTIFICATION = 0x96, /* not used */ REPLY_TX_PWR_TABLE_CMD = 0x97, REPLY_TX_POWER_DBM_CMD_V1 = 0x98, /* old version of API */ - TX_ANT_CONFIGURATION_CMD = 0x98, /* not used */ + TX_ANT_CONFIGURATION_CMD = 0x98, MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ /* Bluetooth device coexistence config command */ @@ -411,6 +411,16 @@ struct iwl5000_tx_power_dbm_cmd { u8 reserved; } __attribute__ ((packed)); +/** + * Command TX_ANT_CONFIGURATION_CMD = 0x98 + * This command is used to configure valid Tx antenna. + * By default uCode concludes the valid antenna according to the radio flavor. + * This command enables the driver to override/modify this conclusion. + */ +struct iwl_tx_ant_config_cmd { + __le32 valid; +} __attribute__ ((packed)); + /****************************************************************************** * (0a) * Alive and Error Commands & Responses: diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index c7675c387140..f094cd9de443 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -89,6 +89,7 @@ struct iwl_hcmd_ops { int (*rxon_assoc)(struct iwl_priv *priv); int (*commit_rxon)(struct iwl_priv *priv); void (*set_rxon_chain)(struct iwl_priv *priv); + int (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant); }; struct iwl_hcmd_utils_ops { -- cgit v1.2.3 From 4bd0914fa2a09d655c54fb0355aed7f9182b2187 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:52 -0700 Subject: iwlwifi: update PCI Subsystem ID for 1000 series Update PCI Subsystem ID for 1000 series based on HW SKU. Adding new SKU for "BG" only devices. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 20 ++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 14 ++++++++++++-- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 879b3753a3bd..3b3e6bc74ba9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -167,3 +167,23 @@ struct iwl_cfg iwl1000_bgn_cfg = { .led_compensation = 51, }; +struct iwl_cfg iwl1000_bg_cfg = { + .name = "1000 Series BG", + .fw_name_pre = IWL1000_FW_PRE, + .ucode_api_max = IWL1000_UCODE_API_MAX, + .ucode_api_min = IWL1000_UCODE_API_MIN, + .sku = IWL_SKU_G, + .ops = &iwl1000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_1000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_AB, + .need_pll_cfg = true, + .max_ll_items = OTP_MAX_LL_ITEMS_1000, + .shadow_ram_support = false, + .ht_greenfield_support = true, + .led_compensation = 51, +}; + diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 5505878dcaf7..0c95b0ec5fb3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3270,8 +3270,18 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x0088, PCI_ANY_ID, iwl6050_3agn_cfg)}, {IWL_PCI_DEVICE(0x0089, PCI_ANY_ID, iwl6050_2agn_cfg)}, /* 1000 Series WiFi */ - {IWL_PCI_DEVICE(0x0083, PCI_ANY_ID, iwl1000_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0084, PCI_ANY_ID, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1305, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1225, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1325, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0084, 0x1215, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0084, 0x1315, iwl1000_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1206, iwl1000_bg_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1306, iwl1000_bg_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1226, iwl1000_bg_cfg)}, + {IWL_PCI_DEVICE(0x0083, 0x1326, iwl1000_bg_cfg)}, + {IWL_PCI_DEVICE(0x0084, 0x1216, iwl1000_bg_cfg)}, + {IWL_PCI_DEVICE(0x0084, 0x1316, iwl1000_bg_cfg)}, #endif /* CONFIG_IWL5000 */ {0} diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0c80692f934b..cca4c6a4b060 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -62,6 +62,7 @@ extern struct iwl_cfg iwl6000_3agn_cfg; extern struct iwl_cfg iwl6050_2agn_cfg; extern struct iwl_cfg iwl6050_3agn_cfg; extern struct iwl_cfg iwl1000_bgn_cfg; +extern struct iwl_cfg iwl1000_bg_cfg; struct iwl_tx_queue; -- cgit v1.2.3 From 5953a62e7df064a5d7ba7e790d590f27c65ddf4c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:53 -0700 Subject: iwlwifi: update PCI Subsystem ID for 6000 series Update PCI Subsystem ID for 60x0 series based on HW SKU. Adding new SKU for "ABG" and "BG" only devices. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 105 ++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 43 +++++++++---- drivers/net/wireless/iwlwifi/iwl-dev.h | 5 ++ 3 files changed, 142 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 0d2cbab1f7d2..01a1f81cba2a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -262,6 +262,48 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ }; +struct iwl_cfg iwl6000h_2abg_cfg = { + .name = "6000 Series 2x2 ABG", + .fw_name_pre = IWL6000_FW_PRE, + .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_min = IWL6000_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G, + .ops = &iwl6000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, + .need_pll_cfg = false, + .pa_type = IWL_PA_HYBRID, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, + .led_compensation = 51, +}; + +struct iwl_cfg iwl6000h_2bg_cfg = { + .name = "6000 Series 2x2 BG", + .fw_name_pre = IWL6000_FW_PRE, + .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_min = IWL6000_UCODE_API_MIN, + .sku = IWL_SKU_G, + .ops = &iwl6000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, + .need_pll_cfg = false, + .pa_type = IWL_PA_HYBRID, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, + .led_compensation = 51, +}; + /* * "i": Internal configuration, use internal Power Amplifier */ @@ -287,6 +329,48 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ }; +struct iwl_cfg iwl6000i_2abg_cfg = { + .name = "6000 Series 2x2 ABG", + .fw_name_pre = IWL6000_FW_PRE, + .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_min = IWL6000_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G, + .ops = &iwl6000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_BC, + .valid_rx_ant = ANT_BC, + .need_pll_cfg = false, + .pa_type = IWL_PA_INTERNAL, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, + .led_compensation = 51, +}; + +struct iwl_cfg iwl6000i_2bg_cfg = { + .name = "6000 Series 2x2 BG", + .fw_name_pre = IWL6000_FW_PRE, + .ucode_api_max = IWL6000_UCODE_API_MAX, + .ucode_api_min = IWL6000_UCODE_API_MIN, + .sku = IWL_SKU_G, + .ops = &iwl6000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_BC, + .valid_rx_ant = ANT_BC, + .need_pll_cfg = false, + .pa_type = IWL_PA_INTERNAL, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, + .led_compensation = 51, +}; + struct iwl_cfg iwl6050_2agn_cfg = { .name = "6050 Series 2x2 AGN", .fw_name_pre = IWL6050_FW_PRE, @@ -309,6 +393,27 @@ struct iwl_cfg iwl6050_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ }; +struct iwl_cfg iwl6050_2abg_cfg = { + .name = "6050 Series 2x2 ABG", + .fw_name_pre = IWL6050_FW_PRE, + .ucode_api_max = IWL6050_UCODE_API_MAX, + .ucode_api_min = IWL6050_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G, + .ops = &iwl6000_ops, + .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, + .need_pll_cfg = false, + .pa_type = IWL_PA_SYSTEM, + .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .shadow_ram_support = true, + .ht_greenfield_support = true, + .led_compensation = 51, +}; + struct iwl_cfg iwl6000_3agn_cfg = { .name = "6000 Series 3x3 AGN", .fw_name_pre = IWL6000_FW_PRE, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0c95b0ec5fb3..26c66b4ffd60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3258,17 +3258,38 @@ static struct pci_device_id iwl_hw_card_ids[] = { /* 5150 Wifi/WiMax */ {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)}, {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, -/* 6000/6050 Series */ - {IWL_PCI_DEVICE(0x008D, PCI_ANY_ID, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x008E, PCI_ANY_ID, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x422B, PCI_ANY_ID, iwl6000_3agn_cfg)}, - {IWL_PCI_DEVICE(0x422C, PCI_ANY_ID, iwl6000i_2agn_cfg)}, - {IWL_PCI_DEVICE(0x4238, PCI_ANY_ID, iwl6000_3agn_cfg)}, - {IWL_PCI_DEVICE(0x4239, PCI_ANY_ID, iwl6000i_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0086, PCI_ANY_ID, iwl6050_3agn_cfg)}, - {IWL_PCI_DEVICE(0x0087, PCI_ANY_ID, iwl6050_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0088, PCI_ANY_ID, iwl6050_3agn_cfg)}, - {IWL_PCI_DEVICE(0x0089, PCI_ANY_ID, iwl6050_2agn_cfg)}, + +/* 6x00 Series */ + {IWL_PCI_DEVICE(0x008D, 0x1301, iwl6000h_2agn_cfg)}, + {IWL_PCI_DEVICE(0x008D, 0x1321, iwl6000h_2agn_cfg)}, + {IWL_PCI_DEVICE(0x008D, 0x1326, iwl6000h_2abg_cfg)}, + {IWL_PCI_DEVICE(0x008D, 0x1306, iwl6000h_2abg_cfg)}, + {IWL_PCI_DEVICE(0x008D, 0x1307, iwl6000h_2bg_cfg)}, + {IWL_PCI_DEVICE(0x008E, 0x1311, iwl6000h_2agn_cfg)}, + {IWL_PCI_DEVICE(0x008E, 0x1316, iwl6000h_2abg_cfg)}, + + {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)}, + {IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)}, + {IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)}, + {IWL_PCI_DEVICE(0x422C, 0x1306, iwl6000i_2abg_cfg)}, + {IWL_PCI_DEVICE(0x422C, 0x1307, iwl6000i_2bg_cfg)}, + {IWL_PCI_DEVICE(0x422C, 0x1321, iwl6000i_2agn_cfg)}, + {IWL_PCI_DEVICE(0x422C, 0x1326, iwl6000i_2abg_cfg)}, + {IWL_PCI_DEVICE(0x4238, 0x1111, iwl6000_3agn_cfg)}, + {IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)}, + {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)}, + +/* 6x50 WiFi/WiMax Series */ + {IWL_PCI_DEVICE(0x0086, 0x1101, iwl6050_3agn_cfg)}, + {IWL_PCI_DEVICE(0x0086, 0x1121, iwl6050_3agn_cfg)}, + {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)}, + {IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)}, + {IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)}, + {IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)}, + {IWL_PCI_DEVICE(0x0088, 0x1111, iwl6050_3agn_cfg)}, + {IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)}, + {IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)}, + /* 1000 Series WiFi */ {IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)}, {IWL_PCI_DEVICE(0x0083, 0x1305, iwl1000_bgn_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cca4c6a4b060..3ea97be7f6b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -57,9 +57,14 @@ extern struct iwl_cfg iwl5100_bg_cfg; extern struct iwl_cfg iwl5100_abg_cfg; extern struct iwl_cfg iwl5150_agn_cfg; extern struct iwl_cfg iwl6000h_2agn_cfg; +extern struct iwl_cfg iwl6000h_2abg_cfg; +extern struct iwl_cfg iwl6000h_2bg_cfg; extern struct iwl_cfg iwl6000i_2agn_cfg; +extern struct iwl_cfg iwl6000i_2abg_cfg; +extern struct iwl_cfg iwl6000i_2bg_cfg; extern struct iwl_cfg iwl6000_3agn_cfg; extern struct iwl_cfg iwl6050_2agn_cfg; +extern struct iwl_cfg iwl6050_2abg_cfg; extern struct iwl_cfg iwl6050_3agn_cfg; extern struct iwl_cfg iwl1000_bgn_cfg; extern struct iwl_cfg iwl1000_bg_cfg; -- cgit v1.2.3 From 02f5dac08364d01a8b2c8e298b529b97f356b3f5 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 17 Sep 2009 10:43:54 -0700 Subject: iwlwifi: add LED mode to support different LED behavior Today's implementation allow LED to blink based on the traffic condition. We introduce an additional LED mode that reflects the RF state. The supported LED modes after this are: IWL_LED_BLINK (current/default) - blink rate based on current Tx/Rx traffic IWL_LED_RF_STATE (new) - LED OFF: No power/RF disabled, the LED is emitting no light LED ON: Powered/RF enabled, the LED is emitting light in a stable non-flashing state. In order to provide the flexibility to support different LED behavior per user/system preference we add "led_mode" iwlcore module parameter. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-led.c | 9 ++++++++- drivers/net/wireless/iwlwifi/iwl-led.h | 12 ++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index f547233c5b79..685ba9d6f082 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -42,6 +42,12 @@ #include "iwl-core.h" #include "iwl-io.h" +/* default: IWL_LED_BLINK(0) using blinking index table */ +static int led_mode; +module_param(led_mode, int, S_IRUGO); +MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), " + "(default 0)\n"); + #ifdef CONFIG_IWLWIFI_DEBUG static const char *led_type_str[] = { __stringify(IWL_LED_TRG_TX), @@ -199,7 +205,8 @@ static int iwl_led_off_reg(struct iwl_priv *priv, int led_id) static int iwl_led_associate(struct iwl_priv *priv, int led_id) { IWL_DEBUG_LED(priv, "Associated\n"); - priv->allow_blinking = 1; + if (led_mode == IWL_LED_BLINK) + priv->allow_blinking = 1; return iwl_led_on_reg(priv, led_id); } static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index ef9b174c37ff..dd76b266c633 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -47,6 +47,18 @@ enum led_type { IWL_LED_TRG_RADIO, IWL_LED_TRG_MAX, }; + +/* + * LED mode + * IWL_LED_BLINK: adjust led blink rate based on blink table + * IWL_LED_RF_STATE: turn LED on/off based on RF state + * LED ON = RF ON + * LED OFF = RF OFF + */ +enum iwl_led_mode { + IWL_LED_BLINK, + IWL_LED_RF_STATE, +}; #endif #ifdef CONFIG_IWLWIFI_LEDS -- cgit v1.2.3 From 9bddbab36d736c181678e07515aaa63045bdcea7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Sep 2009 14:24:24 -0700 Subject: iwlwifi: fix a typo We never have four chains, but let's fix the typo while we noticed it. You count 0, 1, 2, 3, not 0, 1, 2, 4 :) Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2908bff49a3b..5ff0f66f8aa1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -984,7 +984,7 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap) res = (chain_bitmap & BIT(0)) >> 0; res += (chain_bitmap & BIT(1)) >> 1; res += (chain_bitmap & BIT(2)) >> 2; - res += (chain_bitmap & BIT(4)) >> 4; + res += (chain_bitmap & BIT(3)) >> 3; return res; } -- cgit v1.2.3 From 2b396a120922062a0ffd2648be3ed7e72ff83620 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Sep 2009 14:24:25 -0700 Subject: iwlwifi: default to using all chains When instructing the microcode to use just a single chain when we have power saving enabled, we should also tell the AP that we are doing SM powersave. However, using a single chain doesn't actually have any power saving advantage while idle -- measurements show that the power consumption is no different when using one vs. two or three chains. Therefore, always instruct the microcode to use all chains. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5ff0f66f8aa1..e97b104ba1d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -948,8 +948,13 @@ EXPORT_SYMBOL(iwl_set_rxon_ht); #define IWL_NUM_IDLE_CHAINS_DUAL 2 #define IWL_NUM_IDLE_CHAINS_SINGLE 1 -/* Determine how many receiver/antenna chains to use. - * More provides better reception via diversity. Fewer saves power. +/* + * Determine how many receiver/antenna chains to use. + * + * More provides better reception via diversity. Fewer saves power + * at the expense of throughput, but only when not in powersave to + * start with. + * * MIMO (dual stream) requires at least 2, but works better with 3. * This does not determine *which* chains to use, just how many. */ @@ -962,19 +967,18 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) return IWL_NUM_RX_CHAINS_MULTIPLE; } +/* + * When we are in power saving, there's no difference between + * using multiple chains or just a single chain, but due to the + * lack of SM PS we lose a lot of throughput if we use just a + * single chain. + * + * Therefore, use the active count here (which will use multiple + * chains unless connected to a legacy AP). + */ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) { - bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); - - /* # Rx chains when idling and maybe trying to save power */ - - /* - * XXX: this is incorrect!! - * we always indicate to the AP that - * our SM PS mode is "disabled" - */ - - return is_cam ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; + return active_cnt; } /* up to 4 chains */ -- cgit v1.2.3 From d8c07e7a84950b5fdef424c6dabe6bed3a9ffa19 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 25 Sep 2009 14:24:26 -0700 Subject: iwlwifi: Chain Noise Calibration for 6000 series Adding support of Chain Noise Calibration for 6000 series NICs. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 + drivers/net/wireless/iwlwifi/iwl-4965.c | 6 ++- drivers/net/wireless/iwlwifi/iwl-5000.c | 15 ++++++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 19 ++++++---- drivers/net/wireless/iwlwifi/iwl-calib.c | 64 ++++++++++++++++++++++---------- drivers/net/wireless/iwlwifi/iwl-core.h | 5 ++- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 +- 7 files changed, 80 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 3b3e6bc74ba9..9dfd4c407efb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -165,6 +165,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .shadow_ram_support = false, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl1000_bg_cfg = { @@ -185,5 +186,6 @@ struct iwl_cfg iwl1000_bg_cfg = { .shadow_ram_support = false, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b5111702856a..4e492c154f88 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -495,14 +495,15 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv) static void iwl4965_gain_computation(struct iwl_priv *priv, u32 *average_noise, u16 min_average_noise_antenna_i, - u32 min_average_noise) + u32 min_average_noise, + u8 default_chain) { int i, ret; struct iwl_chain_noise_data *data = &priv->chain_noise_data; data->delta_gain_code[min_average_noise_antenna_i] = 0; - for (i = 0; i < NUM_RX_CHAINS; i++) { + for (i = default_chain; i < NUM_RX_CHAINS; i++) { s32 delta_g = 0; if (!(data->disconn_array[i]) && @@ -2356,6 +2357,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .ht_greenfield_support = false, .broken_powersave = true, .led_compensation = 61, + .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 68d97f50fd00..660fd51d190b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -301,14 +301,17 @@ u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv) static void iwl5000_gain_computation(struct iwl_priv *priv, u32 average_noise[NUM_RX_CHAINS], u16 min_average_noise_antenna_i, - u32 min_average_noise) + u32 min_average_noise, + u8 default_chain) { int i; s32 delta_g; struct iwl_chain_noise_data *data = &priv->chain_noise_data; - /* Find Gain Code for the antennas B and C */ - for (i = 1; i < NUM_RX_CHAINS; i++) { + /* + * Find Gain Code for the chains based on "default chain" + */ + for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) { if ((data->disconn_array[i])) { data->delta_gain_code[i] = 0; continue; @@ -1676,6 +1679,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl5100_bg_cfg = { @@ -1694,6 +1698,7 @@ struct iwl_cfg iwl5100_bg_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl5100_abg_cfg = { @@ -1712,6 +1717,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl5100_agn_cfg = { @@ -1730,6 +1736,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1748,6 +1755,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1766,6 +1774,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .need_pll_cfg = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 01a1f81cba2a..ad5d77c96494 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -222,18 +222,11 @@ static struct iwl_lib_ops iwl6000_lib = { }, }; -static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = { - .get_hcmd_size = iwl5000_get_hcmd_size, - .build_addsta_hcmd = iwl5000_build_addsta_hcmd, - .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag, - .calc_rssi = iwl5000_calc_rssi, -}; - static struct iwl_ops iwl6000_ops = { .ucode = &iwl5000_ucode, .lib = &iwl6000_lib, .hcmd = &iwl5000_hcmd, - .utils = &iwl6000_hcmd_utils, + .utils = &iwl5000_hcmd_utils, }; @@ -260,6 +253,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6000h_2abg_cfg = { @@ -281,6 +275,7 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6000h_2bg_cfg = { @@ -302,6 +297,7 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; /* @@ -327,6 +323,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -348,6 +345,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -369,6 +367,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -391,6 +390,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -412,6 +412,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -434,6 +435,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -456,6 +458,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 6e73317c3b40..69a80d7c2e44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -643,6 +643,15 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_sensitivity_calibration); +static inline u8 find_first_chain(u8 mask) +{ + if (mask & ANT_A) + return CHAIN_A; + if (mask & ANT_B) + return CHAIN_B; + return CHAIN_C; +} + /* * Accumulate 20 beacons of signal and noise statistics for each of * 3 receivers/antennas/rx-chains, then figure out: @@ -675,14 +684,17 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, u8 num_tx_chains; unsigned long flags; struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general); + u8 first_chain; if (priv->disable_chain_noise_cal) return; data = &(priv->chain_noise_data); - /* Accumulate just the first 20 beacons after the first association, - * then we're done forever. */ + /* + * Accumulate just the first "chain_noise_num_beacons" after + * the first association, then we're done forever. + */ if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) { if (data->state == IWL_CHAIN_NOISE_ALIVE) IWL_DEBUG_CALIB(priv, "Wait for noise calib reset\n"); @@ -710,7 +722,10 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, return; } - /* Accumulate beacon statistics values across 20 beacons */ + /* + * Accumulate beacon statistics values across + * "chain_noise_num_beacons" + */ chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) & @@ -741,16 +756,19 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, IWL_DEBUG_CALIB(priv, "chain_noise: a %d b %d c %d\n", chain_noise_a, chain_noise_b, chain_noise_c); - /* If this is the 20th beacon, determine: + /* If this is the "chain_noise_num_beacons", determine: * 1) Disconnected antennas (using signal strengths) * 2) Differential gain (using silence noise) to balance receivers */ - if (data->beacon_count != CAL_NUM_OF_BEACONS) + if (data->beacon_count != priv->cfg->chain_noise_num_beacons) return; /* Analyze signal for disconnected antenna */ - average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS; - average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS; - average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS; + average_sig[0] = + (data->chain_signal_a) / priv->cfg->chain_noise_num_beacons; + average_sig[1] = + (data->chain_signal_b) / priv->cfg->chain_noise_num_beacons; + average_sig[2] = + (data->chain_signal_c) / priv->cfg->chain_noise_num_beacons; if (average_sig[0] >= average_sig[1]) { max_average_sig = average_sig[0]; @@ -803,13 +821,17 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, /* there is a Tx antenna connected */ break; if (num_tx_chains == priv->hw_params.tx_chains_num && - data->disconn_array[i]) { - /* This is the last TX antenna and is also - * disconnected connect it anyway */ - data->disconn_array[i] = 0; - active_chains |= ant_msk; - IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - " - "declare %d as connected\n", i); + data->disconn_array[i]) { + /* + * If all chains are disconnected + * connect the first valid tx chain + */ + first_chain = + find_first_chain(priv->cfg->valid_tx_ant); + data->disconn_array[first_chain] = 0; + active_chains |= BIT(first_chain); + IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - declare %d as connected\n", + first_chain); break; } } @@ -820,9 +842,12 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, active_chains); /* Analyze noise for rx balance */ - average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); - average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); - average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS); + average_noise[0] = + ((data->chain_noise_a) / priv->cfg->chain_noise_num_beacons); + average_noise[1] = + ((data->chain_noise_b) / priv->cfg->chain_noise_num_beacons); + average_noise[2] = + ((data->chain_noise_c) / priv->cfg->chain_noise_num_beacons); for (i = 0; i < NUM_RX_CHAINS; i++) { if (!(data->disconn_array[i]) && @@ -843,7 +868,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, if (priv->cfg->ops->utils->gain_computation) priv->cfg->ops->utils->gain_computation(priv, average_noise, - min_average_noise_antenna_i, min_average_noise); + min_average_noise_antenna_i, min_average_noise, + find_first_chain(priv->cfg->valid_rx_ant)); /* Some power changes may have been made during the calibration. * Update and commit the RXON diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f094cd9de443..b66bf7b4b0a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -98,7 +98,8 @@ struct iwl_hcmd_utils_ops { void (*gain_computation)(struct iwl_priv *priv, u32 *average_noise, u16 min_average_noise_antennat_i, - u32 min_average_noise); + u32 min_average_noise, + u8 default_chain); void (*chain_noise_reset)(struct iwl_priv *priv); void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info, __le32 *tx_flags); @@ -218,6 +219,7 @@ struct iwl_mod_params { * to the deviation to achieve the desired led frequency. * The detail algorithm is described in iwl-led.c * @use_rts_for_ht: use rts/cts protection for HT traffic + * @chain_noise_num_beacons: number of beacons used to compute chain noise * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -262,6 +264,7 @@ struct iwl_cfg { u16 led_compensation; const bool broken_powersave; bool use_rts_for_ht; + int chain_noise_num_beacons; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 3ea97be7f6b2..ad99ce7824c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -743,7 +743,8 @@ struct iwl_dma_ptr { /* Sensitivity and chain noise calibration */ #define INITIALIZATION_VALUE 0xFFFF -#define CAL_NUM_OF_BEACONS 20 +#define IWL4965_CAL_NUM_BEACONS 20 +#define IWL_CAL_NUM_BEACONS 16 #define MAXIMUM_ALLOWED_PATHLOSS 15 #define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3 -- cgit v1.2.3 From 78f5fb7fc6c2c668a12fd6892c18baa20e4ffd27 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Sep 2009 14:24:27 -0700 Subject: iwlwifi: support idle for 6000 series hw Using powersave while idle saves a lot of power, but we've had problems with this on some cards (5150 has been reported to be problematic). However, on the new 6000 series we're seeing no problems, so for now let that hardware benefit from idle mode, we can look at the problems with other hardware one by one and then enable those once we figure out the problems. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-power.c | 3 +++ 4 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index ad5d77c96494..6f4ee27e07c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -254,6 +254,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6000h_2abg_cfg = { @@ -276,6 +277,7 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6000h_2bg_cfg = { @@ -298,6 +300,7 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; /* @@ -324,6 +327,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -346,6 +350,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -368,6 +373,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -391,6 +397,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -413,6 +420,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -436,6 +444,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -459,6 +468,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .led_compensation = 51, .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .supports_idle = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e97b104ba1d5..1cf2e04fe3f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2650,7 +2650,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) iwl_set_rate(priv); } - if (changed & IEEE80211_CONF_CHANGE_PS) { + if (changed & (IEEE80211_CONF_CHANGE_PS | + IEEE80211_CONF_CHANGE_IDLE)) { ret = iwl_power_update_mode(priv, false); if (ret) IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b66bf7b4b0a4..744f0cac6859 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -265,6 +265,7 @@ struct iwl_cfg { const bool broken_powersave; bool use_rts_for_ht; int chain_noise_num_beacons; + const bool supports_idle; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 60be976afff8..e50d77bd7aad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -294,6 +294,9 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) if (priv->cfg->broken_powersave) iwl_power_sleep_cam_cmd(priv, &cmd); + else if (priv->cfg->supports_idle && + priv->hw->conf.flags & IEEE80211_CONF_IDLE) + iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20); else if (tt->state >= IWL_TI_1) iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper); else if (!enabled) -- cgit v1.2.3 From 9554b34ad5817f424253aab265d0e2a54207f810 Mon Sep 17 00:00:00 2001 From: Huaxu Wan Date: Fri, 25 Sep 2009 14:24:28 -0700 Subject: iwlwifi: add module firmware info for 1000 series The module firmware information of 1000 series is missing from iwlagn. Signed-off-by: Huaxu Wan Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 9dfd4c407efb..af91dbab255a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -189,3 +189,4 @@ struct iwl_cfg iwl1000_bg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; +MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); -- cgit v1.2.3 From 90f2908d3263e5c84c8408ce382a669b528b10e3 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Tue, 15 Sep 2009 22:20:22 +0200 Subject: ar9170: fixed coding style, moved define This patch fixes some coding style issues and moves MAX_RATE_POWER into hw.h Signed-off-by: Joerg Albert Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/hw.h | 2 ++ drivers/net/wireless/ath/ar9170/phy.c | 28 +++++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 6cbfb2f83391..88113148331c 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -311,6 +311,8 @@ struct ar9170_tx_control { #define AR9170_TX_PHY_SHORT_GI 0x80000000 +#define AR5416_MAX_RATE_POWER 63 + struct ar9170_rx_head { u8 plcp[12]; } __packed; diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index dbd488da18b1..07625a97851c 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -1239,9 +1239,6 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar, struct ar9170_calctl_edges edges[], u32 freq) { -/* TODO: move somewhere else */ -#define AR5416_MAX_RATE_POWER 63 - int i; u8 rc = AR5416_MAX_RATE_POWER; u8 f; @@ -1259,10 +1256,11 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar, break; } if (i > 0 && f < edges[i].channel) { - if (f > edges[i-1].channel && - edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { + if (f > edges[i - 1].channel && + edges[i - 1].power_flags & + AR9170_CALCTL_EDGE_FLAGS) { /* lower channel has the inband flag set */ - rc = edges[i-1].power_flags & + rc = edges[i - 1].power_flags & ~AR9170_CALCTL_EDGE_FLAGS; } break; @@ -1270,10 +1268,10 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar, } if (i == AR5416_NUM_BAND_EDGES) { - if (f > edges[i-1].channel && - edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { + if (f > edges[i - 1].channel && + edges[i - 1].power_flags & AR9170_CALCTL_EDGE_FLAGS) { /* lower channel has the inband flag set */ - rc = edges[i-1].power_flags & + rc = edges[i - 1].power_flags & ~AR9170_CALCTL_EDGE_FLAGS; } } @@ -1295,7 +1293,8 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) int pwr_cal_len; } *modes; - /* order is relevant in the mode_list_*: we fall back to the + /* + * order is relevant in the mode_list_*: we fall back to the * lower indices if any mode is missed in the EEPROM. */ struct ctl_modes mode_list_2ghz[] = { @@ -1313,7 +1312,8 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) #define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) - /* TODO: investigate the differences between OTUS' + /* + * TODO: investigate the differences between OTUS' * hpreg.c::zfHpGetRegulatoryDomain() and * ath/regd.c::ath_regd_get_band_ctl() - * e.g. for FCC3_WORLD the OTUS procedure @@ -1360,13 +1360,15 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1), freq+f_off); - /* TODO: check if the regulatory max. power is + /* + * TODO: check if the regulatory max. power is * controlled by cfg80211 for DFS * (hpmain applies it to max_power itself for DFS freq) */ } else { - /* Workaround in otus driver, hpmain.c, line 3906: + /* + * Workaround in otus driver, hpmain.c, line 3906: * if no data for 5GHT20 are found, take the * legacy 5G value. * We extend this here to fallback from any other *HT or -- cgit v1.2.3 From 7c52c07de8bd0433db6b3e0147544e5a2f01b786 Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Tue, 15 Sep 2009 22:23:06 +0200 Subject: ar9170: add heavy clip handling add heavy clip handling for 2.4GHz only (similar to the vendor driver). Signed-off-by: Joerg Albert Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 2 + drivers/net/wireless/ath/ar9170/phy.c | 71 ++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index c5576eec12ae..ec034af26980 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -202,6 +202,8 @@ struct ar9170 { u8 power_2G_ht20[8]; u8 power_2G_ht40[8]; + u8 phy_heavy_clip; + #ifdef CONFIG_AR9170_LEDS struct delayed_work led_work; struct ar9170_led leds[AR9170_NUM_LEDS]; diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index 07625a97851c..45a415ea809a 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -1278,8 +1278,38 @@ static u8 ar9170_get_max_edge_power(struct ar9170 *ar, return rc; } -/* calculate the conformance test limits and apply them to ar->power* - * (derived from otus hal/hpmain.c, line 3706 ff.) +static u8 ar9170_get_heavy_clip(struct ar9170 *ar, + struct ar9170_calctl_edges edges[], + u32 freq, enum ar9170_bw bw) +{ + u8 f; + int i; + u8 rc = 0; + + if (freq < 3000) + f = freq - 2300; + else + f = (freq - 4800) / 5; + + if (bw == AR9170_BW_40_BELOW || bw == AR9170_BW_40_ABOVE) + rc |= 0xf0; + + for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) { + if (edges[i].channel == 0xff) + break; + if (f == edges[i].channel) { + if (!(edges[i].power_flags & AR9170_CALCTL_EDGE_FLAGS)) + rc |= 0x0f; + break; + } + } + + return rc; +} + +/* + * calculate the conformance test limits and the heavy clip parameter + * and apply them to ar->power* (derived from otus hal/hpmain.c, line 3706) */ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) { @@ -1312,6 +1342,8 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) #define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n]) + ar->phy_heavy_clip = 0; + /* * TODO: investigate the differences between OTUS' * hpreg.c::zfHpGetRegulatoryDomain() and @@ -1347,6 +1379,15 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) if (ctl_idx < AR5416_NUM_CTLS) { int f_off = 0; + /* determine heav clip parameter from + the 11G edges array */ + if (modes[i].ctl_mode == CTL_11G) { + ar->phy_heavy_clip = + ar9170_get_heavy_clip(ar, + EDGES(ctl_idx, 1), + freq, bw); + } + /* adjust freq for 40MHz */ if (modes[i].ctl_mode == CTL_2GHT40 || modes[i].ctl_mode == CTL_5GHT40) { @@ -1392,6 +1433,19 @@ static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) modes[i].max_power); } } + + if (ar->phy_heavy_clip & 0xf0) { + ar->power_2G_ht40[0]--; + ar->power_2G_ht40[1]--; + ar->power_2G_ht40[2]--; + } + if (ar->phy_heavy_clip & 0xf) { + ar->power_2G_ht20[0]++; + ar->power_2G_ht20[1]++; + ar->power_2G_ht20[2]++; + } + + #undef EDGES } @@ -1501,8 +1555,6 @@ static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) /* calc. conformance test limits and apply to ar->power*[] */ ar9170_calc_ctl(ar, freq, bw); - /* TODO: (heavy clip) regulatory domain power level fine-tuning. */ - /* set ACK/CTS TX power */ ar9170_regwrite_begin(ar); @@ -1645,6 +1697,17 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, if (err) return err; + if (ar->phy_heavy_clip) { + err = ar9170_write_reg(ar, 0x1c59e0, + 0x200 | ar->phy_heavy_clip); + if (err) { + if (ar9170_nag_limiter(ar)) + printk(KERN_ERR "%s: failed to set " + "heavy clip\n", + wiphy_name(ar->hw->wiphy)); + } + } + for (i = 0; i < 2; i++) { ar->noise[i] = ar9170_calc_noise_dbm( (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff); -- cgit v1.2.3 From 181af387033e20065e94363d07ecbace7738278c Mon Sep 17 00:00:00 2001 From: Joerg Albert Date: Tue, 15 Sep 2009 23:27:53 +0200 Subject: ar9170: handle overflow in tsf_low register during get_tsf ar9170_op_get_tsf: handle a carry from TSF_L into TSF_H by reading TSF_H twice. Signed-off-by: Joerg Albert Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/cmd.c | 3 +-- drivers/net/wireless/ath/ar9170/cmd.h | 1 + drivers/net/wireless/ath/ar9170/main.c | 24 ++++++++++++++++-------- 3 files changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c index f57a6200167b..cf6f5c4174a6 100644 --- a/drivers/net/wireless/ath/ar9170/cmd.c +++ b/drivers/net/wireless/ath/ar9170/cmd.c @@ -72,8 +72,7 @@ int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val) return err; } -static int ar9170_read_mreg(struct ar9170 *ar, int nregs, - const u32 *regs, u32 *out) +int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out) { int i, err; __le32 *offs, *res; diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h index a4f0e50e52b4..826c45e6b274 100644 --- a/drivers/net/wireless/ath/ar9170/cmd.h +++ b/drivers/net/wireless/ath/ar9170/cmd.h @@ -44,6 +44,7 @@ int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len); int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val); int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val); +int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out); int ar9170_echo_test(struct ar9170 *ar, u32 v); /* diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 81c6cf1135bc..de0ba2bf7691 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2192,22 +2192,30 @@ static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw) { struct ar9170 *ar = hw->priv; int err; - u32 tsf_low; - u32 tsf_high; u64 tsf; +#define NR 3 + static const u32 addr[NR] = { AR9170_MAC_REG_TSF_H, + AR9170_MAC_REG_TSF_L, + AR9170_MAC_REG_TSF_H }; + u32 val[NR]; + int loops = 0; mutex_lock(&ar->mutex); - err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_L, &tsf_low); - if (!err) - err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_H, &tsf_high); + + while (loops++ < 10) { + err = ar9170_read_mreg(ar, NR, addr, val); + if (err || val[0] == val[2]) + break; + } + mutex_unlock(&ar->mutex); if (WARN_ON(err)) return 0; - - tsf = tsf_high; - tsf = (tsf << 32) | tsf_low; + tsf = val[0]; + tsf = (tsf << 32) | val[1]; return tsf; +#undef NR } static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, -- cgit v1.2.3 From 0b98eaaa02965fb06dee4ad8c605bb3c93df2c98 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Fri, 18 Sep 2009 15:03:42 +0530 Subject: ath9k: Add Calibration checks * Prevent divide-by-zero errors in IQ Calibration. * Do not run temperature compensation if initPDADC or currPDADC is zero. * Also, introduce a separate function for handling OLC for AR9287. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 78 ++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 36c5f89e2fc7..9c46b54d2a98 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -403,7 +403,8 @@ static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; qCoffDenom = powerMeasQ / 64; - if (powerMeasQ != 0) { + if ((powerMeasQ != 0) && (iCoffDenom != 0) && + (qCoffDenom != 0)) { iCoff = iqCorrMeas / iCoffDenom; qCoff = powerMeasI / qCoffDenom - 64; ath_print(common, ATH_DBG_CALIBRATE, @@ -746,44 +747,65 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) return nf; } -static void ath9k_olc_temp_compensation(struct ath_hw *ah) +static void ath9k_olc_temp_compensation_9287(struct ath_hw *ah) { - u32 rddata, i; - int delta, currPDADC, regval, slope; + u32 rddata; + int32_t delta, currPDADC, slope; rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); + if (ah->initPDADC == 0 || currPDADC == 0) { + /* + * Zero value indicates that no frames have been transmitted yet, + * can't do temperature compensation until frames are transmitted. + */ + return; + } else { + slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE); + + if (slope == 0) { /* to avoid divide by zero case */ + delta = 0; + } else { + delta = ((currPDADC - ah->initPDADC)*4) / slope; + } + REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, + AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); + REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, + AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); + } +} + +static void ath9k_olc_temp_compensation(struct ath_hw *ah) +{ + u32 rddata, i; + int delta, currPDADC, regval; if (OLC_FOR_AR9287_10_LATER) { + ath9k_olc_temp_compensation_9287(ah); + } else { + rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); + currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); + if (ah->initPDADC == 0 || currPDADC == 0) { return; } else { - slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE); - if (slope == 0) - delta = 0; + if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) + delta = (currPDADC - ah->initPDADC + 4) / 8; else - delta = ((currPDADC - ah->initPDADC)*4) / slope; - REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, - AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); - REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, - AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); - } - } else { - if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) - delta = (currPDADC - ah->initPDADC + 4) / 8; - else - delta = (currPDADC - ah->initPDADC + 5) / 10; - - if (delta != ah->PDADCdelta) { - ah->PDADCdelta = delta; - for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { - regval = ah->originalGain[i] - delta; - if (regval < 0) - regval = 0; - - REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, - AR_PHY_TX_GAIN, regval); + delta = (currPDADC - ah->initPDADC + 5) / 10; + + if (delta != ah->PDADCdelta) { + ah->PDADCdelta = delta; + for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { + regval = ah->originalGain[i] - delta; + if (regval < 0) + regval = 0; + + REG_RMW_FIELD(ah, + AR_PHY_TX_GAIN_TBL1 + i * 4, + AR_PHY_TX_GAIN, regval); + } } } } -- cgit v1.2.3 From 193cd4585e6c5650875e98ccfef2fa93616fef30 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 18 Sep 2009 15:04:07 +0530 Subject: ath9k: Update INI release for AR9287 If the current channel is between 2412 and 2472 MHz and if the channel is changing to 2484 MHz, then the registers 0xa1f4, 0xa1f8 and 0xa1fc need to be programmed to the "japan_2484" values. Conversely, if the current channel is 2484 MHz and if the channel is changing to one between 2412 and 2472 MHz, then the three registers need to be programmed to the "normal" values. This is needed for compliance with Japanese regulatory requirements. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 10 ++++++++++ drivers/net/wireless/ath/ath9k/hw.h | 2 ++ drivers/net/wireless/ath/ath9k/initvals.h | 23 ++++++++++++++++++----- drivers/net/wireless/ath/ath9k/phy.c | 25 ++++++++++++++++++------- 4 files changed, 48 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index b120c2127e9a..1e0f5bd702c6 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -943,6 +943,16 @@ int ath9k_hw_init(struct ath_hw *ah) else ath9k_hw_disablepcie(ah); + /* Support for Japan ch.14 (2484) spread */ + if (AR_SREV_9287_11_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniCckfirNormal, + ar9287Common_normal_cck_fir_coeff_92871_1, + ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_92871_1), 2); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9287Common_japan_2484_cck_fir_coeff_92871_1, + ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_92871_1), 2); + } + r = ath9k_hw_post_init(ah); if (r) return r; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index d854c17b8688..6673a8103364 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -592,6 +592,8 @@ struct ath_hw { struct ar5416IniArray iniModesAdditional; struct ar5416IniArray iniModesRxGain; struct ar5416IniArray iniModesTxGain; + struct ar5416IniArray iniCckfirNormal; + struct ar5416IniArray iniCckfirJapan2484; u32 intr_gen_timer_trigger; u32 intr_gen_timer_thresh; diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index 8622265a030a..d8aaeeef6d56 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -5918,9 +5918,6 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = { { 0x000099ec, 0x0cc80caa }, { 0x000099f0, 0x00000000 }, { 0x000099fc, 0x00001042 }, - { 0x0000a1f4, 0x00fffeff }, - { 0x0000a1f8, 0x00f5f9ff }, - { 0x0000a1fc, 0xb79f6427 }, { 0x0000a208, 0x803e4788 }, { 0x0000a210, 0x4080a333 }, { 0x0000a214, 0x40206c10 }, @@ -5980,7 +5977,7 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = { { 0x0000b3f4, 0x00000000 }, { 0x0000a7d8, 0x000003f1 }, { 0x00007800, 0x00000800 }, - { 0x00007804, 0x6c35ffc2 }, + { 0x00007804, 0x6c35ffd2 }, { 0x00007808, 0x6db6c000 }, { 0x0000780c, 0x6db6cb30 }, { 0x00007810, 0x6db6cb6c }, @@ -6000,7 +5997,7 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = { { 0x00007848, 0x934934a8 }, { 0x00007850, 0x00000000 }, { 0x00007854, 0x00000800 }, - { 0x00007858, 0x6c35ffc2 }, + { 0x00007858, 0x6c35ffd2 }, { 0x0000785c, 0x6db6c000 }, { 0x00007860, 0x6db6cb30 }, { 0x00007864, 0x6db6cb6c }, @@ -6027,6 +6024,22 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = { { 0x000078b8, 0x2a850160 }, }; +/* + * For Japanese regulatory requirements, 2484 MHz requires the following three + * registers be programmed differently from the channel between 2412 and 2472 MHz. + */ +static const u_int32_t ar9287Common_normal_cck_fir_coeff_92871_1[][2] = { + { 0x0000a1f4, 0x00fffeff }, + { 0x0000a1f8, 0x00f5f9ff }, + { 0x0000a1fc, 0xb79f6427 }, +}; + +static const u_int32_t ar9287Common_japan_2484_cck_fir_coeff_92871_1[][2] = { + { 0x0000a1f4, 0x00000000 }, + { 0x0000a1f8, 0xefff0301 }, + { 0x0000a1fc, 0xca9228ee }, +}; + static const u_int32_t ar9287Modes_tx_gain_9287_1_1[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index eec4f1064a68..72a17c43a5a0 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -113,20 +113,31 @@ void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, if (freq < 4800) { u32 txctl; + int regWrites = 0; bMode = 1; fracMode = 1; aModeRefSel = 0; channelSel = (freq * 0x10000) / 15; - txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); - if (freq == 2484) { - - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + if (AR_SREV_9287_11_OR_LATER(ah)) { + if (freq == 2484) { + REG_WRITE_ARRAY(&ah->iniCckfirJapan2484, + 1, regWrites); + } else { + REG_WRITE_ARRAY(&ah->iniCckfirNormal, + 1, regWrites); + } } else { - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); + txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (freq == 2484) { + /* Enable channel spreading for channel 14 */ + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); + } } } else { bMode = 0; -- cgit v1.2.3 From 4921be8058f1c8854e501305b96196856fe7f830 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 18 Sep 2009 15:04:27 +0530 Subject: ath9k: Fix RTC reset for AR5416 For AR5416 chipsets, clearing RTC_RESET_EN when setting the chip to SLEEP mode results in high power consumption. This patch fixes this issue by not clearing it for AR5416. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1e0f5bd702c6..0a3de3f7b0a6 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2851,8 +2851,9 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) if (!AR_SREV_9100(ah)) REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - REG_CLR_BIT(ah, (AR_RTC_RESET), - AR_RTC_RESET_EN); + if(!AR_SREV_5416(ah)) + REG_CLR_BIT(ah, (AR_RTC_RESET), + AR_RTC_RESET_EN); } } -- cgit v1.2.3 From 7aa034928392f16d48c536b315575e2dcfa53252 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 18 Sep 2009 15:04:51 +0530 Subject: ath9k: Update initvals * Move 0xa274 and 0xa27c to the top of tx_gain table. * Update initvals to fix random failure of noise floor calibration. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/initvals.h | 49 ++++++++++++++++--------------- 1 file changed, 25 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index d8aaeeef6d56..3ee6658d809b 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -21,6 +21,8 @@ static const u32 ar5416Modes[][6] = { { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, + { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 }, + { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a }, { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, @@ -31,11 +33,11 @@ static const u32 ar5416Modes[][6] = { { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de }, + { 0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de }, { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, + { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e }, { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 }, - { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, @@ -46,10 +48,10 @@ static const u32 ar5416Modes[][6] = { { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 }, - { 0x0000c9bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 }, + { 0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 }, { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c }, + { 0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c }, { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, @@ -199,7 +201,6 @@ static const u32 ar5416Common[][2] = { { 0x00008110, 0x00000168 }, { 0x00008118, 0x000100aa }, { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04800 }, { 0x00008124, 0x00000000 }, { 0x00008128, 0x00000000 }, { 0x0000812c, 0x00000000 }, @@ -215,7 +216,6 @@ static const u32 ar5416Common[][2] = { { 0x00008178, 0x00000100 }, { 0x0000817c, 0x00000000 }, { 0x000081c4, 0x00000000 }, - { 0x000081d0, 0x00003210 }, { 0x000081ec, 0x00000000 }, { 0x000081f0, 0x00000000 }, { 0x000081f4, 0x00000000 }, @@ -246,6 +246,7 @@ static const u32 ar5416Common[][2] = { { 0x00008258, 0x00000000 }, { 0x0000825c, 0x400000ff }, { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8000010 }, { 0x00008270, 0x00000000 }, { 0x00008274, 0x40000000 }, { 0x00008278, 0x003e4180 }, @@ -406,9 +407,9 @@ static const u32 ar5416Common[][2] = { { 0x0000a25c, 0x0f0f0f01 }, { 0x0000a260, 0xdfa91f01 }, { 0x0000a268, 0x00000000 }, - { 0x0000a26c, 0x0ebae9c6 }, - { 0x0000b26c, 0x0ebae9c6 }, - { 0x0000c26c, 0x0ebae9c6 }, + { 0x0000a26c, 0x0e79e5c6 }, + { 0x0000b26c, 0x0e79e5c6 }, + { 0x0000c26c, 0x0e79e5c6 }, { 0x0000d270, 0x00820820 }, { 0x0000a278, 0x1ce739ce }, { 0x0000a27c, 0x051701ce }, @@ -2551,26 +2552,27 @@ static const u32 ar9280Modes_9280_2[][6] = { { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e }, { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e }, { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, - { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 }, + { 0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 }, { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, - { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e }, + { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e }, { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, - { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b, 0x00000016 }, { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 }, { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 }, + { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce }, { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c }, { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, @@ -2585,8 +2587,10 @@ static const u32 ar9280Modes_9280_2[][6] = { { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000, 0x13c88000 }, { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 }, { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, + { 0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000, 0x0c000000 }, { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 }, }; @@ -2813,7 +2817,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00009958, 0x2108ecff }, { 0x00009940, 0x14750604 }, { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, { 0x00009970, 0x190fb515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, @@ -2849,7 +2852,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000a22c, 0x233f7180 }, { 0x0000a234, 0x20202020 }, { 0x0000a238, 0x20202020 }, - { 0x0000a23c, 0x13c88000 }, { 0x0000a240, 0x38490a20 }, { 0x0000a244, 0x00007bb6 }, { 0x0000a248, 0x0fff3ffc }, @@ -2859,8 +2861,8 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000a25c, 0x0f0f0f01 }, { 0x0000a260, 0xdfa91f01 }, { 0x0000a268, 0x00000000 }, - { 0x0000a26c, 0x0ebae9c6 }, - { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000a26c, 0x0e79e5c6 }, + { 0x0000b26c, 0x0e79e5c6 }, { 0x0000d270, 0x00820820 }, { 0x0000a278, 0x1ce739ce }, { 0x0000d35c, 0x07ffffef }, @@ -2874,7 +2876,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000d37c, 0x7fffffe2 }, { 0x0000d380, 0x7f3c7bba }, { 0x0000d384, 0xf3307ff0 }, - { 0x0000a388, 0x0c000000 }, { 0x0000a38c, 0x20202020 }, { 0x0000a390, 0x20202020 }, { 0x0000a394, 0x1ce739ce }, @@ -2940,7 +2941,7 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = { { 0x0000801c, 0x148ec02b, 0x148ec057 }, { 0x00008318, 0x000044c0, 0x00008980 }, { 0x00009820, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000f0f, 0x00000f0f }, + { 0x00009824, 0x01000f0f, 0x01000f0f }, { 0x00009828, 0x0b020001, 0x0b020001 }, { 0x00009834, 0x00000f0f, 0x00000f0f }, { 0x00009844, 0x03721821, 0x03721821 }, @@ -3348,6 +3349,8 @@ static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = { }; static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = { + { 0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, + { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce }, { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 }, { 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 }, @@ -3376,11 +3379,11 @@ static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = { { 0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000 }, { 0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 }, { 0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480 }, - { 0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, - { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce }, }; static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = { + { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, + { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 }, { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 }, @@ -3409,8 +3412,6 @@ static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = { { 0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000 }, { 0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 }, { 0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480 }, - { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, - { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, }; static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { -- cgit v1.2.3 From 66afad0156a0b673688f309147e57c3a85541329 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 18 Sep 2009 15:06:07 +0530 Subject: ath9k: Allow PSPOLL only when the interface is configured in AP mode Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 3a2204d84702..c880a55939bf 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -423,7 +423,10 @@ u32 ath_calcrxfilter(struct ath_softc *sc) else rfilt |= ATH9K_RX_FILTER_BEACON; - if (sc->rx.rxfilter & FIF_PSPOLL) + if ((AR_SREV_9280_10_OR_LATER(sc->sc_ah) || + AR_SREV_9285_10_OR_LATER(sc->sc_ah)) && + (sc->sc_ah->opmode == NL80211_IFTYPE_AP) && + (sc->rx.rxfilter & FIF_PSPOLL)) rfilt |= ATH9K_RX_FILTER_PSPOLL; if (conf_is_ht(&sc->hw->conf)) -- cgit v1.2.3 From 1d50a69b18818b276333590d1f2c9382d292d84d Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 18 Sep 2009 15:06:37 +0530 Subject: ath9k: Handle ATH9K_BEACON_RESET_TSF properly Clearing a local variable is unnecessary. Get rid of it. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 0a3de3f7b0a6..eb408831f3cf 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3422,7 +3422,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) beacon_period &= ~ATH9K_BEACON_ENA; if (beacon_period & ATH9K_BEACON_RESET_TSF) { - beacon_period &= ~ATH9K_BEACON_RESET_TSF; ath9k_hw_reset_tsf(ah); } -- cgit v1.2.3 From 63a75b912b00fbafeb54849ca3bcd0295ad68609 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 18 Sep 2009 15:07:03 +0530 Subject: ath9k: Reduce PLL Settle time and eliminate redundant PLL calls. Reduce PLL Settle time and eliminate redundant PLL calls. Also reduce the LoadNF timeout from 10 msec to 250usec as the 10 msec timeout was hit with AR9285 in some cases. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 4 ++-- drivers/net/wireless/ath/ath9k/hw.c | 15 +++++++++++---- drivers/net/wireless/ath/ath9k/hw.h | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 9c46b54d2a98..d347ea79e778 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -653,11 +653,11 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) AR_PHY_AGC_CONTROL_NO_UPDATE_NF); REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); - for (j = 0; j < 1000; j++) { + for (j = 0; j < 5; j++) { if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) break; - udelay(10); + udelay(50); } for (i = 0; i < NUM_NF_READINGS; i++) { diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index eb408831f3cf..b53faa09bdb5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1691,8 +1691,6 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) if (!AR_SREV_9100(ah)) REG_WRITE(ah, AR_RC, 0); - ath9k_hw_init_pll(ah, NULL); - if (AR_SREV_9100(ah)) udelay(50); @@ -2885,6 +2883,7 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) ATH9K_RESET_POWER_ON) != true) { return false; } + ath9k_hw_init_pll(ah, NULL); } if (AR_SREV_9100(ah)) REG_SET_BIT(ah, AR_RTC_RESET, @@ -3968,7 +3967,11 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) bool ath9k_hw_phy_disable(struct ath_hw *ah) { - return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM); + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) + return false; + + ath9k_hw_init_pll(ah, NULL); + return true; } bool ath9k_hw_disable(struct ath_hw *ah) @@ -3976,7 +3979,11 @@ bool ath9k_hw_disable(struct ath_hw *ah) if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return false; - return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD)) + return false; + + ath9k_hw_init_pll(ah, NULL); + return true; } void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6673a8103364..773f5c405c0e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -102,7 +102,7 @@ #define AR_GPIO_BIT(_gpio) (1 << (_gpio)) #define BASE_ACTIVATE_DELAY 100 -#define RTC_PLL_SETTLE_DELAY 1000 +#define RTC_PLL_SETTLE_DELAY 100 #define COEF_SCALE_S 24 #define HT40_CHANNEL_CENTER_SHIFT 10 -- cgit v1.2.3 From ebb90cfc32f0d7ee55be7787ce7d88e521e9ed01 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 18 Sep 2009 15:07:33 +0530 Subject: ath9k: Advertise midband for AR5416 devices This has to be done if the EEPROM supports FCC Midband capability. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.h | 1 + drivers/net/wireless/ath/ath9k/hw.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 8463ba09c12c..33492741735d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -639,6 +639,7 @@ struct ar9287_eeprom { } __packed; enum reg_ext_bitmap { + REG_EXT_FCC_MIDBAND = 0, REG_EXT_JAPAN_MIDBAND = 1, REG_EXT_FCC_DFS_HT40 = 2, REG_EXT_JAPAN_NONDFS_HT40 = 3, diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index b53faa09bdb5..7a4de3d8e6fb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3660,7 +3660,10 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; } - pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; + /* Advertise midband for AR5416 with FCC midband set in eeprom */ + if (regulatory->current_rd_ext & (1 << REG_EXT_FCC_MIDBAND) && + AR_SREV_5416(ah)) + pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; pCap->num_antcfg_5ghz = ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ); -- cgit v1.2.3 From e41f0bfcb130d9f17cf5ee8e46d739c1bebda963 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 18 Sep 2009 15:08:20 +0530 Subject: ath9k: Fix bugs in handling TX power * Get power table offset from the EEPROM instead of using a hardcoded value of -5 if the EEPROM rev is >= 21. * Add support in the 4k eeprom code for tx power offset in case we have a 4k AR9280 implementation. * Fix tx power accuracy at high powers. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.h | 5 +- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 4 +- drivers/net/wireless/ath/ath9k/eeprom_def.c | 102 ++++++++++++++++++++++++++-- 3 files changed, 104 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 33492741735d..2f2993b50e2f 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -134,6 +134,7 @@ #define AR5416_EEP_MINOR_VER_17 0x11 #define AR5416_EEP_MINOR_VER_19 0x13 #define AR5416_EEP_MINOR_VER_20 0x14 +#define AR5416_EEP_MINOR_VER_21 0x15 #define AR5416_EEP_MINOR_VER_22 0x16 #define AR5416_NUM_5G_CAL_PIERS 8 @@ -154,7 +155,7 @@ #define AR5416_BCHAN_UNUSED 0xFF #define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 #define AR5416_MAX_CHAINS 3 -#define AR5416_PWR_TABLE_OFFSET -5 +#define AR5416_PWR_TABLE_OFFSET_DB -5 /* Rx gain type values */ #define AR5416_EEP_RXGAIN_23DB_BACKOFF 0 @@ -302,7 +303,7 @@ struct base_eep_header { u8 txGainType; u8 rcChainMask; u8 desiredScaleCCK; - u8 power_table_offset; + u8 pwr_table_offset; u8 frac_n_5g; u8 futureBase_3[21]; } __packed; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 2a27b1d51a1b..58167d861dc6 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -210,6 +210,8 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, return pBase->rxMask; case EEP_FRAC_N_5G: return 0; + case EEP_PWR_TABLE_OFFSET: + return AR5416_PWR_TABLE_OFFSET_DB; default: return 0; } @@ -753,7 +755,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, if (AR_SREV_9280_10_OR_LATER(ah)) { for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; } /* OFDM power per rate */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 8f04b644e2e6..404a0341242c 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -291,6 +291,11 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, return pBase->frac_n_5g; else return 0; + case EEP_PWR_TABLE_OFFSET: + if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_21) + return pBase->pwr_table_offset; + else + return AR5416_PWR_TABLE_OFFSET_DB; default: return 0; } @@ -741,6 +746,76 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, return; } +static int16_t ath9k_change_gain_boundary_setting(struct ath_hw *ah, + u16 *gb, + u16 numXpdGain, + u16 pdGainOverlap_t2, + int8_t pwr_table_offset, + int16_t *diff) + +{ + u16 k; + + /* Prior to writing the boundaries or the pdadc vs. power table + * into the chip registers the default starting point on the pdadc + * vs. power table needs to be checked and the curve boundaries + * adjusted accordingly + */ + if (AR_SREV_9280_20_OR_LATER(ah)) { + u16 gb_limit; + + if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) { + /* get the difference in dB */ + *diff = (u16)(pwr_table_offset - AR5416_PWR_TABLE_OFFSET_DB); + /* get the number of half dB steps */ + *diff *= 2; + /* change the original gain boundary settings + * by the number of half dB steps + */ + for (k = 0; k < numXpdGain; k++) + gb[k] = (u16)(gb[k] - *diff); + } + /* Because of a hardware limitation, ensure the gain boundary + * is not larger than (63 - overlap) + */ + gb_limit = (u16)(AR5416_MAX_RATE_POWER - pdGainOverlap_t2); + + for (k = 0; k < numXpdGain; k++) + gb[k] = (u16)min(gb_limit, gb[k]); + } + + return *diff; +} + +static void ath9k_adjust_pdadc_values(struct ath_hw *ah, + int8_t pwr_table_offset, + int16_t diff, + u8 *pdadcValues) +{ +#define NUM_PDADC(diff) (AR5416_NUM_PDADC_VALUES - diff) + u16 k; + + /* If this is a board that has a pwrTableOffset that differs from + * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the + * pdadc vs pwr table needs to be adjusted prior to writing to the + * chip. + */ + if (AR_SREV_9280_20_OR_LATER(ah)) { + if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) { + /* shift the table to start at the new offset */ + for (k = 0; k < (u16)NUM_PDADC(diff); k++ ) { + pdadcValues[k] = pdadcValues[k + diff]; + } + + /* fill the back of the table */ + for (k = (u16)NUM_PDADC(diff); k < NUM_PDADC(0); k++) { + pdadcValues[k] = pdadcValues[NUM_PDADC(diff)]; + } + } + } +#undef NUM_PDADC +} + static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *pTxPowerIndexOffset) @@ -756,15 +831,18 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; u16 numPiers, i, j; - int16_t tMinCalPower; + int16_t tMinCalPower, diff = 0; u16 numXpdGain, xpdMask; u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; u32 reg32, regOffset, regChainOffset; int16_t modalIdx; + int8_t pwr_table_offset; modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; xpdMask = pEepData->modalHeader[modalIdx].xpdGain; + pwr_table_offset = ah->eep_ops->get_eeprom(ah, EEP_PWR_TABLE_OFFSET); + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= AR5416_EEP_MINOR_VER_2) { pdGainOverlap_t2 = @@ -844,6 +922,13 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, numXpdGain); } + diff = ath9k_change_gain_boundary_setting(ah, + gainBoundaries, + numXpdGain, + pdGainOverlap_t2, + pwr_table_offset, + &diff); + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { if (OLC_FOR_AR9280_20_LATER) { REG_WRITE(ah, @@ -864,6 +949,10 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, } } + + ath9k_adjust_pdadc_values(ah, pwr_table_offset, + diff, pdadcValues); + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; for (j = 0; j < 32; j++) { reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | @@ -1199,8 +1288,13 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, } if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + for (i = 0; i < Ar5416RateSize; i++) { + int8_t pwr_table_offset; + + pwr_table_offset = ah->eep_ops->get_eeprom(ah, + EEP_PWR_TABLE_OFFSET); + ratesArray[i] -= pwr_table_offset * 2; + } } REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, @@ -1299,7 +1393,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, if (AR_SREV_9280_10_OR_LATER(ah)) regulatory->max_power_level = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + ratesArray[i] + AR5416_PWR_TABLE_OFFSET_DB * 2; else regulatory->max_power_level = ratesArray[i]; -- cgit v1.2.3 From c099752ae06784fcd9cd393cbf3dfbc6b54f4569 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 18 Sep 2009 18:20:03 +0200 Subject: iwlwifi: drop lib80211 dependency Ever since Johannes' "iwlwifi: improve scan support" iwlwifi no longer needs any of lib80211's functions or definitions. This patch updates iwlwifi's Kconfig _selections_ and removes all left lib80211.h inclusions from the source files. Signed-off-by: Christian Lamparter Acked-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 1 - drivers/net/wireless/iwlwifi/iwl-scan.c | 1 - drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 99310c033253..eb62c20e8019 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -1,7 +1,6 @@ config IWLWIFI tristate "Intel Wireless Wifi" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL - select LIB80211 select FW_LOADER select MAC80211_LEDS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 4f3a108fa990..41f9a0621250 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -27,7 +27,6 @@ *****************************************************************************/ #include #include -#include #include #include "iwl-eeprom.h" diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4a4af0f782f0..3575e7fbadc7 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -41,7 +41,6 @@ #include #include -#include #include #include -- cgit v1.2.3 From bdcf8ff3dd7e89ee4b3f303b6f7e5e04876f9d76 Mon Sep 17 00:00:00 2001 From: Jaswinder Singh Rajput Date: Sun, 20 Sep 2009 13:39:24 +0530 Subject: b43: Comment unused functions lpphy_restore_dig_flt_state and lpphy_disable_rx_gain_override MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commenting unused functions lpphy_restore_dig_flt_state and lpphy_disable_rx_gain_override, may be we need these functions in future. This also fixed following compilation warnings : CC [M] drivers/net/wireless/b43/phy_lp.o drivers/net/wireless/b43/phy_lp.c:383: warning: ‘lpphy_restore_dig_flt_state’ defined but not used drivers/net/wireless/b43/phy_lp.c:891: warning: ‘lpphy_disable_rx_gain_override’ defined but not used Signed-off-by: Jaswinder Singh Rajput Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 1e318d815a5b..c6987b147af4 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -379,6 +379,8 @@ static void lpphy_save_dig_flt_state(struct b43_wldev *dev) } } +/* lpphy_restore_dig_flt_state is unused but kept as a reference */ +#if 0 static void lpphy_restore_dig_flt_state(struct b43_wldev *dev) { static const u16 addr[] = { @@ -399,6 +401,7 @@ static void lpphy_restore_dig_flt_state(struct b43_wldev *dev) for (i = 0; i < ARRAY_SIZE(addr); i++) b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]); } +#endif static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) { @@ -887,6 +890,8 @@ static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain) } } +/* lpphy_disable_rx_gain_override is unused but kept as a reference */ +#if 0 static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) { b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_0, 0xFFFE); @@ -902,6 +907,7 @@ static void lpphy_disable_rx_gain_override(struct b43_wldev *dev) b43_phy_mask(dev, B43_LPPHY_RF_OVERRIDE_2, 0xFDFF); } } +#endif static void lpphy_enable_rx_gain_override(struct b43_wldev *dev) { -- cgit v1.2.3 From 475a6e4d3907d6af412d081a9eab3b1e8a24afd1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 23 Sep 2009 23:06:59 -0400 Subject: ath9k: use common read/write ops on pci and debug code PCI and debug code will not be shared between ath9k and ath9k_htc, so make that code use the common read/write ops. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 21 +++++++++++++-------- drivers/net/wireless/ath/ath9k/pci.c | 4 ++-- 2 files changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 5dfc0e97d96d..352914cae6d8 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -18,6 +18,11 @@ #include "ath9k.h" +#define REG_WRITE_D(_ah, _reg, _val) \ + ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg)) +#define REG_READ_D(_ah, _reg) \ + ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) + static unsigned int ath9k_debug = ATH_DBG_DEFAULT; module_param_named(debug, ath9k_debug, uint, 0); @@ -82,7 +87,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, ath9k_ps_wakeup(sc); - REG_WRITE(ah, AR_MACMISC, + REG_WRITE_D(ah, AR_MACMISC, ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | (AR_MACMISC_MISC_OBS_BUS_1 << AR_MACMISC_MISC_OBS_BUS_MSB_S))); @@ -94,7 +99,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, if (i % 4 == 0) len += snprintf(buf + len, sizeof(buf) - len, "\n"); - val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); + val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32))); len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ", i, val[i]); } @@ -144,9 +149,9 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n", - REG_READ(ah, AR_OBS_BUS_1)); + REG_READ_D(ah, AR_OBS_BUS_1)); len += snprintf(buf + len, sizeof(buf) - len, - "AR_CR: 0x%x \n", REG_READ(ah, AR_CR)); + "AR_CR: 0x%x \n", REG_READ_D(ah, AR_CR)); ath9k_ps_restore(sc); @@ -363,12 +368,12 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, aphy->chan_idx, aphy->chan_is_ht); } - put_unaligned_le32(REG_READ(sc->sc_ah, AR_STA_ID0), addr); - put_unaligned_le16(REG_READ(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); + put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr); + put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4); len += snprintf(buf + len, sizeof(buf) - len, "addr: %pM\n", addr); - put_unaligned_le32(REG_READ(sc->sc_ah, AR_BSSMSKL), addr); - put_unaligned_le16(REG_READ(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4); + put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_BSSMSKL), addr); + put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4); len += snprintf(buf + len, sizeof(buf) - len, "addrmask: %pM\n", addr); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index a1001ffdd389..b2a45ce62698 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -65,7 +65,7 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) { struct ath_hw *ah = (struct ath_hw *) common->ah; - (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); if (!ath9k_hw_wait(ah, AR_EEPROM_STATUS_DATA, @@ -75,7 +75,7 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) return false; } - *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), + *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA), AR_EEPROM_STATUS_DATA_VAL); return true; -- cgit v1.2.3 From 7322fd19295fa7f7d954a19a5f0b77687d441846 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 23 Sep 2009 23:07:00 -0400 Subject: ath9k: move hw code to its own module hw code for Atheros 802.11n hardware is commmon between different chipsets. This moves this code into a separate module, the next expected user of this code will be the ath9k_htc module. The ath9k/ dir is now selected by ATH9K_HW, an option which gets selected by either ath9k or ath9k_htc, but remains invisible for user menuconfig configuration. If either ath9k or ath9k_htc will be compiled into the kernel ath9k_hw will also be compiled in. Cc: Jouni Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/Makefile | 2 +- drivers/net/wireless/ath/ath9k/Kconfig | 4 +++ drivers/net/wireless/ath/ath9k/Makefile | 27 ++++++++------- drivers/net/wireless/ath/ath9k/ani.c | 2 ++ drivers/net/wireless/ath/ath9k/btcoex.c | 6 ++++ drivers/net/wireless/ath/ath9k/calib.c | 3 ++ drivers/net/wireless/ath/ath9k/hw.c | 61 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/mac.c | 30 ++++++++++++++++ 8 files changed, 121 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 5c8e6b2bbaab..8113a5042afa 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_ATH5K) += ath5k/ -obj-$(CONFIG_ATH9K) += ath9k/ +obj-$(CONFIG_ATH9K_HW) += ath9k/ obj-$(CONFIG_AR9170_USB) += ar9170/ obj-$(CONFIG_ATH_COMMON) += ath.o diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index de4aeea8a005..99ce066392a7 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -1,6 +1,10 @@ +config ATH9K_HW + tristate + config ATH9K tristate "Atheros 802.11n wireless cards support" depends on PCI && MAC80211 && WLAN_80211 + select ATH9K_HW select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index f3221af73eb7..8caf2a8f8953 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -1,16 +1,4 @@ -ATH9K_HW += hw.o \ - eeprom.o \ - eeprom_def.o \ - eeprom_4k.o \ - eeprom_9287.o \ - calib.o \ - ani.o \ - phy.o \ - btcoex.o \ - mac.o \ - -ath9k-y += $(ATH9K_HW) \ - beacon.o \ +ath9k-y += beacon.o \ main.o \ recv.o \ xmit.o \ @@ -22,3 +10,16 @@ ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o obj-$(CONFIG_ATH9K) += ath9k.o + +ath9k_hw-y:= hw.o \ + eeprom.o \ + eeprom_def.o \ + eeprom_4k.o \ + eeprom_9287.o \ + calib.o \ + ani.o \ + phy.o \ + btcoex.o \ + mac.o \ + +obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index ecb23f302c3d..2a0cd64c2bfb 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -629,6 +629,7 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, } } } +EXPORT_SYMBOL(ath9k_hw_ani_monitor); void ath9k_enable_mib_counters(struct ath_hw *ah) { @@ -756,6 +757,7 @@ void ath9k_hw_procmibevent(struct ath_hw *ah) ath9k_ani_restart(ah); } } +EXPORT_SYMBOL(ath9k_hw_procmibevent); void ath9k_hw_ani_setup(struct ath_hw *ah) { diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 0c54489ca443..fb4ac15f3b93 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -95,6 +95,7 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) for (i = 0; i < 32; i++) ah->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; } +EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw); void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) { @@ -116,6 +117,7 @@ void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) /* Configure the desired gpio port for input */ ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio); } +EXPORT_SYMBOL(ath9k_hw_btcoex_init_2wire); void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) { @@ -141,6 +143,7 @@ void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio); ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btpriority_gpio); } +EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire); static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah) { @@ -160,6 +163,7 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | SM(wlan_weight, AR_BTCOEX_WL_WGHT); } +EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) { @@ -201,6 +205,7 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) ah->btcoex_hw.enabled = true; } +EXPORT_SYMBOL(ath9k_hw_btcoex_enable); void ath9k_hw_btcoex_disable(struct ath_hw *ah) { @@ -219,3 +224,4 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) ah->btcoex_hw.enabled = false; } +EXPORT_SYMBOL(ath9k_hw_btcoex_disable); diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index d347ea79e778..f46bd05df443 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -594,6 +594,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) return false; } +EXPORT_SYMBOL(ath9k_hw_reset_calvalid); void ath9k_hw_start_nfcal(struct ath_hw *ah) { @@ -746,6 +747,7 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) return nf; } +EXPORT_SYMBOL(ath9k_hw_getchan_noise); static void ath9k_olc_temp_compensation_9287(struct ath_hw *ah) { @@ -1066,6 +1068,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, return iscaldone; } +EXPORT_SYMBOL(ath9k_hw_calibrate); static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) { diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7a4de3d8e6fb..7d167a1b286d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -33,6 +33,23 @@ static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); +MODULE_AUTHOR("Atheros Communications"); +MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); +MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); +MODULE_LICENSE("Dual BSD/GPL"); + +static int __init ath9k_init(void) +{ + return 0; +} +module_init(ath9k_init); + +static void __exit ath9k_exit(void) +{ + return; +} +module_exit(ath9k_exit); + /********************/ /* Helper Functions */ /********************/ @@ -99,6 +116,7 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) return false; } +EXPORT_SYMBOL(ath9k_hw_wait); u32 ath9k_hw_reverse_bits(u32 val, u32 n) { @@ -186,6 +204,7 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, return txTime; } +EXPORT_SYMBOL(ath9k_hw_computetxtime); void ath9k_hw_get_channel_centers(struct ath_hw *ah, struct ath9k_channel *chan, @@ -402,6 +421,7 @@ static void ath9k_hw_init_config(struct ath_hw *ah) if (num_possible_cpus() > 1) ah->config.serialize_regmode = SER_REG_MODE_AUTO; } +EXPORT_SYMBOL(ath9k_hw_init); static void ath9k_hw_init_defaults(struct ath_hw *ah) { @@ -1223,6 +1243,7 @@ void ath9k_hw_detach(struct ath_hw *ah) kfree(ah); ah = NULL; } +EXPORT_SYMBOL(ath9k_hw_detach); /*******/ /* INI */ @@ -2561,6 +2582,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, return 0; } +EXPORT_SYMBOL(ath9k_hw_reset); /************************/ /* Key Cache Management */ @@ -2599,6 +2621,7 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry) return true; } +EXPORT_SYMBOL(ath9k_hw_keyreset); bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) { @@ -2627,6 +2650,7 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac) return true; } +EXPORT_SYMBOL(ath9k_hw_keysetmac); bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, const struct ath9k_keyval *k, @@ -2825,6 +2849,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, return true; } +EXPORT_SYMBOL(ath9k_hw_set_keycache_entry); bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry) { @@ -2835,6 +2860,7 @@ bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry) } return false; } +EXPORT_SYMBOL(ath9k_hw_keyisvalid); /******************************/ /* Power Management (Chipset) */ @@ -2951,6 +2977,7 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) return status; } +EXPORT_SYMBOL(ath9k_hw_setpower); /* * Helper for ASPM support. @@ -3083,6 +3110,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off) } } } +EXPORT_SYMBOL(ath9k_hw_configpcipowersave); /**********************/ /* Interrupt Handling */ @@ -3106,6 +3134,7 @@ bool ath9k_hw_intrpend(struct ath_hw *ah) return false; } +EXPORT_SYMBOL(ath9k_hw_intrpend); bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) { @@ -3258,6 +3287,7 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) return true; } +EXPORT_SYMBOL(ath9k_hw_getisr); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) { @@ -3365,6 +3395,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) return omask; } +EXPORT_SYMBOL(ath9k_hw_set_interrupts); /*******************/ /* Beacon Handling */ @@ -3426,6 +3457,7 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) REG_SET_BIT(ah, AR_TIMER_MODE, flags); } +EXPORT_SYMBOL(ath9k_hw_beaconinit); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, const struct ath9k_beacon_state *bs) @@ -3489,6 +3521,7 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, /* TSF Out of Range Threshold */ REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold); } +EXPORT_SYMBOL(ath9k_hw_set_sta_beacon_timers); /*******************/ /* HW Capabilities */ @@ -3756,6 +3789,7 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, return false; } } +EXPORT_SYMBOL(ath9k_hw_getcapability); bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 setting, int *status) @@ -3789,6 +3823,7 @@ bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, return false; } } +EXPORT_SYMBOL(ath9k_hw_setcapability); /****************************/ /* GPIO / RFKILL / Antennae */ @@ -3835,6 +3870,7 @@ void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio) (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), (AR_GPIO_OE_OUT_DRV << gpio_shift)); } +EXPORT_SYMBOL(ath9k_hw_cfg_gpio_input); u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) { @@ -3853,6 +3889,7 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) else return MS_REG_READ(AR, gpio) != 0; } +EXPORT_SYMBOL(ath9k_hw_gpio_get); void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, u32 ah_signal_type) @@ -3868,22 +3905,26 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), (AR_GPIO_OE_OUT_DRV << gpio_shift)); } +EXPORT_SYMBOL(ath9k_hw_cfg_output); void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) { REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), AR_GPIO_BIT(gpio)); } +EXPORT_SYMBOL(ath9k_hw_set_gpio); u32 ath9k_hw_getdefantenna(struct ath_hw *ah) { return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; } +EXPORT_SYMBOL(ath9k_hw_getdefantenna); void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna) { REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); } +EXPORT_SYMBOL(ath9k_hw_setantenna); bool ath9k_hw_setantennaswitch(struct ath_hw *ah, enum ath9k_ant_setting settings, @@ -3946,6 +3987,7 @@ u32 ath9k_hw_getrxfilter(struct ath_hw *ah) return bits; } +EXPORT_SYMBOL(ath9k_hw_getrxfilter); void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) { @@ -3967,6 +4009,7 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) REG_WRITE(ah, AR_RXCFG, REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); } +EXPORT_SYMBOL(ath9k_hw_setrxfilter); bool ath9k_hw_phy_disable(struct ath_hw *ah) { @@ -3976,6 +4019,7 @@ bool ath9k_hw_phy_disable(struct ath_hw *ah) ath9k_hw_init_pll(ah, NULL); return true; } +EXPORT_SYMBOL(ath9k_hw_phy_disable); bool ath9k_hw_disable(struct ath_hw *ah) { @@ -3988,6 +4032,7 @@ bool ath9k_hw_disable(struct ath_hw *ah) ath9k_hw_init_pll(ah, NULL); return true; } +EXPORT_SYMBOL(ath9k_hw_disable); void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) { @@ -4004,22 +4049,26 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) min((u32) MAX_RATE_POWER, (u32) regulatory->power_limit)); } +EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit); void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac) { memcpy(ath9k_hw_common(ah)->macaddr, mac, ETH_ALEN); } +EXPORT_SYMBOL(ath9k_hw_setmac); void ath9k_hw_setopmode(struct ath_hw *ah) { ath9k_hw_set_operating_mode(ah, ah->opmode); } +EXPORT_SYMBOL(ath9k_hw_setopmode); void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1) { REG_WRITE(ah, AR_MCAST_FIL0, filter0); REG_WRITE(ah, AR_MCAST_FIL1, filter1); } +EXPORT_SYMBOL(ath9k_hw_setmcastfilter); void ath9k_hw_write_associd(struct ath_hw *ah) { @@ -4029,6 +4078,7 @@ void ath9k_hw_write_associd(struct ath_hw *ah) REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(common->curbssid + 4) | ((common->curaid & 0x3fff) << AR_BSS_ID1_AID_S)); } +EXPORT_SYMBOL(ath9k_hw_write_associd); u64 ath9k_hw_gettsf64(struct ath_hw *ah) { @@ -4039,12 +4089,14 @@ u64 ath9k_hw_gettsf64(struct ath_hw *ah) return tsf; } +EXPORT_SYMBOL(ath9k_hw_gettsf64); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64) { REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff); REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff); } +EXPORT_SYMBOL(ath9k_hw_settsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah) { @@ -4055,6 +4107,7 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); } +EXPORT_SYMBOL(ath9k_hw_reset_tsf); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) { @@ -4063,6 +4116,7 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) else ah->misc_mode &= ~AR_PCU_TX_ADD_TSF; } +EXPORT_SYMBOL(ath9k_hw_set_tsfadjust); bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) { @@ -4077,6 +4131,7 @@ bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) return true; } } +EXPORT_SYMBOL(ath9k_hw_setslottime); void ath9k_hw_set11nmac2040(struct ath_hw *ah) { @@ -4140,6 +4195,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah) { return REG_READ(ah, AR_TSF_L32); } +EXPORT_SYMBOL(ath9k_hw_gettsf32); struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, void (*trigger)(void *), @@ -4168,6 +4224,7 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, return timer; } +EXPORT_SYMBOL(ath_gen_timer_alloc); void ath9k_hw_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, @@ -4209,6 +4266,7 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); } +EXPORT_SYMBOL(ath9k_hw_gen_timer_start); void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) { @@ -4230,6 +4288,7 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) clear_bit(timer->index, &timer_table->timer_mask.timer_bits); } +EXPORT_SYMBOL(ath9k_hw_gen_timer_stop); void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer) { @@ -4239,6 +4298,7 @@ void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer) timer_table->timers[timer->index] = NULL; kfree(timer); } +EXPORT_SYMBOL(ath_gen_timer_free); /* * Generic Timer Interrupts handling @@ -4276,3 +4336,4 @@ void ath_gen_timer_isr(struct ath_hw *ah) timer->trigger(timer->arg); } } +EXPORT_SYMBOL(ath_gen_timer_isr); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 3be658d42a53..e2c1ba3ea483 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -39,11 +39,13 @@ u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q) { return REG_READ(ah, AR_QTXDP(q)); } +EXPORT_SYMBOL(ath9k_hw_gettxbuf); void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp) { REG_WRITE(ah, AR_QTXDP(q), txdp); } +EXPORT_SYMBOL(ath9k_hw_puttxbuf); void ath9k_hw_txstart(struct ath_hw *ah, u32 q) { @@ -51,6 +53,7 @@ void ath9k_hw_txstart(struct ath_hw *ah, u32 q) "Enable TXE on queue: %u\n", q); REG_WRITE(ah, AR_Q_TXE, 1 << q); } +EXPORT_SYMBOL(ath9k_hw_txstart); u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) { @@ -65,6 +68,7 @@ u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) return npend; } +EXPORT_SYMBOL(ath9k_hw_numtxpending); bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) { @@ -94,6 +98,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) return newLevel != curLevel; } +EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel); bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) { @@ -173,6 +178,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) #undef ATH9K_TX_STOP_DMA_TIMEOUT #undef ATH9K_TIME_QUANTUM } +EXPORT_SYMBOL(ath9k_hw_stoptxdma); void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 segLen, bool firstSeg, @@ -199,6 +205,7 @@ void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, ads->ds_txstatus6 = ads->ds_txstatus7 = 0; ads->ds_txstatus8 = ads->ds_txstatus9 = 0; } +EXPORT_SYMBOL(ath9k_hw_filltxdesc); void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds) { @@ -210,6 +217,7 @@ void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds) ads->ds_txstatus6 = ads->ds_txstatus7 = 0; ads->ds_txstatus8 = ads->ds_txstatus9 = 0; } +EXPORT_SYMBOL(ath9k_hw_cleartxdesc); int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds) { @@ -285,6 +293,7 @@ int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds) return 0; } +EXPORT_SYMBOL(ath9k_hw_txprocdesc); void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, u32 pktLen, enum ath9k_pkt_type type, u32 txPower, @@ -320,6 +329,7 @@ void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, ads->ds_ctl11 = 0; } } +EXPORT_SYMBOL(ath9k_hw_set11n_txdesc); void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds, struct ath_desc *lastds, @@ -375,6 +385,7 @@ void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds, last_ads->ds_ctl2 = ads->ds_ctl2; last_ads->ds_ctl3 = ads->ds_ctl3; } +EXPORT_SYMBOL(ath9k_hw_set11n_ratescenario); void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds, u32 aggrLen) @@ -385,6 +396,7 @@ void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds, ads->ds_ctl6 &= ~AR_AggrLen; ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); } +EXPORT_SYMBOL(ath9k_hw_set11n_aggr_first); void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds, u32 numDelims) @@ -399,6 +411,7 @@ void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds, ctl6 |= SM(numDelims, AR_PadDelim); ads->ds_ctl6 = ctl6; } +EXPORT_SYMBOL(ath9k_hw_set11n_aggr_middle); void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds) { @@ -408,6 +421,7 @@ void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds) ads->ds_ctl1 &= ~AR_MoreAggr; ads->ds_ctl6 &= ~AR_PadDelim; } +EXPORT_SYMBOL(ath9k_hw_set11n_aggr_last); void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds) { @@ -415,6 +429,7 @@ void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds) ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); } +EXPORT_SYMBOL(ath9k_hw_clr11n_aggr); void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds, u32 burstDuration) @@ -424,6 +439,7 @@ void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds, ads->ds_ctl2 &= ~AR_BurstDur; ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); } +EXPORT_SYMBOL(ath9k_hw_set11n_burstduration); void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds, u32 vmf) @@ -441,6 +457,7 @@ void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs) *txqs &= ah->intr_txqs; ah->intr_txqs &= ~(*txqs); } +EXPORT_SYMBOL(ath9k_hw_gettxintrtxqs); bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, const struct ath9k_tx_queue_info *qinfo) @@ -512,6 +529,7 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, return true; } +EXPORT_SYMBOL(ath9k_hw_set_txq_props); bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, struct ath9k_tx_queue_info *qinfo) @@ -550,6 +568,7 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q, return true; } +EXPORT_SYMBOL(ath9k_hw_get_txq_props); int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, const struct ath9k_tx_queue_info *qinfo) @@ -617,6 +636,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, return q; } +EXPORT_SYMBOL(ath9k_hw_setuptxqueue); bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) { @@ -648,6 +668,7 @@ bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q) return true; } +EXPORT_SYMBOL(ath9k_hw_releasetxqueue); bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) { @@ -805,6 +826,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) return true; } +EXPORT_SYMBOL(ath9k_hw_resettxqueue); int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, u32 pa, struct ath_desc *nds, u64 tsf) @@ -886,6 +908,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, return 0; } +EXPORT_SYMBOL(ath9k_hw_rxprocdesc); void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) @@ -901,6 +924,7 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) memset(&(ads->u), 0, sizeof(ads->u)); } +EXPORT_SYMBOL(ath9k_hw_setuprxdesc); bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) { @@ -930,16 +954,19 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) return true; } +EXPORT_SYMBOL(ath9k_hw_setrxabort); void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp) { REG_WRITE(ah, AR_RXDP, rxdp); } +EXPORT_SYMBOL(ath9k_hw_putrxbuf); void ath9k_hw_rxena(struct ath_hw *ah) { REG_WRITE(ah, AR_CR, AR_CR_RXE); } +EXPORT_SYMBOL(ath9k_hw_rxena); void ath9k_hw_startpcureceive(struct ath_hw *ah) { @@ -949,6 +976,7 @@ void ath9k_hw_startpcureceive(struct ath_hw *ah) REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); } +EXPORT_SYMBOL(ath9k_hw_startpcureceive); void ath9k_hw_stoppcurecv(struct ath_hw *ah) { @@ -956,6 +984,7 @@ void ath9k_hw_stoppcurecv(struct ath_hw *ah) ath9k_hw_disable_mib_counters(ah); } +EXPORT_SYMBOL(ath9k_hw_stoppcurecv); bool ath9k_hw_stopdmarecv(struct ath_hw *ah) { @@ -988,3 +1017,4 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah) #undef AH_RX_TIME_QUANTUM #undef AH_RX_STOP_DMA_TIMEOUT } +EXPORT_SYMBOL(ath9k_hw_stopdmarecv); -- cgit v1.2.3 From 3ca340381a1da26906dc766a1e4f8a5d0a613189 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 23 Sep 2009 23:07:01 -0400 Subject: ath9k_hw: print device ID if not supported Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7d167a1b286d..7bf0f8c42e6d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -900,8 +900,12 @@ int ath9k_hw_init(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); int r = 0; - if (!ath9k_hw_devid_supported(ah->hw_version.devid)) + if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { + ath_print(common, ATH_DBG_FATAL, + "Unsupported device ID: 0x%0x\n", + ah->hw_version.devid); return -EOPNOTSUPP; + } ath9k_hw_init_defaults(ah); ath9k_hw_init_config(ah); -- cgit v1.2.3 From 7976b4263cb05dc638297d35f2a42375090ebaff Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 23 Sep 2009 23:07:02 -0400 Subject: ath9k_hw: add AR9271 srev and device ID to allow hw to support ar9271 This allows for hw support to be enabled for ar9271. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 4 ++-- drivers/net/wireless/ath/ath9k/hw.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7bf0f8c42e6d..692fd1dd909e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -609,6 +609,7 @@ static bool ath9k_hw_devid_supported(u16 devid) case AR9285_DEVID_PCIE: case AR5416_DEVID_AR9287_PCI: case AR5416_DEVID_AR9287_PCIE: + case AR9271_USB: return true; default: break; @@ -626,9 +627,8 @@ static bool ath9k_hw_macversion_supported(u32 macversion) case AR_SREV_VERSION_9280: case AR_SREV_VERSION_9285: case AR_SREV_VERSION_9287: - return true; - /* Not yet */ case AR_SREV_VERSION_9271: + return true; default: break; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 773f5c405c0e..f782c1a06b34 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -33,13 +33,18 @@ #include "../debug.h" #define ATHEROS_VENDOR_ID 0x168c + #define AR5416_DEVID_PCI 0x0023 #define AR5416_DEVID_PCIE 0x0024 #define AR9160_DEVID_PCI 0x0027 #define AR9280_DEVID_PCI 0x0029 #define AR9280_DEVID_PCIE 0x002a #define AR9285_DEVID_PCIE 0x002b + #define AR5416_AR9100_DEVID 0x000b + +#define AR9271_USB 0x9271 + #define AR_SUBVENDOR_ID_NOG 0x0e11 #define AR_SUBVENDOR_ID_NEW_A 0x7065 #define AR5416_MAGIC 0x19641014 -- cgit v1.2.3 From bc974f4a230756faf4f69114f271de2e678b363b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 28 Sep 2009 02:54:40 -0400 Subject: atheros: define a common priv struct hw code should never use private driver data, but sometimes we need a backpointer so just stuff it on the common ath struct. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 1 + drivers/net/wireless/ath/ath9k/debug.c | 7 ++++--- drivers/net/wireless/ath/ath9k/hw.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 37 +++++++++++++++++++++------------- drivers/net/wireless/ath/ath9k/pci.c | 9 +++------ 5 files changed, 31 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index e0341fefc921..b6cd752df839 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -56,6 +56,7 @@ struct ath_bus_ops { struct ath_common { void *ah; + void *priv; struct ieee80211_hw *hw; int debug_mask; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 352914cae6d8..25ae88ebdfac 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -562,8 +562,8 @@ static const struct file_operations fops_xmit = { int ath9k_init_debug(struct ath_hw *ah) { - struct ath_softc *sc = ah->ah_sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; common->debug_mask = ath9k_debug; @@ -620,7 +620,8 @@ err: void ath9k_exit_debug(struct ath_hw *ah) { - struct ath_softc *sc = ah->ah_sc; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; debugfs_remove(sc->debug.debugfs_xmit); debugfs_remove(sc->debug.debugfs_wiphy); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f782c1a06b34..cdaec526db35 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -450,7 +450,6 @@ struct ath_gen_timer_table { struct ath_hw { struct ieee80211_hw *hw; - struct ath_softc *ah_sc; struct ath_common common; struct ath9k_hw_version hw_version; struct ath9k_ops_config config; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2278dcbeee16..86374ad9313c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1438,17 +1438,22 @@ static void ath9k_gen_timer_start(struct ath_hw *ah, u32 timer_next, u32 timer_period) { + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; + ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); - if ((ah->ah_sc->imask & ATH9K_INT_GENTIMER) == 0) { + if ((sc->imask & ATH9K_INT_GENTIMER) == 0) { ath9k_hw_set_interrupts(ah, 0); - ah->ah_sc->imask |= ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, ah->ah_sc->imask); + sc->imask |= ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, sc->imask); } } static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) { + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; ath9k_hw_gen_timer_stop(ah, timer); @@ -1456,8 +1461,8 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) /* if no timer is enabled, turn off interrupt mask */ if (timer_table->timer_mask.val == 0) { ath9k_hw_set_interrupts(ah, 0); - ah->ah_sc->imask &= ~ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, ah->ah_sc->imask); + sc->imask &= ~ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, sc->imask); } } @@ -1554,28 +1559,32 @@ static int ath_init_btcoex_timer(struct ath_softc *sc) static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) { struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; if (ah->config.serialize_regmode == SER_REG_MODE_ON) { unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - iowrite32(val, ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + spin_lock_irqsave(&sc->sc_serial_rw, flags); + iowrite32(val, sc->mem + reg_offset); + spin_unlock_irqrestore(&sc->sc_serial_rw, flags); } else - iowrite32(val, ah->ah_sc->mem + reg_offset); + iowrite32(val, sc->mem + reg_offset); } static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) { struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_softc *sc = (struct ath_softc *) common->priv; u32 val; if (ah->config.serialize_regmode == SER_REG_MODE_ON) { unsigned long flags; - spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags); - val = ioread32(ah->ah_sc->mem + reg_offset); - spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags); + spin_lock_irqsave(&sc->sc_serial_rw, flags); + val = ioread32(sc->mem + reg_offset); + spin_unlock_irqrestore(&sc->sc_serial_rw, flags); } else - val = ioread32(ah->ah_sc->mem + reg_offset); + val = ioread32(sc->mem + reg_offset); return val; } @@ -1618,7 +1627,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, goto bad_no_ah; } - ah->ah_sc = sc; ah->hw_version.devid = devid; ah->hw_version.subsysid = subsysid; sc->sc_ah = ah; @@ -1628,6 +1636,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, common->bus_ops = bus_ops; common->ah = ah; common->hw = sc->hw; + common->priv = sc; /* * Cache line size is used to size and align various diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index b2a45ce62698..63059b6a90da 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -33,8 +33,7 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { /* return bus cachesize in 4B word units */ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) { - struct ath_hw *ah = (struct ath_hw *) common->ah; - struct ath_softc *sc = ah->ah_sc; + struct ath_softc *sc = (struct ath_softc *) common->priv; u8 u8tmp; pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp); @@ -52,8 +51,7 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) static void ath_pci_cleanup(struct ath_common *common) { - struct ath_hw *ah = (struct ath_hw *) common->ah; - struct ath_softc *sc = ah->ah_sc; + struct ath_softc *sc = (struct ath_softc *) common->priv; struct pci_dev *pdev = to_pci_dev(sc->dev); pci_iounmap(pdev, sc->mem); @@ -86,8 +84,7 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) */ static void ath_pci_bt_coex_prep(struct ath_common *common) { - struct ath_hw *ah = (struct ath_hw *) common->ah; - struct ath_softc *sc = ah->ah_sc; + struct ath_softc *sc = (struct ath_softc *) common->priv; struct pci_dev *pdev = to_pci_dev(sc->dev); u8 aspm; -- cgit v1.2.3 From 3d23e349d807177eaf519d444677cee86b1a04cf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 29 Sep 2009 23:27:28 +0200 Subject: wext: refactor Refactor wext to * split out iwpriv handling * split out iwspy handling * split out procfs support * allow cfg80211 to have wireless extensions compat code w/o CONFIG_WIRELESS_EXT After this, drivers need to - select WIRELESS_EXT - for wext support - select WEXT_PRIV - for iwpriv support - select WEXT_SPY - for iwspy support except cfg80211 -- which gets new hooks in wext-core.c and can then get wext handlers without CONFIG_WIRELESS_EXT. Wireless extensions procfs support is auto-selected based on PROC_FS and anything that requires the wext core (i.e. WIRELESS_EXT or CFG80211_WEXT). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 29 +- drivers/net/wireless/hostap/Kconfig | 2 + drivers/net/wireless/ipw2x00/Kconfig | 5 + drivers/net/wireless/orinoco/Kconfig | 2 + include/net/cfg80211.h | 6 +- include/net/iw_handler.h | 14 +- include/net/net_namespace.h | 2 +- include/net/wext.h | 49 +- net/core/net-sysfs.c | 6 +- net/socket.c | 4 +- net/wireless/Kconfig | 50 +- net/wireless/Makefile | 8 +- net/wireless/core.c | 14 +- net/wireless/ibss.c | 10 +- net/wireless/mlme.c | 2 +- net/wireless/nl80211.c | 4 +- net/wireless/scan.c | 6 +- net/wireless/sme.c | 12 +- net/wireless/wext-core.c | 1063 ++++++++++++++++++++ net/wireless/wext-priv.c | 248 +++++ net/wireless/wext-proc.c | 155 +++ net/wireless/wext-spy.c | 231 +++++ net/wireless/wext.c | 1775 ---------------------------------- 23 files changed, 1850 insertions(+), 1847 deletions(-) create mode 100644 net/wireless/wext-core.c create mode 100644 net/wireless/wext-priv.c create mode 100644 net/wireless/wext-proc.c create mode 100644 net/wireless/wext-spy.c delete mode 100644 net/wireless/wext.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index d7a764a2fc1a..c9829c59fd98 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -67,6 +67,8 @@ config WAVELAN tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support" depends on ISA && WLAN_PRE80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV ---help--- The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is a Radio LAN (wireless Ethernet-like Local Area Network) using the @@ -90,6 +92,8 @@ config PCMCIA_WAVELAN tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support" depends on PCMCIA && WLAN_PRE80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV help Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA (PC-card) wireless Ethernet networking card to your computer. This @@ -102,6 +106,7 @@ config PCMCIA_NETWAVE tristate "Xircom Netwave AirSurfer Pcmcia wireless support" depends on PCMCIA && WLAN_PRE80211 select WIRELESS_EXT + select WEXT_PRIV help Say Y here if you intend to attach this type of PCMCIA (PC-card) wireless Ethernet networking card to your computer. @@ -123,6 +128,8 @@ config PCMCIA_RAYCS tristate "Aviator/Raytheon 2.4GHz wireless support" depends on PCMCIA && WLAN_80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV ---help--- Say Y here if you intend to attach an Aviator/Raytheon PCMCIA (PC-card) wireless Ethernet networking card to your computer. @@ -136,6 +143,7 @@ config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" depends on WLAN_80211 select WIRELESS_EXT + select WEXT_SPY select LIB80211 select FW_LOADER ---help--- @@ -190,6 +198,8 @@ config AIRO depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN) select WIRELESS_EXT select CRYPTO + select WEXT_SPY + select WEXT_PRIV ---help--- This is the standard Linux driver to support Cisco/Aironet ISA and PCI 802.11 wireless cards. @@ -207,6 +217,7 @@ config ATMEL tristate "Atmel at76c50x chipset 802.11b support" depends on (PCI || PCMCIA) && WLAN_80211 select WIRELESS_EXT + select WEXT_PRIV select FW_LOADER select CRC32 ---help--- @@ -266,18 +277,21 @@ config AIRO_CS Cisco Linux utilities can be used to configure the card. config PCMCIA_WL3501 - tristate "Planet WL3501 PCMCIA cards" - depends on EXPERIMENTAL && PCMCIA && WLAN_80211 - select WIRELESS_EXT - ---help--- - A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. - It has basic support for Linux wireless extensions and initial - micro support for ethtool. + tristate "Planet WL3501 PCMCIA cards" + depends on EXPERIMENTAL && PCMCIA && WLAN_80211 + select WIRELESS_EXT + select WEXT_SPY + help + A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. + It has basic support for Linux wireless extensions and initial + micro support for ethtool. config PRISM54 tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' depends on PCI && EXPERIMENTAL && WLAN_80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV select FW_LOADER ---help--- This enables support for FullMAC PCI/Cardbus prism54 devices. This @@ -300,6 +314,7 @@ config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" depends on USB && WLAN_80211 select WIRELESS_EXT + select WEXT_PRIV select FW_LOADER ---help--- Say Y if you want to use wireless LAN adapters based on the ZyDAS diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig index c15db2293515..08f1e989653d 100644 --- a/drivers/net/wireless/hostap/Kconfig +++ b/drivers/net/wireless/hostap/Kconfig @@ -2,6 +2,8 @@ config HOSTAP tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" depends on WLAN_80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV select CRYPTO select CRYPTO_ARC4 select CRYPTO_ECB diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index a8131384c6b9..56fab79dc365 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -6,6 +6,8 @@ config IPW2100 tristate "Intel PRO/Wireless 2100 Network Connection" depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV select FW_LOADER select LIB80211 select LIBIPW @@ -65,6 +67,8 @@ config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV select FW_LOADER select LIB80211 select LIBIPW @@ -152,6 +156,7 @@ config LIBIPW tristate depends on PCI && WLAN_80211 && CFG80211 select WIRELESS_EXT + select WEXT_SPY select CRYPTO select CRYPTO_ARC4 select CRYPTO_ECB diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig index 83b635fd7784..13b03b3e8fce 100644 --- a/drivers/net/wireless/orinoco/Kconfig +++ b/drivers/net/wireless/orinoco/Kconfig @@ -3,6 +3,8 @@ config HERMES depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 depends on CFG80211 select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV select FW_LOADER select CRYPTO select CRYPTO_MICHAEL_MIC diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3d874c620219..241ea14d6df8 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1171,6 +1171,10 @@ struct wiphy { struct net *_net; #endif +#ifdef CONFIG_CFG80211_WEXT + const struct iw_handler_def *wext; +#endif + char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; @@ -1345,7 +1349,7 @@ struct wireless_dev { struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; struct cfg80211_internal_bss *current_bss; /* associated / joined */ -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT /* wext data */ struct { struct cfg80211_ibss_params ibss; diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h index e9054a283fde..d5d337170a56 100644 --- a/include/net/iw_handler.h +++ b/include/net/iw_handler.h @@ -323,18 +323,19 @@ typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, */ struct iw_handler_def { - /* Number of handlers defined (more precisely, index of the - * last defined handler + 1) */ - __u16 num_standard; - __u16 num_private; - /* Number of private arg description */ - __u16 num_private_args; /* Array of handlers for standard ioctls * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWCOMMIT] */ const iw_handler * standard; + /* Number of handlers defined (more precisely, index of the + * last defined handler + 1) */ + __u16 num_standard; +#ifdef CONFIG_WEXT_PRIV + __u16 num_private; + /* Number of private arg description */ + __u16 num_private_args; /* Array of handlers for private ioctls * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV] */ @@ -344,6 +345,7 @@ struct iw_handler_def * can put it in any order you want and should not leave holes... * We will automatically export that to user space... */ const struct iw_priv_args * private_args; +#endif /* New location of get_wireless_stats, to de-bloat struct net_device. * The old pointer in struct net_device will be gradually phased diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index a1202841aadd..699410142bfa 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -80,7 +80,7 @@ struct net { #ifdef CONFIG_XFRM struct netns_xfrm xfrm; #endif -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_WEXT_CORE struct sk_buff_head wext_nlevents; #endif struct net_generic *gen; diff --git a/include/net/wext.h b/include/net/wext.h index 3f2b94de2cfa..4f6e7423174c 100644 --- a/include/net/wext.h +++ b/include/net/wext.h @@ -1,29 +1,19 @@ #ifndef __NET_WEXT_H #define __NET_WEXT_H -/* - * wireless extensions interface to the core code - */ +#include struct net; -#ifdef CONFIG_WIRELESS_EXT -extern int wext_proc_init(struct net *net); -extern void wext_proc_exit(struct net *net); +#ifdef CONFIG_WEXT_CORE extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, void __user *arg); extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, unsigned long arg); + extern struct iw_statistics *get_wireless_stats(struct net_device *dev); +extern int call_commit_handler(struct net_device *dev); #else -static inline int wext_proc_init(struct net *net) -{ - return 0; -} -static inline void wext_proc_exit(struct net *net) -{ - return; -} static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, void __user *arg) { @@ -36,4 +26,35 @@ static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, } #endif +#ifdef CONFIG_WEXT_PROC +extern int wext_proc_init(struct net *net); +extern void wext_proc_exit(struct net *net); +#else +static inline int wext_proc_init(struct net *net) +{ + return 0; +} +static inline void wext_proc_exit(struct net *net) +{ + return; +} +#endif + +#ifdef CONFIG_WEXT_PRIV +int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler); +int compat_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler); +int iw_handler_get_private(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra); +#else +#define ioctl_private_call NULL +#define compat_private_call NULL +#endif + + #endif /* __NET_WEXT_H */ diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index effb78410eb2..9b07535c2889 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -543,8 +543,12 @@ int netdev_register_kobject(struct net_device *net) *groups++ = &netstat_group; #ifdef CONFIG_WIRELESS_EXT_SYSFS - if (net->wireless_handlers || net->ieee80211_ptr) + if (net->ieee80211_ptr) *groups++ = &wireless_group; +#ifdef CONFIG_WIRELESS_EXT + else if (net->wireless_handlers) + *groups++ = &wireless_group; +#endif #endif #endif /* CONFIG_SYSFS */ diff --git a/net/socket.c b/net/socket.c index 75655365b5fd..92a56709fd7d 100644 --- a/net/socket.c +++ b/net/socket.c @@ -905,11 +905,11 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { err = dev_ioctl(net, cmd, argp); } else -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_WEXT_CORE if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { err = dev_ioctl(net, cmd, argp); } else -#endif /* CONFIG_WIRELESS_EXT */ +#endif switch (cmd) { case FIOSETOWN: case SIOCSPGRP: diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index abf7ca3f9ff9..614bdcec1c80 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -1,3 +1,21 @@ +config WIRELESS_EXT + bool + +config WEXT_CORE + def_bool y + depends on CFG80211_WEXT || WIRELESS_EXT + +config WEXT_PROC + def_bool y + depends on PROC_FS + depends on WEXT_CORE + +config WEXT_SPY + bool + +config WEXT_PRIV + bool + config CFG80211 tristate "cfg80211 - wireless configuration API" depends on RFKILL || !RFKILL @@ -56,6 +74,12 @@ config CFG80211_REG_DEBUG If unsure, say N. +config CFG80211_DEFAULT_PS_VALUE + int + default 1 if CFG80211_DEFAULT_PS + default 0 + depends on CFG80211 + config CFG80211_DEFAULT_PS bool "enable powersave by default" depends on CFG80211 @@ -67,14 +91,10 @@ config CFG80211_DEFAULT_PS applications instead -- they need to register their network latency requirement, see Documentation/power/pm_qos_interface.txt. -config CFG80211_DEFAULT_PS_VALUE - int - default 1 if CFG80211_DEFAULT_PS - default 0 - config CFG80211_DEBUGFS bool "cfg80211 DebugFS entries" - depends on CFG80211 && DEBUG_FS + depends on CFG80211 + depends on DEBUG_FS ---help--- You can enable this if you want to debugfs entries for cfg80211. @@ -83,6 +103,7 @@ config CFG80211_DEBUGFS config WIRELESS_OLD_REGULATORY bool "Old wireless static regulatory definitions" default n + depends on CFG80211 ---help--- This option enables the old static regulatory information and uses it within the new framework. This option is available @@ -94,20 +115,19 @@ config WIRELESS_OLD_REGULATORY Say N and if you say Y, please tell us why. The default is N. -config WIRELESS_EXT - bool "Wireless extensions" +config CFG80211_WEXT + bool "cfg80211 wireless extensions compatibility" + depends on CFG80211 + select WEXT_CORE default y - ---help--- - This option enables the legacy wireless extensions - (wireless network interface configuration via ioctls.) - - Say Y unless you've upgraded all your userspace to use - nl80211 instead of wireless extensions. + help + Enable this option if you need old userspace for wireless + extensions with cfg80211-based drivers. config WIRELESS_EXT_SYSFS bool "Wireless extensions sysfs files" default y - depends on WIRELESS_EXT && SYSFS + depends on WEXT_CORE && SYSFS help This option enables the deprecated wireless statistics files in /sys/class/net/*/wireless/. The same information diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 3ecaa9179977..c8141505a83a 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -1,13 +1,17 @@ -obj-$(CONFIG_WIRELESS_EXT) += wext.o obj-$(CONFIG_CFG80211) += cfg80211.o obj-$(CONFIG_LIB80211) += lib80211.o obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o +obj-$(CONFIG_WEXT_CORE) += wext-core.o +obj-$(CONFIG_WEXT_PROC) += wext-proc.o +obj-$(CONFIG_WEXT_SPY) += wext-spy.o +obj-$(CONFIG_WEXT_PRIV) += wext-priv.o + cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o cfg80211-y += mlme.o ibss.o sme.o chan.o cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o -cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o +cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/wireless/core.c b/net/wireless/core.c index e6f02e98e5fd..eb0bb24b99c3 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -358,6 +358,10 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) INIT_LIST_HEAD(&rdev->bss_list); INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); +#ifdef CONFIG_CFG80211_WEXT + rdev->wiphy.wext = &cfg80211_wext_handler; +#endif + device_initialize(&rdev->wiphy.dev); rdev->wiphy.dev.class = &ieee80211_class; rdev->wiphy.dev.platform_data = rdev; @@ -672,9 +676,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev->netdev = dev; wdev->sme_state = CFG80211_SME_IDLE; mutex_unlock(&rdev->devlist_mtx); -#ifdef CONFIG_WIRELESS_EXT - if (!dev->wireless_handlers) - dev->wireless_handlers = &cfg80211_wext_handler; +#ifdef CONFIG_CFG80211_WEXT wdev->wext.default_key = -1; wdev->wext.default_mgmt_key = -1; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; @@ -696,7 +698,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, break; case NL80211_IFTYPE_STATION: wdev_lock(wdev); -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT kfree(wdev->wext.ie); wdev->wext.ie = NULL; wdev->wext.ie_len = 0; @@ -728,7 +730,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, mutex_unlock(&rdev->devlist_mtx); dev_put(dev); } -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); @@ -766,7 +768,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, sysfs_remove_link(&dev->dev.kobj, "phy80211"); list_del_init(&wdev->list); rdev->devlist_generation++; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT kfree(wdev->wext.keys); #endif } diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index c88338911979..39b6d92e2828 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -15,7 +15,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_bss *bss; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif @@ -44,7 +44,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, GFP_KERNEL); -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT memset(&wrqu, 0, sizeof(wrqu)); memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); @@ -96,7 +96,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, kfree(wdev->connect_keys); wdev->connect_keys = connkeys; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT wdev->wext.ibss.channel = params->channel; #endif err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); @@ -154,7 +154,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) wdev->current_bss = NULL; wdev->ssid_len = 0; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT if (!nowext) wdev->wext.ibss.ssid_len = 0; #endif @@ -203,7 +203,7 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, return err; } -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev) { diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 79d2eec54cec..ceb2c14c8f47 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -331,7 +331,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, { struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; char *buf = kmalloc(128, gfp); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e0ecc9f153d4..14004e2ebd62 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1264,7 +1264,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) if (!err) err = func(&rdev->wiphy, dev, key.idx); -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT if (!err) { if (func == rdev->ops->set_default_key) dev->ieee80211_ptr->wext.default_key = key.idx; @@ -1365,7 +1365,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) if (!err) err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT if (!err) { if (key.idx == dev->ieee80211_ptr->wext.default_key) dev->ieee80211_ptr->wext.default_key = -1; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index e5f92ee758f4..2e8c515f3c5c 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -22,7 +22,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) { struct cfg80211_scan_request *request; struct net_device *dev; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif @@ -47,7 +47,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) else nl80211_send_scan_done(rdev, dev); -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT if (!request->aborted) { memset(&wrqu, 0, sizeof(wrqu)); @@ -592,7 +592,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) } EXPORT_SYMBOL(cfg80211_unlink_bss); -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT int cfg80211_wext_siwscan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 93c3ed329204..d3624152f7f7 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -345,7 +345,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, { struct wireless_dev *wdev = dev->ieee80211_ptr; u8 *country_ie; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif @@ -362,7 +362,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, resp_ie, resp_ie_len, status, GFP_KERNEL); -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT if (wextev) { if (req_ie && status == WLAN_STATUS_SUCCESS) { memset(&wrqu, 0, sizeof(wrqu)); @@ -477,7 +477,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, const u8 *resp_ie, size_t resp_ie_len) { struct cfg80211_bss *bss; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif @@ -512,7 +512,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, GFP_KERNEL); -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT if (req_ie) { memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = req_ie_len; @@ -573,7 +573,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); int i; -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif @@ -631,7 +631,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, for (i = 0; i < 6; i++) rdev->ops->del_key(wdev->wiphy, dev, i, NULL); -#ifdef CONFIG_WIRELESS_EXT +#ifdef CONFIG_CFG80211_WEXT memset(&wrqu, 0, sizeof(wrqu)); wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c new file mode 100644 index 000000000000..a4e5ddc8d4f5 --- /dev/null +++ b/net/wireless/wext-core.c @@ -0,0 +1,1063 @@ +/* + * This file implement the Wireless Extensions core API. + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * Copyright 2009 Johannes Berg + * + * (As all part of the Linux kernel, this file is GPL) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, + unsigned int, struct iw_request_info *, + iw_handler); + + +/* + * Meta-data about all the standard Wireless Extension request we + * know about. + */ +static const struct iw_ioctl_description standard_ioctl[] = { + [SIOCSIWCOMMIT - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWNAME - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_CHAR, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWNWID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWNWID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWFREQ - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_FREQ, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWFREQ - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_FREQ, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWMODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_UINT, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWMODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_UINT, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWSENS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWSENS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWRANGE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWRANGE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_range), + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWPRIV - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_priv_args), + .max_tokens = 16, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [SIOCSIWSTATS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_NULL, + }, + [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_statistics), + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr), + .max_tokens = IW_MAX_SPY, + }, + [SIOCGIWSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr) + + sizeof(struct iw_quality), + .max_tokens = IW_MAX_SPY, + }, + [SIOCSIWTHRSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_thrspy), + .min_tokens = 1, + .max_tokens = 1, + }, + [SIOCGIWTHRSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_thrspy), + .min_tokens = 1, + .max_tokens = 1, + }, + [SIOCSIWAP - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [SIOCGIWAP - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWMLME - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_mlme), + .max_tokens = sizeof(struct iw_mlme), + }, + [SIOCGIWAPLIST - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct sockaddr) + + sizeof(struct iw_quality), + .max_tokens = IW_MAX_AP, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [SIOCSIWSCAN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = 0, + .max_tokens = sizeof(struct iw_scan_req), + }, + [SIOCGIWSCAN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_SCAN_MAX_DATA, + .flags = IW_DESCR_FLAG_NOMAX, + }, + [SIOCSIWESSID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + .flags = IW_DESCR_FLAG_EVENT, + }, + [SIOCGIWESSID - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + .flags = IW_DESCR_FLAG_DUMP, + }, + [SIOCSIWNICKN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + }, + [SIOCGIWNICKN - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ESSID_MAX_SIZE, + }, + [SIOCSIWRATE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWRATE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWRTS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWRTS - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWFRAG - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWFRAG - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWTXPOW - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWTXPOW - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWRETRY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWRETRY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWENCODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ENCODING_TOKEN_MAX, + .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, + }, + [SIOCGIWENCODE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_ENCODING_TOKEN_MAX, + .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, + }, + [SIOCSIWPOWER - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWPOWER - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWGENIE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [SIOCGIWGENIE - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [SIOCSIWAUTH - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCGIWAUTH - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_PARAM, + }, + [SIOCSIWENCODEEXT - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_encode_ext), + .max_tokens = sizeof(struct iw_encode_ext) + + IW_ENCODING_TOKEN_MAX, + }, + [SIOCGIWENCODEEXT - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_encode_ext), + .max_tokens = sizeof(struct iw_encode_ext) + + IW_ENCODING_TOKEN_MAX, + }, + [SIOCSIWPMKSA - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .min_tokens = sizeof(struct iw_pmksa), + .max_tokens = sizeof(struct iw_pmksa), + }, +}; +static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl); + +/* + * Meta-data about all the additional standard Wireless Extension events + * we know about. + */ +static const struct iw_ioctl_description standard_event[] = { + [IWEVTXDROP - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IWEVQUAL - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_QUAL, + }, + [IWEVCUSTOM - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_CUSTOM_MAX, + }, + [IWEVREGISTERED - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IWEVEXPIRED - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_ADDR, + }, + [IWEVGENIE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IWEVMICHAELMICFAILURE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_michaelmicfailure), + }, + [IWEVASSOCREQIE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IWEVASSOCRESPIE - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = IW_GENERIC_IE_MAX, + }, + [IWEVPMKIDCAND - IWEVFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = 1, + .max_tokens = sizeof(struct iw_pmkid_cand), + }, +}; +static const unsigned standard_event_num = ARRAY_SIZE(standard_event); + +/* Size (in bytes) of various events */ +static const int event_type_size[] = { + IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ + 0, + IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, + IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ + IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ + IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, + IW_EV_POINT_LEN, /* Without variable payload */ + IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ + IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ +}; + +#ifdef CONFIG_COMPAT +static const int compat_event_type_size[] = { + IW_EV_COMPAT_LCP_LEN, /* IW_HEADER_TYPE_NULL */ + 0, + IW_EV_COMPAT_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, + IW_EV_COMPAT_UINT_LEN, /* IW_HEADER_TYPE_UINT */ + IW_EV_COMPAT_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ + IW_EV_COMPAT_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, + IW_EV_COMPAT_POINT_LEN, /* Without variable payload */ + IW_EV_COMPAT_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ + IW_EV_COMPAT_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ +}; +#endif + + +/* IW event code */ + +static int __net_init wext_pernet_init(struct net *net) +{ + skb_queue_head_init(&net->wext_nlevents); + return 0; +} + +static void __net_exit wext_pernet_exit(struct net *net) +{ + skb_queue_purge(&net->wext_nlevents); +} + +static struct pernet_operations wext_pernet_ops = { + .init = wext_pernet_init, + .exit = wext_pernet_exit, +}; + +static int __init wireless_nlevent_init(void) +{ + return register_pernet_subsys(&wext_pernet_ops); +} + +subsys_initcall(wireless_nlevent_init); + +/* Process events generated by the wireless layer or the driver. */ +static void wireless_nlevent_process(struct work_struct *work) +{ + struct sk_buff *skb; + struct net *net; + + rtnl_lock(); + + for_each_net(net) { + while ((skb = skb_dequeue(&net->wext_nlevents))) + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, + GFP_KERNEL); + } + + rtnl_unlock(); +} + +static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process); + +static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev, + struct sk_buff *skb) +{ + struct ifinfomsg *r; + struct nlmsghdr *nlh; + + nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0); + if (!nlh) + return NULL; + + r = nlmsg_data(nlh); + r->ifi_family = AF_UNSPEC; + r->__ifi_pad = 0; + r->ifi_type = dev->type; + r->ifi_index = dev->ifindex; + r->ifi_flags = dev_get_flags(dev); + r->ifi_change = 0; /* Wireless changes don't affect those flags */ + + NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); + + return nlh; + nla_put_failure: + nlmsg_cancel(skb, nlh); + return NULL; +} + + +/* + * Main event dispatcher. Called from other parts and drivers. + * Send the event on the appropriate channels. + * May be called from interrupt context. + */ +void wireless_send_event(struct net_device * dev, + unsigned int cmd, + union iwreq_data * wrqu, + const char * extra) +{ + const struct iw_ioctl_description * descr = NULL; + int extra_len = 0; + struct iw_event *event; /* Mallocated whole event */ + int event_len; /* Its size */ + int hdr_len; /* Size of the event header */ + int wrqu_off = 0; /* Offset in wrqu */ + /* Don't "optimise" the following variable, it will crash */ + unsigned cmd_index; /* *MUST* be unsigned */ + struct sk_buff *skb; + struct nlmsghdr *nlh; + struct nlattr *nla; +#ifdef CONFIG_COMPAT + struct __compat_iw_event *compat_event; + struct compat_iw_point compat_wrqu; + struct sk_buff *compskb; +#endif + + /* + * Nothing in the kernel sends scan events with data, be safe. + * This is necessary because we cannot fix up scan event data + * for compat, due to being contained in 'extra', but normally + * applications are required to retrieve the scan data anyway + * and no data is included in the event, this codifies that + * practice. + */ + if (WARN_ON(cmd == SIOCGIWSCAN && extra)) + extra = NULL; + + /* Get the description of the Event */ + if (cmd <= SIOCIWLAST) { + cmd_index = cmd - SIOCIWFIRST; + if (cmd_index < standard_ioctl_num) + descr = &(standard_ioctl[cmd_index]); + } else { + cmd_index = cmd - IWEVFIRST; + if (cmd_index < standard_event_num) + descr = &(standard_event[cmd_index]); + } + /* Don't accept unknown events */ + if (descr == NULL) { + /* Note : we don't return an error to the driver, because + * the driver would not know what to do about it. It can't + * return an error to the user, because the event is not + * initiated by a user request. + * The best the driver could do is to log an error message. + * We will do it ourselves instead... + */ + printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", + dev->name, cmd); + return; + } + + /* Check extra parameters and set extra_len */ + if (descr->header_type == IW_HEADER_TYPE_POINT) { + /* Check if number of token fits within bounds */ + if (wrqu->data.length > descr->max_tokens) { + printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); + return; + } + if (wrqu->data.length < descr->min_tokens) { + printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); + return; + } + /* Calculate extra_len - extra is NULL for restricted events */ + if (extra != NULL) + extra_len = wrqu->data.length * descr->token_size; + /* Always at an offset in wrqu */ + wrqu_off = IW_EV_POINT_OFF; + } + + /* Total length of the event */ + hdr_len = event_type_size[descr->header_type]; + event_len = hdr_len + extra_len; + + /* + * The problem for 64/32 bit. + * + * On 64-bit, a regular event is laid out as follows: + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + * | event.len | event.cmd | p a d d i n g | + * | wrqu data ... (with the correct size) | + * + * This padding exists because we manipulate event->u, + * and 'event' is not packed. + * + * An iw_point event is laid out like this instead: + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + * | event.len | event.cmd | p a d d i n g | + * | iwpnt.len | iwpnt.flg | p a d d i n g | + * | extra data ... + * + * The second padding exists because struct iw_point is extended, + * but this depends on the platform... + * + * On 32-bit, all the padding shouldn't be there. + */ + + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + return; + + /* Send via the RtNetlink event channel */ + nlh = rtnetlink_ifinfo_prep(dev, skb); + if (WARN_ON(!nlh)) { + kfree_skb(skb); + return; + } + + /* Add the wireless events in the netlink packet */ + nla = nla_reserve(skb, IFLA_WIRELESS, event_len); + if (!nla) { + kfree_skb(skb); + return; + } + event = nla_data(nla); + + /* Fill event - first clear to avoid data leaking */ + memset(event, 0, hdr_len); + event->len = event_len; + event->cmd = cmd; + memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); + if (extra_len) + memcpy(((char *) event) + hdr_len, extra, extra_len); + + nlmsg_end(skb, nlh); +#ifdef CONFIG_COMPAT + hdr_len = compat_event_type_size[descr->header_type]; + event_len = hdr_len + extra_len; + + compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!compskb) { + kfree_skb(skb); + return; + } + + /* Send via the RtNetlink event channel */ + nlh = rtnetlink_ifinfo_prep(dev, compskb); + if (WARN_ON(!nlh)) { + kfree_skb(skb); + kfree_skb(compskb); + return; + } + + /* Add the wireless events in the netlink packet */ + nla = nla_reserve(compskb, IFLA_WIRELESS, event_len); + if (!nla) { + kfree_skb(skb); + kfree_skb(compskb); + return; + } + compat_event = nla_data(nla); + + compat_event->len = event_len; + compat_event->cmd = cmd; + if (descr->header_type == IW_HEADER_TYPE_POINT) { + compat_wrqu.length = wrqu->data.length; + compat_wrqu.flags = wrqu->data.flags; + memcpy(&compat_event->pointer, + ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF, + hdr_len - IW_EV_COMPAT_LCP_LEN); + if (extra_len) + memcpy(((char *) compat_event) + hdr_len, + extra, extra_len); + } else { + /* extra_len must be zero, so no if (extra) needed */ + memcpy(&compat_event->pointer, wrqu, + hdr_len - IW_EV_COMPAT_LCP_LEN); + } + + nlmsg_end(compskb, nlh); + + skb_shinfo(skb)->frag_list = compskb; +#endif + skb_queue_tail(&dev_net(dev)->wext_nlevents, skb); + schedule_work(&wireless_nlevent_work); +} +EXPORT_SYMBOL(wireless_send_event); + + + +/* IW handlers */ + +struct iw_statistics *get_wireless_stats(struct net_device *dev) +{ +#ifdef CONFIG_WIRELESS_EXT + if ((dev->wireless_handlers != NULL) && + (dev->wireless_handlers->get_wireless_stats != NULL)) + return dev->wireless_handlers->get_wireless_stats(dev); +#endif + +#ifdef CONFIG_CFG80211_WEXT + if (dev->ieee80211_ptr && dev->ieee80211_ptr && + dev->ieee80211_ptr->wiphy && + dev->ieee80211_ptr->wiphy->wext && + dev->ieee80211_ptr->wiphy->wext->get_wireless_stats) + return dev->ieee80211_ptr->wiphy->wext->get_wireless_stats(dev); +#endif + + /* not found */ + return NULL; +} + +static int iw_handler_get_iwstats(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + /* Get stats from the driver */ + struct iw_statistics *stats; + + stats = get_wireless_stats(dev); + if (stats) { + /* Copy statistics to extra */ + memcpy(extra, stats, sizeof(struct iw_statistics)); + wrqu->data.length = sizeof(struct iw_statistics); + + /* Check if we need to clear the updated flag */ + if (wrqu->data.flags != 0) + stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; + return 0; + } else + return -EOPNOTSUPP; +} + +static iw_handler get_handler(struct net_device *dev, unsigned int cmd) +{ + /* Don't "optimise" the following variable, it will crash */ + unsigned int index; /* *MUST* be unsigned */ + const struct iw_handler_def *handlers = NULL; + +#ifdef CONFIG_CFG80211_WEXT + if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy) + handlers = dev->ieee80211_ptr->wiphy->wext; +#endif +#ifdef CONFIG_WIRELESS_EXT + if (dev->wireless_handlers) + handlers = dev->wireless_handlers; +#endif + + if (!handlers) + return NULL; + + /* Try as a standard command */ + index = cmd - SIOCIWFIRST; + if (index < handlers->num_standard) + return handlers->standard[index]; + +#ifdef CONFIG_WEXT_PRIV + /* Try as a private command */ + index = cmd - SIOCIWFIRSTPRIV; + if (index < handlers->num_private) + return handlers->private[index]; +#endif + + /* Not found */ + return NULL; +} + +static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, + const struct iw_ioctl_description *descr, + iw_handler handler, struct net_device *dev, + struct iw_request_info *info) +{ + int err, extra_size, user_length = 0, essid_compat = 0; + char *extra; + + /* Calculate space needed by arguments. Always allocate + * for max space. + */ + extra_size = descr->max_tokens * descr->token_size; + + /* Check need for ESSID compatibility for WE < 21 */ + switch (cmd) { + case SIOCSIWESSID: + case SIOCGIWESSID: + case SIOCSIWNICKN: + case SIOCGIWNICKN: + if (iwp->length == descr->max_tokens + 1) + essid_compat = 1; + else if (IW_IS_SET(cmd) && (iwp->length != 0)) { + char essid[IW_ESSID_MAX_SIZE + 1]; + unsigned int len; + len = iwp->length * descr->token_size; + + if (len > IW_ESSID_MAX_SIZE) + return -EFAULT; + + err = copy_from_user(essid, iwp->pointer, len); + if (err) + return -EFAULT; + + if (essid[iwp->length - 1] == '\0') + essid_compat = 1; + } + break; + default: + break; + } + + iwp->length -= essid_compat; + + /* Check what user space is giving us */ + if (IW_IS_SET(cmd)) { + /* Check NULL pointer */ + if (!iwp->pointer && iwp->length != 0) + return -EFAULT; + /* Check if number of token fits within bounds */ + if (iwp->length > descr->max_tokens) + return -E2BIG; + if (iwp->length < descr->min_tokens) + return -EINVAL; + } else { + /* Check NULL pointer */ + if (!iwp->pointer) + return -EFAULT; + /* Save user space buffer size for checking */ + user_length = iwp->length; + + /* Don't check if user_length > max to allow forward + * compatibility. The test user_length < min is + * implied by the test at the end. + */ + + /* Support for very large requests */ + if ((descr->flags & IW_DESCR_FLAG_NOMAX) && + (user_length > descr->max_tokens)) { + /* Allow userspace to GET more than max so + * we can support any size GET requests. + * There is still a limit : -ENOMEM. + */ + extra_size = user_length * descr->token_size; + + /* Note : user_length is originally a __u16, + * and token_size is controlled by us, + * so extra_size won't get negative and + * won't overflow... + */ + } + } + + /* kzalloc() ensures NULL-termination for essid_compat. */ + extra = kzalloc(extra_size, GFP_KERNEL); + if (!extra) + return -ENOMEM; + + /* If it is a SET, get all the extra data in here */ + if (IW_IS_SET(cmd) && (iwp->length != 0)) { + if (copy_from_user(extra, iwp->pointer, + iwp->length * + descr->token_size)) { + err = -EFAULT; + goto out; + } + + if (cmd == SIOCSIWENCODEEXT) { + struct iw_encode_ext *ee = (void *) extra; + + if (iwp->length < sizeof(*ee) + ee->key_len) + return -EFAULT; + } + } + + err = handler(dev, info, (union iwreq_data *) iwp, extra); + + iwp->length += essid_compat; + + /* If we have something to return to the user */ + if (!err && IW_IS_GET(cmd)) { + /* Check if there is enough buffer up there */ + if (user_length < iwp->length) { + err = -E2BIG; + goto out; + } + + if (copy_to_user(iwp->pointer, extra, + iwp->length * + descr->token_size)) { + err = -EFAULT; + goto out; + } + } + + /* Generate an event to notify listeners of the change */ + if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { + union iwreq_data *data = (union iwreq_data *) iwp; + + if (descr->flags & IW_DESCR_FLAG_RESTRICT) + /* If the event is restricted, don't + * export the payload. + */ + wireless_send_event(dev, cmd, data, NULL); + else + wireless_send_event(dev, cmd, data, extra); + } + +out: + kfree(extra); + return err; +} + +/* + * Call the commit handler in the driver + * (if exist and if conditions are right) + * + * Note : our current commit strategy is currently pretty dumb, + * but we will be able to improve on that... + * The goal is to try to agreagate as many changes as possible + * before doing the commit. Drivers that will define a commit handler + * are usually those that need a reset after changing parameters, so + * we want to minimise the number of reset. + * A cool idea is to use a timer : at each "set" command, we re-set the + * timer, when the timer eventually fires, we call the driver. + * Hopefully, more on that later. + * + * Also, I'm waiting to see how many people will complain about the + * netif_running(dev) test. I'm open on that one... + * Hopefully, the driver will remember to do a commit in "open()" ;-) + */ +int call_commit_handler(struct net_device *dev) +{ +#ifdef CONFIG_WIRELESS_EXT + if ((netif_running(dev)) && + (dev->wireless_handlers->standard[0] != NULL)) + /* Call the commit handler on the driver */ + return dev->wireless_handlers->standard[0](dev, NULL, + NULL, NULL); + else + return 0; /* Command completed successfully */ +#else + /* cfg80211 has no commit */ + return 0; +#endif +} + +/* + * Main IOCTl dispatcher. + * Check the type of IOCTL and call the appropriate wrapper... + */ +static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, + unsigned int cmd, + struct iw_request_info *info, + wext_ioctl_func standard, + wext_ioctl_func private) +{ + struct iwreq *iwr = (struct iwreq *) ifr; + struct net_device *dev; + iw_handler handler; + + /* Permissions are already checked in dev_ioctl() before calling us. + * The copy_to/from_user() of ifr is also dealt with in there */ + + /* Make sure the device exist */ + if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) + return -ENODEV; + + /* A bunch of special cases, then the generic case... + * Note that 'cmd' is already filtered in dev_ioctl() with + * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ + if (cmd == SIOCGIWSTATS) + return standard(dev, iwr, cmd, info, + &iw_handler_get_iwstats); + +#ifdef CONFIG_WEXT_PRIV + if (cmd == SIOCGIWPRIV && dev->wireless_handlers) + return standard(dev, iwr, cmd, info, + iw_handler_get_private); +#endif + + /* Basic check */ + if (!netif_device_present(dev)) + return -ENODEV; + + /* New driver API : try to find the handler */ + handler = get_handler(dev, cmd); + if (handler) { + /* Standard and private are not the same */ + if (cmd < SIOCIWFIRSTPRIV) + return standard(dev, iwr, cmd, info, handler); + else if (private) + return private(dev, iwr, cmd, info, handler); + } + /* Old driver API : call driver ioctl handler */ + if (dev->netdev_ops->ndo_do_ioctl) + return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); + return -EOPNOTSUPP; +} + +/* If command is `set a parameter', or `get the encoding parameters', + * check if the user has the right to do it. + */ +static int wext_permission_check(unsigned int cmd) +{ + if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) + && !capable(CAP_NET_ADMIN)) + return -EPERM; + + return 0; +} + +/* entry point from dev ioctl */ +static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, + unsigned int cmd, struct iw_request_info *info, + wext_ioctl_func standard, + wext_ioctl_func private) +{ + int ret = wext_permission_check(cmd); + + if (ret) + return ret; + + dev_load(net, ifr->ifr_name); + rtnl_lock(); + ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); + rtnl_unlock(); + + return ret; +} + +/* + * Wrapper to call a standard Wireless Extension handler. + * We do various checks and also take care of moving data between + * user space and kernel space. + */ +static int ioctl_standard_call(struct net_device * dev, + struct iwreq *iwr, + unsigned int cmd, + struct iw_request_info *info, + iw_handler handler) +{ + const struct iw_ioctl_description * descr; + int ret = -EINVAL; + + /* Get the description of the IOCTL */ + if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) + return -EOPNOTSUPP; + descr = &(standard_ioctl[cmd - SIOCIWFIRST]); + + /* Check if we have a pointer to user space data or not */ + if (descr->header_type != IW_HEADER_TYPE_POINT) { + + /* No extra arguments. Trivial to handle */ + ret = handler(dev, info, &(iwr->u), NULL); + + /* Generate an event to notify listeners of the change */ + if ((descr->flags & IW_DESCR_FLAG_EVENT) && + ((ret == 0) || (ret == -EIWCOMMIT))) + wireless_send_event(dev, cmd, &(iwr->u), NULL); + } else { + ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, + handler, dev, info); + } + + /* Call commit handler if needed and defined */ + if (ret == -EIWCOMMIT) + ret = call_commit_handler(dev); + + /* Here, we will generate the appropriate event if needed */ + + return ret; +} + + +int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, + void __user *arg) +{ + struct iw_request_info info = { .cmd = cmd, .flags = 0 }; + int ret; + + ret = wext_ioctl_dispatch(net, ifr, cmd, &info, + ioctl_standard_call, + ioctl_private_call); + if (ret >= 0 && + IW_IS_GET(cmd) && + copy_to_user(arg, ifr, sizeof(struct iwreq))) + return -EFAULT; + + return ret; +} + +#ifdef CONFIG_COMPAT +static int compat_standard_call(struct net_device *dev, + struct iwreq *iwr, + unsigned int cmd, + struct iw_request_info *info, + iw_handler handler) +{ + const struct iw_ioctl_description *descr; + struct compat_iw_point *iwp_compat; + struct iw_point iwp; + int err; + + descr = standard_ioctl + (cmd - SIOCIWFIRST); + + if (descr->header_type != IW_HEADER_TYPE_POINT) + return ioctl_standard_call(dev, iwr, cmd, info, handler); + + iwp_compat = (struct compat_iw_point *) &iwr->u.data; + iwp.pointer = compat_ptr(iwp_compat->pointer); + iwp.length = iwp_compat->length; + iwp.flags = iwp_compat->flags; + + err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info); + + iwp_compat->pointer = ptr_to_compat(iwp.pointer); + iwp_compat->length = iwp.length; + iwp_compat->flags = iwp.flags; + + return err; +} + +int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct iw_request_info info; + struct iwreq iwr; + char *colon; + int ret; + + if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) + return -EFAULT; + + iwr.ifr_name[IFNAMSIZ-1] = 0; + colon = strchr(iwr.ifr_name, ':'); + if (colon) + *colon = 0; + + info.cmd = cmd; + info.flags = IW_REQUEST_FLAG_COMPAT; + + ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, + compat_standard_call, + compat_private_call); + + if (ret >= 0 && + IW_IS_GET(cmd) && + copy_to_user(argp, &iwr, sizeof(struct iwreq))) + return -EFAULT; + + return ret; +} +#endif diff --git a/net/wireless/wext-priv.c b/net/wireless/wext-priv.c new file mode 100644 index 000000000000..a3c2277de9e5 --- /dev/null +++ b/net/wireless/wext-priv.c @@ -0,0 +1,248 @@ +/* + * This file implement the Wireless Extensions priv API. + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * Copyright 2009 Johannes Berg + * + * (As all part of the Linux kernel, this file is GPL) + */ +#include +#include +#include +#include + +int iw_handler_get_private(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + /* Check if the driver has something to export */ + if ((dev->wireless_handlers->num_private_args == 0) || + (dev->wireless_handlers->private_args == NULL)) + return -EOPNOTSUPP; + + /* Check if there is enough buffer up there */ + if (wrqu->data.length < dev->wireless_handlers->num_private_args) { + /* User space can't know in advance how large the buffer + * needs to be. Give it a hint, so that we can support + * any size buffer we want somewhat efficiently... */ + wrqu->data.length = dev->wireless_handlers->num_private_args; + return -E2BIG; + } + + /* Set the number of available ioctls. */ + wrqu->data.length = dev->wireless_handlers->num_private_args; + + /* Copy structure to the user buffer. */ + memcpy(extra, dev->wireless_handlers->private_args, + sizeof(struct iw_priv_args) * wrqu->data.length); + + return 0; +} + +/* Size (in bytes) of the various private data types */ +static const char iw_priv_type_size[] = { + 0, /* IW_PRIV_TYPE_NONE */ + 1, /* IW_PRIV_TYPE_BYTE */ + 1, /* IW_PRIV_TYPE_CHAR */ + 0, /* Not defined */ + sizeof(__u32), /* IW_PRIV_TYPE_INT */ + sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ + sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ + 0, /* Not defined */ +}; + +static int get_priv_size(__u16 args) +{ + int num = args & IW_PRIV_SIZE_MASK; + int type = (args & IW_PRIV_TYPE_MASK) >> 12; + + return num * iw_priv_type_size[type]; +} + +static int adjust_priv_size(__u16 args, struct iw_point *iwp) +{ + int num = iwp->length; + int max = args & IW_PRIV_SIZE_MASK; + int type = (args & IW_PRIV_TYPE_MASK) >> 12; + + /* Make sure the driver doesn't goof up */ + if (max < num) + num = max; + + return num * iw_priv_type_size[type]; +} + +/* + * Wrapper to call a private Wireless Extension handler. + * We do various checks and also take care of moving data between + * user space and kernel space. + * It's not as nice and slimline as the standard wrapper. The cause + * is struct iw_priv_args, which was not really designed for the + * job we are going here. + * + * IMPORTANT : This function prevent to set and get data on the same + * IOCTL and enforce the SET/GET convention. Not doing it would be + * far too hairy... + * If you need to set and get data at the same time, please don't use + * a iw_handler but process it in your ioctl handler (i.e. use the + * old driver API). + */ +static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd, + const struct iw_priv_args **descrp) +{ + const struct iw_priv_args *descr; + int i, extra_size; + + descr = NULL; + for (i = 0; i < dev->wireless_handlers->num_private_args; i++) { + if (cmd == dev->wireless_handlers->private_args[i].cmd) { + descr = &dev->wireless_handlers->private_args[i]; + break; + } + } + + extra_size = 0; + if (descr) { + if (IW_IS_SET(cmd)) { + int offset = 0; /* For sub-ioctls */ + /* Check for sub-ioctl handler */ + if (descr->name[0] == '\0') + /* Reserve one int for sub-ioctl index */ + offset = sizeof(__u32); + + /* Size of set arguments */ + extra_size = get_priv_size(descr->set_args); + + /* Does it fits in iwr ? */ + if ((descr->set_args & IW_PRIV_SIZE_FIXED) && + ((extra_size + offset) <= IFNAMSIZ)) + extra_size = 0; + } else { + /* Size of get arguments */ + extra_size = get_priv_size(descr->get_args); + + /* Does it fits in iwr ? */ + if ((descr->get_args & IW_PRIV_SIZE_FIXED) && + (extra_size <= IFNAMSIZ)) + extra_size = 0; + } + } + *descrp = descr; + return extra_size; +} + +static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd, + const struct iw_priv_args *descr, + iw_handler handler, struct net_device *dev, + struct iw_request_info *info, int extra_size) +{ + char *extra; + int err; + + /* Check what user space is giving us */ + if (IW_IS_SET(cmd)) { + if (!iwp->pointer && iwp->length != 0) + return -EFAULT; + + if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK)) + return -E2BIG; + } else if (!iwp->pointer) + return -EFAULT; + + extra = kmalloc(extra_size, GFP_KERNEL); + if (!extra) + return -ENOMEM; + + /* If it is a SET, get all the extra data in here */ + if (IW_IS_SET(cmd) && (iwp->length != 0)) { + if (copy_from_user(extra, iwp->pointer, extra_size)) { + err = -EFAULT; + goto out; + } + } + + /* Call the handler */ + err = handler(dev, info, (union iwreq_data *) iwp, extra); + + /* If we have something to return to the user */ + if (!err && IW_IS_GET(cmd)) { + /* Adjust for the actual length if it's variable, + * avoid leaking kernel bits outside. + */ + if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) + extra_size = adjust_priv_size(descr->get_args, iwp); + + if (copy_to_user(iwp->pointer, extra, extra_size)) + err = -EFAULT; + } + +out: + kfree(extra); + return err; +} + +int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler) +{ + int extra_size = 0, ret = -EINVAL; + const struct iw_priv_args *descr; + + extra_size = get_priv_descr_and_size(dev, cmd, &descr); + + /* Check if we have a pointer to user space data or not. */ + if (extra_size == 0) { + /* No extra arguments. Trivial to handle */ + ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); + } else { + ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, + handler, dev, info, extra_size); + } + + /* Call commit handler if needed and defined */ + if (ret == -EIWCOMMIT) + ret = call_commit_handler(dev); + + return ret; +} + +#ifdef CONFIG_COMPAT +int compat_private_call(struct net_device *dev, struct iwreq *iwr, + unsigned int cmd, struct iw_request_info *info, + iw_handler handler) +{ + const struct iw_priv_args *descr; + int ret, extra_size; + + extra_size = get_priv_descr_and_size(dev, cmd, &descr); + + /* Check if we have a pointer to user space data or not. */ + if (extra_size == 0) { + /* No extra arguments. Trivial to handle */ + ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); + } else { + struct compat_iw_point *iwp_compat; + struct iw_point iwp; + + iwp_compat = (struct compat_iw_point *) &iwr->u.data; + iwp.pointer = compat_ptr(iwp_compat->pointer); + iwp.length = iwp_compat->length; + iwp.flags = iwp_compat->flags; + + ret = ioctl_private_iw_point(&iwp, cmd, descr, + handler, dev, info, extra_size); + + iwp_compat->pointer = ptr_to_compat(iwp.pointer); + iwp_compat->length = iwp.length; + iwp_compat->flags = iwp.flags; + } + + /* Call commit handler if needed and defined */ + if (ret == -EIWCOMMIT) + ret = call_commit_handler(dev); + + return ret; +} +#endif diff --git a/net/wireless/wext-proc.c b/net/wireless/wext-proc.c new file mode 100644 index 000000000000..273a7f77c834 --- /dev/null +++ b/net/wireless/wext-proc.c @@ -0,0 +1,155 @@ +/* + * This file implement the Wireless Extensions proc API. + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ + +/* + * The /proc/net/wireless file is a human readable user-space interface + * exporting various wireless specific statistics from the wireless devices. + * This is the most popular part of the Wireless Extensions ;-) + * + * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). + * The content of the file is basically the content of "struct iw_statistics". + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +static void wireless_seq_printf_stats(struct seq_file *seq, + struct net_device *dev) +{ + /* Get stats from the driver */ + struct iw_statistics *stats = get_wireless_stats(dev); + static struct iw_statistics nullstats = {}; + + /* show device if it's wireless regardless of current stats */ + if (!stats) { +#ifdef CONFIG_WIRELESS_EXT + if (dev->wireless_handlers) + stats = &nullstats; +#endif +#ifdef CONFIG_CFG80211 + if (dev->ieee80211_ptr) + stats = &nullstats; +#endif + } + + if (stats) { + seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " + "%6d %6d %6d\n", + dev->name, stats->status, stats->qual.qual, + stats->qual.updated & IW_QUAL_QUAL_UPDATED + ? '.' : ' ', + ((__s32) stats->qual.level) - + ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), + stats->qual.updated & IW_QUAL_LEVEL_UPDATED + ? '.' : ' ', + ((__s32) stats->qual.noise) - + ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), + stats->qual.updated & IW_QUAL_NOISE_UPDATED + ? '.' : ' ', + stats->discard.nwid, stats->discard.code, + stats->discard.fragment, stats->discard.retries, + stats->discard.misc, stats->miss.beacon); + + if (stats != &nullstats) + stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; + } +} + +/* ---------------------------------------------------------------- */ +/* + * Print info for /proc/net/wireless (print all entries) + */ +static int wireless_dev_seq_show(struct seq_file *seq, void *v) +{ + might_sleep(); + + if (v == SEQ_START_TOKEN) + seq_printf(seq, "Inter-| sta-| Quality | Discarded " + "packets | Missed | WE\n" + " face | tus | link level noise | nwid " + "crypt frag retry misc | beacon | %d\n", + WIRELESS_EXT); + else + wireless_seq_printf_stats(seq, v); + return 0; +} + +static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct net *net = seq_file_net(seq); + loff_t off; + struct net_device *dev; + + rtnl_lock(); + if (!*pos) + return SEQ_START_TOKEN; + + off = 1; + for_each_netdev(net, dev) + if (off++ == *pos) + return dev; + return NULL; +} + +static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct net *net = seq_file_net(seq); + + ++*pos; + + return v == SEQ_START_TOKEN ? + first_net_device(net) : next_net_device(v); +} + +static void wireless_dev_seq_stop(struct seq_file *seq, void *v) +{ + rtnl_unlock(); +} + +static const struct seq_operations wireless_seq_ops = { + .start = wireless_dev_seq_start, + .next = wireless_dev_seq_next, + .stop = wireless_dev_seq_stop, + .show = wireless_dev_seq_show, +}; + +static int seq_open_wireless(struct inode *inode, struct file *file) +{ + return seq_open_net(inode, file, &wireless_seq_ops, + sizeof(struct seq_net_private)); +} + +static const struct file_operations wireless_seq_fops = { + .owner = THIS_MODULE, + .open = seq_open_wireless, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_net, +}; + +int wext_proc_init(struct net *net) +{ + /* Create /proc/net/wireless entry */ + if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops)) + return -ENOMEM; + + return 0; +} + +void wext_proc_exit(struct net *net) +{ + proc_net_remove(net, "wireless"); +} diff --git a/net/wireless/wext-spy.c b/net/wireless/wext-spy.c new file mode 100644 index 000000000000..6dcfe65a2d1a --- /dev/null +++ b/net/wireless/wext-spy.c @@ -0,0 +1,231 @@ +/* + * This file implement the Wireless Extensions spy API. + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ + +#include +#include +#include +#include +#include +#include + +static inline struct iw_spy_data *get_spydata(struct net_device *dev) +{ + /* This is the new way */ + if (dev->wireless_data) + return dev->wireless_data->spy_data; + return NULL; +} + +int iw_handler_set_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct sockaddr * address = (struct sockaddr *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Disable spy collection while we copy the addresses. + * While we copy addresses, any call to wireless_spy_update() + * will NOP. This is OK, as anyway the addresses are changing. */ + spydata->spy_number = 0; + + /* We want to operate without locking, because wireless_spy_update() + * most likely will happen in the interrupt handler, and therefore + * have its own locking constraints and needs performance. + * The rtnl_lock() make sure we don't race with the other iw_handlers. + * This make sure wireless_spy_update() "see" that the spy list + * is temporarily disabled. */ + smp_wmb(); + + /* Are there are addresses to copy? */ + if (wrqu->data.length > 0) { + int i; + + /* Copy addresses */ + for (i = 0; i < wrqu->data.length; i++) + memcpy(spydata->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(spydata->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + } + + /* Make sure above is updated before re-enabling */ + smp_wmb(); + + /* Enable addresses */ + spydata->spy_number = wrqu->data.length; + + return 0; +} +EXPORT_SYMBOL(iw_handler_set_spy); + +int iw_handler_get_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct sockaddr * address = (struct sockaddr *) extra; + int i; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + wrqu->data.length = spydata->spy_number; + + /* Copy addresses. */ + for (i = 0; i < spydata->spy_number; i++) { + memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats to the user buffer (just after). */ + if (spydata->spy_number > 0) + memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), + spydata->spy_stat, + sizeof(struct iw_quality) * spydata->spy_number); + /* Reset updated flags. */ + for (i = 0; i < spydata->spy_number; i++) + spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; + return 0; +} +EXPORT_SYMBOL(iw_handler_get_spy); + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : set spy threshold + */ +int iw_handler_set_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Just do it */ + memcpy(&(spydata->spy_thr_low), &(threshold->low), + 2 * sizeof(struct iw_quality)); + + /* Clear flag */ + memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); + + return 0; +} +EXPORT_SYMBOL(iw_handler_set_thrspy); + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : get spy threshold + */ +int iw_handler_get_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Just do it */ + memcpy(&(threshold->low), &(spydata->spy_thr_low), + 2 * sizeof(struct iw_quality)); + + return 0; +} +EXPORT_SYMBOL(iw_handler_get_thrspy); + +/*------------------------------------------------------------------*/ +/* + * Prepare and send a Spy Threshold event + */ +static void iw_send_thrspy_event(struct net_device * dev, + struct iw_spy_data * spydata, + unsigned char * address, + struct iw_quality * wstats) +{ + union iwreq_data wrqu; + struct iw_thrspy threshold; + + /* Init */ + wrqu.data.length = 1; + wrqu.data.flags = 0; + /* Copy address */ + memcpy(threshold.addr.sa_data, address, ETH_ALEN); + threshold.addr.sa_family = ARPHRD_ETHER; + /* Copy stats */ + memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); + /* Copy also thresholds */ + memcpy(&(threshold.low), &(spydata->spy_thr_low), + 2 * sizeof(struct iw_quality)); + + /* Send event to user space */ + wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); +} + +/* ---------------------------------------------------------------- */ +/* + * Call for the driver to update the spy data. + * For now, the spy data is a simple array. As the size of the array is + * small, this is good enough. If we wanted to support larger number of + * spy addresses, we should use something more efficient... + */ +void wireless_spy_update(struct net_device * dev, + unsigned char * address, + struct iw_quality * wstats) +{ + struct iw_spy_data * spydata = get_spydata(dev); + int i; + int match = -1; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return; + + /* Update all records that match */ + for (i = 0; i < spydata->spy_number; i++) + if (!compare_ether_addr(address, spydata->spy_address[i])) { + memcpy(&(spydata->spy_stat[i]), wstats, + sizeof(struct iw_quality)); + match = i; + } + + /* Generate an event if we cross the spy threshold. + * To avoid event storms, we have a simple hysteresis : we generate + * event only when we go under the low threshold or above the + * high threshold. */ + if (match >= 0) { + if (spydata->spy_thr_under[match]) { + if (wstats->level > spydata->spy_thr_high.level) { + spydata->spy_thr_under[match] = 0; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } else { + if (wstats->level < spydata->spy_thr_low.level) { + spydata->spy_thr_under[match] = 1; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } + } +} +EXPORT_SYMBOL(wireless_spy_update); diff --git a/net/wireless/wext.c b/net/wireless/wext.c deleted file mode 100644 index 60fe57761ca9..000000000000 --- a/net/wireless/wext.c +++ /dev/null @@ -1,1775 +0,0 @@ -/* - * This file implement the Wireless Extensions APIs. - * - * Authors : Jean Tourrilhes - HPL - - * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. - * - * (As all part of the Linux kernel, this file is GPL) - */ - -/************************** DOCUMENTATION **************************/ -/* - * API definition : - * -------------- - * See for details of the APIs and the rest. - * - * History : - * ------- - * - * v1 - 5.12.01 - Jean II - * o Created this file. - * - * v2 - 13.12.01 - Jean II - * o Move /proc/net/wireless stuff from net/core/dev.c to here - * o Make Wireless Extension IOCTLs go through here - * o Added iw_handler handling ;-) - * o Added standard ioctl description - * o Initial dumb commit strategy based on orinoco.c - * - * v3 - 19.12.01 - Jean II - * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call - * o Add event dispatcher function - * o Add event description - * o Propagate events as rtnetlink IFLA_WIRELESS option - * o Generate event on selected SET requests - * - * v4 - 18.04.02 - Jean II - * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 - * - * v5 - 21.06.02 - Jean II - * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup) - * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes - * o Add IWEVCUSTOM for driver specific event/scanning token - * o Turn on WE_STRICT_WRITE by default + kernel warning - * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) - * o Fix off-by-one in test (extra_size <= IFNAMSIZ) - * - * v6 - 9.01.03 - Jean II - * o Add common spy support : iw_handler_set_spy(), wireless_spy_update() - * o Add enhanced spy support : iw_handler_set_thrspy() and event. - * o Add WIRELESS_EXT version display in /proc/net/wireless - * - * v6 - 18.06.04 - Jean II - * o Change get_spydata() method for added safety - * o Remove spy #ifdef, they are always on -> cleaner code - * o Allow any size GET request if user specifies length > max - * and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV - * o Start migrating get_wireless_stats to struct iw_handler_def - * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus - * Based on patch from Pavel Roskin : - * o Fix kernel data leak to user space in private handler handling - * - * v7 - 18.3.05 - Jean II - * o Remove (struct iw_point *)->pointer from events and streams - * o Remove spy_offset from struct iw_handler_def - * o Start deprecating dev->get_wireless_stats, output a warning - * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless - * o Don't lose INVALID/DBM flags when clearing UPDATED flags (iwstats) - * - * v8 - 17.02.06 - Jean II - * o RtNetlink requests support (SET/GET) - * - * v8b - 03.08.06 - Herbert Xu - * o Fix Wireless Event locking issues. - * - * v9 - 14.3.06 - Jean II - * o Change length in ESSID and NICK to strlen() instead of strlen()+1 - * o Make standard_ioctl_num and standard_event_num unsigned - * o Remove (struct net_device *)->get_wireless_stats() - * - * v10 - 16.3.07 - Jean II - * o Prevent leaking of kernel space in stream on 64 bits. - */ - -/***************************** INCLUDES *****************************/ - -#include -#include /* off_t */ -#include /* struct ifreq, dev_get_by_name() */ -#include -#include /* rtnetlink stuff */ -#include -#include /* for __init */ -#include /* ARPHRD_ETHER */ -#include /* compare_ether_addr */ -#include -#include - -#include /* Pretty obvious */ -#include /* New driver API */ -#include -#include - -#include /* copy_to_user() */ - -/************************* GLOBAL VARIABLES *************************/ -/* - * You should not use global variables, because of re-entrancy. - * On our case, it's only const, so it's OK... - */ -/* - * Meta-data about all the standard Wireless Extension request we - * know about. - */ -static const struct iw_ioctl_description standard_ioctl[] = { - [SIOCSIWCOMMIT - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_NULL, - }, - [SIOCGIWNAME - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_CHAR, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWNWID - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - .flags = IW_DESCR_FLAG_EVENT, - }, - [SIOCGIWNWID - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWFREQ - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_FREQ, - .flags = IW_DESCR_FLAG_EVENT, - }, - [SIOCGIWFREQ - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_FREQ, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWMODE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_UINT, - .flags = IW_DESCR_FLAG_EVENT, - }, - [SIOCGIWMODE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_UINT, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWSENS - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWSENS - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWRANGE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_NULL, - }, - [SIOCGIWRANGE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = sizeof(struct iw_range), - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWPRIV - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_NULL, - }, - [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct iw_priv_args), - .max_tokens = 16, - .flags = IW_DESCR_FLAG_NOMAX, - }, - [SIOCSIWSTATS - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_NULL, - }, - [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = sizeof(struct iw_statistics), - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWSPY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct sockaddr), - .max_tokens = IW_MAX_SPY, - }, - [SIOCGIWSPY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct sockaddr) + - sizeof(struct iw_quality), - .max_tokens = IW_MAX_SPY, - }, - [SIOCSIWTHRSPY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct iw_thrspy), - .min_tokens = 1, - .max_tokens = 1, - }, - [SIOCGIWTHRSPY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct iw_thrspy), - .min_tokens = 1, - .max_tokens = 1, - }, - [SIOCSIWAP - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_ADDR, - }, - [SIOCGIWAP - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_ADDR, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWMLME - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .min_tokens = sizeof(struct iw_mlme), - .max_tokens = sizeof(struct iw_mlme), - }, - [SIOCGIWAPLIST - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = sizeof(struct sockaddr) + - sizeof(struct iw_quality), - .max_tokens = IW_MAX_AP, - .flags = IW_DESCR_FLAG_NOMAX, - }, - [SIOCSIWSCAN - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .min_tokens = 0, - .max_tokens = sizeof(struct iw_scan_req), - }, - [SIOCGIWSCAN - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_SCAN_MAX_DATA, - .flags = IW_DESCR_FLAG_NOMAX, - }, - [SIOCSIWESSID - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE, - .flags = IW_DESCR_FLAG_EVENT, - }, - [SIOCGIWESSID - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE, - .flags = IW_DESCR_FLAG_DUMP, - }, - [SIOCSIWNICKN - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE, - }, - [SIOCGIWNICKN - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ESSID_MAX_SIZE, - }, - [SIOCSIWRATE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWRATE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWRTS - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWRTS - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWFRAG - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWFRAG - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWTXPOW - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWTXPOW - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWRETRY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWRETRY - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWENCODE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ENCODING_TOKEN_MAX, - .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, - }, - [SIOCGIWENCODE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_ENCODING_TOKEN_MAX, - .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, - }, - [SIOCSIWPOWER - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWPOWER - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWGENIE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_GENERIC_IE_MAX, - }, - [SIOCGIWGENIE - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_GENERIC_IE_MAX, - }, - [SIOCSIWAUTH - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCGIWAUTH - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_PARAM, - }, - [SIOCSIWENCODEEXT - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .min_tokens = sizeof(struct iw_encode_ext), - .max_tokens = sizeof(struct iw_encode_ext) + - IW_ENCODING_TOKEN_MAX, - }, - [SIOCGIWENCODEEXT - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .min_tokens = sizeof(struct iw_encode_ext), - .max_tokens = sizeof(struct iw_encode_ext) + - IW_ENCODING_TOKEN_MAX, - }, - [SIOCSIWPMKSA - SIOCIWFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .min_tokens = sizeof(struct iw_pmksa), - .max_tokens = sizeof(struct iw_pmksa), - }, -}; -static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl); - -/* - * Meta-data about all the additional standard Wireless Extension events - * we know about. - */ -static const struct iw_ioctl_description standard_event[] = { - [IWEVTXDROP - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_ADDR, - }, - [IWEVQUAL - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_QUAL, - }, - [IWEVCUSTOM - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_CUSTOM_MAX, - }, - [IWEVREGISTERED - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_ADDR, - }, - [IWEVEXPIRED - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_ADDR, - }, - [IWEVGENIE - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_GENERIC_IE_MAX, - }, - [IWEVMICHAELMICFAILURE - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = sizeof(struct iw_michaelmicfailure), - }, - [IWEVASSOCREQIE - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_GENERIC_IE_MAX, - }, - [IWEVASSOCRESPIE - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = IW_GENERIC_IE_MAX, - }, - [IWEVPMKIDCAND - IWEVFIRST] = { - .header_type = IW_HEADER_TYPE_POINT, - .token_size = 1, - .max_tokens = sizeof(struct iw_pmkid_cand), - }, -}; -static const unsigned standard_event_num = ARRAY_SIZE(standard_event); - -/* Size (in bytes) of the various private data types */ -static const char iw_priv_type_size[] = { - 0, /* IW_PRIV_TYPE_NONE */ - 1, /* IW_PRIV_TYPE_BYTE */ - 1, /* IW_PRIV_TYPE_CHAR */ - 0, /* Not defined */ - sizeof(__u32), /* IW_PRIV_TYPE_INT */ - sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ - sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ - 0, /* Not defined */ -}; - -/* Size (in bytes) of various events */ -static const int event_type_size[] = { - IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ - 0, - IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ - 0, - IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ - IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ - IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ - 0, - IW_EV_POINT_LEN, /* Without variable payload */ - IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ - IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ -}; - -#ifdef CONFIG_COMPAT -static const int compat_event_type_size[] = { - IW_EV_COMPAT_LCP_LEN, /* IW_HEADER_TYPE_NULL */ - 0, - IW_EV_COMPAT_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ - 0, - IW_EV_COMPAT_UINT_LEN, /* IW_HEADER_TYPE_UINT */ - IW_EV_COMPAT_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ - IW_EV_COMPAT_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ - 0, - IW_EV_COMPAT_POINT_LEN, /* Without variable payload */ - IW_EV_COMPAT_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ - IW_EV_COMPAT_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ -}; -#endif - -/************************ COMMON SUBROUTINES ************************/ -/* - * Stuff that may be used in various place or doesn't fit in one - * of the section below. - */ - -/* ---------------------------------------------------------------- */ -/* - * Return the driver handler associated with a specific Wireless Extension. - */ -static iw_handler get_handler(struct net_device *dev, unsigned int cmd) -{ - /* Don't "optimise" the following variable, it will crash */ - unsigned int index; /* *MUST* be unsigned */ - - /* Check if we have some wireless handlers defined */ - if (dev->wireless_handlers == NULL) - return NULL; - - /* Try as a standard command */ - index = cmd - SIOCIWFIRST; - if (index < dev->wireless_handlers->num_standard) - return dev->wireless_handlers->standard[index]; - - /* Try as a private command */ - index = cmd - SIOCIWFIRSTPRIV; - if (index < dev->wireless_handlers->num_private) - return dev->wireless_handlers->private[index]; - - /* Not found */ - return NULL; -} - -/* ---------------------------------------------------------------- */ -/* - * Get statistics out of the driver - */ -struct iw_statistics *get_wireless_stats(struct net_device *dev) -{ - /* New location */ - if ((dev->wireless_handlers != NULL) && - (dev->wireless_handlers->get_wireless_stats != NULL)) - return dev->wireless_handlers->get_wireless_stats(dev); - - /* Not found */ - return NULL; -} - -/* ---------------------------------------------------------------- */ -/* - * Call the commit handler in the driver - * (if exist and if conditions are right) - * - * Note : our current commit strategy is currently pretty dumb, - * but we will be able to improve on that... - * The goal is to try to agreagate as many changes as possible - * before doing the commit. Drivers that will define a commit handler - * are usually those that need a reset after changing parameters, so - * we want to minimise the number of reset. - * A cool idea is to use a timer : at each "set" command, we re-set the - * timer, when the timer eventually fires, we call the driver. - * Hopefully, more on that later. - * - * Also, I'm waiting to see how many people will complain about the - * netif_running(dev) test. I'm open on that one... - * Hopefully, the driver will remember to do a commit in "open()" ;-) - */ -static int call_commit_handler(struct net_device *dev) -{ - if ((netif_running(dev)) && - (dev->wireless_handlers->standard[0] != NULL)) - /* Call the commit handler on the driver */ - return dev->wireless_handlers->standard[0](dev, NULL, - NULL, NULL); - else - return 0; /* Command completed successfully */ -} - -/* ---------------------------------------------------------------- */ -/* - * Calculate size of private arguments - */ -static int get_priv_size(__u16 args) -{ - int num = args & IW_PRIV_SIZE_MASK; - int type = (args & IW_PRIV_TYPE_MASK) >> 12; - - return num * iw_priv_type_size[type]; -} - -/* ---------------------------------------------------------------- */ -/* - * Re-calculate the size of private arguments - */ -static int adjust_priv_size(__u16 args, struct iw_point *iwp) -{ - int num = iwp->length; - int max = args & IW_PRIV_SIZE_MASK; - int type = (args & IW_PRIV_TYPE_MASK) >> 12; - - /* Make sure the driver doesn't goof up */ - if (max < num) - num = max; - - return num * iw_priv_type_size[type]; -} - -/* ---------------------------------------------------------------- */ -/* - * Standard Wireless Handler : get wireless stats - * Allow programatic access to /proc/net/wireless even if /proc - * doesn't exist... Also more efficient... - */ -static int iw_handler_get_iwstats(struct net_device * dev, - struct iw_request_info * info, - union iwreq_data * wrqu, - char * extra) -{ - /* Get stats from the driver */ - struct iw_statistics *stats; - - stats = get_wireless_stats(dev); - if (stats) { - /* Copy statistics to extra */ - memcpy(extra, stats, sizeof(struct iw_statistics)); - wrqu->data.length = sizeof(struct iw_statistics); - - /* Check if we need to clear the updated flag */ - if (wrqu->data.flags != 0) - stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; - return 0; - } else - return -EOPNOTSUPP; -} - -/* ---------------------------------------------------------------- */ -/* - * Standard Wireless Handler : get iwpriv definitions - * Export the driver private handler definition - * They will be picked up by tools like iwpriv... - */ -static int iw_handler_get_private(struct net_device * dev, - struct iw_request_info * info, - union iwreq_data * wrqu, - char * extra) -{ - /* Check if the driver has something to export */ - if ((dev->wireless_handlers->num_private_args == 0) || - (dev->wireless_handlers->private_args == NULL)) - return -EOPNOTSUPP; - - /* Check if there is enough buffer up there */ - if (wrqu->data.length < dev->wireless_handlers->num_private_args) { - /* User space can't know in advance how large the buffer - * needs to be. Give it a hint, so that we can support - * any size buffer we want somewhat efficiently... */ - wrqu->data.length = dev->wireless_handlers->num_private_args; - return -E2BIG; - } - - /* Set the number of available ioctls. */ - wrqu->data.length = dev->wireless_handlers->num_private_args; - - /* Copy structure to the user buffer. */ - memcpy(extra, dev->wireless_handlers->private_args, - sizeof(struct iw_priv_args) * wrqu->data.length); - - return 0; -} - - -/******************** /proc/net/wireless SUPPORT ********************/ -/* - * The /proc/net/wireless file is a human readable user-space interface - * exporting various wireless specific statistics from the wireless devices. - * This is the most popular part of the Wireless Extensions ;-) - * - * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). - * The content of the file is basically the content of "struct iw_statistics". - */ - -#ifdef CONFIG_PROC_FS - -/* ---------------------------------------------------------------- */ -/* - * Print one entry (line) of /proc/net/wireless - */ -static void wireless_seq_printf_stats(struct seq_file *seq, - struct net_device *dev) -{ - /* Get stats from the driver */ - struct iw_statistics *stats = get_wireless_stats(dev); - static struct iw_statistics nullstats = {}; - - /* show device if it's wireless regardless of current stats */ - if (!stats && dev->wireless_handlers) - stats = &nullstats; - - if (stats) { - seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " - "%6d %6d %6d\n", - dev->name, stats->status, stats->qual.qual, - stats->qual.updated & IW_QUAL_QUAL_UPDATED - ? '.' : ' ', - ((__s32) stats->qual.level) - - ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), - stats->qual.updated & IW_QUAL_LEVEL_UPDATED - ? '.' : ' ', - ((__s32) stats->qual.noise) - - ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), - stats->qual.updated & IW_QUAL_NOISE_UPDATED - ? '.' : ' ', - stats->discard.nwid, stats->discard.code, - stats->discard.fragment, stats->discard.retries, - stats->discard.misc, stats->miss.beacon); - - if (stats != &nullstats) - stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; - } -} - -/* ---------------------------------------------------------------- */ -/* - * Print info for /proc/net/wireless (print all entries) - */ -static int wireless_dev_seq_show(struct seq_file *seq, void *v) -{ - might_sleep(); - - if (v == SEQ_START_TOKEN) - seq_printf(seq, "Inter-| sta-| Quality | Discarded " - "packets | Missed | WE\n" - " face | tus | link level noise | nwid " - "crypt frag retry misc | beacon | %d\n", - WIRELESS_EXT); - else - wireless_seq_printf_stats(seq, v); - return 0; -} - -static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct net *net = seq_file_net(seq); - loff_t off; - struct net_device *dev; - - rtnl_lock(); - if (!*pos) - return SEQ_START_TOKEN; - - off = 1; - for_each_netdev(net, dev) - if (off++ == *pos) - return dev; - return NULL; -} - -static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct net *net = seq_file_net(seq); - - ++*pos; - - return v == SEQ_START_TOKEN ? - first_net_device(net) : next_net_device(v); -} - -static void wireless_dev_seq_stop(struct seq_file *seq, void *v) -{ - rtnl_unlock(); -} - -static const struct seq_operations wireless_seq_ops = { - .start = wireless_dev_seq_start, - .next = wireless_dev_seq_next, - .stop = wireless_dev_seq_stop, - .show = wireless_dev_seq_show, -}; - -static int seq_open_wireless(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &wireless_seq_ops, - sizeof(struct seq_net_private)); -} - -static const struct file_operations wireless_seq_fops = { - .owner = THIS_MODULE, - .open = seq_open_wireless, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -int wext_proc_init(struct net *net) -{ - /* Create /proc/net/wireless entry */ - if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops)) - return -ENOMEM; - - return 0; -} - -void wext_proc_exit(struct net *net) -{ - proc_net_remove(net, "wireless"); -} -#endif /* CONFIG_PROC_FS */ - -/************************** IOCTL SUPPORT **************************/ -/* - * The original user space API to configure all those Wireless Extensions - * is through IOCTLs. - * In there, we check if we need to call the new driver API (iw_handler) - * or just call the driver ioctl handler. - */ - -/* ---------------------------------------------------------------- */ -static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, - const struct iw_ioctl_description *descr, - iw_handler handler, struct net_device *dev, - struct iw_request_info *info) -{ - int err, extra_size, user_length = 0, essid_compat = 0; - char *extra; - - /* Calculate space needed by arguments. Always allocate - * for max space. - */ - extra_size = descr->max_tokens * descr->token_size; - - /* Check need for ESSID compatibility for WE < 21 */ - switch (cmd) { - case SIOCSIWESSID: - case SIOCGIWESSID: - case SIOCSIWNICKN: - case SIOCGIWNICKN: - if (iwp->length == descr->max_tokens + 1) - essid_compat = 1; - else if (IW_IS_SET(cmd) && (iwp->length != 0)) { - char essid[IW_ESSID_MAX_SIZE + 1]; - unsigned int len; - len = iwp->length * descr->token_size; - - if (len > IW_ESSID_MAX_SIZE) - return -EFAULT; - - err = copy_from_user(essid, iwp->pointer, len); - if (err) - return -EFAULT; - - if (essid[iwp->length - 1] == '\0') - essid_compat = 1; - } - break; - default: - break; - } - - iwp->length -= essid_compat; - - /* Check what user space is giving us */ - if (IW_IS_SET(cmd)) { - /* Check NULL pointer */ - if (!iwp->pointer && iwp->length != 0) - return -EFAULT; - /* Check if number of token fits within bounds */ - if (iwp->length > descr->max_tokens) - return -E2BIG; - if (iwp->length < descr->min_tokens) - return -EINVAL; - } else { - /* Check NULL pointer */ - if (!iwp->pointer) - return -EFAULT; - /* Save user space buffer size for checking */ - user_length = iwp->length; - - /* Don't check if user_length > max to allow forward - * compatibility. The test user_length < min is - * implied by the test at the end. - */ - - /* Support for very large requests */ - if ((descr->flags & IW_DESCR_FLAG_NOMAX) && - (user_length > descr->max_tokens)) { - /* Allow userspace to GET more than max so - * we can support any size GET requests. - * There is still a limit : -ENOMEM. - */ - extra_size = user_length * descr->token_size; - - /* Note : user_length is originally a __u16, - * and token_size is controlled by us, - * so extra_size won't get negative and - * won't overflow... - */ - } - } - - /* kzalloc() ensures NULL-termination for essid_compat. */ - extra = kzalloc(extra_size, GFP_KERNEL); - if (!extra) - return -ENOMEM; - - /* If it is a SET, get all the extra data in here */ - if (IW_IS_SET(cmd) && (iwp->length != 0)) { - if (copy_from_user(extra, iwp->pointer, - iwp->length * - descr->token_size)) { - err = -EFAULT; - goto out; - } - - if (cmd == SIOCSIWENCODEEXT) { - struct iw_encode_ext *ee = (void *) extra; - - if (iwp->length < sizeof(*ee) + ee->key_len) - return -EFAULT; - } - } - - err = handler(dev, info, (union iwreq_data *) iwp, extra); - - iwp->length += essid_compat; - - /* If we have something to return to the user */ - if (!err && IW_IS_GET(cmd)) { - /* Check if there is enough buffer up there */ - if (user_length < iwp->length) { - err = -E2BIG; - goto out; - } - - if (copy_to_user(iwp->pointer, extra, - iwp->length * - descr->token_size)) { - err = -EFAULT; - goto out; - } - } - - /* Generate an event to notify listeners of the change */ - if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { - union iwreq_data *data = (union iwreq_data *) iwp; - - if (descr->flags & IW_DESCR_FLAG_RESTRICT) - /* If the event is restricted, don't - * export the payload. - */ - wireless_send_event(dev, cmd, data, NULL); - else - wireless_send_event(dev, cmd, data, extra); - } - -out: - kfree(extra); - return err; -} - -/* - * Wrapper to call a standard Wireless Extension handler. - * We do various checks and also take care of moving data between - * user space and kernel space. - */ -static int ioctl_standard_call(struct net_device * dev, - struct iwreq *iwr, - unsigned int cmd, - struct iw_request_info *info, - iw_handler handler) -{ - const struct iw_ioctl_description * descr; - int ret = -EINVAL; - - /* Get the description of the IOCTL */ - if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) - return -EOPNOTSUPP; - descr = &(standard_ioctl[cmd - SIOCIWFIRST]); - - /* Check if we have a pointer to user space data or not */ - if (descr->header_type != IW_HEADER_TYPE_POINT) { - - /* No extra arguments. Trivial to handle */ - ret = handler(dev, info, &(iwr->u), NULL); - - /* Generate an event to notify listeners of the change */ - if ((descr->flags & IW_DESCR_FLAG_EVENT) && - ((ret == 0) || (ret == -EIWCOMMIT))) - wireless_send_event(dev, cmd, &(iwr->u), NULL); - } else { - ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, - handler, dev, info); - } - - /* Call commit handler if needed and defined */ - if (ret == -EIWCOMMIT) - ret = call_commit_handler(dev); - - /* Here, we will generate the appropriate event if needed */ - - return ret; -} - -/* ---------------------------------------------------------------- */ -/* - * Wrapper to call a private Wireless Extension handler. - * We do various checks and also take care of moving data between - * user space and kernel space. - * It's not as nice and slimline as the standard wrapper. The cause - * is struct iw_priv_args, which was not really designed for the - * job we are going here. - * - * IMPORTANT : This function prevent to set and get data on the same - * IOCTL and enforce the SET/GET convention. Not doing it would be - * far too hairy... - * If you need to set and get data at the same time, please don't use - * a iw_handler but process it in your ioctl handler (i.e. use the - * old driver API). - */ -static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd, - const struct iw_priv_args **descrp) -{ - const struct iw_priv_args *descr; - int i, extra_size; - - descr = NULL; - for (i = 0; i < dev->wireless_handlers->num_private_args; i++) { - if (cmd == dev->wireless_handlers->private_args[i].cmd) { - descr = &dev->wireless_handlers->private_args[i]; - break; - } - } - - extra_size = 0; - if (descr) { - if (IW_IS_SET(cmd)) { - int offset = 0; /* For sub-ioctls */ - /* Check for sub-ioctl handler */ - if (descr->name[0] == '\0') - /* Reserve one int for sub-ioctl index */ - offset = sizeof(__u32); - - /* Size of set arguments */ - extra_size = get_priv_size(descr->set_args); - - /* Does it fits in iwr ? */ - if ((descr->set_args & IW_PRIV_SIZE_FIXED) && - ((extra_size + offset) <= IFNAMSIZ)) - extra_size = 0; - } else { - /* Size of get arguments */ - extra_size = get_priv_size(descr->get_args); - - /* Does it fits in iwr ? */ - if ((descr->get_args & IW_PRIV_SIZE_FIXED) && - (extra_size <= IFNAMSIZ)) - extra_size = 0; - } - } - *descrp = descr; - return extra_size; -} - -static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd, - const struct iw_priv_args *descr, - iw_handler handler, struct net_device *dev, - struct iw_request_info *info, int extra_size) -{ - char *extra; - int err; - - /* Check what user space is giving us */ - if (IW_IS_SET(cmd)) { - if (!iwp->pointer && iwp->length != 0) - return -EFAULT; - - if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK)) - return -E2BIG; - } else if (!iwp->pointer) - return -EFAULT; - - extra = kmalloc(extra_size, GFP_KERNEL); - if (!extra) - return -ENOMEM; - - /* If it is a SET, get all the extra data in here */ - if (IW_IS_SET(cmd) && (iwp->length != 0)) { - if (copy_from_user(extra, iwp->pointer, extra_size)) { - err = -EFAULT; - goto out; - } - } - - /* Call the handler */ - err = handler(dev, info, (union iwreq_data *) iwp, extra); - - /* If we have something to return to the user */ - if (!err && IW_IS_GET(cmd)) { - /* Adjust for the actual length if it's variable, - * avoid leaking kernel bits outside. - */ - if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) - extra_size = adjust_priv_size(descr->get_args, iwp); - - if (copy_to_user(iwp->pointer, extra, extra_size)) - err = -EFAULT; - } - -out: - kfree(extra); - return err; -} - -static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, - unsigned int cmd, struct iw_request_info *info, - iw_handler handler) -{ - int extra_size = 0, ret = -EINVAL; - const struct iw_priv_args *descr; - - extra_size = get_priv_descr_and_size(dev, cmd, &descr); - - /* Check if we have a pointer to user space data or not. */ - if (extra_size == 0) { - /* No extra arguments. Trivial to handle */ - ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); - } else { - ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, - handler, dev, info, extra_size); - } - - /* Call commit handler if needed and defined */ - if (ret == -EIWCOMMIT) - ret = call_commit_handler(dev); - - return ret; -} - -/* ---------------------------------------------------------------- */ -typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, - unsigned int, struct iw_request_info *, - iw_handler); - -/* - * Main IOCTl dispatcher. - * Check the type of IOCTL and call the appropriate wrapper... - */ -static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, - unsigned int cmd, - struct iw_request_info *info, - wext_ioctl_func standard, - wext_ioctl_func private) -{ - struct iwreq *iwr = (struct iwreq *) ifr; - struct net_device *dev; - iw_handler handler; - - /* Permissions are already checked in dev_ioctl() before calling us. - * The copy_to/from_user() of ifr is also dealt with in there */ - - /* Make sure the device exist */ - if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) - return -ENODEV; - - /* A bunch of special cases, then the generic case... - * Note that 'cmd' is already filtered in dev_ioctl() with - * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ - if (cmd == SIOCGIWSTATS) - return standard(dev, iwr, cmd, info, - &iw_handler_get_iwstats); - - if (cmd == SIOCGIWPRIV && dev->wireless_handlers) - return standard(dev, iwr, cmd, info, - &iw_handler_get_private); - - /* Basic check */ - if (!netif_device_present(dev)) - return -ENODEV; - - /* New driver API : try to find the handler */ - handler = get_handler(dev, cmd); - if (handler) { - /* Standard and private are not the same */ - if (cmd < SIOCIWFIRSTPRIV) - return standard(dev, iwr, cmd, info, handler); - else - return private(dev, iwr, cmd, info, handler); - } - /* Old driver API : call driver ioctl handler */ - if (dev->netdev_ops->ndo_do_ioctl) - return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); - return -EOPNOTSUPP; -} - -/* If command is `set a parameter', or `get the encoding parameters', - * check if the user has the right to do it. - */ -static int wext_permission_check(unsigned int cmd) -{ - if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) - && !capable(CAP_NET_ADMIN)) - return -EPERM; - - return 0; -} - -/* entry point from dev ioctl */ -static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, - unsigned int cmd, struct iw_request_info *info, - wext_ioctl_func standard, - wext_ioctl_func private) -{ - int ret = wext_permission_check(cmd); - - if (ret) - return ret; - - dev_load(net, ifr->ifr_name); - rtnl_lock(); - ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); - rtnl_unlock(); - - return ret; -} - -int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, - void __user *arg) -{ - struct iw_request_info info = { .cmd = cmd, .flags = 0 }; - int ret; - - ret = wext_ioctl_dispatch(net, ifr, cmd, &info, - ioctl_standard_call, - ioctl_private_call); - if (ret >= 0 && - IW_IS_GET(cmd) && - copy_to_user(arg, ifr, sizeof(struct iwreq))) - return -EFAULT; - - return ret; -} - -#ifdef CONFIG_COMPAT -static int compat_standard_call(struct net_device *dev, - struct iwreq *iwr, - unsigned int cmd, - struct iw_request_info *info, - iw_handler handler) -{ - const struct iw_ioctl_description *descr; - struct compat_iw_point *iwp_compat; - struct iw_point iwp; - int err; - - descr = standard_ioctl + (cmd - SIOCIWFIRST); - - if (descr->header_type != IW_HEADER_TYPE_POINT) - return ioctl_standard_call(dev, iwr, cmd, info, handler); - - iwp_compat = (struct compat_iw_point *) &iwr->u.data; - iwp.pointer = compat_ptr(iwp_compat->pointer); - iwp.length = iwp_compat->length; - iwp.flags = iwp_compat->flags; - - err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info); - - iwp_compat->pointer = ptr_to_compat(iwp.pointer); - iwp_compat->length = iwp.length; - iwp_compat->flags = iwp.flags; - - return err; -} - -static int compat_private_call(struct net_device *dev, struct iwreq *iwr, - unsigned int cmd, struct iw_request_info *info, - iw_handler handler) -{ - const struct iw_priv_args *descr; - int ret, extra_size; - - extra_size = get_priv_descr_and_size(dev, cmd, &descr); - - /* Check if we have a pointer to user space data or not. */ - if (extra_size == 0) { - /* No extra arguments. Trivial to handle */ - ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); - } else { - struct compat_iw_point *iwp_compat; - struct iw_point iwp; - - iwp_compat = (struct compat_iw_point *) &iwr->u.data; - iwp.pointer = compat_ptr(iwp_compat->pointer); - iwp.length = iwp_compat->length; - iwp.flags = iwp_compat->flags; - - ret = ioctl_private_iw_point(&iwp, cmd, descr, - handler, dev, info, extra_size); - - iwp_compat->pointer = ptr_to_compat(iwp.pointer); - iwp_compat->length = iwp.length; - iwp_compat->flags = iwp.flags; - } - - /* Call commit handler if needed and defined */ - if (ret == -EIWCOMMIT) - ret = call_commit_handler(dev); - - return ret; -} - -int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, - unsigned long arg) -{ - void __user *argp = (void __user *)arg; - struct iw_request_info info; - struct iwreq iwr; - char *colon; - int ret; - - if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) - return -EFAULT; - - iwr.ifr_name[IFNAMSIZ-1] = 0; - colon = strchr(iwr.ifr_name, ':'); - if (colon) - *colon = 0; - - info.cmd = cmd; - info.flags = IW_REQUEST_FLAG_COMPAT; - - ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, - compat_standard_call, - compat_private_call); - - if (ret >= 0 && - IW_IS_GET(cmd) && - copy_to_user(argp, &iwr, sizeof(struct iwreq))) - return -EFAULT; - - return ret; -} -#endif - -static int __net_init wext_pernet_init(struct net *net) -{ - skb_queue_head_init(&net->wext_nlevents); - return 0; -} - -static void __net_exit wext_pernet_exit(struct net *net) -{ - skb_queue_purge(&net->wext_nlevents); -} - -static struct pernet_operations wext_pernet_ops = { - .init = wext_pernet_init, - .exit = wext_pernet_exit, -}; - -static int __init wireless_nlevent_init(void) -{ - return register_pernet_subsys(&wext_pernet_ops); -} - -subsys_initcall(wireless_nlevent_init); - -/* Process events generated by the wireless layer or the driver. */ -static void wireless_nlevent_process(struct work_struct *work) -{ - struct sk_buff *skb; - struct net *net; - - rtnl_lock(); - - for_each_net(net) { - while ((skb = skb_dequeue(&net->wext_nlevents))) - rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, - GFP_KERNEL); - } - - rtnl_unlock(); -} - -static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process); - -static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev, - struct sk_buff *skb) -{ - struct ifinfomsg *r; - struct nlmsghdr *nlh; - - nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0); - if (!nlh) - return NULL; - - r = nlmsg_data(nlh); - r->ifi_family = AF_UNSPEC; - r->__ifi_pad = 0; - r->ifi_type = dev->type; - r->ifi_index = dev->ifindex; - r->ifi_flags = dev_get_flags(dev); - r->ifi_change = 0; /* Wireless changes don't affect those flags */ - - NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); - - return nlh; - nla_put_failure: - nlmsg_cancel(skb, nlh); - return NULL; -} - - -/* - * Main event dispatcher. Called from other parts and drivers. - * Send the event on the appropriate channels. - * May be called from interrupt context. - */ -void wireless_send_event(struct net_device * dev, - unsigned int cmd, - union iwreq_data * wrqu, - const char * extra) -{ - const struct iw_ioctl_description * descr = NULL; - int extra_len = 0; - struct iw_event *event; /* Mallocated whole event */ - int event_len; /* Its size */ - int hdr_len; /* Size of the event header */ - int wrqu_off = 0; /* Offset in wrqu */ - /* Don't "optimise" the following variable, it will crash */ - unsigned cmd_index; /* *MUST* be unsigned */ - struct sk_buff *skb; - struct nlmsghdr *nlh; - struct nlattr *nla; -#ifdef CONFIG_COMPAT - struct __compat_iw_event *compat_event; - struct compat_iw_point compat_wrqu; - struct sk_buff *compskb; -#endif - - /* - * Nothing in the kernel sends scan events with data, be safe. - * This is necessary because we cannot fix up scan event data - * for compat, due to being contained in 'extra', but normally - * applications are required to retrieve the scan data anyway - * and no data is included in the event, this codifies that - * practice. - */ - if (WARN_ON(cmd == SIOCGIWSCAN && extra)) - extra = NULL; - - /* Get the description of the Event */ - if (cmd <= SIOCIWLAST) { - cmd_index = cmd - SIOCIWFIRST; - if (cmd_index < standard_ioctl_num) - descr = &(standard_ioctl[cmd_index]); - } else { - cmd_index = cmd - IWEVFIRST; - if (cmd_index < standard_event_num) - descr = &(standard_event[cmd_index]); - } - /* Don't accept unknown events */ - if (descr == NULL) { - /* Note : we don't return an error to the driver, because - * the driver would not know what to do about it. It can't - * return an error to the user, because the event is not - * initiated by a user request. - * The best the driver could do is to log an error message. - * We will do it ourselves instead... - */ - printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", - dev->name, cmd); - return; - } - - /* Check extra parameters and set extra_len */ - if (descr->header_type == IW_HEADER_TYPE_POINT) { - /* Check if number of token fits within bounds */ - if (wrqu->data.length > descr->max_tokens) { - printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); - return; - } - if (wrqu->data.length < descr->min_tokens) { - printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); - return; - } - /* Calculate extra_len - extra is NULL for restricted events */ - if (extra != NULL) - extra_len = wrqu->data.length * descr->token_size; - /* Always at an offset in wrqu */ - wrqu_off = IW_EV_POINT_OFF; - } - - /* Total length of the event */ - hdr_len = event_type_size[descr->header_type]; - event_len = hdr_len + extra_len; - - /* - * The problem for 64/32 bit. - * - * On 64-bit, a regular event is laid out as follows: - * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | - * | event.len | event.cmd | p a d d i n g | - * | wrqu data ... (with the correct size) | - * - * This padding exists because we manipulate event->u, - * and 'event' is not packed. - * - * An iw_point event is laid out like this instead: - * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | - * | event.len | event.cmd | p a d d i n g | - * | iwpnt.len | iwpnt.flg | p a d d i n g | - * | extra data ... - * - * The second padding exists because struct iw_point is extended, - * but this depends on the platform... - * - * On 32-bit, all the padding shouldn't be there. - */ - - skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); - if (!skb) - return; - - /* Send via the RtNetlink event channel */ - nlh = rtnetlink_ifinfo_prep(dev, skb); - if (WARN_ON(!nlh)) { - kfree_skb(skb); - return; - } - - /* Add the wireless events in the netlink packet */ - nla = nla_reserve(skb, IFLA_WIRELESS, event_len); - if (!nla) { - kfree_skb(skb); - return; - } - event = nla_data(nla); - - /* Fill event - first clear to avoid data leaking */ - memset(event, 0, hdr_len); - event->len = event_len; - event->cmd = cmd; - memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); - if (extra_len) - memcpy(((char *) event) + hdr_len, extra, extra_len); - - nlmsg_end(skb, nlh); -#ifdef CONFIG_COMPAT - hdr_len = compat_event_type_size[descr->header_type]; - event_len = hdr_len + extra_len; - - compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); - if (!compskb) { - kfree_skb(skb); - return; - } - - /* Send via the RtNetlink event channel */ - nlh = rtnetlink_ifinfo_prep(dev, compskb); - if (WARN_ON(!nlh)) { - kfree_skb(skb); - kfree_skb(compskb); - return; - } - - /* Add the wireless events in the netlink packet */ - nla = nla_reserve(compskb, IFLA_WIRELESS, event_len); - if (!nla) { - kfree_skb(skb); - kfree_skb(compskb); - return; - } - compat_event = nla_data(nla); - - compat_event->len = event_len; - compat_event->cmd = cmd; - if (descr->header_type == IW_HEADER_TYPE_POINT) { - compat_wrqu.length = wrqu->data.length; - compat_wrqu.flags = wrqu->data.flags; - memcpy(&compat_event->pointer, - ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF, - hdr_len - IW_EV_COMPAT_LCP_LEN); - if (extra_len) - memcpy(((char *) compat_event) + hdr_len, - extra, extra_len); - } else { - /* extra_len must be zero, so no if (extra) needed */ - memcpy(&compat_event->pointer, wrqu, - hdr_len - IW_EV_COMPAT_LCP_LEN); - } - - nlmsg_end(compskb, nlh); - - skb_shinfo(skb)->frag_list = compskb; -#endif - skb_queue_tail(&dev_net(dev)->wext_nlevents, skb); - schedule_work(&wireless_nlevent_work); -} -EXPORT_SYMBOL(wireless_send_event); - -/********************** ENHANCED IWSPY SUPPORT **********************/ -/* - * In the old days, the driver was handling spy support all by itself. - * Now, the driver can delegate this task to Wireless Extensions. - * It needs to use those standard spy iw_handler in struct iw_handler_def, - * push data to us via wireless_spy_update() and include struct iw_spy_data - * in its private part (and export it in net_device->wireless_data->spy_data). - * One of the main advantage of centralising spy support here is that - * it becomes much easier to improve and extend it without having to touch - * the drivers. One example is the addition of the Spy-Threshold events. - */ - -/* ---------------------------------------------------------------- */ -/* - * Return the pointer to the spy data in the driver. - * Because this is called on the Rx path via wireless_spy_update(), - * we want it to be efficient... - */ -static inline struct iw_spy_data *get_spydata(struct net_device *dev) -{ - /* This is the new way */ - if (dev->wireless_data) - return dev->wireless_data->spy_data; - return NULL; -} - -/*------------------------------------------------------------------*/ -/* - * Standard Wireless Handler : set Spy List - */ -int iw_handler_set_spy(struct net_device * dev, - struct iw_request_info * info, - union iwreq_data * wrqu, - char * extra) -{ - struct iw_spy_data * spydata = get_spydata(dev); - struct sockaddr * address = (struct sockaddr *) extra; - - /* Make sure driver is not buggy or using the old API */ - if (!spydata) - return -EOPNOTSUPP; - - /* Disable spy collection while we copy the addresses. - * While we copy addresses, any call to wireless_spy_update() - * will NOP. This is OK, as anyway the addresses are changing. */ - spydata->spy_number = 0; - - /* We want to operate without locking, because wireless_spy_update() - * most likely will happen in the interrupt handler, and therefore - * have its own locking constraints and needs performance. - * The rtnl_lock() make sure we don't race with the other iw_handlers. - * This make sure wireless_spy_update() "see" that the spy list - * is temporarily disabled. */ - smp_wmb(); - - /* Are there are addresses to copy? */ - if (wrqu->data.length > 0) { - int i; - - /* Copy addresses */ - for (i = 0; i < wrqu->data.length; i++) - memcpy(spydata->spy_address[i], address[i].sa_data, - ETH_ALEN); - /* Reset stats */ - memset(spydata->spy_stat, 0, - sizeof(struct iw_quality) * IW_MAX_SPY); - } - - /* Make sure above is updated before re-enabling */ - smp_wmb(); - - /* Enable addresses */ - spydata->spy_number = wrqu->data.length; - - return 0; -} -EXPORT_SYMBOL(iw_handler_set_spy); - -/*------------------------------------------------------------------*/ -/* - * Standard Wireless Handler : get Spy List - */ -int iw_handler_get_spy(struct net_device * dev, - struct iw_request_info * info, - union iwreq_data * wrqu, - char * extra) -{ - struct iw_spy_data * spydata = get_spydata(dev); - struct sockaddr * address = (struct sockaddr *) extra; - int i; - - /* Make sure driver is not buggy or using the old API */ - if (!spydata) - return -EOPNOTSUPP; - - wrqu->data.length = spydata->spy_number; - - /* Copy addresses. */ - for (i = 0; i < spydata->spy_number; i++) { - memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); - address[i].sa_family = AF_UNIX; - } - /* Copy stats to the user buffer (just after). */ - if (spydata->spy_number > 0) - memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), - spydata->spy_stat, - sizeof(struct iw_quality) * spydata->spy_number); - /* Reset updated flags. */ - for (i = 0; i < spydata->spy_number; i++) - spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; - return 0; -} -EXPORT_SYMBOL(iw_handler_get_spy); - -/*------------------------------------------------------------------*/ -/* - * Standard Wireless Handler : set spy threshold - */ -int iw_handler_set_thrspy(struct net_device * dev, - struct iw_request_info *info, - union iwreq_data * wrqu, - char * extra) -{ - struct iw_spy_data * spydata = get_spydata(dev); - struct iw_thrspy * threshold = (struct iw_thrspy *) extra; - - /* Make sure driver is not buggy or using the old API */ - if (!spydata) - return -EOPNOTSUPP; - - /* Just do it */ - memcpy(&(spydata->spy_thr_low), &(threshold->low), - 2 * sizeof(struct iw_quality)); - - /* Clear flag */ - memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); - - return 0; -} -EXPORT_SYMBOL(iw_handler_set_thrspy); - -/*------------------------------------------------------------------*/ -/* - * Standard Wireless Handler : get spy threshold - */ -int iw_handler_get_thrspy(struct net_device * dev, - struct iw_request_info *info, - union iwreq_data * wrqu, - char * extra) -{ - struct iw_spy_data * spydata = get_spydata(dev); - struct iw_thrspy * threshold = (struct iw_thrspy *) extra; - - /* Make sure driver is not buggy or using the old API */ - if (!spydata) - return -EOPNOTSUPP; - - /* Just do it */ - memcpy(&(threshold->low), &(spydata->spy_thr_low), - 2 * sizeof(struct iw_quality)); - - return 0; -} -EXPORT_SYMBOL(iw_handler_get_thrspy); - -/*------------------------------------------------------------------*/ -/* - * Prepare and send a Spy Threshold event - */ -static void iw_send_thrspy_event(struct net_device * dev, - struct iw_spy_data * spydata, - unsigned char * address, - struct iw_quality * wstats) -{ - union iwreq_data wrqu; - struct iw_thrspy threshold; - - /* Init */ - wrqu.data.length = 1; - wrqu.data.flags = 0; - /* Copy address */ - memcpy(threshold.addr.sa_data, address, ETH_ALEN); - threshold.addr.sa_family = ARPHRD_ETHER; - /* Copy stats */ - memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); - /* Copy also thresholds */ - memcpy(&(threshold.low), &(spydata->spy_thr_low), - 2 * sizeof(struct iw_quality)); - - /* Send event to user space */ - wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); -} - -/* ---------------------------------------------------------------- */ -/* - * Call for the driver to update the spy data. - * For now, the spy data is a simple array. As the size of the array is - * small, this is good enough. If we wanted to support larger number of - * spy addresses, we should use something more efficient... - */ -void wireless_spy_update(struct net_device * dev, - unsigned char * address, - struct iw_quality * wstats) -{ - struct iw_spy_data * spydata = get_spydata(dev); - int i; - int match = -1; - - /* Make sure driver is not buggy or using the old API */ - if (!spydata) - return; - - /* Update all records that match */ - for (i = 0; i < spydata->spy_number; i++) - if (!compare_ether_addr(address, spydata->spy_address[i])) { - memcpy(&(spydata->spy_stat[i]), wstats, - sizeof(struct iw_quality)); - match = i; - } - - /* Generate an event if we cross the spy threshold. - * To avoid event storms, we have a simple hysteresis : we generate - * event only when we go under the low threshold or above the - * high threshold. */ - if (match >= 0) { - if (spydata->spy_thr_under[match]) { - if (wstats->level > spydata->spy_thr_high.level) { - spydata->spy_thr_under[match] = 0; - iw_send_thrspy_event(dev, spydata, - address, wstats); - } - } else { - if (wstats->level < spydata->spy_thr_low.level) { - spydata->spy_thr_under[match] = 1; - iw_send_thrspy_event(dev, spydata, - address, wstats); - } - } - } -} -EXPORT_SYMBOL(wireless_spy_update); -- cgit v1.2.3 From 4912545472d71e3dd546b18b397aec4c89fd7403 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 30 Sep 2009 20:04:38 -0700 Subject: libertas: Add auto deep sleep support for SD8385/SD8686/SD8688 Add timer based auto deep sleep feature in libertas driver which can be configured using iwconfig command. This is tested on SD8688, SD8686 cards with firmware versions 10.38.1.p25, 9.70.4.p0 respectively on 32-bit and 64-bit platforms. Tests have been done for USB/CS cards to make sure that the patch won't break USB/CS code. We didn't test the if_spi driver. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/README | 26 ++++- drivers/net/wireless/libertas/cmd.c | 72 ++++++++++++- drivers/net/wireless/libertas/cmdresp.c | 12 +++ drivers/net/wireless/libertas/debugfs.c | 46 ++++++++ drivers/net/wireless/libertas/decl.h | 4 + drivers/net/wireless/libertas/dev.h | 18 ++++ drivers/net/wireless/libertas/host.h | 1 + drivers/net/wireless/libertas/if_cs.c | 3 + drivers/net/wireless/libertas/if_sdio.c | 56 ++++++++++ drivers/net/wireless/libertas/if_sdio.h | 3 +- drivers/net/wireless/libertas/if_spi.c | 3 + drivers/net/wireless/libertas/if_usb.c | 3 + drivers/net/wireless/libertas/main.c | 111 ++++++++++++++++--- drivers/net/wireless/libertas/scan.c | 11 ++ drivers/net/wireless/libertas/wext.c | 185 +++++++++++++++++++++++++++++++- 15 files changed, 533 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README index ab6a2d518af0..2726c044430f 100644 --- a/drivers/net/wireless/libertas/README +++ b/drivers/net/wireless/libertas/README @@ -1,5 +1,5 @@ ================================================================================ - README for USB8388 + README for Libertas (c) Copyright © 2003-2006, Marvell International Ltd. All Rights Reserved @@ -226,4 +226,28 @@ setuserscan All entries in the scan table (not just the new scan data when keep=1) will be displayed upon completion by use of the getscantable ioctl. +======================== +IWCONFIG COMMANDS +======================== +power period + + This command is used to configure the station in deep sleep mode / + auto deep sleep mode. + + The timer is implemented to monitor the activities (command, event, + etc.). When an activity is detected station will exit from deep + sleep mode automatically and restart the timer. At timer expiry + (no activity for defined time period) the deep sleep mode is entered + automatically. + + Note: this command is for SDIO interface only. + + Usage: + To enable deep sleep mode do: + iwconfig wlan0 power period 0 + To enable auto deep sleep mode with idle time period 5 seconds do: + iwconfig wlan0 power period 5 + To disable deep sleep/auto deep sleep mode do: + iwconfig wlan0 power period -1 + ============================================================================== diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 685098148e10..3a3e8947e84a 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -17,7 +17,6 @@ static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv); - /** * @brief Simple callback that copies response back into command * @@ -319,6 +318,60 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, return 0; } +static int lbs_wait_for_ds_awake(struct lbs_private *priv) +{ + int ret = 0; + + lbs_deb_enter(LBS_DEB_CMD); + + if (priv->is_deep_sleep) { + if (!wait_event_interruptible_timeout(priv->ds_awake_q, + !priv->is_deep_sleep, (10 * HZ))) { + lbs_pr_err("ds_awake_q: timer expired\n"); + ret = -1; + } + } + + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} + +int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) +{ + int ret = 0; + + lbs_deb_enter(LBS_DEB_CMD); + + if (deep_sleep) { + if (priv->is_deep_sleep != 1) { + lbs_deb_cmd("deep sleep: sleep\n"); + BUG_ON(!priv->enter_deep_sleep); + ret = priv->enter_deep_sleep(priv); + if (!ret) { + netif_stop_queue(priv->dev); + netif_carrier_off(priv->dev); + } + } else { + lbs_pr_err("deep sleep: already enabled\n"); + } + } else { + if (priv->is_deep_sleep) { + lbs_deb_cmd("deep sleep: wakeup\n"); + BUG_ON(!priv->exit_deep_sleep); + ret = priv->exit_deep_sleep(priv); + if (!ret) { + ret = lbs_wait_for_ds_awake(priv); + if (ret) + lbs_pr_err("deep sleep: wakeup" + "failed\n"); + } + } + } + + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} + int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, struct assoc_request *assoc) { @@ -1242,8 +1295,17 @@ static void lbs_submit_command(struct lbs_private *priv, timeo = HZ/4; } - /* Setup the timer after transmit command */ - mod_timer(&priv->command_timer, jiffies + timeo); + if (command == CMD_802_11_DEEP_SLEEP) { + if (priv->is_auto_deep_sleep_enabled) { + priv->wakeup_dev_required = 1; + priv->dnld_sent = 0; + } + priv->is_deep_sleep = 1; + lbs_complete_command(priv, cmdnode, 0); + } else { + /* Setup the timer after transmit command */ + mod_timer(&priv->command_timer, jiffies + timeo); + } lbs_deb_leave(LBS_DEB_HOST); } @@ -1505,6 +1567,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, case CMD_802_11_BEACON_CTRL: ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); break; + case CMD_802_11_DEEP_SLEEP: + cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP); + cmdptr->size = cpu_to_le16(S_DS_GEN); + break; default: lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no); ret = -1; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index c42d3faa2660..47d2b1909d69 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -504,9 +504,21 @@ int lbs_process_event(struct lbs_private *priv, u32 event) case MACREG_INT_CODE_HOST_AWAKE: lbs_deb_cmd("EVENT: host awake\n"); + if (priv->reset_deep_sleep_wakeup) + priv->reset_deep_sleep_wakeup(priv); + priv->is_deep_sleep = 0; lbs_send_confirmwake(priv); break; + case MACREG_INT_CODE_DEEP_SLEEP_AWAKE: + if (priv->reset_deep_sleep_wakeup) + priv->reset_deep_sleep_wakeup(priv); + lbs_deb_cmd("EVENT: ds awake\n"); + priv->is_deep_sleep = 0; + priv->wakeup_dev_required = 0; + wake_up_interruptible(&priv->ds_awake_q); + break; + case MACREG_INT_CODE_PS_AWAKE: lbs_deb_cmd("EVENT: ps awake\n"); /* handle unexpected PS AWAKE event */ diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 893a55ca344a..8a7e9319c9e5 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -117,6 +117,11 @@ static ssize_t lbs_sleepparams_write(struct file *file, if (!buf) return -ENOMEM; + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out_unlock; + } + buf_size = min(count, len - 1); if (copy_from_user(buf, user_buf, buf_size)) { ret = -EFAULT; @@ -157,6 +162,11 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf, if (!buf) return -ENOMEM; + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out_unlock; + } + ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp); if (ret) goto out_unlock; @@ -223,6 +233,9 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask, u8 freq; int events = 0; + if (!lbs_is_cmd_allowed(priv)) + return -EBUSY; + buf = (char *)get_zeroed_page(GFP_KERNEL); if (!buf) return -ENOMEM; @@ -275,6 +288,9 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, char *buf; int ret; + if (!lbs_is_cmd_allowed(priv)) + return -EBUSY; + buf = (char *)get_zeroed_page(GFP_KERNEL); if (!buf) return -ENOMEM; @@ -444,6 +460,11 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, if (!buf) return -ENOMEM; + if (!lbs_is_cmd_allowed(priv)) { + free_page(addr); + return -EBUSY; + } + offval.offset = priv->mac_offset; offval.value = 0; @@ -496,6 +517,11 @@ static ssize_t lbs_wrmac_write(struct file *file, if (!buf) return -ENOMEM; + if (!lbs_is_cmd_allowed(priv)) { + res = -EBUSY; + goto out_unlock; + } + buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { res = -EFAULT; @@ -532,6 +558,11 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf, if (!buf) return -ENOMEM; + if (!lbs_is_cmd_allowed(priv)) { + free_page(addr); + return -EBUSY; + } + offval.offset = priv->bbp_offset; offval.value = 0; @@ -585,6 +616,11 @@ static ssize_t lbs_wrbbp_write(struct file *file, if (!buf) return -ENOMEM; + if (!lbs_is_cmd_allowed(priv)) { + res = -EBUSY; + goto out_unlock; + } + buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { res = -EFAULT; @@ -621,6 +657,11 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf, if (!buf) return -ENOMEM; + if (!lbs_is_cmd_allowed(priv)) { + free_page(addr); + return -EBUSY; + } + offval.offset = priv->rf_offset; offval.value = 0; @@ -674,6 +715,11 @@ static ssize_t lbs_wrrf_write(struct file *file, if (!buf) return -ENOMEM; + if (!lbs_is_cmd_allowed(priv)) { + res = -EBUSY; + goto out_unlock; + } + buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { res = -EFAULT; diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 8b15380ae6e1..44f0b248ace9 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -33,6 +33,10 @@ int lbs_execute_next_command(struct lbs_private *priv); int lbs_process_event(struct lbs_private *priv, u32 event); void lbs_queue_event(struct lbs_private *priv, u32 event); void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); +int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep); +int lbs_is_cmd_allowed(struct lbs_private *priv); +int lbs_enter_auto_deep_sleep(struct lbs_private *priv); +int lbs_exit_auto_deep_sleep(struct lbs_private *priv); u32 lbs_fw_index_to_data_rate(u8 index); u8 lbs_data_rate_to_fw_index(u32 rate); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index d3b69a4b4b5e..0018df14fad9 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -129,6 +129,20 @@ struct lbs_private { u32 bbp_offset; u32 rf_offset; + /** Deep sleep flag */ + int is_deep_sleep; + /** Auto deep sleep enabled flag */ + int is_auto_deep_sleep_enabled; + /** Device wakeup required flag */ + int wakeup_dev_required; + /** Auto deep sleep flag*/ + int is_activity_detected; + /** Auto deep sleep timeout (in miliseconds) */ + int auto_deep_sleep_timeout; + + /** Deep sleep wait queue */ + wait_queue_head_t ds_awake_q; + /* Download sent: bit0 1/0=data_sent/data_tx_done, bit1 1/0=cmd_sent/cmd_tx_done, @@ -154,6 +168,9 @@ struct lbs_private { /** Hardware access */ int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); void (*reset_card) (struct lbs_private *priv); + int (*enter_deep_sleep) (struct lbs_private *priv); + int (*exit_deep_sleep) (struct lbs_private *priv); + int (*reset_deep_sleep_wakeup) (struct lbs_private *priv); /* Wake On LAN */ uint32_t wol_criteria; @@ -204,6 +221,7 @@ struct lbs_private { /** Timers */ struct timer_list command_timer; + struct timer_list auto_deepsleep_timer; int nr_retries; int cmd_timed_out; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index fe8f0cb737bc..c055daabea13 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -57,6 +57,7 @@ #define CMD_802_11_ENABLE_RSN 0x002f #define CMD_802_11_SET_AFC 0x003c #define CMD_802_11_GET_AFC 0x003d +#define CMD_802_11_DEEP_SLEEP 0x003e #define CMD_802_11_AD_HOC_STOP 0x0040 #define CMD_802_11_HOST_SLEEP_CFG 0x0043 #define CMD_802_11_WAKEUP_CONFIRM 0x0044 diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 62381768f2d5..465742f19ecb 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -946,6 +946,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev) card->priv = priv; priv->card = card; priv->hw_host_to_card = if_cs_host_to_card; + priv->enter_deep_sleep = NULL; + priv->exit_deep_sleep = NULL; + priv->reset_deep_sleep_wakeup = NULL; priv->fw_ready = 1; /* Now actually get the IRQ */ diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 485a8d406525..9716728a33cb 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -831,6 +831,58 @@ out: return ret; } +static int if_sdio_enter_deep_sleep(struct lbs_private *priv) +{ + int ret = -1; + struct cmd_header cmd; + + memset(&cmd, 0, sizeof(cmd)); + + lbs_deb_sdio("send DEEP_SLEEP command\n"); + ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd), + lbs_cmd_copyback, (unsigned long) &cmd); + if (ret) + lbs_pr_err("DEEP_SLEEP cmd failed\n"); + + mdelay(200); + return ret; +} + +static int if_sdio_exit_deep_sleep(struct lbs_private *priv) +{ + struct if_sdio_card *card = priv->card; + int ret = -1; + + lbs_deb_enter(LBS_DEB_SDIO); + sdio_claim_host(card->func); + + sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret); + if (ret) + lbs_pr_err("sdio_writeb failed!\n"); + + sdio_release_host(card->func); + lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); + return ret; +} + +static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv) +{ + struct if_sdio_card *card = priv->card; + int ret = -1; + + lbs_deb_enter(LBS_DEB_SDIO); + sdio_claim_host(card->func); + + sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret); + if (ret) + lbs_pr_err("sdio_writeb failed!\n"); + + sdio_release_host(card->func); + lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); + return ret; + +} + /*******************************************************************/ /* SDIO callbacks */ /*******************************************************************/ @@ -859,6 +911,7 @@ static void if_sdio_interrupt(struct sdio_func *func) * Ignore the define name, this really means the card has * successfully received the command. */ + card->priv->is_activity_detected = 1; if (cause & IF_SDIO_H_INT_DNLD) lbs_host_to_card_done(card->priv); @@ -998,6 +1051,9 @@ static int if_sdio_probe(struct sdio_func *func, priv->card = card; priv->hw_host_to_card = if_sdio_host_to_card; + priv->enter_deep_sleep = if_sdio_enter_deep_sleep; + priv->exit_deep_sleep = if_sdio_exit_deep_sleep; + priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup; priv->fw_ready = 1; diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h index 60c9b2fcef03..12179c1dc9c9 100644 --- a/drivers/net/wireless/libertas/if_sdio.h +++ b/drivers/net/wireless/libertas/if_sdio.h @@ -51,5 +51,6 @@ #define IF_SDIO_EVENT 0x80fc #define IF_SDIO_BLOCK_SIZE 256 - +#define CONFIGURATION_REG 0x03 +#define HOST_POWER_UP (0x1U << 1) #endif diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index cb8be8d7abc1..06df2e174b50 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -1117,6 +1117,9 @@ static int __devinit if_spi_probe(struct spi_device *spi) card->priv = priv; priv->card = card; priv->hw_host_to_card = if_spi_host_to_card; + priv->enter_deep_sleep = NULL; + priv->exit_deep_sleep = NULL; + priv->reset_deep_sleep_wakeup = NULL; priv->fw_ready = 1; /* Initialize interrupt handling stuff. */ diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 92bc8c5f1ca2..a8262dea9b1f 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -300,6 +300,9 @@ static int if_usb_probe(struct usb_interface *intf, cardp->priv->fw_ready = 1; priv->hw_host_to_card = if_usb_host_to_card; + priv->enter_deep_sleep = NULL; + priv->exit_deep_sleep = NULL; + priv->reset_deep_sleep_wakeup = NULL; #ifdef CONFIG_OLPC if (machine_is_olpc()) priv->reset_card = if_usb_reset_olpc_card; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 87b4e497faa2..9b2a9174a017 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -574,8 +574,10 @@ void lbs_host_to_card_done(struct lbs_private *priv) priv->dnld_sent = DNLD_RES_RECEIVED; /* Wake main thread if commands are pending */ - if (!priv->cur_cmd || priv->tx_pending_len > 0) - wake_up_interruptible(&priv->waitq); + if (!priv->cur_cmd || priv->tx_pending_len > 0) { + if (!priv->wakeup_dev_required) + wake_up_interruptible(&priv->waitq); + } spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_leave(LBS_DEB_THREAD); @@ -770,7 +772,8 @@ static int lbs_thread(void *data) shouldsleep = 0; /* We have a command response */ else if (priv->cur_cmd) shouldsleep = 1; /* Can't send a command; one already running */ - else if (!list_empty(&priv->cmdpendingq)) + else if (!list_empty(&priv->cmdpendingq) && + !(priv->wakeup_dev_required)) shouldsleep = 0; /* We have a command to send */ else if (__kfifo_len(priv->event_fifo)) shouldsleep = 0; /* We have an event to process */ @@ -822,6 +825,26 @@ static int lbs_thread(void *data) } spin_unlock_irq(&priv->driver_lock); + /* Process hardware events, e.g. card removed, link lost */ + spin_lock_irq(&priv->driver_lock); + while (__kfifo_len(priv->event_fifo)) { + u32 event; + __kfifo_get(priv->event_fifo, (unsigned char *) &event, + sizeof(event)); + spin_unlock_irq(&priv->driver_lock); + lbs_process_event(priv, event); + spin_lock_irq(&priv->driver_lock); + } + spin_unlock_irq(&priv->driver_lock); + + if (priv->wakeup_dev_required) { + lbs_deb_thread("Waking up device...\n"); + /* Wake up device */ + if (priv->exit_deep_sleep(priv)) + lbs_deb_thread("Wakeup device failed\n"); + continue; + } + /* command timeout stuff */ if (priv->cmd_timed_out && priv->cur_cmd) { struct cmd_ctrl_node *cmdnode = priv->cur_cmd; @@ -849,18 +872,7 @@ static int lbs_thread(void *data) } priv->cmd_timed_out = 0; - /* Process hardware events, e.g. card removed, link lost */ - spin_lock_irq(&priv->driver_lock); - while (__kfifo_len(priv->event_fifo)) { - u32 event; - __kfifo_get(priv->event_fifo, (unsigned char *) &event, - sizeof(event)); - spin_unlock_irq(&priv->driver_lock); - lbs_process_event(priv, event); - spin_lock_irq(&priv->driver_lock); - } - spin_unlock_irq(&priv->driver_lock); if (!priv->fw_ready) continue; @@ -894,6 +906,9 @@ static int lbs_thread(void *data) (priv->psstate == PS_STATE_PRE_SLEEP)) continue; + if (priv->is_deep_sleep) + continue; + /* Execute the next command */ if (!priv->dnld_sent && !priv->cur_cmd) lbs_execute_next_command(priv); @@ -928,6 +943,7 @@ static int lbs_thread(void *data) } del_timer(&priv->command_timer); + del_timer(&priv->auto_deepsleep_timer); wake_up_all(&priv->cmd_pending); lbs_deb_leave(LBS_DEB_THREAD); @@ -1050,6 +1066,60 @@ out: lbs_deb_leave(LBS_DEB_CMD); } +/** + * This function put the device back to deep sleep mode when timer expires + * and no activity (command, event, data etc.) is detected. + */ +static void auto_deepsleep_timer_fn(unsigned long data) +{ + struct lbs_private *priv = (struct lbs_private *)data; + int ret; + + lbs_deb_enter(LBS_DEB_CMD); + + if (priv->is_activity_detected) { + priv->is_activity_detected = 0; + } else { + if (priv->is_auto_deep_sleep_enabled && + (!priv->wakeup_dev_required) && + (priv->connect_status != LBS_CONNECTED)) { + lbs_deb_main("Entering auto deep sleep mode...\n"); + ret = lbs_prepare_and_send_command(priv, + CMD_802_11_DEEP_SLEEP, 0, + 0, 0, NULL); + } + } + mod_timer(&priv->auto_deepsleep_timer , jiffies + + (priv->auto_deep_sleep_timeout * HZ)/1000); + lbs_deb_leave(LBS_DEB_CMD); +} + +int lbs_enter_auto_deep_sleep(struct lbs_private *priv) +{ + lbs_deb_enter(LBS_DEB_SDIO); + + priv->is_auto_deep_sleep_enabled = 1; + if (priv->is_deep_sleep) + priv->wakeup_dev_required = 1; + mod_timer(&priv->auto_deepsleep_timer , + jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000); + + lbs_deb_leave(LBS_DEB_SDIO); + return 0; +} + +int lbs_exit_auto_deep_sleep(struct lbs_private *priv) +{ + lbs_deb_enter(LBS_DEB_SDIO); + + priv->is_auto_deep_sleep_enabled = 0; + priv->auto_deep_sleep_timeout = 0; + del_timer(&priv->auto_deepsleep_timer); + + lbs_deb_leave(LBS_DEB_SDIO); + return 0; +} + static void lbs_sync_channel_worker(struct work_struct *work) { struct lbs_private *priv = container_of(work, struct lbs_private, @@ -1099,11 +1169,17 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->psmode = LBS802_11POWERMODECAM; priv->psstate = PS_STATE_FULL_POWER; + priv->is_deep_sleep = 0; + priv->is_auto_deep_sleep_enabled = 0; + priv->wakeup_dev_required = 0; + init_waitqueue_head(&priv->ds_awake_q); mutex_init(&priv->lock); setup_timer(&priv->command_timer, command_timer_fn, (unsigned long)priv); + setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn, + (unsigned long)priv); INIT_LIST_HEAD(&priv->cmdfreeq); INIT_LIST_HEAD(&priv->cmdpendingq); @@ -1142,6 +1218,7 @@ static void lbs_free_adapter(struct lbs_private *priv) if (priv->event_fifo) kfifo_free(priv->event_fifo); del_timer(&priv->command_timer); + del_timer(&priv->auto_deepsleep_timer); kfree(priv->networks); priv->networks = NULL; @@ -1272,6 +1349,11 @@ void lbs_remove_card(struct lbs_private *priv) wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + if (priv->is_deep_sleep) { + priv->is_deep_sleep = 0; + wake_up_interruptible(&priv->ds_awake_q); + } + /* Stop the thread servicing the interrupts */ priv->surpriseremoved = 1; kthread_stop(priv->main_thread); @@ -1392,6 +1474,7 @@ void lbs_stop_card(struct lbs_private *priv) /* Delete the timeout of the currently processing command */ del_timer_sync(&priv->command_timer); + del_timer_sync(&priv->auto_deepsleep_timer); /* Flush pending command nodes */ spin_lock_irqsave(&priv->driver_lock, flags); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 6c95af3023cc..e468e155e8be 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -950,6 +950,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + if (!priv->radio_on) { ret = -EINVAL; goto out; @@ -1017,6 +1022,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + err = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err); + return err; + } + /* iwlist should wait until the current scan is finished */ if (priv->scan_channel) return -EAGAIN; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index be837a0d2517..38a451edb703 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -45,6 +45,31 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv) priv->pending_assoc_req = NULL; } +/** + * @brief This function checks if the command is allowed. + * + * @param priv A pointer to lbs_private structure + * @return allowed or not allowed. + */ + +int lbs_is_cmd_allowed(struct lbs_private *priv) +{ + int ret = 1; + + lbs_deb_enter(LBS_DEB_WEXT); + + if (!priv->is_auto_deep_sleep_enabled) { + if (priv->is_deep_sleep) { + lbs_deb_wext("IOCTLS called when station" + "is in deep sleep\n"); + ret = 0; + } + } + + lbs_deb_leave(LBS_DEB_WEXT); + return ret; +} + /** * @brief Find the channel frequency power info with specific channel @@ -168,6 +193,11 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + lbs_deb_leave(LBS_DEB_WEXT); + return -EBUSY; + } + cfp = lbs_find_cfp_by_band_and_channel(priv, 0, priv->curbssparams.channel); @@ -278,6 +308,12 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + if (vwrq->disabled) val = MRVDRV_RTS_MAX_VALUE; @@ -299,6 +335,11 @@ static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val); if (ret) goto out; @@ -321,6 +362,12 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + if (vwrq->disabled) val = MRVDRV_FRAG_MAX_VALUE; @@ -342,6 +389,11 @@ static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val); if (ret) goto out; @@ -391,6 +443,11 @@ static int lbs_get_txpow(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + if (!priv->radio_on) { lbs_deb_wext("tx power off\n"); vwrq->value = 0; @@ -424,6 +481,11 @@ static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) return -EOPNOTSUPP; @@ -472,6 +534,11 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + vwrq->disabled = 0; if (vwrq->flags & IW_RETRY_LONG) { @@ -709,6 +776,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { struct lbs_private *priv = dev->ml_priv; + int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); @@ -737,8 +805,54 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, "setting power timeout is not supported\n"); return -EINVAL; } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { - lbs_deb_wext("setting power period not supported\n"); - return -EINVAL; + vwrq->value = vwrq->value / 1000; + if (!priv->enter_deep_sleep) { + lbs_pr_err("deep sleep feature is not implemented " + "for this interface driver\n"); + return -EINVAL; + } + + if (priv->connect_status == LBS_CONNECTED) { + if ((priv->is_auto_deep_sleep_enabled) && + (vwrq->value == -1000)) { + lbs_exit_auto_deep_sleep(priv); + return 0; + } else { + lbs_pr_err("can't use deep sleep cmd in " + "connected state\n"); + return -EINVAL; + } + } + + if ((vwrq->value < 0) && (vwrq->value != -1000)) { + lbs_pr_err("unknown option\n"); + return -EINVAL; + } + + if (vwrq->value > 0) { + if (!priv->is_auto_deep_sleep_enabled) { + priv->is_activity_detected = 0; + priv->auto_deep_sleep_timeout = vwrq->value; + lbs_enter_auto_deep_sleep(priv); + } else { + priv->auto_deep_sleep_timeout = vwrq->value; + lbs_deb_debugfs("auto deep sleep: " + "already enabled\n"); + } + return 0; + } else { + if (priv->is_auto_deep_sleep_enabled) { + lbs_exit_auto_deep_sleep(priv); + /* Try to exit deep sleep if auto */ + /*deep sleep disabled */ + ret = lbs_set_deep_sleep(priv, 0); + } + if (vwrq->value == 0) + ret = lbs_set_deep_sleep(priv, 1); + else if (vwrq->value == -1000) + ret = lbs_set_deep_sleep(priv, 0); + return ret; + } } if (priv->psmode != LBS802_11POWERMODECAM) { @@ -752,6 +866,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, } lbs_deb_leave(LBS_DEB_WEXT); + return 0; } @@ -792,6 +907,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) + return NULL; + priv->wstats.status = priv->mode; /* If we're not associated, all quality values are meaningless */ @@ -892,6 +1010,12 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1000,6 +1124,12 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, u8 rates[MAX_RATES + 1]; lbs_deb_enter(LBS_DEB_WEXT); + + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + lbs_deb_wext("vwrq->value %d\n", vwrq->value); lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed); @@ -1058,6 +1188,11 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + lbs_deb_leave(LBS_DEB_WEXT); + return -EBUSY; + } + if (priv->connect_status == LBS_CONNECTED) { vwrq->value = priv->cur_rate * 500000; @@ -1084,6 +1219,11 @@ static int lbs_set_mode(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + if ( (*uwrq != IW_MODE_ADHOC) && (*uwrq != IW_MODE_INFRA) && (*uwrq != IW_MODE_AUTO)) { @@ -1325,6 +1465,12 @@ static int lbs_set_encode(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1508,6 +1654,12 @@ static int lbs_set_encodeext(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1720,6 +1872,12 @@ static int lbs_set_auth(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1822,6 +1980,12 @@ static int lbs_get_auth(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + switch (dwrq->flags & IW_AUTH_INDEX) { case IW_AUTH_KEY_MGMT: dwrq->value = priv->secinfo.key_mgmt; @@ -1864,6 +2028,11 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto out; + } + if (vwrq->disabled) { lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0); goto out; @@ -1983,6 +2152,12 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + if (!priv->radio_on) { ret = -EINVAL; goto out; @@ -2110,6 +2285,12 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; + } + if (!priv->radio_on) return -EINVAL; -- cgit v1.2.3 From ffe9793252de2e9a3cc7e29a6c7debd1d549df07 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 1 Oct 2009 12:51:20 +0300 Subject: wl1251: remove wl1251_netlink.h The file was accidentally added in commit ef2f8d4577 ("wl1251: add wl1251 prefix to all 1251 files"). This happened when I rebased the patches from a private tree. Reported-by: Robert P. J. Day Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_netlink.h | 30 ---------------------------- 1 file changed, 30 deletions(-) delete mode 100644 drivers/net/wireless/wl12xx/wl1251_netlink.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h deleted file mode 100644 index ee36695e134e..000000000000 --- a/drivers/net/wireless/wl12xx/wl1251_netlink.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This file is part of wl1251 - * - * Copyright (C) 2009 Nokia Corporation - * - * Contact: Kalle Valo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __WL1251_NETLINK_H__ -#define __WL1251_NETLINK_H__ - -int wl1251_nl_register(void); -void wl1251_nl_unregister(void); - -#endif /* __WL1251_NETLINK_H__ */ -- cgit v1.2.3 From 7812b16730ccebce71a3b2228ac08dd4f8b39469 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 2 Oct 2009 13:43:58 -0700 Subject: iwlwifi: reliable entering of critical temperature state When uCode detects critical temperature it should send "card state notification" interrupt to driver and then shut itself down to prevent overheating. There is a race condition where uCode shuts down before it can deliver the interrupt to driver. Additional method provided here for driver to enter CT_KILL state based on temperature reading. How it works: Method 1: If driver receive "card state notification" interrupt from uCode; it enters "CT_KILL" state immediately Method 2: If the last temperature report by Card reach Critical temperature, driver will send "statistic notification" request to uCode to verify the temperature reading, if driver can not get reply from uCode within 300ms, driver will enter CT_KILL state automatically. Method 3: If the last temperature report by Card did not reach Critical temperature, but uCode already shut down due to critical temperature. All the host commands send to uCode will not get process by uCode; when command queue reach the limit, driver will check the last reported temperature reading, if it is within pre-defined margin, enter "CT_KILL" state immediately. In this case, when uCode ready to exit from "CT_KILL" state, driver need to restart the adapter in order to reset all the queues and resume normal operation. One additional issue being address here, when system is in CT_KILL state, both tx and rx already stopped, but driver still can send host command to uCode, it will flood the command queue since card was not responding; adding STATUS_CT_KILL flag to reject enqueue host commands to uCode if it is in CT_KILL state, when uCode is ready to come out of CT_KILL, driver will clear the STATUS_CT_KILL bit and allow enqueue the host commands to uCode to recover from CT_KILL state. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.h | 6 ++ drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 + drivers/net/wireless/iwlwifi/iwl-power.c | 146 +++++++++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-power.h | 3 + drivers/net/wireless/iwlwifi/iwl-tx.c | 10 +- 5 files changed, 135 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 744f0cac6859..3bd0e59bb5a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -580,6 +580,7 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 #define STATUS_RF_KILL_HW 3 +#define STATUS_CT_KILL 4 #define STATUS_INIT 5 #define STATUS_ALIVE 6 #define STATUS_READY 7 @@ -624,6 +625,11 @@ static inline int iwl_is_rfkill(struct iwl_priv *priv) return iwl_is_rfkill_hw(priv); } +static inline int iwl_is_ctkill(struct iwl_priv *priv) +{ + return test_bit(STATUS_CT_KILL, &priv->status); +} + static inline int iwl_is_ready_rf(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 037b75ca77f1..fa6371d171c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -535,6 +535,8 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, test_bit(STATUS_INT_ENABLED, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", test_bit(STATUS_RF_KILL_HW, &priv->status)); + pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n", + test_bit(STATUS_CT_KILL, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n", test_bit(STATUS_INIT, &priv->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index e50d77bd7aad..9c6b14952061 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -165,26 +165,26 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, *============================================================================= * Condition Nxt State Condition Nxt State Condition Nxt State *----------------------------------------------------------------------------- - * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A - * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 - * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 + * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A + * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0 + * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1 * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 *============================================================================= */ static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = { {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104}, - {IWL_TI_1, 105, CT_KILL_THRESHOLD}, - {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} + {IWL_TI_1, 105, CT_KILL_THRESHOLD - 1}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX} }; static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = { {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95}, - {IWL_TI_2, 110, CT_KILL_THRESHOLD}, - {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} + {IWL_TI_2, 110, CT_KILL_THRESHOLD - 1}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX} }; static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = { {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100}, - {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX}, - {IWL_TI_CT_KILL, CT_KILL_THRESHOLD + 1, IWL_ABSOLUTE_MAX} + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}, + {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX} }; static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = { {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD}, @@ -351,6 +351,23 @@ bool iwl_ht_enabled(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_ht_enabled); +bool iwl_within_ct_kill_margin(struct iwl_priv *priv) +{ + s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ + bool within_margin = false; + + if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) + temp = KELVIN_TO_CELSIUS(priv->temperature); + + if (!priv->thermal_throttle.advanced_tt) + within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >= + CT_KILL_THRESHOLD_LEGACY) ? true : false; + else + within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >= + CT_KILL_THRESHOLD) ? true : false; + return within_margin; +} + enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; @@ -375,6 +392,7 @@ enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv) } #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ +#define CT_KILL_WAITING_DURATION (300) /* 300ms duration */ /* * toggle the bit to wake up uCode and check the temperature @@ -412,6 +430,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) /* Reschedule the ct_kill timer to occur in * CT_KILL_EXIT_DURATION seconds to ensure we get a * thermal update */ + IWL_DEBUG_POWER(priv, "schedule ct_kill exit timer\n"); mod_timer(&priv->thermal_throttle.ct_kill_exit_tm, jiffies + CT_KILL_EXIT_DURATION * HZ); } @@ -435,6 +454,33 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, } } +static void iwl_tt_ready_for_ct_kill(unsigned long data) +{ + struct iwl_priv *priv = (struct iwl_priv *)data; + struct iwl_tt_mgmt *tt = &priv->thermal_throttle; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + /* temperature timer expired, ready to go into CT_KILL state */ + if (tt->state != IWL_TI_CT_KILL) { + IWL_DEBUG_POWER(priv, "entering CT_KILL state when temperature timer expired\n"); + tt->state = IWL_TI_CT_KILL; + set_bit(STATUS_CT_KILL, &priv->status); + iwl_perform_ct_kill_task(priv, true); + } +} + +static void iwl_prepare_ct_kill_task(struct iwl_priv *priv) +{ + IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n"); + /* make request to retrieve statistics information */ + iwl_send_statistics_request(priv, 0); + /* Reschedule the ct_kill wait timer */ + mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm, + jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION)); +} + #define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY) #define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100) #define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90) @@ -448,7 +494,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv, * Throttle early enough to lower the power consumption before * drastic steps are needed */ -static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) +static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; enum iwl_tt_state old_state; @@ -477,6 +523,8 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) #ifdef CONFIG_IWLWIFI_DEBUG tt->tt_previous_temp = temp; #endif + /* stop ct_kill_waiting_tm timer */ + del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm); if (tt->state != old_state) { switch (tt->state) { case IWL_TI_0: @@ -497,17 +545,28 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) break; } mutex_lock(&priv->mutex); - if (iwl_power_update_mode(priv, true)) { + if (old_state == IWL_TI_CT_KILL) + clear_bit(STATUS_CT_KILL, &priv->status); + if (tt->state != IWL_TI_CT_KILL && + iwl_power_update_mode(priv, true)) { /* TT state not updated * try again during next temperature read */ + if (old_state == IWL_TI_CT_KILL) + set_bit(STATUS_CT_KILL, &priv->status); tt->state = old_state; IWL_ERR(priv, "Cannot update power mode, " "TT state not updated\n"); } else { - if (tt->state == IWL_TI_CT_KILL) - iwl_perform_ct_kill_task(priv, true); - else if (old_state == IWL_TI_CT_KILL && + if (tt->state == IWL_TI_CT_KILL) { + if (force) { + set_bit(STATUS_CT_KILL, &priv->status); + iwl_perform_ct_kill_task(priv, true); + } else { + iwl_prepare_ct_kill_task(priv); + tt->state = old_state; + } + } else if (old_state == IWL_TI_CT_KILL && tt->state != IWL_TI_CT_KILL) iwl_perform_ct_kill_task(priv, false); IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", @@ -534,13 +593,13 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) *============================================================================= * Condition Nxt State Condition Nxt State Condition Nxt State *----------------------------------------------------------------------------- - * IWL_TI_0 T >= 115 CT_KILL 115>T>=105 TI_1 N/A N/A - * IWL_TI_1 T >= 115 CT_KILL 115>T>=110 TI_2 T<=95 TI_0 - * IWL_TI_2 T >= 115 CT_KILL T<=100 TI_1 + * IWL_TI_0 T >= 114 CT_KILL 114>T>=105 TI_1 N/A N/A + * IWL_TI_1 T >= 114 CT_KILL 114>T>=110 TI_2 T<=95 TI_0 + * IWL_TI_2 T >= 114 CT_KILL T<=100 TI_1 * IWL_CT_KILL N/A N/A N/A N/A T<=95 TI_0 *============================================================================= */ -static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) +static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force) { struct iwl_tt_mgmt *tt = &priv->thermal_throttle; int i; @@ -585,6 +644,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) break; } } + /* stop ct_kill_waiting_tm timer */ + del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm); if (changed) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -616,12 +677,17 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) iwl_set_rxon_ht(priv, &priv->current_ht_config); } mutex_lock(&priv->mutex); - if (iwl_power_update_mode(priv, true)) { + if (old_state == IWL_TI_CT_KILL) + clear_bit(STATUS_CT_KILL, &priv->status); + if (tt->state != IWL_TI_CT_KILL && + iwl_power_update_mode(priv, true)) { /* TT state not updated * try again during next temperature read */ IWL_ERR(priv, "Cannot update power mode, " "TT state not updated\n"); + if (old_state == IWL_TI_CT_KILL) + set_bit(STATUS_CT_KILL, &priv->status); tt->state = old_state; } else { IWL_DEBUG_POWER(priv, @@ -629,9 +695,15 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) tt->state); if (old_state != IWL_TI_CT_KILL && tt->state == IWL_TI_CT_KILL) { - IWL_DEBUG_POWER(priv, "Enter IWL_TI_CT_KILL\n"); - iwl_perform_ct_kill_task(priv, true); - + if (force) { + IWL_DEBUG_POWER(priv, + "Enter IWL_TI_CT_KILL\n"); + set_bit(STATUS_CT_KILL, &priv->status); + iwl_perform_ct_kill_task(priv, true); + } else { + iwl_prepare_ct_kill_task(priv); + tt->state = old_state; + } } else if (old_state == IWL_TI_CT_KILL && tt->state != IWL_TI_CT_KILL) { IWL_DEBUG_POWER(priv, "Exit IWL_TI_CT_KILL\n"); @@ -668,10 +740,11 @@ static void iwl_bg_ct_enter(struct work_struct *work) "- ucode going to sleep!\n"); if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, - IWL_MINIMAL_POWER_THRESHOLD); + IWL_MINIMAL_POWER_THRESHOLD, + true); else iwl_advance_tt_handler(priv, - CT_KILL_THRESHOLD + 1); + CT_KILL_THRESHOLD + 1, true); } } @@ -698,11 +771,18 @@ static void iwl_bg_ct_exit(struct work_struct *work) IWL_ERR(priv, "Device temperature below critical" "- ucode awake!\n"); + /* + * exit from CT_KILL state + * reset the current temperature reading + */ + priv->temperature = 0; if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, - IWL_REDUCED_PERFORMANCE_THRESHOLD_2); + IWL_REDUCED_PERFORMANCE_THRESHOLD_2, + true); else - iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD); + iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD, + true); } } @@ -738,9 +818,9 @@ static void iwl_bg_tt_work(struct work_struct *work) temp = KELVIN_TO_CELSIUS(priv->temperature); if (!priv->thermal_throttle.advanced_tt) - iwl_legacy_tt_handler(priv, temp); + iwl_legacy_tt_handler(priv, temp, false); else - iwl_advance_tt_handler(priv, temp); + iwl_advance_tt_handler(priv, temp, false); } void iwl_tt_handler(struct iwl_priv *priv) @@ -771,8 +851,12 @@ void iwl_tt_initialize(struct iwl_priv *priv) tt->state = IWL_TI_0; init_timer(&priv->thermal_throttle.ct_kill_exit_tm); priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; - priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; - + priv->thermal_throttle.ct_kill_exit_tm.function = + iwl_tt_check_exit_ct_kill; + init_timer(&priv->thermal_throttle.ct_kill_waiting_tm); + priv->thermal_throttle.ct_kill_waiting_tm.data = (unsigned long)priv; + priv->thermal_throttle.ct_kill_waiting_tm.function = + iwl_tt_ready_for_ct_kill; /* setup deferred ct kill work */ INIT_WORK(&priv->tt_work, iwl_bg_tt_work); INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); @@ -829,6 +913,8 @@ void iwl_tt_exit(struct iwl_priv *priv) /* stop ct_kill_exit_tm timer if activated */ del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm); + /* stop ct_kill_waiting_tm timer if activated */ + del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm); cancel_work_sync(&priv->tt_work); cancel_work_sync(&priv->ct_enter); cancel_work_sync(&priv->ct_exit); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index df6f6a49712b..310c32e8f698 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -33,6 +33,7 @@ #define IWL_ABSOLUTE_ZERO 0 #define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 +#define IWL_TT_CT_KILL_MARGIN 3 enum iwl_antenna_ok { IWL_ANT_OK_NONE, @@ -110,6 +111,7 @@ struct iwl_tt_mgmt { struct iwl_tt_restriction *restriction; struct iwl_tt_trans *transaction; struct timer_list ct_kill_exit_tm; + struct timer_list ct_kill_waiting_tm; }; enum iwl_power_level { @@ -129,6 +131,7 @@ struct iwl_power_mgr { int iwl_power_update_mode(struct iwl_priv *priv, bool force); bool iwl_ht_enabled(struct iwl_priv *priv); +bool iwl_within_ct_kill_margin(struct iwl_priv *priv); enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv); enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv); void iwl_tt_enter_ct_kill(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index ad69479376a6..2ba9725beff9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -969,13 +969,19 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && !(cmd->flags & CMD_SIZE_HUGE)); - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n"); + if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { + IWL_DEBUG_INFO(priv, "Not sending command - RF/CT KILL\n"); return -EIO; } if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERR(priv, "No space for Tx\n"); + if (iwl_within_ct_kill_margin(priv)) + iwl_tt_enter_ct_kill(priv); + else { + IWL_ERR(priv, "Restarting adapter due to queue full\n"); + queue_work(priv->workqueue, &priv->restart); + } return -ENOSPC; } -- cgit v1.2.3 From 72f0ebd9e0af0cb642b5f8955380c5043c5c83b4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 2 Oct 2009 13:43:59 -0700 Subject: iwlwifi: change valid EEPROM version for 1000 series In order to support different type of 1000 series NICs we release to customers before the production release, iwlwifi driver need to support all the NICs has EEPROM version greater than 0x15c. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 75fe02282998..643142f913b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -257,7 +257,7 @@ struct iwl_eeprom_enhanced_txpwr { #define EEPROM_5050_EEPROM_VERSION (0x21E) /* 1000 Specific */ -#define EEPROM_1000_EEPROM_VERSION (0x15D) +#define EEPROM_1000_EEPROM_VERSION (0x15C) /* 60x0 Specific */ #define EEPROM_6000_EEPROM_VERSION (0x434) -- cgit v1.2.3 From 39d5e0ce0f2ab9a4bb88e22a9f07ba3943e3646d Mon Sep 17 00:00:00 2001 From: Huaxu Wan Date: Fri, 2 Oct 2009 13:44:00 -0700 Subject: iwlwifi: clear the translate table area Driver should clear the translate table area after receiving "Alive" response from uCode. This patch corrects a mistake when doing this. Signed-off-by: Huaxu Wan Signed-off-by: Guo Chaohong Acked-by: Ben M Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-5000.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 4e492c154f88..0921e454185b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -663,7 +663,8 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) iwl_write_targ_mem(priv, a, 0); for (; a < priv->scd_base_addr + IWL49_SCD_TRANSLATE_TBL_OFFSET; a += 4) iwl_write_targ_mem(priv, a, 0); - for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4) + for (; a < priv->scd_base_addr + + IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4) iwl_write_targ_mem(priv, a, 0); /* Tel 4965 where to find Tx byte count tables */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 660fd51d190b..01d53ebb96ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -748,7 +748,8 @@ int iwl5000_alive_notify(struct iwl_priv *priv) for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET; a += 4) iwl_write_targ_mem(priv, a, 0); - for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4) + for (; a < priv->scd_base_addr + + IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4) iwl_write_targ_mem(priv, a, 0); iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR, -- cgit v1.2.3 From 4d80d7210bb5a36a18978d1305b44375ecb857d9 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 2 Oct 2009 13:44:01 -0700 Subject: iwlwifi: set default aggregation frame count limit to 31 Multiple MPDUs can be aggregated, transmitted, and finally acknowledged together using a single BA frame. Block ACK (BA) contains bitmap size of 64*16 bits so the maximum frame count is 64. The default value of aggregation frame count suggested by uCode is 31 to achieve best performance. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index e6c35e07f41b..a07be29cc5e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2800,7 +2800,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, repeat_rate--; } - lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX; + lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; lq_cmd->agg_params.agg_time_limit = cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); -- cgit v1.2.3 From be1a71a128ed91372d4ad8d54d8fd972a1a356eb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 2 Oct 2009 13:44:02 -0700 Subject: iwlwifi: device tracing In order to have an easier way to debug issues, create trace events (using the ftrace framework) that will allow us to follow exactly what the driver is doing with the device. The text format isn't all that useful, but the binary format can also be obtained easily via debugfs and then analysed on the fly or offline with debugging tools. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 18 +++ drivers/net/wireless/iwlwifi/Makefile | 7 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++ drivers/net/wireless/iwlwifi/iwl-devtrace.c | 13 ++ drivers/net/wireless/iwlwifi/iwl-devtrace.h | 178 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 2 + drivers/net/wireless/iwlwifi/iwl-io.h | 16 ++- drivers/net/wireless/iwlwifi/iwl-tx.c | 14 ++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 8 +- 9 files changed, 256 insertions(+), 8 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-devtrace.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-devtrace.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index eb62c20e8019..48d8f2cf566c 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -49,6 +49,24 @@ config IWLWIFI_DEBUGFS ---help--- Enable creation of debugfs files for the iwlwifi drivers. +config IWLWIFI_DEVICE_TRACING + bool "iwlwifi device access tracing" + depends on IWLWIFI + depends on EVENT_TRACING + help + Say Y here to trace all commands, including TX frames and IO + accesses, sent to the device. If you say yes, iwlwifi will + register with the ftrace framework for event tracing and dump + all this information to the ringbuffer, you may need to + increase the ringbuffer size. See the ftrace documentation + for more information. + + When tracing is not enabled, this option still has some + (though rather small) overhead. + + If unsure, say Y so we can help you better when problems + occur. + config IWLAGN tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)" depends on IWLWIFI diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 1d4e0a226fd4..3f31d866054b 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -5,7 +5,11 @@ iwlcore-objs += iwl-scan.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o +iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o +CFLAGS_iwl-devtrace.o := -I$(src) + +# AGN obj-$(CONFIG_IWLAGN) += iwlagn.o iwlagn-objs := iwl-agn.o iwl-agn-rs.o @@ -14,7 +18,6 @@ iwlagn-$(CONFIG_IWL5000) += iwl-5000.o iwlagn-$(CONFIG_IWL5000) += iwl-6000.o iwlagn-$(CONFIG_IWL5000) += iwl-1000.o +# 3945 obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o - - diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 26c66b4ffd60..4fb50d0eb536 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -791,6 +791,9 @@ void iwl_rx_handle(struct iwl_priv *priv) PCI_DMA_FROMDEVICE); pkt = (struct iwl_rx_packet *)rxb->skb->data; + trace_iwlwifi_dev_rx(priv, pkt, + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); + /* Reclaim a command buffer only if this packet is a response * to a (driver-originated) command. * If the packet (e.g. Rx frame) originated from uCode, @@ -1610,6 +1613,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); + trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line, + blink1, blink2, ilink1, ilink2); + IWL_ERR(priv, "Desc Time " "data1 data2 line\n"); IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n", @@ -1658,12 +1664,14 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, ptr += sizeof(u32); if (mode == 0) { /* data, ev */ + trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); } else { data = iwl_read_targ_mem(priv, ptr); ptr += sizeof(u32); IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", time, data, ev); + trace_iwlwifi_dev_ucode_event(priv, time, data, ev); } } } diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c new file mode 100644 index 000000000000..4ef5acaa556d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -0,0 +1,13 @@ +#include + +/* sparse doesn't like tracepoint macros */ +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "iwl-devtrace.h" + +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event); +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error); +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h new file mode 100644 index 000000000000..8c7159208da1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -0,0 +1,178 @@ +#if !defined(__IWLWIFI_DEVICE_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define __IWLWIFI_DEVICE_TRACE + +#include +#include "iwl-dev.h" + +#if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__) +#undef TRACE_EVENT +#define TRACE_EVENT(name, proto, ...) \ +static inline void trace_ ## name(proto) {} +#endif + +#define PRIV_ENTRY __field(struct iwl_priv *, priv) +#define PRIV_ASSIGN __entry->priv = priv + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM iwlwifi + +TRACE_EVENT(iwlwifi_dev_ioread32, + TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val), + TP_ARGS(priv, offs, val), + TP_STRUCT__entry( + PRIV_ENTRY + __field(u32, offs) + __field(u32, val) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->offs = offs; + __entry->val = val; + ), + TP_printk("[%p] read io[%#x] = %#x", __entry->priv, __entry->offs, __entry->val) +); + +TRACE_EVENT(iwlwifi_dev_iowrite32, + TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val), + TP_ARGS(priv, offs, val), + TP_STRUCT__entry( + PRIV_ENTRY + __field(u32, offs) + __field(u32, val) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->offs = offs; + __entry->val = val; + ), + TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val) +); + +TRACE_EVENT(iwlwifi_dev_hcmd, + TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags), + TP_ARGS(priv, hcmd, len, flags), + TP_STRUCT__entry( + PRIV_ENTRY + __dynamic_array(u8, hcmd, len) + __field(u32, flags) + ), + TP_fast_assign( + PRIV_ASSIGN; + memcpy(__get_dynamic_array(hcmd), hcmd, len); + __entry->flags = flags; + ), + TP_printk("[%p] hcmd %#.2x (%ssync)", + __entry->priv, ((u8 *)__get_dynamic_array(hcmd))[0], + __entry->flags & CMD_ASYNC ? "a" : "") +); + +TRACE_EVENT(iwlwifi_dev_rx, + TP_PROTO(struct iwl_priv *priv, void *rxbuf, size_t len), + TP_ARGS(priv, rxbuf, len), + TP_STRUCT__entry( + PRIV_ENTRY + __dynamic_array(u8, rxbuf, len) + ), + TP_fast_assign( + PRIV_ASSIGN; + memcpy(__get_dynamic_array(rxbuf), rxbuf, len); + ), + TP_printk("[%p] RX cmd %#.2x", + __entry->priv, ((u8 *)__get_dynamic_array(rxbuf))[4]) +); + +TRACE_EVENT(iwlwifi_dev_tx, + TP_PROTO(struct iwl_priv *priv, void *tfd, size_t tfdlen, + void *buf0, size_t buf0_len, + void *buf1, size_t buf1_len), + TP_ARGS(priv, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len), + TP_STRUCT__entry( + PRIV_ENTRY + + __field(size_t, framelen) + __dynamic_array(u8, tfd, tfdlen) + + /* + * Do not insert between or below these items, + * we want to keep the frame together (except + * for the possible padding). + */ + __dynamic_array(u8, buf0, buf0_len) + __dynamic_array(u8, buf1, buf1_len) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->framelen = buf0_len + buf1_len; + memcpy(__get_dynamic_array(tfd), tfd, tfdlen); + memcpy(__get_dynamic_array(buf0), buf0, buf0_len); + memcpy(__get_dynamic_array(buf1), buf1, buf0_len); + ), + TP_printk("[%p] TX %.2x (%zu bytes)", + __entry->priv, + ((u8 *)__get_dynamic_array(buf0))[0], + __entry->framelen) +); + +TRACE_EVENT(iwlwifi_dev_ucode_error, + TP_PROTO(struct iwl_priv *priv, u32 desc, u32 time, + u32 data1, u32 data2, u32 line, u32 blink1, + u32 blink2, u32 ilink1, u32 ilink2), + TP_ARGS(priv, desc, time, data1, data2, line, + blink1, blink2, ilink1, ilink2), + TP_STRUCT__entry( + PRIV_ENTRY + __field(u32, desc) + __field(u32, time) + __field(u32, data1) + __field(u32, data2) + __field(u32, line) + __field(u32, blink1) + __field(u32, blink2) + __field(u32, ilink1) + __field(u32, ilink2) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->desc = desc; + __entry->time = time; + __entry->data1 = data1; + __entry->data2 = data2; + __entry->line = line; + __entry->blink1 = blink1; + __entry->blink2 = blink2; + __entry->ilink1 = ilink1; + __entry->ilink2 = ilink2; + ), + TP_printk("[%p] #%02d %010u data 0x%08X 0x%08X line %u, " + "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X", + __entry->priv, __entry->desc, __entry->time, __entry->data1, + __entry->data2, __entry->line, __entry->blink1, + __entry->blink2, __entry->ilink1, __entry->ilink2) +); + +TRACE_EVENT(iwlwifi_dev_ucode_event, + TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev), + TP_ARGS(priv, time, data, ev), + TP_STRUCT__entry( + PRIV_ENTRY + + __field(u32, time) + __field(u32, data) + __field(u32, ev) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->time = time; + __entry->data = data; + __entry->ev = ev; + ), + TP_printk("[%p] EVT_LOGT:%010u:0x%08x:%04u", + __entry->priv, __entry->time, __entry->data, __entry->ev) +); +#endif /* __IWLWIFI_DEVICE_TRACE */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE iwl-devtrace +#include diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 643142f913b6..fee6f0c7503e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -63,6 +63,8 @@ #ifndef __iwl_eeprom_h__ #define __iwl_eeprom_h__ +#include + struct iwl_priv; /* diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index d30cb0275d19..0a078b082833 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -32,6 +32,7 @@ #include #include "iwl-debug.h" +#include "iwl-devtrace.h" /* * IO, register, and NIC memory access functions @@ -61,7 +62,12 @@ * */ -#define _iwl_write32(priv, ofs, val) iowrite32((val), (priv)->hw_base + (ofs)) +static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) +{ + trace_iwlwifi_dev_iowrite32(priv, ofs, val); + iowrite32(val, priv->hw_base + ofs); +} + #ifdef CONFIG_IWLWIFI_DEBUG static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, u32 ofs, u32 val) @@ -75,7 +81,13 @@ static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv, #define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val) #endif -#define _iwl_read32(priv, ofs) ioread32((priv)->hw_base + (ofs)) +static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs) +{ + u32 val = ioread32(priv->hw_base + ofs); + trace_iwlwifi_dev_ioread32(priv, ofs, val); + return val; +} + #ifdef CONFIG_IWLWIFI_DEBUG static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) { diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 2ba9725beff9..c832ba085dba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -709,7 +709,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) dma_addr_t phys_addr; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; - u16 len, len_org; + u16 len, len_org, firstlen, secondlen; u16 seq_number = 0; __le16 fc; u8 hdr_len; @@ -842,7 +842,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) sizeof(struct iwl_cmd_header) + hdr_len; len_org = len; - len = (len + 3) & ~3; + firstlen = len = (len + 3) & ~3; if (len_org != len) len_org = 1; @@ -876,7 +876,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Set up TFD's 2nd entry to point directly to remainder of skb, * if any (802.11 null frames have no payload). */ - len = skb->len - hdr_len; + secondlen = len = skb->len - hdr_len; if (len) { phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, len, PCI_DMA_TODEVICE); @@ -910,6 +910,12 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys, len, PCI_DMA_BIDIRECTIONAL); + trace_iwlwifi_dev_tx(priv, + &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr], + sizeof(struct iwl_tfd), + &out_cmd->hdr, firstlen, + skb->data + hdr_len, secondlen); + /* Tell device the write index *just past* this latest filled TFD */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); ret = iwl_txq_update_write_ptr(priv, txq); @@ -1044,6 +1050,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) pci_unmap_addr_set(out_meta, mapping, phys_addr); pci_unmap_len_set(out_meta, len, fix_size); + trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags); + priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, phys_addr, fix_size, 1, U32_PAD(cmd->len)); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 3575e7fbadc7..d0d1b7f4c396 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1404,6 +1404,9 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) PCI_DMA_FROMDEVICE); pkt = (struct iwl_rx_packet *)rxb->skb->data; + trace_iwlwifi_dev_rx(priv, pkt, + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); + /* Reclaim a command buffer only if this packet is a response * to a (driver-originated) command. * If the packet (e.g. Rx frame) originated from uCode, @@ -1549,8 +1552,9 @@ void iwl3945_dump_nic_error_log(struct iwl_priv *priv) "%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n", desc_lookup(desc), desc, time, blink1, blink2, ilink1, ilink2, data1); + trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, 0, + 0, blink1, blink2, ilink1, ilink2); } - } #define EVENT_START_OFFSET (6 * sizeof(u32)) @@ -1590,10 +1594,12 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, if (mode == 0) { /* data, ev */ IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); + trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); } else { data = iwl_read_targ_mem(priv, ptr); ptr += sizeof(u32); IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev); + trace_iwlwifi_dev_ucode_event(priv, time, data, ev); } } } -- cgit v1.2.3 From e932a609e9759cc75db0c234f465a5fd6e20d362 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 2 Oct 2009 13:44:03 -0700 Subject: iwlwifi: LED cleanup The iwlwifi drivers have LED blinking requirements that mac80211 cannot fulfill due to the use of just a single LED instead of different ones for TX, RX, radio etc. Instead, the single LED blinks according to transfers and is solid on the rest of the time. As such, having LED class devices registered that mac80211 triggers are connected to is pointless as we don't use the triggers anyway. Remove all the useless code and add hooks into the driver itself. At the same time, make the LED code abstracted so the core code that determines blink rate etc. can be shared between 3945 and agn in iwlcore. At the same time, the fact that we removed the use of the mac80211 LED triggers means we can also remove the IWLWIFI_LEDS Kconfig symbol since the LED support is now self-contained. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 9 - drivers/net/wireless/iwlwifi/Makefile | 5 +- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 + drivers/net/wireless/iwlwifi/iwl-3945-led.c | 371 ++-------------------------- drivers/net/wireless/iwlwifi/iwl-3945-led.h | 22 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 10 +- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 + drivers/net/wireless/iwlwifi/iwl-5000.c | 5 +- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 + drivers/net/wireless/iwlwifi/iwl-agn-led.c | 85 +++++++ drivers/net/wireless/iwlwifi/iwl-agn-led.h | 32 +++ drivers/net/wireless/iwlwifi/iwl-agn.c | 6 +- drivers/net/wireless/iwlwifi/iwl-core.c | 7 +- drivers/net/wireless/iwlwifi/iwl-core.h | 7 + drivers/net/wireless/iwlwifi/iwl-debug.h | 2 - drivers/net/wireless/iwlwifi/iwl-debugfs.c | 8 - drivers/net/wireless/iwlwifi/iwl-dev.h | 7 +- drivers/net/wireless/iwlwifi/iwl-led.c | 285 ++------------------- drivers/net/wireless/iwlwifi/iwl-led.h | 38 +-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 8 +- 21 files changed, 194 insertions(+), 721 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-agn-led.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-agn-led.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 48d8f2cf566c..c82c97be7bfa 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -2,15 +2,6 @@ config IWLWIFI tristate "Intel Wireless Wifi" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER - select MAC80211_LEDS if IWLWIFI_LEDS - select LEDS_CLASS if IWLWIFI_LEDS - -config IWLWIFI_LEDS - bool "Enable LED support in iwlagn and iwl3945 drivers" - depends on IWLWIFI - default y - ---help--- - Select this if you want LED support. config IWLWIFI_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwlagn driver" diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 3f31d866054b..7f82044af242 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,9 +1,8 @@ obj-$(CONFIG_IWLWIFI) += iwlcore.o iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o -iwlcore-objs += iwl-scan.o +iwlcore-objs += iwl-scan.o iwl-led.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o -iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o @@ -11,7 +10,7 @@ CFLAGS_iwl-devtrace.o := -I$(src) # AGN obj-$(CONFIG_IWLAGN) += iwlagn.o -iwlagn-objs := iwl-agn.o iwl-agn-rs.o +iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwlagn-$(CONFIG_IWL4965) += iwl-4965.o iwlagn-$(CONFIG_IWL5000) += iwl-5000.o diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index af91dbab255a..86d93b52c6fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -44,6 +44,7 @@ #include "iwl-sta.h" #include "iwl-helpers.h" #include "iwl-5000-hw.h" +#include "iwl-agn-led.h" /* Highest firmware API version supported */ #define IWL1000_UCODE_API_MAX 3 @@ -145,6 +146,7 @@ static struct iwl_ops iwl1000_ops = { .lib = &iwl1000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, + .led = &iwlagn_led_ops, }; struct iwl_cfg iwl1000_bgn_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index 8c29ded7d02c..a871d09d598f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -24,8 +24,6 @@ * *****************************************************************************/ -#ifdef CONFIG_IWLWIFI_LEDS - #include #include #include @@ -43,388 +41,51 @@ #include "iwl-3945.h" #include "iwl-core.h" #include "iwl-dev.h" +#include "iwl-3945-led.h" -#ifdef CONFIG_IWLWIFI_DEBUG -static const char *led_type_str[] = { - __stringify(IWL_LED_TRG_TX), - __stringify(IWL_LED_TRG_RX), - __stringify(IWL_LED_TRG_ASSOC), - __stringify(IWL_LED_TRG_RADIO), - NULL -}; -#endif /* CONFIG_IWLWIFI_DEBUG */ - -static const struct { - u16 brightness; - u8 on_time; - u8 off_time; -} blink_tbl[] = -{ - {300, 25, 25}, - {200, 40, 40}, - {100, 55, 55}, - {70, 65, 65}, - {50, 75, 75}, - {20, 85, 85}, - {15, 95, 95 }, - {10, 110, 110}, - {5, 130, 130}, - {0, 167, 167}, - /* SOLID_ON */ - {-1, IWL_LED_SOLID, 0} -}; - -#define IWL_1MB_RATE (128 * 1024) -#define IWL_LED_THRESHOLD (16) -#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/ -#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) - -static void iwl3945_led_cmd_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct sk_buff *skb) -{ -} - -static inline int iwl3945_brightness_to_idx(enum led_brightness brightness) -{ - return fls(0x000000FF & (u32)brightness); -} /* Send led command */ -static int iwl_send_led_cmd(struct iwl_priv *priv, - struct iwl_led_cmd *led_cmd) +static int iwl3945_send_led_cmd(struct iwl_priv *priv, + struct iwl_led_cmd *led_cmd) { struct iwl_host_cmd cmd = { .id = REPLY_LEDS_CMD, .len = sizeof(struct iwl_led_cmd), .data = led_cmd, .flags = CMD_ASYNC, - .callback = iwl3945_led_cmd_callback, + .callback = NULL, }; return iwl_send_cmd(priv, &cmd); } - - -/* Set led on command */ -static int iwl3945_led_pattern(struct iwl_priv *priv, int led_id, - unsigned int idx) -{ - struct iwl_led_cmd led_cmd = { - .id = led_id, - .interval = IWL_DEF_LED_INTRVL - }; - - BUG_ON(idx > IWL_MAX_BLINK_TBL); - - led_cmd.on = blink_tbl[idx].on_time; - led_cmd.off = blink_tbl[idx].off_time; - - return iwl_send_led_cmd(priv, &led_cmd); -} - - /* Set led on command */ -static int iwl3945_led_on(struct iwl_priv *priv, int led_id) +static int iwl3945_led_on(struct iwl_priv *priv) { struct iwl_led_cmd led_cmd = { - .id = led_id, + .id = IWL_LED_LINK, .on = IWL_LED_SOLID, .off = 0, .interval = IWL_DEF_LED_INTRVL }; - return iwl_send_led_cmd(priv, &led_cmd); + return iwl3945_send_led_cmd(priv, &led_cmd); } /* Set led off command */ -static int iwl3945_led_off(struct iwl_priv *priv, int led_id) +static int iwl3945_led_off(struct iwl_priv *priv) { struct iwl_led_cmd led_cmd = { - .id = led_id, + .id = IWL_LED_LINK, .on = 0, .off = 0, .interval = IWL_DEF_LED_INTRVL }; - IWL_DEBUG_LED(priv, "led off %d\n", led_id); - return iwl_send_led_cmd(priv, &led_cmd); + IWL_DEBUG_LED(priv, "led off\n"); + return iwl3945_send_led_cmd(priv, &led_cmd); } -/* - * Set led on in case of association - * */ -static int iwl3945_led_associate(struct iwl_priv *priv, int led_id) -{ - IWL_DEBUG_LED(priv, "Associated\n"); - - priv->allow_blinking = 1; - return iwl3945_led_on(priv, led_id); -} -/* Set Led off in case of disassociation */ -static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id) -{ - IWL_DEBUG_LED(priv, "Disassociated\n"); - - priv->allow_blinking = 0; - - return 0; -} - -/* - * brightness call back function for Tx/Rx LED - */ -static int iwl3945_led_associated(struct iwl_priv *priv, int led_id) -{ - if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - !test_bit(STATUS_READY, &priv->status)) - return 0; - - - /* start counting Tx/Rx bytes */ - if (!priv->last_blink_time && priv->allow_blinking) - priv->last_blink_time = jiffies; - return 0; -} - -/* - * brightness call back for association and radio - */ -static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct iwl_led *led = container_of(led_cdev, - struct iwl_led, led_dev); - struct iwl_priv *priv = led->priv; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n", - led_type_str[led->type], brightness); - - switch (brightness) { - case LED_FULL: - if (led->led_on) - led->led_on(priv, IWL_LED_LINK); - break; - case LED_OFF: - if (led->led_off) - led->led_off(priv, IWL_LED_LINK); - break; - default: - if (led->led_pattern) { - int idx = iwl3945_brightness_to_idx(brightness); - led->led_pattern(priv, IWL_LED_LINK, idx); - } - break; - } -} - -/* - * Register led class with the system - */ -static int iwl3945_led_register_led(struct iwl_priv *priv, - struct iwl_led *led, - enum led_type type, u8 set_led, - char *trigger) -{ - struct device *device = wiphy_dev(priv->hw->wiphy); - int ret; - - led->led_dev.name = led->name; - led->led_dev.brightness_set = iwl3945_led_brightness_set; - led->led_dev.default_trigger = trigger; - - led->priv = priv; - led->type = type; - - ret = led_classdev_register(device, &led->led_dev); - if (ret) { - IWL_ERR(priv, "Error: failed to register led handler.\n"); - return ret; - } - - led->registered = 1; - - if (set_led && led->led_on) - led->led_on(priv, IWL_LED_LINK); - return 0; -} - - -/* - * calculate blink rate according to last 2 sec Tx/Rx activities - */ -static inline u8 get_blink_rate(struct iwl_priv *priv) -{ - int index; - s64 tpt = priv->rxtxpackets; - - if (tpt < 0) - tpt = -tpt; - - IWL_DEBUG_LED(priv, "tpt %lld \n", (long long)tpt); - - if (!priv->allow_blinking) - index = IWL_MAX_BLINK_TBL; - else - for (index = 0; index < IWL_MAX_BLINK_TBL; index++) - if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE)) - break; - - IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", index); - return index; -} - -/* - * this function called from handler. Since setting Led command can - * happen very frequent we postpone led command to be called from - * REPLY handler so we know ucode is up - */ -void iwl3945_led_background(struct iwl_priv *priv) -{ - u8 blink_idx; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { - priv->last_blink_time = 0; - return; - } - if (iwl_is_rfkill(priv)) { - priv->last_blink_time = 0; - return; - } - - if (!priv->allow_blinking) { - priv->last_blink_time = 0; - if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { - priv->last_blink_rate = IWL_SOLID_BLINK_IDX; - iwl3945_led_pattern(priv, IWL_LED_LINK, - IWL_SOLID_BLINK_IDX); - } - return; - } - if (!priv->last_blink_time || - !time_after(jiffies, priv->last_blink_time + - msecs_to_jiffies(1000))) - return; - - blink_idx = get_blink_rate(priv); - - /* call only if blink rate change */ - if (blink_idx != priv->last_blink_rate) - iwl3945_led_pattern(priv, IWL_LED_LINK, blink_idx); - - priv->last_blink_time = jiffies; - priv->last_blink_rate = blink_idx; - priv->rxtxpackets = 0; -} - - -/* Register all led handler */ -int iwl3945_led_register(struct iwl_priv *priv) -{ - char *trigger; - int ret; - - priv->last_blink_rate = 0; - priv->rxtxpackets = 0; - priv->led_tpt = 0; - priv->last_blink_time = 0; - priv->allow_blinking = 0; - - trigger = ieee80211_get_radio_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_RADIO].name, - sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio", - wiphy_name(priv->hw->wiphy)); - - priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on; - priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off; - priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; - - ret = iwl3945_led_register_led(priv, - &priv->led[IWL_LED_TRG_RADIO], - IWL_LED_TRG_RADIO, 1, trigger); - - if (ret) - goto exit_fail; - - trigger = ieee80211_get_assoc_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_ASSOC].name, - sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc", - wiphy_name(priv->hw->wiphy)); - - ret = iwl3945_led_register_led(priv, - &priv->led[IWL_LED_TRG_ASSOC], - IWL_LED_TRG_ASSOC, 0, trigger); - - /* for assoc always turn led on */ - priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_associate; - priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_disassociate; - priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; - - if (ret) - goto exit_fail; - - trigger = ieee80211_get_rx_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_RX].name, - sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX", - wiphy_name(priv->hw->wiphy)); - - ret = iwl3945_led_register_led(priv, - &priv->led[IWL_LED_TRG_RX], - IWL_LED_TRG_RX, 0, trigger); - - priv->led[IWL_LED_TRG_RX].led_on = iwl3945_led_associated; - priv->led[IWL_LED_TRG_RX].led_off = iwl3945_led_associated; - priv->led[IWL_LED_TRG_RX].led_pattern = iwl3945_led_pattern; - - if (ret) - goto exit_fail; - - trigger = ieee80211_get_tx_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_TX].name, - sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX", - wiphy_name(priv->hw->wiphy)); - - ret = iwl3945_led_register_led(priv, - &priv->led[IWL_LED_TRG_TX], - IWL_LED_TRG_TX, 0, trigger); - - priv->led[IWL_LED_TRG_TX].led_on = iwl3945_led_associated; - priv->led[IWL_LED_TRG_TX].led_off = iwl3945_led_associated; - priv->led[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern; - - if (ret) - goto exit_fail; - - return 0; - -exit_fail: - iwl3945_led_unregister(priv); - return ret; -} - - -/* unregister led class */ -static void iwl3945_led_unregister_led(struct iwl_led *led, u8 set_led) -{ - if (!led->registered) - return; - - led_classdev_unregister(&led->led_dev); - - if (set_led) - led->led_dev.brightness_set(&led->led_dev, LED_OFF); - led->registered = 0; -} - -/* Unregister all led handlers */ -void iwl3945_led_unregister(struct iwl_priv *priv) -{ - iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0); - iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RX], 0); - iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_TX], 0); - iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1); -} - -#endif +const struct iwl_led_ops iwl3945_led_ops = { + .cmd = iwl3945_send_led_cmd, + .on = iwl3945_led_on, + .off = iwl3945_led_off, +}; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h index 3b65642258ca..5a1033ca7aaa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h @@ -24,23 +24,9 @@ * *****************************************************************************/ -#ifndef IWL3945_LEDS_H -#define IWL3945_LEDS_H +#ifndef __iwl_3945_led_h__ +#define __iwl_3945_led_h__ -struct iwl_priv; +extern const struct iwl_led_ops iwl3945_led_ops; -#ifdef CONFIG_IWLWIFI_LEDS - -#include "iwl-led.h" - -extern int iwl3945_led_register(struct iwl_priv *priv); -extern void iwl3945_led_unregister(struct iwl_priv *priv); -extern void iwl3945_led_background(struct iwl_priv *priv); - -#else -static inline int iwl3945_led_register(struct iwl_priv *priv) { return 0; } -static inline void iwl3945_led_unregister(struct iwl_priv *priv) {} -static inline void iwl3945_led_background(struct iwl_priv *priv) {} - -#endif /* IWLWIFI_LEDS*/ -#endif /* IWL3945_LEDS_H */ +#endif /* __iwl_3945_led_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 33e40c21eb72..f0ce5c45ca05 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -46,7 +46,8 @@ #include "iwl-eeprom.h" #include "iwl-helpers.h" #include "iwl-core.h" -#include "iwl-agn-rs.h" +#include "iwl-led.h" +#include "iwl-3945-led.h" #define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ @@ -359,7 +360,7 @@ void iwl3945_hw_rx_statistics(struct iwl_priv *priv, memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39)); - iwl3945_led_background(priv); + iwl_leds_background(priv); priv->last_statistics_time = jiffies; } @@ -572,10 +573,6 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, (struct ieee80211_hdr *)rxb->skb->data, le32_to_cpu(rx_end->status), stats); -#ifdef CONFIG_IWLWIFI_LEDS - if (ieee80211_is_data(hdr->frame_control)) - priv->rxtxpackets += len; -#endif iwl_update_stats(priv, false, hdr->frame_control, len); memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); @@ -2880,6 +2877,7 @@ static struct iwl_ops iwl3945_ops = { .lib = &iwl3945_lib, .hcmd = &iwl3945_hcmd, .utils = &iwl3945_hcmd_utils, + .led = &iwl3945_led_ops, }; static struct iwl_cfg iwl3945_bg_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 21679bf3a1aa..f3907c1079f5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -46,7 +46,7 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; #include "iwl-debug.h" #include "iwl-power.h" #include "iwl-dev.h" -#include "iwl-3945-led.h" +#include "iwl-led.h" /* Highest firmware API version supported */ #define IWL3945_UCODE_API_MAX 2 diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 0921e454185b..8717946de011 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -44,6 +44,7 @@ #include "iwl-helpers.h" #include "iwl-calib.h" #include "iwl-sta.h" +#include "iwl-agn-led.h" static int iwl4965_send_tx_power(struct iwl_priv *priv); static int iwl4965_hw_get_temperature(struct iwl_priv *priv); @@ -2341,6 +2342,7 @@ static struct iwl_ops iwl4965_ops = { .lib = &iwl4965_lib, .hcmd = &iwl4965_hcmd, .utils = &iwl4965_hcmd_utils, + .led = &iwlagn_led_ops, }; struct iwl_cfg iwl4965_agn_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 01d53ebb96ad..624853503db1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -42,6 +42,7 @@ #include "iwl-io.h" #include "iwl-sta.h" #include "iwl-helpers.h" +#include "iwl-agn-led.h" #include "iwl-5000-hw.h" #include "iwl-6000-hw.h" @@ -1641,11 +1642,12 @@ static struct iwl_lib_ops iwl5150_lib = { }, }; -struct iwl_ops iwl5000_ops = { +static struct iwl_ops iwl5000_ops = { .ucode = &iwl5000_ucode, .lib = &iwl5000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, + .led = &iwlagn_led_ops, }; static struct iwl_ops iwl5150_ops = { @@ -1653,6 +1655,7 @@ static struct iwl_ops iwl5150_ops = { .lib = &iwl5150_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, + .led = &iwlagn_led_ops, }; struct iwl_mod_params iwl50_mod_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 6f4ee27e07c9..a002214f4d49 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -45,6 +45,7 @@ #include "iwl-helpers.h" #include "iwl-5000-hw.h" #include "iwl-6000-hw.h" +#include "iwl-agn-led.h" /* Highest firmware API version supported */ #define IWL6000_UCODE_API_MAX 4 @@ -227,6 +228,7 @@ static struct iwl_ops iwl6000_ops = { .lib = &iwl6000_lib, .hcmd = &iwl5000_hcmd, .utils = &iwl5000_hcmd_utils, + .led = &iwlagn_led_ops, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c new file mode 100644 index 000000000000..3bccba20f6da --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.c @@ -0,0 +1,85 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iwl-commands.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-agn-led.h" + +/* Send led command */ +static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl_led_cmd), + .data = led_cmd, + .flags = CMD_ASYNC, + .callback = NULL, + }; + u32 reg; + + reg = iwl_read32(priv, CSR_LED_REG); + if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) + iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); + + return iwl_send_cmd(priv, &cmd); +} + +/* Set led register off */ +static int iwl_led_on_reg(struct iwl_priv *priv) +{ + IWL_DEBUG_LED(priv, "led on\n"); + iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); + return 0; +} + +/* Set led register off */ +static int iwl_led_off_reg(struct iwl_priv *priv) +{ + IWL_DEBUG_LED(priv, "LED Reg off\n"); + iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); + return 0; +} + +const struct iwl_led_ops iwlagn_led_ops = { + .cmd = iwl_send_led_cmd, + .on = iwl_led_on_reg, + .off = iwl_led_off_reg, +}; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/iwlwifi/iwl-agn-led.h new file mode 100644 index 000000000000..ab55f92a161d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-led.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_agn_led_h__ +#define __iwl_agn_led_h__ + +extern const struct iwl_led_ops iwlagn_led_ops; + +#endif /* __iwl_agn_led_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4fb50d0eb536..046b571fd9ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1801,7 +1801,7 @@ static void iwl_alive_start(struct iwl_priv *priv) /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); - iwl_leds_register(priv); + iwl_leds_init(priv); IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); set_bit(STATUS_READY, &priv->status); @@ -1839,8 +1839,6 @@ static void __iwl_down(struct iwl_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); - iwl_leds_unregister(priv); - iwl_clear_stations_table(priv); /* Unblock any waiting calls */ @@ -2339,6 +2337,8 @@ static int iwl_mac_start(struct ieee80211_hw *hw) } } + iwl_led_start(priv); + out: priv->is_open = 1; IWL_DEBUG_MAC80211(priv, "leave\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1cf2e04fe3f9..34547cf3a66e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2384,6 +2384,8 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, priv->timestamp = bss_conf->timestamp; priv->assoc_capability = bss_conf->assoc_capability; + iwl_led_associate(priv); + /* * We have just associated, don't start scan too early * leave time for EAPOL exchange to complete. @@ -2394,9 +2396,10 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; if (!iwl_is_rfkill(priv)) priv->cfg->ops->lib->post_associate(priv); - } else + } else { priv->assoc_id = 0; - + iwl_led_disassociate(priv); + } } if (changes && iwl_is_associated(priv) && priv->assoc_id) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3bd0e59bb5a4..eb586a546181 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -187,11 +187,18 @@ struct iwl_lib_ops { struct iwl_temp_ops temp_ops; }; +struct iwl_led_ops { + int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd); + int (*on)(struct iwl_priv *priv); + int (*off)(struct iwl_priv *priv); +}; + struct iwl_ops { const struct iwl_ucode_ops *ucode; const struct iwl_lib_ops *lib; const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_utils_ops *utils; + const struct iwl_led_ops *led; }; struct iwl_mod_params { diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index cbc62904655d..b9ca475cc61c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -84,9 +84,7 @@ struct iwl_debugfs { struct dentry *file_interrupt; struct dentry *file_qos; struct dentry *file_thermal_throttling; -#ifdef CONFIG_IWLWIFI_LEDS struct dentry *file_led; -#endif struct dentry *file_disable_ht40; struct dentry *file_sleep_level_override; struct dentry *file_current_sleep_command; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index fa6371d171c5..1794b9c4e6ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -677,7 +677,6 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, return ret; } -#ifdef CONFIG_IWLWIFI_LEDS static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -702,7 +701,6 @@ static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); return ret; } -#endif static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, char __user *user_buf, @@ -866,9 +864,7 @@ DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(qos); -#ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_READ_FILE_OPS(led); -#endif DEBUGFS_READ_FILE_OPS(thermal_throttling); DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); @@ -1666,9 +1662,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(status, data); DEBUGFS_ADD_FILE(interrupt, data); DEBUGFS_ADD_FILE(qos, data); -#ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_ADD_FILE(led, data); -#endif DEBUGFS_ADD_FILE(sleep_level_override, data); DEBUGFS_ADD_FILE(current_sleep_command, data); DEBUGFS_ADD_FILE(thermal_throttling, data); @@ -1721,9 +1715,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos); -#ifdef CONFIG_IWLWIFI_LEDS DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led); -#endif DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_thermal_throttling); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_disable_ht40); DEBUGFS_REMOVE(priv->dbgfs->dir_data); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index ad99ce7824c6..eabc55695aff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -43,7 +43,6 @@ #include "iwl-debug.h" #include "iwl-4965-hw.h" #include "iwl-3945-hw.h" -#include "iwl-3945-led.h" #include "iwl-led.h" #include "iwl-power.h" #include "iwl-agn-rs.h" @@ -73,7 +72,6 @@ struct iwl_tx_queue; /* shared structures from iwl-5000.c */ extern struct iwl_mod_params iwl50_mod_params; -extern struct iwl_ops iwl5000_ops; extern struct iwl_ucode_ops iwl5000_ucode; extern struct iwl_lib_ops iwl5000_lib; extern struct iwl_hcmd_ops iwl5000_hcmd; @@ -1066,14 +1064,11 @@ struct iwl_priv { struct iwl_init_alive_resp card_alive_init; struct iwl_alive_resp card_alive; -#ifdef CONFIG_IWLWIFI_LEDS unsigned long last_blink_time; u8 last_blink_rate; u8 allow_blinking; u64 led_tpt; - struct iwl_led led[IWL_LED_TRG_MAX]; - unsigned int rxtxpackets; -#endif + u16 active_rate; u16 active_rate_basic; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 685ba9d6f082..478c90511ebf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -48,16 +48,6 @@ module_param(led_mode, int, S_IRUGO); MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), " "(default 0)\n"); -#ifdef CONFIG_IWLWIFI_DEBUG -static const char *led_type_str[] = { - __stringify(IWL_LED_TRG_TX), - __stringify(IWL_LED_TRG_RX), - __stringify(IWL_LED_TRG_ASSOC), - __stringify(IWL_LED_TRG_RADIO), - NULL -}; -#endif /* CONFIG_IWLWIFI_DEBUG */ - static const struct { u16 tpt; /* Mb/s */ @@ -75,7 +65,7 @@ static const struct { {5, 110, 110}, {1, 130, 130}, {0, 167, 167}, -/* SOLID_ON */ + /* SOLID_ON */ {-1, IWL_LED_SOLID, 0} }; @@ -107,37 +97,11 @@ static inline u8 iwl_blink_compensation(struct iwl_priv *priv, return (u8)((time * compensation) >> 6); } -/* [0-256] -> [0..8] FIXME: we need [0..10] */ -static inline int iwl_brightness_to_idx(enum led_brightness brightness) -{ - return fls(0x000000FF & (u32)brightness); -} - -/* Send led command */ -static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) -{ - struct iwl_host_cmd cmd = { - .id = REPLY_LEDS_CMD, - .len = sizeof(struct iwl_led_cmd), - .data = led_cmd, - .flags = CMD_ASYNC, - .callback = NULL, - }; - u32 reg; - - reg = iwl_read32(priv, CSR_LED_REG); - if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) - iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); - - return iwl_send_cmd(priv, &cmd); -} - /* Set led pattern command */ -static int iwl_led_pattern(struct iwl_priv *priv, int led_id, - unsigned int idx) +static int iwl_led_pattern(struct iwl_priv *priv, unsigned int idx) { struct iwl_led_cmd led_cmd = { - .id = led_id, + .id = IWL_LED_LINK, .interval = IWL_DEF_LED_INTRVL }; @@ -152,153 +116,32 @@ static int iwl_led_pattern(struct iwl_priv *priv, int led_id, iwl_blink_compensation(priv, blink_tbl[idx].off_time, priv->cfg->led_compensation); - return iwl_send_led_cmd(priv, &led_cmd); -} - -/* Set led register off */ -static int iwl_led_on_reg(struct iwl_priv *priv, int led_id) -{ - IWL_DEBUG_LED(priv, "led on %d\n", led_id); - iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); - return 0; -} - -#if 0 -/* Set led on command */ -static int iwl_led_on(struct iwl_priv *priv, int led_id) -{ - struct iwl_led_cmd led_cmd = { - .id = led_id, - .on = IWL_LED_SOLID, - .off = 0, - .interval = IWL_DEF_LED_INTRVL - }; - return iwl_send_led_cmd(priv, &led_cmd); -} - -/* Set led off command */ -int iwl_led_off(struct iwl_priv *priv, int led_id) -{ - struct iwl_led_cmd led_cmd = { - .id = led_id, - .on = 0, - .off = 0, - .interval = IWL_DEF_LED_INTRVL - }; - IWL_DEBUG_LED(priv, "led off %d\n", led_id); - return iwl_send_led_cmd(priv, &led_cmd); + return priv->cfg->ops->led->cmd(priv, &led_cmd); } -#endif - -/* Set led register off */ -static int iwl_led_off_reg(struct iwl_priv *priv, int led_id) +int iwl_led_start(struct iwl_priv *priv) { - IWL_DEBUG_LED(priv, "LED Reg off\n"); - iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); - return 0; + return priv->cfg->ops->led->on(priv); } +EXPORT_SYMBOL(iwl_led_start); -/* - * Set led register in case of disassociation according to rfkill state - */ -static int iwl_led_associate(struct iwl_priv *priv, int led_id) +int iwl_led_associate(struct iwl_priv *priv) { IWL_DEBUG_LED(priv, "Associated\n"); if (led_mode == IWL_LED_BLINK) priv->allow_blinking = 1; - return iwl_led_on_reg(priv, led_id); -} -static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) -{ - priv->allow_blinking = 0; - - return 0; -} - -/* - * brightness call back function for Tx/Rx LED - */ -static int iwl_led_associated(struct iwl_priv *priv, int led_id) -{ - if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - !test_bit(STATUS_READY, &priv->status)) - return 0; - + priv->last_blink_time = jiffies; - /* start counting Tx/Rx bytes */ - if (!priv->last_blink_time && priv->allow_blinking) - priv->last_blink_time = jiffies; return 0; } -/* - * brightness call back for association and radio - */ -static void iwl_led_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brightness) +int iwl_led_disassociate(struct iwl_priv *priv) { - struct iwl_led *led = container_of(led_cdev, struct iwl_led, led_dev); - struct iwl_priv *priv = led->priv; - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - - IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n", - led_type_str[led->type], brightness); - switch (brightness) { - case LED_FULL: - if (led->led_on) - led->led_on(priv, IWL_LED_LINK); - break; - case LED_OFF: - if (led->led_off) - led->led_off(priv, IWL_LED_LINK); - break; - default: - if (led->led_pattern) { - int idx = iwl_brightness_to_idx(brightness); - led->led_pattern(priv, IWL_LED_LINK, idx); - } - break; - } -} - - - -/* - * Register led class with the system - */ -static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led, - enum led_type type, u8 set_led, - char *trigger) -{ - struct device *device = wiphy_dev(priv->hw->wiphy); - int ret; - - led->led_dev.name = led->name; - led->led_dev.brightness_set = iwl_led_brightness_set; - led->led_dev.default_trigger = trigger; - - led->priv = priv; - led->type = type; - - ret = led_classdev_register(device, &led->led_dev); - if (ret) { - IWL_ERR(priv, "Error: failed to register led handler.\n"); - return ret; - } - - led->registered = 1; - - if (set_led && led->led_on) - led->led_on(priv, IWL_LED_LINK); + priv->allow_blinking = 0; return 0; } - /* * calculate blink rate according to last second Tx/Rx activities */ @@ -324,7 +167,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) i = IWL_MAX_BLINK_TBL; else for (i = 0; i < IWL_MAX_BLINK_TBL; i++) - if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) + if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) break; IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", i); @@ -353,8 +196,7 @@ void iwl_leds_background(struct iwl_priv *priv) priv->last_blink_time = 0; if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { priv->last_blink_rate = IWL_SOLID_BLINK_IDX; - iwl_led_pattern(priv, IWL_LED_LINK, - IWL_SOLID_BLINK_IDX); + iwl_led_pattern(priv, IWL_SOLID_BLINK_IDX); } return; } @@ -367,111 +209,18 @@ void iwl_leds_background(struct iwl_priv *priv) /* call only if blink rate change */ if (blink_idx != priv->last_blink_rate) - iwl_led_pattern(priv, IWL_LED_LINK, blink_idx); + iwl_led_pattern(priv, blink_idx); priv->last_blink_time = jiffies; priv->last_blink_rate = blink_idx; } +EXPORT_SYMBOL(iwl_leds_background); -/* Register all led handler */ -int iwl_leds_register(struct iwl_priv *priv) +void iwl_leds_init(struct iwl_priv *priv) { - char *trigger; - int ret; - priv->last_blink_rate = 0; priv->led_tpt = 0; priv->last_blink_time = 0; priv->allow_blinking = 0; - - trigger = ieee80211_get_radio_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_RADIO].name, - sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio", - wiphy_name(priv->hw->wiphy)); - - priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg; - priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg; - priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; - - ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO], - IWL_LED_TRG_RADIO, 1, trigger); - if (ret) - goto exit_fail; - - trigger = ieee80211_get_assoc_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_ASSOC].name, - sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc", - wiphy_name(priv->hw->wiphy)); - - ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC], - IWL_LED_TRG_ASSOC, 0, trigger); - - /* for assoc always turn led on */ - priv->led[IWL_LED_TRG_ASSOC].led_on = iwl_led_associate; - priv->led[IWL_LED_TRG_ASSOC].led_off = iwl_led_disassociate; - priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; - - if (ret) - goto exit_fail; - - trigger = ieee80211_get_rx_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_RX].name, - sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX", - wiphy_name(priv->hw->wiphy)); - - ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX], - IWL_LED_TRG_RX, 0, trigger); - - priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated; - priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated; - priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern; - - if (ret) - goto exit_fail; - - trigger = ieee80211_get_tx_led_name(priv->hw); - snprintf(priv->led[IWL_LED_TRG_TX].name, - sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX", - wiphy_name(priv->hw->wiphy)); - - ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX], - IWL_LED_TRG_TX, 0, trigger); - - priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated; - priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated; - priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern; - - if (ret) - goto exit_fail; - - return 0; - -exit_fail: - iwl_leds_unregister(priv); - return ret; } -EXPORT_SYMBOL(iwl_leds_register); - -/* unregister led class */ -static void iwl_leds_unregister_led(struct iwl_led *led, u8 set_led) -{ - if (!led->registered) - return; - - led_classdev_unregister(&led->led_dev); - - if (set_led) - led->led_dev.brightness_set(&led->led_dev, LED_OFF); - led->registered = 0; -} - -/* Unregister all led handlers */ -void iwl_leds_unregister(struct iwl_priv *priv) -{ - iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0); - iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RX], 0); - iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_TX], 0); - iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1); -} -EXPORT_SYMBOL(iwl_leds_unregister); - +EXPORT_SYMBOL(iwl_leds_init); diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index dd76b266c633..f47f053f02ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -30,9 +30,6 @@ struct iwl_priv; -#ifdef CONFIG_IWLWIFI_LEDS -#include - #define IWL_LED_SOLID 11 #define IWL_LED_NAME_LEN 31 #define IWL_DEF_LED_INTRVL cpu_to_le32(1000) @@ -59,38 +56,11 @@ enum iwl_led_mode { IWL_LED_BLINK, IWL_LED_RF_STATE, }; -#endif - -#ifdef CONFIG_IWLWIFI_LEDS - -struct iwl_led { - struct iwl_priv *priv; - struct led_classdev led_dev; - char name[32]; - - int (*led_on) (struct iwl_priv *priv, int led_id); - int (*led_off) (struct iwl_priv *priv, int led_id); - int (*led_pattern) (struct iwl_priv *priv, int led_id, unsigned int idx); - enum led_type type; - unsigned int registered; -}; - -int iwl_leds_register(struct iwl_priv *priv); -void iwl_leds_unregister(struct iwl_priv *priv); +void iwl_leds_init(struct iwl_priv *priv); void iwl_leds_background(struct iwl_priv *priv); +int iwl_led_start(struct iwl_priv *priv); +int iwl_led_associate(struct iwl_priv *priv); +int iwl_led_disassociate(struct iwl_priv *priv); -#else -static inline int iwl_leds_register(struct iwl_priv *priv) -{ - return 0; -} -static inline void iwl_leds_unregister(struct iwl_priv *priv) -{ -} -static inline void iwl_leds_background(struct iwl_priv *priv) -{ -} - -#endif /* CONFIG_IWLWIFI_LEDS */ #endif /* __iwl_leds_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index d0d1b7f4c396..ecbe036ecb63 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -455,9 +455,6 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, tx->timeout.pm_frame_timeout = cpu_to_le16(2); } else { tx->timeout.pm_frame_timeout = 0; -#ifdef CONFIG_IWLWIFI_LEDS - priv->rxtxpackets += le16_to_cpu(cmd->cmd.tx.len); -#endif } tx->driver_txop = 0; @@ -2483,7 +2480,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) iwl3945_reg_txpower_periodic(priv); - iwl3945_led_register(priv); + iwl_leds_init(priv); IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); set_bit(STATUS_READY, &priv->status); @@ -2521,7 +2518,6 @@ static void __iwl3945_down(struct iwl_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); - iwl3945_led_unregister(priv); iwl_clear_stations_table(priv); /* Unblock any waiting calls */ @@ -3156,6 +3152,8 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) * no need to poll the killswitch state anymore */ cancel_delayed_work(&priv->rfkill_poll); + iwl_led_start(priv); + priv->is_open = 1; IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; -- cgit v1.2.3 From d68b603cf01a6e7d8c85c5a86db751ed3960c0c7 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 2 Oct 2009 13:44:04 -0700 Subject: iwlwifi/iwl3945 : unify apm stop operation Unify the usage of apm_stop_master and apm_stop across all hardwares. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-3945.c | 43 ++---------------------------- drivers/net/wireless/iwlwifi/iwl-4965.c | 38 ++------------------------- drivers/net/wireless/iwlwifi/iwl-5000.c | 46 +++------------------------------ drivers/net/wireless/iwlwifi/iwl-6000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 36 ++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 3 ++- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 8 files changed, 47 insertions(+), 124 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 86d93b52c6fc..679a67ff76eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -112,7 +112,7 @@ static struct iwl_lib_ops iwl1000_lib = { .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, - .stop = iwl5000_apm_stop, + .stop = iwl_apm_stop, .config = iwl1000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index f0ce5c45ca05..c5d1d57b4e0b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1167,48 +1167,9 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) iwl3945_hw_txq_ctx_free(priv); } -static int iwl3945_apm_stop_master(struct iwl_priv *priv) -{ - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - /* set stop master bit */ - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - - iwl_poll_direct_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - - if (ret < 0) - goto out; - -out: - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO(priv, "stop master\n"); - - return ret; -} - -static void iwl3945_apm_stop(struct iwl_priv *priv) -{ - unsigned long flags; - - iwl3945_apm_stop_master(priv); - - spin_lock_irqsave(&priv->lock, flags); - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - - udelay(10); - /* clear "init complete" move adapter D0A* --> D0U state */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - spin_unlock_irqrestore(&priv->lock, flags); -} - static int iwl3945_apm_reset(struct iwl_priv *priv) { - iwl3945_apm_stop_master(priv); + iwl_apm_stop_master(priv); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); @@ -2841,7 +2802,7 @@ static struct iwl_lib_ops iwl3945_lib = { .apm_ops = { .init = iwl3945_apm_init, .reset = iwl3945_apm_reset, - .stop = iwl3945_apm_stop, + .stop = iwl_apm_stop, .config = iwl3945_nic_config, .set_pwr_src = iwl3945_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 8717946de011..dd10c426ecc4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -396,45 +396,11 @@ static void iwl4965_nic_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static int iwl4965_apm_stop_master(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - /* set stop master bit */ - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - - iwl_poll_direct_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO(priv, "stop master\n"); - - return 0; -} - -static void iwl4965_apm_stop(struct iwl_priv *priv) -{ - unsigned long flags; - - iwl4965_apm_stop_master(priv); - - spin_lock_irqsave(&priv->lock, flags); - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - - udelay(10); - /* clear "init complete" move adapter D0A* --> D0U state */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - spin_unlock_irqrestore(&priv->lock, flags); -} - static int iwl4965_apm_reset(struct iwl_priv *priv) { int ret = 0; - iwl4965_apm_stop_master(priv); + iwl_apm_stop_master(priv); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); @@ -2306,7 +2272,7 @@ static struct iwl_lib_ops iwl4965_lib = { .apm_ops = { .init = iwl4965_apm_init, .reset = iwl4965_apm_reset, - .stop = iwl4965_apm_stop, + .stop = iwl_apm_stop, .config = iwl4965_nic_config, .set_pwr_src = iwl_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 624853503db1..d8dadbf04138 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -72,26 +72,6 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = { IWL_TX_FIFO_HCCA_2 }; -/* FIXME: same implementation as 4965 */ -static int iwl5000_apm_stop_master(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - /* set stop master bit */ - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - - iwl_poll_direct_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_INFO(priv, "stop master\n"); - - return 0; -} - - int iwl5000_apm_init(struct iwl_priv *priv) { int ret = 0; @@ -137,31 +117,11 @@ int iwl5000_apm_init(struct iwl_priv *priv) return ret; } -/* FIXME: this is identical to 4965 */ -void iwl5000_apm_stop(struct iwl_priv *priv) -{ - unsigned long flags; - - iwl5000_apm_stop_master(priv); - - spin_lock_irqsave(&priv->lock, flags); - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - - udelay(10); - - /* clear "init complete" move adapter D0A* --> D0U state */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - spin_unlock_irqrestore(&priv->lock, flags); -} - - int iwl5000_apm_reset(struct iwl_priv *priv) { int ret = 0; - iwl5000_apm_stop_master(priv); + iwl_apm_stop_master(priv); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); @@ -1561,7 +1521,7 @@ struct iwl_lib_ops iwl5000_lib = { .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, - .stop = iwl5000_apm_stop, + .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, @@ -1613,7 +1573,7 @@ static struct iwl_lib_ops iwl5150_lib = { .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, - .stop = iwl5000_apm_stop, + .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a002214f4d49..d1f0b0b4ad0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -193,7 +193,7 @@ static struct iwl_lib_ops iwl6000_lib = { .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, - .stop = iwl5000_apm_stop, + .stop = iwl_apm_stop, .config = iwl6000_nic_config, .set_pwr_src = iwl_set_pwr_src, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 34547cf3a66e..7c0ef8e4ebbf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1329,6 +1329,42 @@ void iwl_irq_handle_error(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_irq_handle_error); +int iwl_apm_stop_master(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* set stop master bit */ + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + + iwl_poll_direct_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_INFO(priv, "stop master\n"); + + return 0; +} +EXPORT_SYMBOL(iwl_apm_stop_master); + +void iwl_apm_stop(struct iwl_priv *priv) +{ + unsigned long flags; + + iwl_apm_stop_master(priv); + + spin_lock_irqsave(&priv->lock, flags); + + iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + udelay(10); + /* clear "init complete" move adapter D0A* --> D0U state */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL(iwl_apm_stop); + void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index eb586a546181..6688b6944200 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -658,6 +658,8 @@ extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); +void iwl_apm_stop(struct iwl_priv *priv); +int iwl_apm_stop_master(struct iwl_priv *priv); void iwl_setup_rxon_timing(struct iwl_priv *priv); static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) @@ -677,5 +679,4 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode( { return priv->hw->wiphy->bands[band]; } - #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index eabc55695aff..72946c144be7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -86,7 +86,6 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, extern int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp); extern int iwl5000_apm_init(struct iwl_priv *priv); -extern void iwl5000_apm_stop(struct iwl_priv *priv); extern int iwl5000_apm_reset(struct iwl_priv *priv); extern void iwl5000_nic_config(struct iwl_priv *priv); extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv); -- cgit v1.2.3 From 1739d3322008fb95e88ad0530bcc057789107879 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 2 Oct 2009 13:44:05 -0700 Subject: iwlwifi: replace iwl_poll_direct_bit with iwl_poll_bit for CSR access Replace iwl_poll_direct_bit with iwl_poll_bit when accessing CSR registers. There is no need to power up the mac to access CSR registers. Signed-off-by: Abhijeet Kolekar Acked-by: Ben M Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 10 ++++++---- drivers/net/wireless/iwlwifi/iwl-4965.c | 6 ++++-- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 ++++-- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 12 ++++++++---- 5 files changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index c5d1d57b4e0b..ced0e33e44b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -999,8 +999,9 @@ static int iwl3945_apm_init(struct iwl_priv *priv) * D0U* --> D0A* state */ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO(priv, "Failed to init the card\n"); goto out; @@ -1177,8 +1178,9 @@ static int iwl3945_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - iwl_poll_direct_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_BSM_CLK_RQT); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index dd10c426ecc4..f8eed9a4abc1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -335,7 +335,8 @@ static int iwl4965_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO(priv, "Failed to init the card\n"); @@ -411,7 +412,8 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d8dadbf04138..98baf8af6da8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -98,7 +98,8 @@ int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO(priv, "Failed to init the card\n"); @@ -138,7 +139,8 @@ int iwl5000_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO(priv, "Failed to init the card\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7c0ef8e4ebbf..dc7fd87bed98 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1338,7 +1338,7 @@ int iwl_apm_stop_master(struct iwl_priv *priv) /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - iwl_poll_direct_bit(priv, CSR_RESET, + iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 3d2b93a61e62..8107132ab66c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -283,7 +283,8 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_poll_direct_bit(priv, CSR_HW_IF_CONFIG_REG, + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, EEPROM_SEM_TIMEOUT); if (ret >= 0) { @@ -322,7 +323,8 @@ static int iwl_init_otp_access(struct iwl_priv *priv) CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock to be ready */ - ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) @@ -345,7 +347,8 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) _iwl_write32(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + ret = iwl_poll_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, CSR_EEPROM_REG_READ_VALID_MSK, IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { @@ -538,7 +541,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) _iwl_write32(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + ret = iwl_poll_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, CSR_EEPROM_REG_READ_VALID_MSK, IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { -- cgit v1.2.3 From f41bb897f202d23a7d896c716002a3d6050b991e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 2 Oct 2009 13:44:06 -0700 Subject: iwlwifi: validate the signature for EEPROM and OTP Both 1000 & 6000 series NICs contain on-chip OTP memory that replaces the off-chip EEPROM memory. The nature of OTP means there is a limited number of times a particular board can go through the factory flow and be (re)calibrated. As a consequence there will be some boards that contain EEPROM memory because OTP blocks were full. In the signature validation routine, iwlwifi needs to make sure "select bit" and "EEPROM/OTP signature" agree on the type of NVM to be used to configure the system. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-csr.h | 7 ++++++- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 33 ++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 06437d13e73e..8f183e0fa512 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -230,13 +230,18 @@ /* EEPROM GP */ #define CSR_EEPROM_GP_VALID_MSK (0x00000007) -#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) #define CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */ #define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ #define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ #define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ +/* EEPROM signature */ +#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000) +#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001) +#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002) +#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004) + /* CSR GIO */ #define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 8107132ab66c..e3dbd79cd13e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -215,12 +215,35 @@ static const struct iwl_txpwr_section enhinfo[] = { int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) { - u32 gp = iwl_read32(priv, CSR_EEPROM_GP); - if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { - IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); - return -ENOENT; + u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; + int ret = 0; + + IWL_DEBUG_INFO(priv, "EEPROM signature=0x%08x\n", gp); + switch (gp) { + case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP: + if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) { + IWL_ERR(priv, "EEPROM with bad signature: 0x%08x\n", + gp); + ret = -ENOENT; + } + break; + case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K: + case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K: + if (priv->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) { + IWL_ERR(priv, "OTP with bad signature: 0x%08x\n", gp); + ret = -ENOENT; + } + break; + case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP: + default: + IWL_ERR(priv, "bad EEPROM/OTP signature, type=%s, " + "EEPROM_GP=0x%08x\n", + (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) + ? "OTP" : "EEPROM", gp); + ret = -ENOENT; + break; } - return 0; + return ret; } EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); -- cgit v1.2.3 From fe348cb628e6a78cc1e82fe64404c9a304ed9c12 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 24 Sep 2009 11:02:51 -0700 Subject: at76c50x-usb: set firmware and hardware version in wiphy Set firmware and hardware version in wiphy so that user space can access it. (Modification from original in favor of cfg80211 ethtool support. -- JWL) Cc: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/at76c50x-usb.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 8e1a55dec351..e559dc960552 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -2217,6 +2217,8 @@ static struct ieee80211_supported_band at76_supported_band = { static int at76_init_new_device(struct at76_priv *priv, struct usb_interface *interface) { + struct wiphy *wiphy; + size_t len; int ret; /* set up the endpoint information */ @@ -2254,6 +2256,7 @@ static int at76_init_new_device(struct at76_priv *priv, priv->device_unplugged = 0; /* mac80211 initialisation */ + wiphy = priv->hw->wiphy; priv->hw->wiphy->max_scan_ssids = 1; priv->hw->wiphy->max_scan_ie_len = 0; priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); @@ -2265,6 +2268,13 @@ static int at76_init_new_device(struct at76_priv *priv, SET_IEEE80211_DEV(priv->hw, &interface->dev); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); + len = sizeof(wiphy->fw_version); + snprintf(wiphy->fw_version, len, "%d.%d.%d-%d", + priv->fw_version.major, priv->fw_version.minor, + priv->fw_version.patch, priv->fw_version.build); + + wiphy->hw_version = priv->board_type; + ret = ieee80211_register_hw(priv->hw); if (ret) { printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n", -- cgit v1.2.3 From baee1f3caa5a771880144358dd07d32e09ba4dcf Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 5 Oct 2009 00:52:09 +0200 Subject: Wireless / ath5k: Simplify suspend and resume callbacks Simplify the suspend and resume callbacks of ath5k by converting the driver to struct dev_pm_ops and allowing the PCI PM core to do the PCI-specific suspend/resume handling. Signed-off-by: Rafael J. Wysocki Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 70831f1bcf04..5aaa9bd036db 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -195,12 +195,13 @@ static int __devinit ath5k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void __devexit ath5k_pci_remove(struct pci_dev *pdev); #ifdef CONFIG_PM -static int ath5k_pci_suspend(struct pci_dev *pdev, - pm_message_t state); -static int ath5k_pci_resume(struct pci_dev *pdev); +static int ath5k_pci_suspend(struct device *dev); +static int ath5k_pci_resume(struct device *dev); + +SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume); +#define ATH5K_PM_OPS (&ath5k_pm_ops) #else -#define ath5k_pci_suspend NULL -#define ath5k_pci_resume NULL +#define ATH5K_PM_OPS NULL #endif /* CONFIG_PM */ static struct pci_driver ath5k_pci_driver = { @@ -208,8 +209,7 @@ static struct pci_driver ath5k_pci_driver = { .id_table = ath5k_pci_id_table, .probe = ath5k_pci_probe, .remove = __devexit_p(ath5k_pci_remove), - .suspend = ath5k_pci_suspend, - .resume = ath5k_pci_resume, + .driver.pm = ATH5K_PM_OPS, }; @@ -703,33 +703,20 @@ ath5k_pci_remove(struct pci_dev *pdev) } #ifdef CONFIG_PM -static int -ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int ath5k_pci_suspend(struct device *dev) { - struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = pci_get_drvdata(to_pci_dev(dev)); struct ath5k_softc *sc = hw->priv; ath5k_led_off(sc); - - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - return 0; } -static int -ath5k_pci_resume(struct pci_dev *pdev) +static int ath5k_pci_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath5k_softc *sc = hw->priv; - int err; - - pci_restore_state(pdev); - - err = pci_enable_device(pdev); - if (err) - return err; /* * Suspend/Resume resets the PCI configuration space, so we have to -- cgit v1.2.3 From 0465af8e03bdc6cd0b49dc5548671387a8674b69 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 6 Oct 2009 16:31:20 +0200 Subject: libertas: separate libertas' Kconfig in it's own file Also sorts all "source" lines in the wireless/Kconfig. Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 56 +++++----------------------------- drivers/net/wireless/libertas/Kconfig | 40 ++++++++++++++++++++++++ drivers/net/wireless/libertas/Makefile | 14 +++++++-- 3 files changed, 60 insertions(+), 50 deletions(-) create mode 100644 drivers/net/wireless/libertas/Kconfig (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index c9829c59fd98..18255fb28d17 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -139,47 +139,6 @@ config PCMCIA_RAYCS To compile this driver as a module, choose M here: the module will be called ray_cs. If unsure, say N. -config LIBERTAS - tristate "Marvell 8xxx Libertas WLAN driver support" - depends on WLAN_80211 - select WIRELESS_EXT - select WEXT_SPY - select LIB80211 - select FW_LOADER - ---help--- - A library for Marvell Libertas 8xxx devices. - -config LIBERTAS_USB - tristate "Marvell Libertas 8388 USB 802.11b/g cards" - depends on LIBERTAS && USB - ---help--- - A driver for Marvell Libertas 8388 USB devices. - -config LIBERTAS_CS - tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" - depends on LIBERTAS && PCMCIA - select FW_LOADER - ---help--- - A driver for Marvell Libertas 8385 CompactFlash devices. - -config LIBERTAS_SDIO - tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards" - depends on LIBERTAS && MMC - ---help--- - A driver for Marvell Libertas 8385/8686/8688 SDIO devices. - -config LIBERTAS_SPI - tristate "Marvell Libertas 8686 SPI 802.11b/g cards" - depends on LIBERTAS && SPI - ---help--- - A driver for Marvell Libertas 8686 SPI devices. - -config LIBERTAS_DEBUG - bool "Enable full debugging output in the Libertas module." - depends on LIBERTAS - ---help--- - Debugging support. - config LIBERTAS_THINFIRM tristate "Marvell 8xxx Libertas WLAN driver support with thin firmware" depends on WLAN_80211 && MAC80211 @@ -491,17 +450,18 @@ config MWL8K To compile this driver as a module, choose M here: the module will be called mwl8k. If unsure, say N. -source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/ath/Kconfig" -source "drivers/net/wireless/ipw2x00/Kconfig" -source "drivers/net/wireless/iwlwifi/Kconfig" -source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/b43/Kconfig" source "drivers/net/wireless/b43legacy/Kconfig" -source "drivers/net/wireless/zd1211rw/Kconfig" -source "drivers/net/wireless/rt2x00/Kconfig" +source "drivers/net/wireless/hostap/Kconfig" +source "drivers/net/wireless/ipw2x00/Kconfig" +source "drivers/net/wireless/iwlwifi/Kconfig" +source "drivers/net/wireless/iwmc3200wifi/Kconfig" +source "drivers/net/wireless/libertas/Kconfig" source "drivers/net/wireless/orinoco/Kconfig" +source "drivers/net/wireless/p54/Kconfig" +source "drivers/net/wireless/rt2x00/Kconfig" source "drivers/net/wireless/wl12xx/Kconfig" -source "drivers/net/wireless/iwmc3200wifi/Kconfig" +source "drivers/net/wireless/zd1211rw/Kconfig" endif # WLAN diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig new file mode 100644 index 000000000000..3e6c922c2f44 --- /dev/null +++ b/drivers/net/wireless/libertas/Kconfig @@ -0,0 +1,40 @@ +config LIBERTAS + tristate "Marvell 8xxx Libertas WLAN driver support" + depends on WLAN_80211 + select WIRELESS_EXT + select WEXT_SPY + select LIB80211 + select FW_LOADER + ---help--- + A library for Marvell Libertas 8xxx devices. + +config LIBERTAS_USB + tristate "Marvell Libertas 8388 USB 802.11b/g cards" + depends on LIBERTAS && USB + ---help--- + A driver for Marvell Libertas 8388 USB devices. + +config LIBERTAS_CS + tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" + depends on LIBERTAS && PCMCIA + select FW_LOADER + ---help--- + A driver for Marvell Libertas 8385 CompactFlash devices. + +config LIBERTAS_SDIO + tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards" + depends on LIBERTAS && MMC + ---help--- + A driver for Marvell Libertas 8385/8686/8688 SDIO devices. + +config LIBERTAS_SPI + tristate "Marvell Libertas 8686 SPI 802.11b/g cards" + depends on LIBERTAS && SPI + ---help--- + A driver for Marvell Libertas 8686 SPI devices. + +config LIBERTAS_DEBUG + bool "Enable full debugging output in the Libertas module." + depends on LIBERTAS + ---help--- + Debugging support. diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index 0b6918584503..2f63940fb7f6 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -1,5 +1,15 @@ -libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \ - debugfs.o persistcfg.o ethtool.o assoc.o +libertas-y += 11d.o +libertas-y += assoc.o +libertas-y += cmd.o +libertas-y += cmdresp.o +libertas-y += debugfs.o +libertas-y += ethtool.o +libertas-y += main.o +libertas-y += persistcfg.o +libertas-y += rx.o +libertas-y += scan.o +libertas-y += tx.o +libertas-y += wext.o usb8xxx-objs += if_usb.o libertas_cs-objs += if_cs.o -- cgit v1.2.3 From ff9fc791940f9ff51387c35f9332efe5007154f1 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Tue, 6 Oct 2009 16:31:54 +0200 Subject: libertas: first stab at cfg80211 support Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/Makefile | 1 + drivers/net/wireless/libertas/cfg.c | 198 +++++++++++++++++++++++++++++++++ drivers/net/wireless/libertas/cfg.h | 16 +++ drivers/net/wireless/libertas/defs.h | 2 + drivers/net/wireless/libertas/dev.h | 1 + drivers/net/wireless/libertas/main.c | 61 +++++++--- 6 files changed, 262 insertions(+), 17 deletions(-) create mode 100644 drivers/net/wireless/libertas/cfg.c create mode 100644 drivers/net/wireless/libertas/cfg.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index 2f63940fb7f6..e5584dd1c79a 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -1,5 +1,6 @@ libertas-y += 11d.o libertas-y += assoc.o +libertas-y += cfg.o libertas-y += cmd.o libertas-y += cmdresp.o libertas-y += debugfs.o diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c new file mode 100644 index 000000000000..4396dccd12ac --- /dev/null +++ b/drivers/net/wireless/libertas/cfg.c @@ -0,0 +1,198 @@ +/* + * Implement cfg80211 ("iw") support. + * + * Copyright (C) 2009 M&N Solutions GmbH, 61191 Rosbach, Germany + * Holger Schurig + * + */ + +#include + +#include "cfg.h" +#include "cmd.h" + + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +static struct ieee80211_channel lbs_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +#define RATETAB_ENT(_rate, _rateid, _flags) { \ + .bitrate = (_rate), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ +} + + +static struct ieee80211_rate lbs_rates[] = { + RATETAB_ENT(10, 0x1, 0), + RATETAB_ENT(20, 0x2, 0), + RATETAB_ENT(55, 0x4, 0), + RATETAB_ENT(110, 0x8, 0), + RATETAB_ENT(60, 0x10, 0), + RATETAB_ENT(90, 0x20, 0), + RATETAB_ENT(120, 0x40, 0), + RATETAB_ENT(180, 0x80, 0), + RATETAB_ENT(240, 0x100, 0), + RATETAB_ENT(360, 0x200, 0), + RATETAB_ENT(480, 0x400, 0), + RATETAB_ENT(540, 0x800, 0), +}; + +static struct ieee80211_supported_band lbs_band_2ghz = { + .channels = lbs_2ghz_channels, + .n_channels = ARRAY_SIZE(lbs_2ghz_channels), + .bitrates = lbs_rates, + .n_bitrates = ARRAY_SIZE(lbs_rates), +}; + + +static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + + + +static int lbs_cfg_set_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct lbs_private *priv = wiphy_priv(wiphy); + int ret = -ENOTSUPP; + + lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", chan->center_freq, channel_type); + + if (channel_type != NL80211_CHAN_NO_HT) + goto out; + + ret = lbs_set_channel(priv, chan->hw_value); + + out: + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); + return ret; +} + + + + +static struct cfg80211_ops lbs_cfg80211_ops = { + .set_channel = lbs_cfg_set_channel, +}; + + +/* + * At this time lbs_private *priv doesn't even exist, so we just allocate + * memory and don't initialize the wiphy further. This is postponed until we + * can talk to the firmware and happens at registration time in + * lbs_cfg_wiphy_register(). + */ +struct wireless_dev *lbs_cfg_alloc(struct device *dev) +{ + int ret = 0; + struct wireless_dev *wdev; + + lbs_deb_enter(LBS_DEB_CFG80211); + + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + dev_err(dev, "cannot allocate wireless device\n"); + return ERR_PTR(-ENOMEM); + } + + wdev->wiphy = wiphy_new(&lbs_cfg80211_ops, sizeof(struct lbs_private)); + if (!wdev->wiphy) { + dev_err(dev, "cannot allocate wiphy\n"); + ret = -ENOMEM; + goto err_wiphy_new; + } + + lbs_deb_leave(LBS_DEB_CFG80211); + return wdev; + + err_wiphy_new: + kfree(wdev); + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); + return ERR_PTR(ret); +} + + +/* + * This function get's called after lbs_setup_firmware() determined the + * firmware capabities. So we can setup the wiphy according to our + * hardware/firmware. + */ +int lbs_cfg_register(struct lbs_private *priv) +{ + struct wireless_dev *wdev = priv->wdev; + int ret; + + lbs_deb_enter(LBS_DEB_CFG80211); + + wdev->wiphy->max_scan_ssids = 1; + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + /* TODO: BIT(NL80211_IFTYPE_ADHOC); */ + wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + + /* TODO: honor priv->regioncode */ + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz; + + /* + * We could check priv->fwcapinfo && FW_CAPINFO_WPA, but I have + * never seen a firmware without WPA + */ + wdev->wiphy->cipher_suites = cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + + ret = wiphy_register(wdev->wiphy); + if (ret < 0) + lbs_pr_err("cannot register wiphy device\n"); + + ret = register_netdev(priv->dev); + if (ret) + lbs_pr_err("cannot register network device\n"); + + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); + return ret; +} + + +void lbs_cfg_free(struct lbs_private *priv) +{ + struct wireless_dev *wdev = priv->wdev; + + lbs_deb_enter(LBS_DEB_CFG80211); + + if (!wdev) + return; + + if (wdev->wiphy) { + wiphy_unregister(wdev->wiphy); + wiphy_free(wdev->wiphy); + } + kfree(wdev); +} diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h new file mode 100644 index 000000000000..e09a193a34d6 --- /dev/null +++ b/drivers/net/wireless/libertas/cfg.h @@ -0,0 +1,16 @@ +#ifndef __LBS_CFG80211_H__ +#define __LBS_CFG80211_H__ + +#include "dev.h" + +struct wireless_dev *lbs_cfg_alloc(struct device *dev); +int lbs_cfg_register(struct lbs_private *priv); +void lbs_cfg_free(struct lbs_private *priv); + +int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, + u8 ssid_len); +int lbs_scan_networks(struct lbs_private *priv, int full_scan); +void lbs_cfg_scan_worker(struct work_struct *work); + + +#endif diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 72f3479a4d70..1cf5d5985dac 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -42,6 +42,7 @@ #define LBS_DEB_SDIO 0x00400000 #define LBS_DEB_SYSFS 0x00800000 #define LBS_DEB_SPI 0x01000000 +#define LBS_DEB_CFG80211 0x02000000 extern unsigned int lbs_debug; @@ -86,6 +87,7 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args) #define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args) #define lbs_deb_spi(fmt, args...) LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args) +#define lbs_deb_cfg80211(fmt, args...) LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args) #define lbs_pr_info(format, args...) \ printk(KERN_INFO DRV_NAME": " format, ## args) diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 0018df14fad9..8abb28af5afa 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -100,6 +100,7 @@ struct lbs_mesh_stats { /** Private structure for the MV device */ struct lbs_private { + struct wireless_dev *wdev; int mesh_open; int mesh_fw_ver; int infra_open; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 9b2a9174a017..e6da1dfa8131 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -14,11 +14,13 @@ #include #include #include +#include #include "host.h" #include "decl.h" #include "dev.h" #include "wext.h" +#include "cfg.h" #include "debugfs.h" #include "scan.h" #include "assoc.h" @@ -1245,31 +1247,42 @@ static const struct net_device_ops lbs_netdev_ops = { */ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) { - struct net_device *dev = NULL; + struct net_device *dev; + struct wireless_dev *wdev; struct lbs_private *priv = NULL; lbs_deb_enter(LBS_DEB_MAIN); /* Allocate an Ethernet device and register it */ - dev = alloc_etherdev(sizeof(struct lbs_private)); - if (!dev) { - lbs_pr_err("init wlanX device failed\n"); + wdev = lbs_cfg_alloc(dmdev); + if (IS_ERR(wdev)) { + lbs_pr_err("cfg80211 init failed\n"); goto done; } - priv = netdev_priv(dev); - dev->ml_priv = priv; + /* TODO? */ + wdev->iftype = NL80211_IFTYPE_STATION; + priv = wdev_priv(wdev); + priv->wdev = wdev; if (lbs_init_adapter(priv)) { lbs_pr_err("failed to initialize adapter structure.\n"); - goto err_init_adapter; + goto err_wdev; + } + + //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES); + dev = alloc_netdev(0, "wlan%d", ether_setup); + if (!dev) { + dev_err(dmdev, "no memory for network device instance\n"); + goto err_adapter; } + dev->netdev_ops = &lbs_netdev_ops; + dev->ieee80211_ptr = wdev; + dev->ml_priv = priv; + SET_NETDEV_DEV(dev, dmdev); + wdev->netdev = dev; priv->dev = dev; - priv->card = card; - priv->mesh_open = 0; - priv->infra_open = 0; - /* Setup the OS Interface to our functions */ dev->netdev_ops = &lbs_netdev_ops; dev->watchdog_timeo = 5 * HZ; dev->ethtool_ops = &lbs_ethtool_ops; @@ -1278,7 +1291,14 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) #endif dev->flags |= IFF_BROADCAST | IFF_MULTICAST; - SET_NETDEV_DEV(dev, dmdev); + + // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ?? + + + priv->card = card; + priv->mesh_open = 0; + priv->infra_open = 0; + priv->rtap_net_dev = NULL; strcpy(dev->name, "wlan%d"); @@ -1288,7 +1308,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main"); if (IS_ERR(priv->main_thread)) { lbs_deb_thread("Error creating main thread.\n"); - goto err_init_adapter; + goto err_ndev; } priv->work_thread = create_singlethread_workqueue("lbs_worker"); @@ -1305,9 +1325,15 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) goto done; -err_init_adapter: - lbs_free_adapter(priv); + err_ndev: free_netdev(dev); + + err_adapter: + lbs_free_adapter(priv); + + err_wdev: + lbs_cfg_free(priv); + priv = NULL; done: @@ -1359,6 +1385,7 @@ void lbs_remove_card(struct lbs_private *priv) kthread_stop(priv->main_thread); lbs_free_adapter(priv); + lbs_cfg_free(priv); priv->dev = NULL; free_netdev(dev); @@ -1383,8 +1410,8 @@ int lbs_start_card(struct lbs_private *priv) /* init 802.11d */ lbs_init_11d(priv); - if (register_netdev(dev)) { - lbs_pr_err("cannot register ethX device\n"); + if (lbs_cfg_register(priv)) { + lbs_pr_err("cannot register device\n"); goto done; } -- cgit v1.2.3 From 5b367378ee826b0566e51d32b78b00ce24eac8f9 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 6 Oct 2009 16:41:21 -0400 Subject: iwmc3200wifi: support ETHTOOL_GPERMADDR Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index d668e4756324..170f33706490 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -637,6 +637,8 @@ static int __iwm_up(struct iwm_priv *iwm) IWM_ERR(iwm, "MAC reading failed\n"); goto err_disable; } + memcpy(iwm_to_ndev(iwm)->perm_addr, iwm_to_ndev(iwm)->dev_addr, + ETH_ALEN); /* We can load the FWs */ ret = iwm_load_fw(iwm); -- cgit v1.2.3 From 5e5eab5dd4339b66e9e59695812fd4b96c3bb1c0 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 6 Oct 2009 16:45:14 -0400 Subject: ipw2200: support ETHTOOL_GPERMADDR Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 8d58e6ed4e7d..61ef8904af97 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11275,6 +11275,7 @@ static int ipw_up(struct ipw_priv *priv) if (!(priv->config & CFG_CUSTOM_MAC)) eeprom_parse_mac(priv, priv->mac_addr); memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); + memcpy(priv->net_dev->perm_addr, priv->mac_addr, ETH_ALEN); for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) { if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE], -- cgit v1.2.3 From cf32ed92432303022be208bb6a173994712f1f23 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 6 Oct 2009 16:47:23 -0400 Subject: orinoco: support ETHTOOL_GPERMADDR Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 7a32bcb0c037..5fdc59c594f2 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -2225,6 +2225,7 @@ int orinoco_if_add(struct orinoco_private *priv, netif_carrier_off(dev); memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); + memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN); dev->base_addr = base_addr; dev->irq = irq; -- cgit v1.2.3 From c6d3597cd54739281e964aa3c063f794e960f75e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 6 Oct 2009 13:27:29 -0700 Subject: wireless: fix CFG80211_WEXT build problems Fix CFG80211_WEXT build dependencies/errors: ERROR: "cfg80211_wext_siwscan" [drivers/net/wireless/orinoco/orinoco.ko] undefined! ERROR: "cfg80211_wext_siwmode" [drivers/net/wireless/orinoco/orinoco.ko] undefined! ERROR: "cfg80211_wext_giwrange" [drivers/net/wireless/orinoco/orinoco.ko] undefined! ERROR: "cfg80211_wext_giwmode" [drivers/net/wireless/orinoco/orinoco.ko] undefined! ERROR: "cfg80211_wext_giwname" [drivers/net/wireless/orinoco/orinoco.ko] undefined! ERROR: "cfg80211_wext_giwscan" [drivers/net/wireless/orinoco/orinoco.ko] undefined! ERROR: "cfg80211_wext_giwname" [drivers/net/wireless/ipw2x00/ipw2200.ko] undefined! Signed-off-by: Randy Dunlap Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/Kconfig | 2 +- drivers/net/wireless/orinoco/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index 56fab79dc365..59ec9eec5024 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -65,7 +65,7 @@ config IPW2100_DEBUG config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && WLAN_80211 && CFG80211 + depends on PCI && WLAN_80211 && CFG80211 && CFG80211_WEXT select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig index 13b03b3e8fce..dce652054afd 100644 --- a/drivers/net/wireless/orinoco/Kconfig +++ b/drivers/net/wireless/orinoco/Kconfig @@ -1,7 +1,7 @@ config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 - depends on CFG80211 + depends on CFG80211 && CFG80211_WEXT select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV -- cgit v1.2.3 From eb053a037d8951018bdc9133c8d312da9cd0aefb Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 20:44:28 -0400 Subject: ath5k: fix regression on setting bssid mask on association There was a typo on the second bssid mask register. This was caused by the patch titled: "ath5k: use common curbssid, bssidmask and macaddr" Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/pcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 9ac763875a98..0385e8022529 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -292,7 +292,7 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) ath5k_hw_reg_write(ah, get_unaligned_le32(common->bssidmask), AR_BSSMSKL); ath5k_hw_reg_write(ah, - get_unaligned_le16(common->curbssid + 4), + get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU); } -- cgit v1.2.3 From a72d57a862f700edf85da81aae3cd8f923e989a1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 20:44:29 -0400 Subject: ath5k: use ath_hw_setbssidmask() for bssid mask setting upon assoc This should avoid future typos. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/pcu.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 0385e8022529..32fd5f88fb73 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -288,13 +288,8 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) /* * Set simple BSSID mask on 5212 */ - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, get_unaligned_le32(common->bssidmask), - AR_BSSMSKL); - ath5k_hw_reg_write(ah, - get_unaligned_le16(common->bssidmask + 4), - AR_BSSMSKU); - } + if (ah->ah_version == AR5K_AR5212) + ath_hw_setbssidmask(common); /* * Set BSSID which triggers the "SME Join" operation -- cgit v1.2.3 From 91b9eb8261acfe473c369750036df24ad071e5c1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 20:44:30 -0400 Subject: ath5k: fix regression introduced upon the removal of AR5K_HIGH_ID() The trick was to add four bytes whenever this was used. There are two places where this was missed. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/pcu.c | 2 +- drivers/net/wireless/ath/ath5k/reset.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 32fd5f88fb73..9e6e41bdd099 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -295,7 +295,7 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) * Set BSSID which triggers the "SME Join" operation */ low_id = get_unaligned_le32(bssid); - high_id = get_unaligned_le16(bssid); + high_id = get_unaligned_le16(bssid + 4); ath5k_hw_reg_write(ah, low_id, AR_BSSMSKL); ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << AR5K_BSS_ID1_AID_S), AR_BSSMSKU); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 51aff7652c4b..39346a26ddb8 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1178,7 +1178,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, get_unaligned_le32(common->macaddr), AR5K_STA_ID0); ath5k_hw_reg_write(ah, - staid1_flags | get_unaligned_le16(common->macaddr), + staid1_flags | get_unaligned_le16(common->macaddr + 4), AR5K_STA_ID1); -- cgit v1.2.3 From be5d6b75e0fb3f7e23ea5325109ef4195f2b282a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 20:44:31 -0400 Subject: ath5k: simplify passed params to ath5k_hw_set_associd() We have access to common->curbssid and common->curaid so just use those. Note that common->curaid is always 0 so this keeps our current behaviour of always using 0 for now. Once we fix storing the association ID passed by mac80211 this will require no changes here. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 2 +- drivers/net/wireless/ath/ath5k/attach.c | 2 +- drivers/net/wireless/ath/ath5k/base.c | 2 +- drivers/net/wireless/ath/ath5k/pcu.c | 10 +++++----- drivers/net/wireless/ath/ath5k/reset.c | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 43585d54c270..647d826bf5fb 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1191,7 +1191,7 @@ extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah); extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); /* BSSID Functions */ extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); -extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id); +extern void ath5k_hw_set_associd(struct ath5k_hw *ah); extern void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); /* Receive start/stop functions */ extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index e230de8ad320..92995adeb5cd 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -326,7 +326,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN); - ath5k_hw_set_associd(ah, common->curbssid, 0); + ath5k_hw_set_associd(ah); ath5k_hw_set_opmode(ah); ath5k_hw_rfgain_opt_init(ah); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 5aaa9bd036db..01da83d75ef4 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -3213,7 +3213,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); /* XXX: assoc id is set to 0 for now, mac80211 doesn't have * a clean way of letting us retrieve this yet. */ - ath5k_hw_set_associd(ah, common->curbssid, 0); + ath5k_hw_set_associd(ah); mmiowb(); } diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 9e6e41bdd099..23e5e7e5b495 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -279,7 +279,7 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) * * Sets the BSSID which trigers the "SME Join" operation */ -void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) +void ath5k_hw_set_associd(struct ath5k_hw *ah) { struct ath_common *common = ath5k_hw_common(ah); u32 low_id, high_id; @@ -294,13 +294,13 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) /* * Set BSSID which triggers the "SME Join" operation */ - low_id = get_unaligned_le32(bssid); - high_id = get_unaligned_le16(bssid + 4); + low_id = get_unaligned_le32(common->curbssid); + high_id = get_unaligned_le16(common->curbssid + 4); ath5k_hw_reg_write(ah, low_id, AR_BSSMSKL); - ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << + ath5k_hw_reg_write(ah, high_id | ((common->curaid & 0x3fff) << AR5K_BSS_ID1_AID_S), AR_BSSMSKU); - if (assoc_id == 0) { + if (common->curaid == 0) { ath5k_hw_disable_pspoll(ah); return; } diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 39346a26ddb8..fb8981548794 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1188,7 +1188,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Restore bssid and bssid mask */ /* XXX: add ah->aid once mac80211 gives this to us */ - ath5k_hw_set_associd(ah, common->curbssid, 0); + ath5k_hw_set_associd(ah); /* Set PCU config */ ath5k_hw_set_opmode(ah); -- cgit v1.2.3 From abba06869e2546484fa142528737d1a0622add54 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 20:44:32 -0400 Subject: ath5k: remove temporary low_id and high_id vars on ath5k_hw_set_associd() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/pcu.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 23e5e7e5b495..2ab9c0ecbb8b 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -282,7 +282,6 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) void ath5k_hw_set_associd(struct ath5k_hw *ah) { struct ath_common *common = ath5k_hw_common(ah); - u32 low_id, high_id; u16 tim_offset = 0; /* @@ -294,11 +293,13 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah) /* * Set BSSID which triggers the "SME Join" operation */ - low_id = get_unaligned_le32(common->curbssid); - high_id = get_unaligned_le16(common->curbssid + 4); - ath5k_hw_reg_write(ah, low_id, AR_BSSMSKL); - ath5k_hw_reg_write(ah, high_id | ((common->curaid & 0x3fff) << - AR5K_BSS_ID1_AID_S), AR_BSSMSKU); + ath5k_hw_reg_write(ah, + get_unaligned_le32(common->curbssid), + AR_BSSMSKL); + ath5k_hw_reg_write(ah, + get_unaligned_le16(common->curbssid + 4) | + ((common->curaid & 0x3fff) << AR5K_BSS_ID1_AID_S), + AR_BSSMSKU); if (common->curaid == 0) { ath5k_hw_disable_pspoll(ah); @@ -306,7 +307,7 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah) } AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM, - tim_offset ? tim_offset + 4 : 0); + tim_offset ? tim_offset + 4 : 0); ath5k_hw_enable_pspoll(ah, NULL, 0); } -- cgit v1.2.3 From a3f86bff1c056f47c2df4c58bfcf7bdda8eaf9d0 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 20:44:33 -0400 Subject: ath5k: fix regression which triggers an SME join upon assoc This fixes a regression introduced by patch titled: "atheros: define shared bssidmask setting" The register for the BSSID was exchanged for the bssid mask register. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/pcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 2ab9c0ecbb8b..64fc1eb9b6d9 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -295,11 +295,11 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah) */ ath5k_hw_reg_write(ah, get_unaligned_le32(common->curbssid), - AR_BSSMSKL); + AR5K_BSS_ID0); ath5k_hw_reg_write(ah, get_unaligned_le16(common->curbssid + 4) | ((common->curaid & 0x3fff) << AR5K_BSS_ID1_AID_S), - AR_BSSMSKU); + AR5K_BSS_ID1); if (common->curaid == 0) { ath5k_hw_disable_pspoll(ah); -- cgit v1.2.3 From 8ce54c5a5f5d2f4f03993395d60f3110670002ca Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 20:44:34 -0400 Subject: ath5k: enable Power-Save Polls by setting the association ID mac80211 has long provided us the association ID. This isn't useful except for Power-Save polling which now gets enabled. We can now poll for our pending frames on the AP during power save. You can review the details of Power-Save on the wireless wiki: http://wireless.kernel.org/en/developers/Documentation/ieee80211/power-savings Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 11 +++++++++-- drivers/net/wireless/ath/ath5k/reset.c | 1 - 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 01da83d75ef4..07c1e52b5a0c 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -3211,8 +3211,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_BSSID) { /* Cache for later use during resets */ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - /* XXX: assoc id is set to 0 for now, mac80211 doesn't have - * a clean way of letting us retrieve this yet. */ + common->curaid = 0; ath5k_hw_set_associd(ah); mmiowb(); } @@ -3226,6 +3225,14 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, set_beacon_filter(hw, sc->assoc); ath5k_hw_set_ledstate(sc->ah, sc->assoc ? AR5K_LED_ASSOC : AR5K_LED_INIT); + if (bss_conf->assoc) { + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, + "Bss Info ASSOC %d, bssid: %pM\n", + bss_conf->aid, common->curbssid); + common->curaid = bss_conf->aid; + ath5k_hw_set_associd(ah); + /* Once ANI is available you would start it here */ + } } if (changes & BSS_CHANGED_BEACON) { diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index fb8981548794..3dab3d856d7b 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1187,7 +1187,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, */ /* Restore bssid and bssid mask */ - /* XXX: add ah->aid once mac80211 gives this to us */ ath5k_hw_set_associd(ah); /* Set PCU config */ -- cgit v1.2.3 From faa27fae7da900b6d977124410caa3d014676478 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 21:19:06 -0400 Subject: ath9k: move common->debug_mask setting to ath_init_softc() What this means is we can enable now debug prints without requiring CONFIG_ATH9K_DEBUG. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 5 ----- drivers/net/wireless/ath/ath9k/main.c | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 25ae88ebdfac..84f44269de47 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -23,9 +23,6 @@ #define REG_READ_D(_ah, _reg) \ ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) -static unsigned int ath9k_debug = ATH_DBG_DEFAULT; -module_param_named(debug, ath9k_debug, uint, 0); - static struct dentry *ath9k_debugfs_root; static int ath9k_debugfs_open(struct inode *inode, struct file *file) @@ -565,8 +562,6 @@ int ath9k_init_debug(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath_softc *sc = (struct ath_softc *) common->priv; - common->debug_mask = ath9k_debug; - if (!ath9k_debugfs_root) return -ENOENT; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 86374ad9313c..7f90cb872a69 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -29,6 +29,10 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); +static unsigned int ath9k_debug = ATH_DBG_DEFAULT; +module_param_named(debug, ath9k_debug, uint, 0); +MODULE_PARM_DESC(ath9k_debug, "Debugging mask"); + /* We use the hw_value as an index into our private channel structure */ #define CHAN2G(_freq, _idx) { \ @@ -1637,6 +1641,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, common->ah = ah; common->hw = sc->hw; common->priv = sc; + common->debug_mask = ath9k_debug; /* * Cache line size is used to size and align various -- cgit v1.2.3 From 211f5859af951788a3fe4752142a5e9047afa5d8 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 21:19:07 -0400 Subject: ath9k: initialize hw prior to debugfs debugfs uses the hardware for several debugfs files as such the hardware must be initialized and available prior to its usage. The same applies to when we free the hw structs -- free debufs file entries prior to free'ing the hardware. Reported-by: Vasanthakumar Thiagarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 6 ++++++ drivers/net/wireless/ath/ath9k/hw.c | 11 ++++++++++- drivers/net/wireless/ath/ath9k/main.c | 28 ++++++++++++++-------------- 3 files changed, 30 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index b6cd752df839..5e19a7330d39 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -23,6 +23,11 @@ static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +enum ath_device_state { + ATH_HW_UNAVAILABLE, + ATH_HW_INITIALIZED, +}; + struct reg_dmn_pair_mapping { u16 regDmnEnum; u16 reg_5ghz_ctl; @@ -59,6 +64,7 @@ struct ath_common { void *priv; struct ieee80211_hw *hw; int debug_mask; + enum ath_device_state state; u16 cachelsz; u16 curaid; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 692fd1dd909e..cab17c6c8a37 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -999,6 +999,8 @@ int ath9k_hw_init(struct ath_hw *ah) ath9k_init_nfcal_hist_buffer(ah); + common->state = ATH_HW_INITIALIZED; + return 0; } @@ -1239,11 +1241,18 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid) void ath9k_hw_detach(struct ath_hw *ah) { + struct ath_common *common = ath9k_hw_common(ah); + + if (common->state <= ATH_HW_INITIALIZED) + goto free_hw; + if (!AR_SREV_9100(ah)) ath9k_hw_ani_disable(ah); - ath9k_hw_rf_free(ah); ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + +free_hw: + ath9k_hw_rf_free(ah); kfree(ah); ah = NULL; } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7f90cb872a69..0fe915acd21e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1365,8 +1365,8 @@ void ath_detach(struct ath_softc *sc) ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); - ath9k_hw_detach(ah); ath9k_exit_debug(ah); + ath9k_hw_detach(ah); sc->sc_ah = NULL; } @@ -1626,10 +1626,8 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, (unsigned long)sc); ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); - if (!ah) { - r = -ENOMEM; - goto bad_no_ah; - } + if (!ah) + return -ENOMEM; ah->hw_version.devid = devid; ah->hw_version.subsysid = subsysid; @@ -1651,15 +1649,18 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, /* XXX assert csz is non-zero */ common->cachelsz = csz << 2; /* convert to bytes */ - if (ath9k_init_debug(ah) < 0) - dev_err(sc->dev, "Unable to create debugfs files\n"); - r = ath9k_hw_init(ah); if (r) { ath_print(common, ATH_DBG_FATAL, "Unable to initialize hardware; " "initialization status: %d\n", r); - goto bad; + goto bad_free_hw; + } + + if (ath9k_init_debug(ah) < 0) { + ath_print(common, ATH_DBG_FATAL, + "Unable to create debugfs files\n"); + goto bad_free_hw; } /* Get the hardware key cache size. */ @@ -1848,12 +1849,11 @@ bad2: for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); -bad: + + ath9k_exit_debug(ah); +bad_free_hw: ath9k_hw_detach(ah); -bad_no_ah: - ath9k_exit_debug(sc->sc_ah); sc->sc_ah = NULL; - return r; } @@ -1966,8 +1966,8 @@ error_attach: if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); - ath9k_hw_detach(ah); ath9k_exit_debug(ah); + ath9k_hw_detach(ah); sc->sc_ah = NULL; return error; -- cgit v1.2.3 From 7fda16665152851fe65ee73e24afdcaf67acba59 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 21:19:08 -0400 Subject: ath9k: add helper to un-init the hw properly This is used in several places, ensure we do it right in all callers by using a helper. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 0fe915acd21e..e6842dd83ce2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1325,6 +1325,17 @@ void ath_cleanup(struct ath_softc *sc) ieee80211_free_hw(sc->hw); } +static void ath9k_uninit_hw(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + BUG_ON(!ah); + + ath9k_exit_debug(ah); + ath9k_hw_detach(ah); + sc->sc_ah = NULL; +} + void ath_detach(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; @@ -1365,9 +1376,7 @@ void ath_detach(struct ath_softc *sc) ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); - ath9k_exit_debug(ah); - ath9k_hw_detach(ah); - sc->sc_ah = NULL; + ath9k_uninit_hw(sc); } static int ath9k_reg_notifier(struct wiphy *wiphy, @@ -1850,10 +1859,8 @@ bad2: if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); - ath9k_exit_debug(ah); bad_free_hw: - ath9k_hw_detach(ah); - sc->sc_ah = NULL; + ath9k_uninit_hw(sc); return r; } @@ -1966,9 +1973,7 @@ error_attach: if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); - ath9k_exit_debug(ah); - ath9k_hw_detach(ah); - sc->sc_ah = NULL; + ath9k_uninit_hw(sc); return error; } -- cgit v1.2.3 From 2568835cb44d6fe976e977d96aeca73c9fe1642c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 21:19:09 -0400 Subject: ath9k: add a helper to clean the core driver upon module unload The core driver needs to be stopped and then as a last step the hardware needs to be stopped and its structure free'd. We do this by moving the core driver cleanup to a new helper ath_clean_core() and have ath_cleanup() call it. Only as a last step does ath_cleanup() now free the hw. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e6842dd83ce2..39b278053056 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1313,16 +1313,21 @@ static void ath_start_rfkill_poll(struct ath_softc *sc) wiphy_rfkill_start_polling(sc->hw->wiphy); } +static void ath_clean_core(struct ath_softc *sc); +static void ath9k_uninit_hw(struct ath_softc *sc); + void ath_cleanup(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - ath_detach(sc); + ath_clean_core(sc); free_irq(sc->irq, sc); ath_bus_cleanup(common); kfree(sc->sec_wiphy); ieee80211_free_hw(sc->hw); + + ath9k_uninit_hw(sc); } static void ath9k_uninit_hw(struct ath_softc *sc) @@ -1336,7 +1341,7 @@ static void ath9k_uninit_hw(struct ath_softc *sc) sc->sc_ah = NULL; } -void ath_detach(struct ath_softc *sc) +static void ath_clean_core(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; struct ath_hw *ah = sc->sc_ah; @@ -1375,7 +1380,11 @@ void ath_detach(struct ath_softc *sc) if ((sc->btcoex.no_stomp_timer) && ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); +} +void ath_detach(struct ath_softc *sc) +{ + ath_clean_core(sc); ath9k_uninit_hw(sc); } -- cgit v1.2.3 From bd96d3909549a0c09388987810e3e81397b500a9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 21:19:10 -0400 Subject: ath9k: move ath_cleanup() below helpers to avoid forward declarations This should fix the oops which occurs during module unload due to the dereferencig of ah upon debugfs exit. IP: [<46412d6b>] 0x46412d6b *pde = 00000000 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC last sysfs file: /sys/class/power_supply/BAT0/energy_full Modules linked in: ath9k(-) ath9k_hw mac80211 ath cfg80211 Pid: 3112, comm: rmmod Not tainted (2.6.32-rc2-wl #101) 9461DUU EIP: 0060:[<46412d6b>] EFLAGS: 00010246 CPU: 0 EIP is at 0x46412d6b EAX: f5870004 EBX: f6700d94 ECX: 00000000 EDX: c14313a7 ESI: f5870000 EDI: fb58ce70 EBP: f6661eb4 ESP: f6661ea8 DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 Process rmmod (pid: 3112, ti=f6660000 task=f6579380 task.ti=f6660000) Stack: fb57e5e5 f5ca5d50 fb58ce70 f6661ebc fb58629a f6661ec8 c11b715e f5ca5da8 <0> f6661ed8 c1223d98 f5ca5da8 f5ca5ddc f6661eec c1223e6f fb58ce70 fb58ce70 <0> c14958a0 f6661f00 c1222edb fb58ce70 fb58ce70 fb58cebc f6661f1c c12243c9 Call Trace: [] ? ath_cleanup+0x35/0x50 [ath9k] [] ? ath_pci_remove+0x1a/0x20 [ath9k] [] ? pci_device_remove+0x1e/0x40 [] ? __device_release_driver+0x58/0xa0 [] ? driver_detach+0x8f/0xa0 [] ? bus_remove_driver+0x7b/0xb0 [] ? driver_unregister+0x49/0x80 [] ? sysfs_remove_file+0x12/0x20 [] ? pci_unregister_driver+0x35/0x90 [] ? ath_pci_exit+0x12/0x20 [ath9k] [] ? ath9k_exit+0x10/0x3d [ath9k] [] ? mutex_unlock+0xd/0x10 [] ? sys_delete_module+0x16f/0x220 [] ? do_munmap+0x23d/0x290 [] ? trace_hardirqs_off_thunk+0xc/0x10 [] ? trace_hardirqs_on_thunk+0xc/0x10 [] ? sysenter_exit+0xf/0x1a [] ? sysenter_do_call+0x12/0x3c Code: Bad EIP value. EIP: [<46412d6b>] 0x46412d6b SS:ESP 0068:f6661ea8 CR2: 0000000046412d6b ---[ end trace 847f3b05ff3dcb19 ]--- Reported-by: Vasanthakumar Thiagarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 39b278053056..c541516a2e9d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1313,23 +1313,6 @@ static void ath_start_rfkill_poll(struct ath_softc *sc) wiphy_rfkill_start_polling(sc->hw->wiphy); } -static void ath_clean_core(struct ath_softc *sc); -static void ath9k_uninit_hw(struct ath_softc *sc); - -void ath_cleanup(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - - ath_clean_core(sc); - free_irq(sc->irq, sc); - ath_bus_cleanup(common); - kfree(sc->sec_wiphy); - ieee80211_free_hw(sc->hw); - - ath9k_uninit_hw(sc); -} - static void ath9k_uninit_hw(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; @@ -1388,6 +1371,20 @@ void ath_detach(struct ath_softc *sc) ath9k_uninit_hw(sc); } +void ath_cleanup(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + + ath_clean_core(sc); + free_irq(sc->irq, sc); + ath_bus_cleanup(common); + kfree(sc->sec_wiphy); + ieee80211_free_hw(sc->hw); + + ath9k_uninit_hw(sc); +} + static int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { -- cgit v1.2.3 From 536b3a7a10c8fd39576a0602bfeca9bbd04658a6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 6 Oct 2009 21:19:11 -0400 Subject: ath9k: rename ath_beaconq_setup() to ath9k_hw_beaconq_setup() And move it to hw code on mac.c where it belongs. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/beacon.c | 12 ------------ drivers/net/wireless/ath/ath9k/mac.c | 13 +++++++++++++ drivers/net/wireless/ath/ath9k/mac.h | 1 + drivers/net/wireless/ath/ath9k/main.c | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 14ff38d1f67c..13dd0202d6b5 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -421,7 +421,6 @@ struct ath_beacon { void ath_beacon_tasklet(unsigned long data); void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); -int ath_beaconq_setup(struct ath_hw *ah); int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif); void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 54be876639a0..b10c884f2933 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -242,18 +242,6 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); } -int ath_beaconq_setup(struct ath_hw *ah) -{ - struct ath9k_tx_queue_info qi; - - memset(&qi, 0, sizeof(qi)); - qi.tqi_aifs = 1; - qi.tqi_cwmin = 0; - qi.tqi_cwmax = 0; - /* NB: don't enable any interrupts */ - return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); -} - int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) { struct ath_softc *sc = aphy->sc; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index e2c1ba3ea483..46466ffebcb0 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -1018,3 +1018,16 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah) #undef AH_RX_STOP_DMA_TIMEOUT } EXPORT_SYMBOL(ath9k_hw_stopdmarecv); + +int ath9k_hw_beaconq_setup(struct ath_hw *ah) +{ + struct ath9k_tx_queue_info qi; + + memset(&qi, 0, sizeof(qi)); + qi.tqi_aifs = 1; + qi.tqi_cwmin = 0; + qi.tqi_cwmax = 0; + /* NB: don't enable any interrupts */ + return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); +} +EXPORT_SYMBOL(ath9k_hw_beaconq_setup); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 9ab343151be4..fefb65dafb1c 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -667,5 +667,6 @@ void ath9k_hw_rxena(struct ath_hw *ah); void ath9k_hw_startpcureceive(struct ath_hw *ah); void ath9k_hw_stoppcurecv(struct ath_hw *ah); bool ath9k_hw_stopdmarecv(struct ath_hw *ah); +int ath9k_hw_beaconq_setup(struct ath_hw *ah); #endif /* MAC_H */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c541516a2e9d..36af6f32652a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1709,7 +1709,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, * priority. Note that the hal handles reseting * these queues at the needed time. */ - sc->beacon.beaconq = ath_beaconq_setup(ah); + sc->beacon.beaconq = ath9k_hw_beaconq_setup(ah); if (sc->beacon.beaconq == -1) { ath_print(common, ATH_DBG_FATAL, "Unable to setup a beacon xmit queue\n"); -- cgit v1.2.3 From 63f275df64dc69a46bbc21e6a68d5506d2da9c51 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 6 Oct 2009 19:20:28 -0700 Subject: libertas: Use lbs_is_cmd_allowed() check in command handling routines. lbs_is_cmd_allowed() check is added in __lbs_cmd_async() and lbs_prepare_and_send_command(). The check is removed from other places. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 34 ++++++++ drivers/net/wireless/libertas/debugfs.c | 46 ----------- drivers/net/wireless/libertas/decl.h | 1 - drivers/net/wireless/libertas/scan.c | 11 --- drivers/net/wireless/libertas/wext.c | 133 -------------------------------- 5 files changed, 34 insertions(+), 191 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 3a3e8947e84a..0fb312576b8d 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -74,6 +74,30 @@ static u8 is_command_allowed_in_ps(u16 cmd) return 0; } +/** + * @brief This function checks if the command is allowed. + * + * @param priv A pointer to lbs_private structure + * @return allowed or not allowed. + */ + +static int lbs_is_cmd_allowed(struct lbs_private *priv) +{ + int ret = 1; + + lbs_deb_enter(LBS_DEB_CMD); + + if (!priv->is_auto_deep_sleep_enabled) { + if (priv->is_deep_sleep) { + lbs_deb_cmd("command not allowed in deep sleep\n"); + ret = 0; + } + } + + lbs_deb_leave(LBS_DEB_CMD); + return ret; +} + /** * @brief Updates the hardware details like MAC address and regulatory region * @@ -1452,6 +1476,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, goto done; } + if (!lbs_is_cmd_allowed(priv)) { + ret = -EBUSY; + goto done; + } + cmdnode = lbs_get_cmd_ctrl_node(priv); if (cmdnode == NULL) { @@ -2104,6 +2133,11 @@ static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, goto done; } + if (!lbs_is_cmd_allowed(priv)) { + cmdnode = ERR_PTR(-EBUSY); + goto done; + } + cmdnode = lbs_get_cmd_ctrl_node(priv); if (cmdnode == NULL) { lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 8a7e9319c9e5..893a55ca344a 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -117,11 +117,6 @@ static ssize_t lbs_sleepparams_write(struct file *file, if (!buf) return -ENOMEM; - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - goto out_unlock; - } - buf_size = min(count, len - 1); if (copy_from_user(buf, user_buf, buf_size)) { ret = -EFAULT; @@ -162,11 +157,6 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf, if (!buf) return -ENOMEM; - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - goto out_unlock; - } - ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp); if (ret) goto out_unlock; @@ -233,9 +223,6 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask, u8 freq; int events = 0; - if (!lbs_is_cmd_allowed(priv)) - return -EBUSY; - buf = (char *)get_zeroed_page(GFP_KERNEL); if (!buf) return -ENOMEM; @@ -288,9 +275,6 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, char *buf; int ret; - if (!lbs_is_cmd_allowed(priv)) - return -EBUSY; - buf = (char *)get_zeroed_page(GFP_KERNEL); if (!buf) return -ENOMEM; @@ -460,11 +444,6 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, if (!buf) return -ENOMEM; - if (!lbs_is_cmd_allowed(priv)) { - free_page(addr); - return -EBUSY; - } - offval.offset = priv->mac_offset; offval.value = 0; @@ -517,11 +496,6 @@ static ssize_t lbs_wrmac_write(struct file *file, if (!buf) return -ENOMEM; - if (!lbs_is_cmd_allowed(priv)) { - res = -EBUSY; - goto out_unlock; - } - buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { res = -EFAULT; @@ -558,11 +532,6 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf, if (!buf) return -ENOMEM; - if (!lbs_is_cmd_allowed(priv)) { - free_page(addr); - return -EBUSY; - } - offval.offset = priv->bbp_offset; offval.value = 0; @@ -616,11 +585,6 @@ static ssize_t lbs_wrbbp_write(struct file *file, if (!buf) return -ENOMEM; - if (!lbs_is_cmd_allowed(priv)) { - res = -EBUSY; - goto out_unlock; - } - buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { res = -EFAULT; @@ -657,11 +621,6 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf, if (!buf) return -ENOMEM; - if (!lbs_is_cmd_allowed(priv)) { - free_page(addr); - return -EBUSY; - } - offval.offset = priv->rf_offset; offval.value = 0; @@ -715,11 +674,6 @@ static ssize_t lbs_wrrf_write(struct file *file, if (!buf) return -ENOMEM; - if (!lbs_is_cmd_allowed(priv)) { - res = -EBUSY; - goto out_unlock; - } - buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { res = -EFAULT; diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 44f0b248ace9..fb91c3639fc1 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -34,7 +34,6 @@ int lbs_process_event(struct lbs_private *priv, u32 event); void lbs_queue_event(struct lbs_private *priv, u32 event); void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep); -int lbs_is_cmd_allowed(struct lbs_private *priv); int lbs_enter_auto_deep_sleep(struct lbs_private *priv); int lbs_exit_auto_deep_sleep(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index e468e155e8be..6c95af3023cc 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -950,11 +950,6 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - goto out; - } - if (!priv->radio_on) { ret = -EINVAL; goto out; @@ -1022,12 +1017,6 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - err = -EBUSY; - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err); - return err; - } - /* iwlist should wait until the current scan is finished */ if (priv->scan_channel) return -EAGAIN; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 38a451edb703..69dd19bf9558 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -45,32 +45,6 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv) priv->pending_assoc_req = NULL; } -/** - * @brief This function checks if the command is allowed. - * - * @param priv A pointer to lbs_private structure - * @return allowed or not allowed. - */ - -int lbs_is_cmd_allowed(struct lbs_private *priv) -{ - int ret = 1; - - lbs_deb_enter(LBS_DEB_WEXT); - - if (!priv->is_auto_deep_sleep_enabled) { - if (priv->is_deep_sleep) { - lbs_deb_wext("IOCTLS called when station" - "is in deep sleep\n"); - ret = 0; - } - } - - lbs_deb_leave(LBS_DEB_WEXT); - return ret; -} - - /** * @brief Find the channel frequency power info with specific channel * @@ -193,11 +167,6 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - lbs_deb_leave(LBS_DEB_WEXT); - return -EBUSY; - } - cfp = lbs_find_cfp_by_band_and_channel(priv, 0, priv->curbssparams.channel); @@ -308,12 +277,6 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; - } - if (vwrq->disabled) val = MRVDRV_RTS_MAX_VALUE; @@ -335,11 +298,6 @@ static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - goto out; - } - ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val); if (ret) goto out; @@ -362,12 +320,6 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; - } - if (vwrq->disabled) val = MRVDRV_FRAG_MAX_VALUE; @@ -389,11 +341,6 @@ static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - goto out; - } - ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val); if (ret) goto out; @@ -443,11 +390,6 @@ static int lbs_get_txpow(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - goto out; - } - if (!priv->radio_on) { lbs_deb_wext("tx power off\n"); vwrq->value = 0; @@ -481,11 +423,6 @@ static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - goto out; - } - if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) return -EOPNOTSUPP; @@ -534,11 +471,6 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - goto out; - } - vwrq->disabled = 0; if (vwrq->flags & IW_RETRY_LONG) { @@ -907,9 +839,6 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) - return NULL; - priv->wstats.status = priv->mode; /* If we're not associated, all quality values are meaningless */ @@ -1010,12 +939,6 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; - } - mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1125,11 +1048,6 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - goto out; - } - lbs_deb_wext("vwrq->value %d\n", vwrq->value); lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed); @@ -1188,11 +1106,6 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - lbs_deb_leave(LBS_DEB_WEXT); - return -EBUSY; - } - if (priv->connect_status == LBS_CONNECTED) { vwrq->value = priv->cur_rate * 500000; @@ -1219,11 +1132,6 @@ static int lbs_set_mode(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - goto out; - } - if ( (*uwrq != IW_MODE_ADHOC) && (*uwrq != IW_MODE_INFRA) && (*uwrq != IW_MODE_AUTO)) { @@ -1465,12 +1373,6 @@ static int lbs_set_encode(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; - } - mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1654,12 +1556,6 @@ static int lbs_set_encodeext(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; - } - mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1872,12 +1768,6 @@ static int lbs_set_auth(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; - } - mutex_lock(&priv->lock); assoc_req = lbs_get_association_request(priv); if (!assoc_req) { @@ -1980,12 +1870,6 @@ static int lbs_get_auth(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; - } - switch (dwrq->flags & IW_AUTH_INDEX) { case IW_AUTH_KEY_MGMT: dwrq->value = priv->secinfo.key_mgmt; @@ -2028,11 +1912,6 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - goto out; - } - if (vwrq->disabled) { lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0); goto out; @@ -2152,12 +2031,6 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; - } - if (!priv->radio_on) { ret = -EINVAL; goto out; @@ -2285,12 +2158,6 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); - if (!lbs_is_cmd_allowed(priv)) { - ret = -EBUSY; - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; - } - if (!priv->radio_on) return -EINVAL; -- cgit v1.2.3 From 82e62926ab31d5a535f85be36d6621635ee34c3c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 7 Oct 2009 09:10:33 +0200 Subject: libertas: remove extraneous select FW_LOADER As kindly pointed out by Andrey Yurovsky, CONFIG_LIBERTAS already selects FW_LOADER. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig index 3e6c922c2f44..77aec7cd03ec 100644 --- a/drivers/net/wireless/libertas/Kconfig +++ b/drivers/net/wireless/libertas/Kconfig @@ -17,7 +17,6 @@ config LIBERTAS_USB config LIBERTAS_CS tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" depends on LIBERTAS && PCMCIA - select FW_LOADER ---help--- A driver for Marvell Libertas 8385 CompactFlash devices. -- cgit v1.2.3 From af1fc67c1a803d303b59e54be45fe3329103e7db Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 8 Oct 2009 01:00:18 -0400 Subject: ath9k: use right parameter for MODULE_PARM_DESC() for debug Reported-by: sujith.manoharan@atheros.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 36af6f32652a..69cf702b18c2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -31,7 +31,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); static unsigned int ath9k_debug = ATH_DBG_DEFAULT; module_param_named(debug, ath9k_debug, uint, 0); -MODULE_PARM_DESC(ath9k_debug, "Debugging mask"); +MODULE_PARM_DESC(debug, "Debugging mask"); /* We use the hw_value as an index into our private channel structure */ -- cgit v1.2.3 From 7891849e5a79eb1e6ddc12abf75a69981f567b98 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 8 Oct 2009 16:46:09 -0400 Subject: libertas: remove double assignment of dev->netdev_ops This came in through the patch titled: libertas: first stab at cfg80211 support I only noticed it because it breaks compat-wireless :) Signed-off-by: Luis R. Rodriguez Acked-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e6da1dfa8131..87bfd17b9c8c 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1276,7 +1276,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) goto err_adapter; } - dev->netdev_ops = &lbs_netdev_ops; dev->ieee80211_ptr = wdev; dev->ml_priv = priv; SET_NETDEV_DEV(dev, dmdev); -- cgit v1.2.3 From 5718f5009b114372fc237254906812c0d6e57ab1 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Fri, 9 Oct 2009 09:10:34 +0200 Subject: libertas: depend on CONFIG_CFG80211 Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig index 77aec7cd03ec..8f8d75b61ea9 100644 --- a/drivers/net/wireless/libertas/Kconfig +++ b/drivers/net/wireless/libertas/Kconfig @@ -1,6 +1,6 @@ config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" - depends on WLAN_80211 + depends on WLAN_80211 && CFG80211 select WIRELESS_EXT select WEXT_SPY select LIB80211 -- cgit v1.2.3 From eab2ec83dbf0e32e28f3108f302ffdaa225d4cce Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 9 Oct 2009 18:17:05 +0200 Subject: wireless: make wireless drivers select core It is somewhat non-sensical to allow selecting wireless drivers without showing wireless core code options, and since the wext refactoring this has made it possible to generate configurations that will not build. Avoid this and make wireless drivers select the wireless options. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 18255fb28d17..85f8bf4112c1 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -5,6 +5,7 @@ menuconfig WLAN bool "Wireless LAN" depends on !S390 + select WIRELESS default y ---help--- This section contains all the pre 802.11 and 802.11 wireless -- cgit v1.2.3 From 439ca3a4b1997858a34ee414856511fe7a282553 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sat, 17 Oct 2009 09:09:35 +0000 Subject: iwmc3200wifi: select IWMC3200TOP in Kconfig iwmc3200wifi requires iwmc3200top for its operation Signed-off-by: Tomas Winkler Acked-by: Zhu Yi Signed-off-by: David S. Miller --- drivers/net/wireless/iwmc3200wifi/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig index c25a04371ca8..9606b3100fde 100644 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -3,6 +3,7 @@ config IWM depends on MMC && WLAN_80211 && EXPERIMENTAL depends on CFG80211 select FW_LOADER + select IWMC3200TOP help The Intel Wireless Multicomm 3200 hardware is a combo card with GPS, Bluetooth, WiMax and 802.11 radios. It -- cgit v1.2.3 From b57df129aaf65819f4eb80c2a5be3765509e9d23 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 7 Oct 2009 16:22:18 -0400 Subject: ath9k_hw: run the carrier leakage calibration fix for ar9271 as well This is required for the ar9271 hardware as well. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index f46bd05df443..7aa3d1d8ec6f 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -1070,6 +1070,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, } EXPORT_SYMBOL(ath9k_hw_calibrate); +/* Carrier leakage Calibration fix */ static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); @@ -1115,7 +1116,7 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); - if (AR_SREV_9285_12_OR_LATER(ah)) { + if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) { if (!ar9285_clc(ah, chan)) return false; } else { -- cgit v1.2.3 From 6226811f4eec35c509b931ac900ac074336103f5 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 7 Oct 2009 16:22:19 -0400 Subject: ath9k_hw: run ath9k_hw_9271_pa_cal() initial calibration The PA calibration for ar9271 ath9k_hw_9271_pa_cal() can run during reset or initial calibration, update the PA calibration to account for that and initialize PA calibration variables for both conditions. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 7aa3d1d8ec6f..551f8801459f 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -813,7 +813,7 @@ static void ath9k_olc_temp_compensation(struct ath_hw *ah) } } -static void ath9k_hw_9271_pa_cal(struct ath_hw *ah) +static void ath9k_hw_9271_pa_cal(struct ath_hw *ah, bool is_reset) { u32 regVal; unsigned int i; @@ -889,10 +889,19 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah) REG_WRITE(ah, 0x7834, regVal); } - /* Empirical offset correction */ -#if 0 - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0x20); -#endif + regVal = (regVal >>20) & 0x7f; + + /* Update PA cal info */ + if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) { + if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) + ah->pacal_info.max_skipcount = + 2 * ah->pacal_info.max_skipcount; + ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; + } else { + ah->pacal_info.max_skipcount = 1; + ah->pacal_info.skipcount = 0; + ah->pacal_info.prev_offset = regVal; + } regVal = REG_READ(ah, 0x7834); regVal |= 0x1; @@ -1043,7 +1052,7 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, if (longcal) { /* Do periodic PAOffset Cal */ if (AR_SREV_9271(ah)) - ath9k_hw_9271_pa_cal(ah); + ath9k_hw_9271_pa_cal(ah, false); else if (AR_SREV_9285_11_OR_LATER(ah)) { if (!ah->pacal_info.skipcount) ath9k_hw_9285_pa_cal(ah, false); @@ -1152,7 +1161,9 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) } /* Do PA Calibration */ - if (AR_SREV_9285_11_OR_LATER(ah)) + if (AR_SREV_9271(ah)) + ath9k_hw_9271_pa_cal(ah, true); + else if (AR_SREV_9285_11_OR_LATER(ah)) ath9k_hw_9285_pa_cal(ah, true); /* Do NF Calibration after DC offset and other calibrations */ -- cgit v1.2.3 From 3414fc3f527ce74cfca543c37bcb52c8e63b915e Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Wed, 7 Oct 2009 22:23:32 +0100 Subject: orinoco: use cfg80211 ethtool ops Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/hw.c | 33 ++++++++++++++++++++++++--------- drivers/net/wireless/orinoco/hw.h | 3 ++- drivers/net/wireless/orinoco/main.c | 33 ++++++--------------------------- drivers/net/wireless/orinoco/orinoco.h | 1 - 4 files changed, 32 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 359652d35e63..404830f47ab2 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -60,8 +60,15 @@ static inline fwtype_t determine_firmware_type(struct comp_id *nic_id) /* Set priv->firmware type, determine firmware properties * This function can be called before we have registerred with netdev, * so all errors go out with dev_* rather than printk + * + * If non-NULL stores a firmware description in fw_name. + * If non-NULL stores a HW version in hw_ver + * + * These are output via generic cfg80211 ethtool support. */ -int determine_fw_capabilities(struct orinoco_private *priv) +int determine_fw_capabilities(struct orinoco_private *priv, + char *fw_name, size_t fw_name_len, + u32 *hw_ver) { struct device *dev = priv->dev; hermes_t *hw = &priv->hw; @@ -85,6 +92,12 @@ int determine_fw_capabilities(struct orinoco_private *priv) dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n", nic_id.id, nic_id.variant, nic_id.major, nic_id.minor); + if (hw_ver) + *hw_ver = (((nic_id.id & 0xff) << 24) | + ((nic_id.variant & 0xff) << 16) | + ((nic_id.major & 0xff) << 8) | + (nic_id.minor & 0xff)); + priv->firmware_type = determine_firmware_type(&nic_id); /* Get the firmware version */ @@ -135,8 +148,9 @@ int determine_fw_capabilities(struct orinoco_private *priv) case FIRMWARE_TYPE_AGERE: /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */ - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor); + if (fw_name) + snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d", + sta_id.major, sta_id.minor); firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor; @@ -185,8 +199,8 @@ int determine_fw_capabilities(struct orinoco_private *priv) tmp[SYMBOL_MAX_VER_LEN] = '\0'; } - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Symbol %s", tmp); + if (fw_name) + snprintf(fw_name, fw_name_len, "Symbol %s", tmp); priv->has_ibss = (firmver >= 0x20000); priv->has_wep = (firmver >= 0x15012); @@ -224,9 +238,9 @@ int determine_fw_capabilities(struct orinoco_private *priv) * different and less well tested */ /* D-Link MAC : 00:40:05:* */ /* Addtron MAC : 00:90:D1:* */ - snprintf(priv->fw_name, sizeof(priv->fw_name) - 1, - "Intersil %d.%d.%d", sta_id.major, sta_id.minor, - sta_id.variant); + if (fw_name) + snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d", + sta_id.major, sta_id.minor, sta_id.variant); firmver = ((unsigned long)sta_id.major << 16) | ((unsigned long)sta_id.minor << 8) | sta_id.variant; @@ -245,7 +259,8 @@ int determine_fw_capabilities(struct orinoco_private *priv) } break; } - dev_info(dev, "Firmware determined as %s\n", priv->fw_name); + if (fw_name) + dev_info(dev, "Firmware determined as %s\n", fw_name); return 0; } diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 8df6e8752be6..e2f7fdc4d45a 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h @@ -24,7 +24,8 @@ struct orinoco_private; struct dev_addr_list; -int determine_fw_capabilities(struct orinoco_private *priv); +int determine_fw_capabilities(struct orinoco_private *priv, char *fw_name, + size_t fw_name_len, u32 *hw_ver); int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr); int orinoco_hw_allocate_fid(struct orinoco_private *priv); int orinoco_get_bitratemode(int bitrate, int automatic); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 5fdc59c594f2..753a1804eee7 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -83,7 +83,6 @@ #include #include #include -#include #include #include #include @@ -162,8 +161,6 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; | HERMES_EV_WTERR | HERMES_EV_INFO \ | HERMES_EV_INFDROP) -static const struct ethtool_ops orinoco_ethtool_ops; - /********************************************************************/ /* Data types */ /********************************************************************/ @@ -1994,7 +1991,9 @@ int orinoco_init(struct orinoco_private *priv) goto out; } - err = determine_fw_capabilities(priv); + err = determine_fw_capabilities(priv, wiphy->fw_version, + sizeof(wiphy->fw_version), + &wiphy->hw_version); if (err != 0) { dev_err(dev, "Incompatible firmware, aborting\n"); goto out; @@ -2010,7 +2009,9 @@ int orinoco_init(struct orinoco_private *priv) priv->do_fw_download = 0; /* Check firmware version again */ - err = determine_fw_capabilities(priv); + err = determine_fw_capabilities(priv, wiphy->fw_version, + sizeof(wiphy->fw_version), + &wiphy->hw_version); if (err != 0) { dev_err(dev, "Incompatible firmware, aborting\n"); goto out; @@ -2212,7 +2213,6 @@ int orinoco_if_add(struct orinoco_private *priv, dev->ieee80211_ptr = wdev; dev->netdev_ops = &orinoco_netdev_ops; dev->watchdog_timeo = HZ; /* 1 second timeout */ - dev->ethtool_ops = &orinoco_ethtool_ops; dev->wireless_handlers = &orinoco_handler_def; #ifdef WIRELESS_SPY dev->wireless_data = &priv->wireless_data; @@ -2349,27 +2349,6 @@ void orinoco_down(struct orinoco_private *priv) } EXPORT_SYMBOL(orinoco_down); -static void orinoco_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct orinoco_private *priv = ndev_priv(dev); - - strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1); - strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); - strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1); - if (dev->dev.parent) - strncpy(info->bus_info, dev_name(dev->dev.parent), - sizeof(info->bus_info) - 1); - else - snprintf(info->bus_info, sizeof(info->bus_info) - 1, - "PCMCIA %p", priv->hw.iobase); -} - -static const struct ethtool_ops orinoco_ethtool_ops = { - .get_drvinfo = orinoco_get_drvinfo, - .get_link = ethtool_op_get_link, -}; - /********************************************************************/ /* Module initialization */ /********************************************************************/ diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 9ac6f1dda4b0..665ef56f8382 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -93,7 +93,6 @@ struct orinoco_private { /* Capabilities of the hardware/firmware */ fwtype_t firmware_type; - char fw_name[32]; int ibss_port; int nicbuf_size; u16 channel_mask; -- cgit v1.2.3 From 9d565973deb09479de5eed7a5b6594428dc49dde Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 8 Oct 2009 21:56:17 +0300 Subject: wl1271: remove unecessary qual parameter from rx status The qual element in ieee80211_rx_status is not used anymore, so we don't need to set it in the wl1271_rx_status() function. This saves a bit of time in the RX path. Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_rx.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index ad8b6904c5eb..5d8d40158981 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -91,12 +91,6 @@ static void wl1271_rx_status(struct wl1271 *wl, */ status->signal = desc->rssi; - /* FIXME: Should this be optimized? */ - status->qual = (desc->rssi - WL1271_RX_MIN_RSSI) * 100 / - (WL1271_RX_MAX_RSSI - WL1271_RX_MIN_RSSI); - status->qual = min(status->qual, 100); - status->qual = max(status->qual, 0); - /* * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we * need to divide by two for now, but TI has been discussing about -- cgit v1.2.3 From 3b4be9e08abd8c390d13001f5dd55f64afa5ab93 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:18 +0300 Subject: wl1271: Correction to TX block allocation calculation Correct the TX path implementation to allocate sufficient blocks in the firmware for TX packets. Signed-off-by: Juuso Oikarinen Reviewed-by: Kalle Valo Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index ff221258b941..0c19688f4405 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -58,7 +58,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) /* approximate the number of blocks required for this packet in the firmware */ /* FIXME: try to figure out what is done here and make it cleaner */ - total_blocks = (skb->len) >> TX_HW_BLOCK_SHIFT_DIV; + total_blocks = (total_len) >> TX_HW_BLOCK_SHIFT_DIV; excluded = (total_blocks << 2) + (skb->len & 0xff) + 34; total_blocks += (excluded > 252) ? 2 : 1; total_blocks += TX_HW_BLOCK_SPARE; -- cgit v1.2.3 From ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:19 +0300 Subject: wl1271: Security sequence number handling for TX (for WPA) Add security sequence number handling to the driver TX data path needed by WPA. Signed-off-by: Juuso Oikarinen Reviewed-by: Kalle Valo Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 5 +++++ drivers/net/wireless/wl12xx/wl1271_cmd.c | 11 +++++++++-- drivers/net/wireless/wl12xx/wl1271_cmd.h | 3 ++- drivers/net/wireless/wl12xx/wl1271_main.c | 13 +++++++++++-- drivers/net/wireless/wl12xx/wl1271_tx.c | 11 +++++++++++ 5 files changed, 38 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 55818f94017b..e575dcc9df27 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -337,6 +337,11 @@ struct wl1271 { /* Pending TX frames */ struct sk_buff *tx_frames[16]; + /* Security sequence number counters */ + u8 tx_security_last_seq; + u16 tx_security_seq_16; + u32 tx_security_seq_32; + /* FW Rx counter */ u32 rx_counter; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 2a4351ff54dc..1ee1b2b4dfa2 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -228,6 +228,10 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; + /* reset TX security counters */ + wl->tx_security_last_seq = 0; + wl->tx_security_seq_16 = 0; + wl->tx_security_seq_32 = 0; ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); if (ret < 0) { @@ -759,7 +763,8 @@ out: } int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, const u8 *addr) + u8 key_size, const u8 *key, const u8 *addr, + u32 tx_seq_32, u16 tx_seq_16) { struct wl1271_cmd_set_keys *cmd; int ret = 0; @@ -777,12 +782,14 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, cmd->key_size = key_size; cmd->key_type = key_type; + cmd->ac_seq_num16[0] = tx_seq_16; + cmd->ac_seq_num32[0] = tx_seq_32; + /* we have only one SSID profile */ cmd->ssid_profile = 0; cmd->id = id; - /* FIXME: this is from wl1251, needs to be checked */ if (key_type == KEY_TKIP) { /* * We get the key in the following form: diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 951a8447a516..7c4d3aaaa819 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -49,7 +49,8 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len); int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, const u8 *addr); + u8 key_size, const u8 *key, const u8 *addr, + u32 tx_seq_32, u16 tx_seq_16); enum wl1271_commands { CMD_INTERROGATE = 1, /*use this to read information elements*/ diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 27298b19d5bd..bedd19b57499 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -592,6 +592,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->tx_blocks_available = 0; wl->tx_results_count = 0; wl->tx_packets_count = 0; + wl->tx_security_last_seq = 0; + wl->tx_security_seq_16 = 0; + wl->tx_security_seq_32 = 0; wl->time_offset = 0; wl->session_counter = 0; for (i = 0; i < NUM_TX_QUEUES; i++) @@ -823,6 +826,8 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct wl1271 *wl = hw->priv; const u8 *addr; int ret; + u32 tx_seq_32 = 0; + u16 tx_seq_16 = 0; u8 key_type; static const u8 bcast_addr[ETH_ALEN] = @@ -861,11 +866,15 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key_type = KEY_TKIP; key_conf->hw_key_idx = key_conf->keyidx; + tx_seq_32 = wl->tx_security_seq_32; + tx_seq_16 = wl->tx_security_seq_16; break; case ALG_CCMP: key_type = KEY_AES; key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + tx_seq_32 = wl->tx_security_seq_32; + tx_seq_16 = wl->tx_security_seq_16; break; default: wl1271_error("Unknown key algo 0x%x", key_conf->alg); @@ -879,7 +888,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE, key_conf->keyidx, key_type, key_conf->keylen, key_conf->key, - addr); + addr, tx_seq_32, tx_seq_16); if (ret < 0) { wl1271_error("Could not add or replace key"); goto out_sleep; @@ -890,7 +899,7 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = wl1271_cmd_set_key(wl, KEY_REMOVE, key_conf->keyidx, key_type, key_conf->keylen, key_conf->key, - addr); + addr, 0, 0); if (ret < 0) { wl1271_error("Could not remove key"); goto out_sleep; diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 0c19688f4405..162f0267a20b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -258,6 +258,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, struct ieee80211_tx_info *info; struct sk_buff *skb; u32 header_len; + u16 seq; int id = result->id; /* check for id legality */ @@ -284,6 +285,16 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, /* info->status.retry_count = result->ack_failures; */ wl->stats.retry_count += result->ack_failures; + /* update security sequence number */ + seq = wl->tx_security_seq_16 + + (result->lsb_security_sequence_number - + wl->tx_security_last_seq); + wl->tx_security_last_seq = result->lsb_security_sequence_number; + + if (seq < wl->tx_security_seq_16) + wl->tx_security_seq_32++; + wl->tx_security_seq_16 = seq; + /* get header len */ if (info->control.hw_key && info->control.hw_key->alg == ALG_TKIP) -- cgit v1.2.3 From 1e2b79761d551c545225e1fa6e7d144f7e804898 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:20 +0300 Subject: wl1271: Correct TKIP header space handling in TX path Correct the position to which TKIP header space is appended for TX packets. Signed-off-by: Juuso Oikarinen Reviewed-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 9 +++------ drivers/net/wireless/wl12xx/wl1271_tx.c | 27 +++++++++++++++++---------- 2 files changed, 20 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index bedd19b57499..3d629daf2246 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1160,12 +1160,9 @@ static int wl1271_register_hw(struct wl1271 *wl) static int wl1271_init_ieee80211(struct wl1271 *wl) { - /* - * The tx descriptor buffer and the TKIP space. - * - * FIXME: add correct 1271 descriptor size - */ - wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE; + /* The tx descriptor buffer and the TKIP space. */ + wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE + + sizeof(struct wl1271_tx_hw_descr); /* unit us */ /* FIXME: find a proper value */ diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 162f0267a20b..1ad1bc3f152e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -92,6 +92,14 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, desc = (struct wl1271_tx_hw_descr *) skb->data; + /* relocate space for security header */ + if (extra) { + void *framestart = skb->data + sizeof(*desc); + u16 fc = *(u16 *)(framestart + extra); + int hdrlen = ieee80211_hdrlen(fc); + memmove(framestart, framestart + extra, hdrlen); + } + /* configure packet life time */ desc->start_time = jiffies_to_usecs(jiffies) - wl->time_offset; desc->life_time = TX_HW_MGMT_PKT_LIFETIME_TU; @@ -257,7 +265,6 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, struct ieee80211_tx_info *info; struct sk_buff *skb; - u32 header_len; u16 seq; int id = result->id; @@ -295,22 +302,22 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, wl->tx_security_seq_32++; wl->tx_security_seq_16 = seq; - /* get header len */ + /* remove private header from packet */ + skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); + + /* remove TKIP header space if present */ if (info->control.hw_key && - info->control.hw_key->alg == ALG_TKIP) - header_len = WL1271_TKIP_IV_SPACE + - sizeof(struct wl1271_tx_hw_descr); - else - header_len = sizeof(struct wl1271_tx_hw_descr); + info->control.hw_key->alg == ALG_TKIP) { + int hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen); + skb_pull(skb, WL1271_TKIP_IV_SPACE); + } wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" " status 0x%x", result->id, skb, result->ack_failures, result->rate_class_index, result->status); - /* remove private header from packet */ - skb_pull(skb, header_len); - /* return the packet to the stack */ ieee80211_tx_status(wl->hw, skb); wl->tx_frames[result->id] = NULL; -- cgit v1.2.3 From 37b70a81855e4a2e66716804ae55ff717520e7fb Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:21 +0300 Subject: wl1271: Implement delayed entry into ELP Implement delayed entry into ELP. This will promote the following: - Less redundant sleep/wake cycles (better perf) - Avoids known firmware issues with going to ELP too fast after an operation Signed-off-by: Juuso Oikarinen Reviewed-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 1 + drivers/net/wireless/wl12xx/wl1271_main.c | 1 + drivers/net/wireless/wl12xx/wl1271_ps.c | 46 +++++++++++++++++++++---------- drivers/net/wireless/wl12xx/wl1271_ps.h | 2 +- 4 files changed, 35 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index e575dcc9df27..c455dcbae524 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -373,6 +373,7 @@ struct wl1271 { bool elp; struct completion *elp_compl; + struct delayed_work elp_work; /* we can be in psm, but not in elp, we have to differentiate */ bool psm; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 3d629daf2246..cc5c3285deac 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1226,6 +1226,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) skb_queue_head_init(&wl->tx_queue); INIT_WORK(&wl->filter_work, wl1271_filter_work); + INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); wl->channel = WL1271_DEFAULT_CHANNEL; wl->scanning = false; wl->default_key = 0; diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index 1dc74b0c7736..0f6ea16cae83 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -27,25 +27,43 @@ #define WL1271_WAKEUP_TIMEOUT 500 -/* Routines to toggle sleep mode while in ELP */ -void wl1271_ps_elp_sleep(struct wl1271 *wl) +void wl1271_elp_work(struct work_struct *work) { + struct delayed_work *dwork; + struct wl1271 *wl; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1271, elp_work); + + wl1271_debug(DEBUG_PSM, "elp work"); + + mutex_lock(&wl->mutex); + /* - * FIXME: due to a problem in the firmware (causing a firmware - * crash), ELP entry is prevented below. Remove the "true" to - * re-enable ELP entry. + * FIXME: below, by means of the "true", ELP has been disabled for now + * to work around a firmware bug. To be enabled upon receiving a new + * firmware version. */ if (true || wl->elp || !wl->psm) - return; + goto out; - /* - * Go to ELP unless there is work already pending - pending work - * will immediately wakeup the chipset anyway. - */ - if (!work_pending(&wl->irq_work) && !work_pending(&wl->tx_work)) { - wl1271_debug(DEBUG_PSM, "chip to elp"); - wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); - wl->elp = true; + wl1271_debug(DEBUG_PSM, "chip to elp"); + wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + wl->elp = true; + +out: + mutex_unlock(&wl->mutex); +} + +#define ELP_ENTRY_DELAY 5 + +/* Routines to toggle sleep mode while in ELP */ +void wl1271_ps_elp_sleep(struct wl1271 *wl) +{ + if (wl->psm) { + cancel_delayed_work(&wl->elp_work); + ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, + msecs_to_jiffies(ELP_ENTRY_DELAY)); } } diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.h b/drivers/net/wireless/wl12xx/wl1271_ps.h index de2bd3c7dc9c..779653d0ae85 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.h +++ b/drivers/net/wireless/wl12xx/wl1271_ps.h @@ -30,6 +30,6 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode); void wl1271_ps_elp_sleep(struct wl1271 *wl); int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake); - +void wl1271_elp_work(struct work_struct *work); #endif /* __WL1271_PS_H__ */ -- cgit v1.2.3 From c3fea1994ac34dafa3ebb40d4f95354b2782af31 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:22 +0300 Subject: wl1271: mask aid bits 14 and 15 in ps-poll template In ps-poll template aid bits 14 and 15 were not masked as required by the standard. Mask them so that aid is sent in correct format. This patch is a direct port of the respective patch for the wl1251 driver by Kalle Valo. Signed-off-by: Juuso Oikarinen Reviewed-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 1ee1b2b4dfa2..bd65b38eb1d9 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -682,7 +682,10 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) memcpy(template.bssid, wl->bssid, ETH_ALEN); memcpy(template.ta, wl->mac_addr, ETH_ALEN); - template.aid = aid; + + /* aid in PS-Poll has its two MSBs each set to 1 */ + template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid); + template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template, -- cgit v1.2.3 From 545f1da8ef0f20923feb500bcfaf0e2fb6068fb4 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:23 +0300 Subject: wl1271: Implementation for SPI busy word checking This patch adds implementation for checking for SPI busy words - i.e. honoring a delay request from the WLAN chipset upon reading registers/memory. To optimized the average SPI ready by 32 bits, also configure the number of busywords to one to disable the "fixed-busy-word" functionality. Signed-off-by: Juuso Oikarinen Reviewed-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 10 ++++- drivers/net/wireless/wl12xx/wl1271_spi.c | 69 +++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index c455dcbae524..957da8c0d9cb 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -107,7 +107,13 @@ enum { #define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin" -#define WL1271_BUSY_WORD_LEN 8 +/* + * FIXME: for the wl1271, a busy word count of 1 here will result in a more + * optimal SPI interface. There is some SPI bug however, causing RXS time outs + * with this mode occasionally on boot, so lets have two for now. + */ +#define WL1271_BUSY_WORD_CNT 2 +#define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32)) #define WL1271_ELP_HW_STATE_ASLEEP 0 #define WL1271_ELP_HW_STATE_IRQ 1 @@ -389,7 +395,7 @@ struct wl1271 { u32 buffer_32; u32 buffer_cmd; - u8 buffer_busyword[WL1271_BUSY_WORD_LEN]; + u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; struct wl1271_rx_descriptor *rx_descriptor; struct wl1271_fw_status *fw_status; diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 4a12880c16a8..504991acb052 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -244,12 +244,75 @@ int wl1271_set_partition(struct wl1271 *wl, return 0; } +#define WL1271_BUSY_WORD_TIMEOUT 1000 + +void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len) +{ + struct spi_transfer t[1]; + struct spi_message m; + u32 *busy_buf; + int num_busy_bytes = 0; + + wl1271_info("spi read BUSY!"); + + /* + * Look for the non-busy word in the read buffer, and if found, + * read in the remaining data into the buffer. + */ + busy_buf = (u32 *)buf; + for (; (u32)busy_buf < (u32)buf + len; busy_buf++) { + num_busy_bytes += sizeof(u32); + if (*busy_buf & 0x1) { + spi_message_init(&m); + memset(t, 0, sizeof(t)); + memmove(buf, busy_buf, len - num_busy_bytes); + t[0].rx_buf = buf + (len - num_busy_bytes); + t[0].len = num_busy_bytes; + spi_message_add_tail(&t[0], &m); + spi_sync(wl->spi, &m); + return; + } + } + + /* + * Read further busy words from SPI until a non-busy word is + * encountered, then read the data itself into the buffer. + */ + wl1271_info("spi read BUSY-polling needed!"); + + num_busy_bytes = WL1271_BUSY_WORD_TIMEOUT; + busy_buf = wl->buffer_busyword; + while (num_busy_bytes) { + num_busy_bytes--; + spi_message_init(&m); + memset(t, 0, sizeof(t)); + t[0].rx_buf = busy_buf; + t[0].len = sizeof(u32); + spi_message_add_tail(&t[0], &m); + spi_sync(wl->spi, &m); + + if (*busy_buf & 0x1) { + spi_message_init(&m); + memset(t, 0, sizeof(t)); + t[0].rx_buf = buf; + t[0].len = len; + spi_message_add_tail(&t[0], &m); + spi_sync(wl->spi, &m); + return; + } + } + + /* The SPI bus is unresponsive, the read failed. */ + memset(buf, 0, len); + wl1271_error("SPI read busy-word timeout!\n"); +} + void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { struct spi_transfer t[3]; struct spi_message m; - u8 *busy_buf; + u32 *busy_buf; u32 *cmd; cmd = &wl->buffer_cmd; @@ -281,7 +344,9 @@ void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, spi_sync(wl->spi, &m); - /* FIXME: check busy words */ + /* Check busy words */ + if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1)) + wl1271_spi_read_busy(wl, buf, len); wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); -- cgit v1.2.3 From 8a5a37a6c492f7c9602aa72ef19f69c926cdca15 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:24 +0300 Subject: wl1271: Configure rate policies based on AP rates Configure the rate policies to the firmware based on the rates given by the AP. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 3 +++ drivers/net/wireless/wl12xx/wl1271_acx.c | 4 ++-- drivers/net/wireless/wl12xx/wl1271_acx.h | 2 +- drivers/net/wireless/wl12xx/wl1271_init.c | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 38 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 957da8c0d9cb..671dc5af2e68 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -369,6 +369,9 @@ struct wl1271 { /* Our association ID */ u16 aid; + /* The current band */ + enum ieee80211_band band; + /* Default key (for WEP) */ u32 default_key; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index f622a4092615..2ae1081ed627 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -703,7 +703,7 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) return 0; } -int wl1271_acx_rate_policies(struct wl1271 *wl) +int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) { struct acx_rate_policy *acx; int ret = 0; @@ -719,7 +719,7 @@ int wl1271_acx_rate_policies(struct wl1271 *wl) /* configure one default (one-size-fits-all) rate class */ acx->rate_class_cnt = 1; - acx->rate_class[0].enabled_rates = ACX_RATE_MASK_ALL; + acx->rate_class[0].enabled_rates = enabled_rates; acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; acx->rate_class[0].aflags = 0; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 9068daaf0ddf..55850eb809ea 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -1209,7 +1209,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); int wl1271_acx_cts_protect(struct wl1271 *wl, enum acx_ctsprotect_type ctsprotect); int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); -int wl1271_acx_rate_policies(struct wl1271 *wl); +int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates); int wl1271_acx_ac_cfg(struct wl1271 *wl); int wl1271_acx_tid_cfg(struct wl1271 *wl); int wl1271_acx_frag_threshold(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 490df217605a..eb6b91ab968a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -369,7 +369,7 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Configure TX rate classes */ - ret = wl1271_acx_rate_policies(wl); + ret = wl1271_acx_rate_policies(wl, ACX_RATE_MASK_ALL); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index cc5c3285deac..b9b1c2013744 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -583,6 +583,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->ssid_len = 0; wl->listen_int = 1; wl->bss_type = MAX_BSS_TYPE; + wl->band = IEEE80211_BAND_2GHZ; wl->rx_counter = 0; wl->elp = false; @@ -727,6 +728,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); + wl->band = conf->channel->band; + ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out; @@ -978,6 +981,22 @@ out: return ret; } +static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set) +{ + struct ieee80211_supported_band *band; + u32 enabled_rates = 0; + int bit; + + band = wl->hw->wiphy->bands[wl->band]; + for (bit = 0; bit < band->n_bitrates; bit++) { + if (basic_rate_set & 0x1) + enabled_rates |= band->bitrates[bit].hw_value; + basic_rate_set >>= 1; + } + + return enabled_rates; +} + static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -1016,6 +1035,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } } + if (changed & BSS_CHANGED_ERP_SLOT) { if (bss_conf->use_short_slot) ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT); @@ -1045,6 +1065,16 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } + if (changed & BSS_CHANGED_BASIC_RATES) { + u32 enabled_rates = wl1271_enabled_rates_get( + wl, bss_conf->basic_rates); + ret = wl1271_acx_rate_policies(wl, enabled_rates); + if (ret < 0) { + wl1271_warning("Set rate policies failed %d", ret); + goto out_sleep; + } + } + out_sleep: wl1271_ps_elp_sleep(wl); @@ -1239,6 +1269,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->psm_requested = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + wl->band = IEEE80211_BAND_2GHZ; /* We use the default power on sleep time until we know which chip * we're using */ -- cgit v1.2.3 From d94cd297e58b55bb272fdfd51ff0de7acbc1941b Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:25 +0300 Subject: wl1271: Update join usage Update the usage of join's, including using actual beacon interval and dtim from AP, and configuring a basic rate set from AP. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 12 +++++++++ drivers/net/wireless/wl12xx/wl1271_cmd.c | 15 ++++------- drivers/net/wireless/wl12xx/wl1271_cmd.h | 3 +-- drivers/net/wireless/wl12xx/wl1271_main.c | 42 +++++++++++++++++++++++-------- 4 files changed, 50 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 671dc5af2e68..05eb29c847c6 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -104,6 +104,8 @@ enum { CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) +#define WL1271_DEFAULT_BASIC_RATE_SET (ACX_RATE_MASK_ALL) + #define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin" @@ -118,6 +120,9 @@ enum { #define WL1271_ELP_HW_STATE_ASLEEP 0 #define WL1271_ELP_HW_STATE_IRQ 1 +#define WL1271_DEFAULT_BEACON_INT 100 +#define WL1271_DEFAULT_DTIM_PERIOD 1 + enum wl1271_state { WL1271_STATE_OFF, WL1271_STATE_ON, @@ -369,6 +374,13 @@ struct wl1271 { /* Our association ID */ u16 aid; + /* Beacon parameters */ + u16 beacon_int; + u8 dtim_period; + + /* currently configured rate set */ + u32 basic_rate_set; + /* The current band */ enum ieee80211_band band; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index bd65b38eb1d9..35a6e67f7ae4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -175,11 +175,9 @@ int wl1271_cmd_cal(struct wl1271 *wl) return ret; } -int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait) +int wl1271_cmd_join(struct wl1271 *wl) { static bool do_cal = true; - unsigned long timeout; struct wl1271_cmd_join *join; int ret, i; u8 *bssid; @@ -213,9 +211,9 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; - join->beacon_interval = beacon_interval; - join->dtim_interval = dtim_interval; - join->bss_type = bss_type; + join->beacon_interval = wl->beacon_int; + join->dtim_interval = wl->dtim_period; + join->bss_type = wl->bss_type; join->channel = wl->channel; join->ssid_len = wl->ssid_len; memcpy(join->ssid, wl->ssid, wl->ssid_len); @@ -239,14 +237,11 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, goto out_free; } - timeout = msecs_to_jiffies(JOIN_TIMEOUT); - /* * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to * simplify locking we just sleep instead, for now */ - if (wait) - msleep(10); + msleep(10); out_free: kfree(join); diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 7c4d3aaaa819..63bc4417deb8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -30,8 +30,7 @@ struct acx_header; int wl1271_cmd_send(struct wl1271 *wl, u16 type, void *buf, size_t buf_len); -int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type, u8 dtim_interval, - u16 beacon_interval, u8 wait); +int wl1271_cmd_join(struct wl1271 *wl); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index b9b1c2013744..6e35fcf37e4f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -394,8 +394,7 @@ static void wl1271_filter_work(struct work_struct *work) if (ret < 0) goto out; - /* FIXME: replace the magic numbers with proper definitions */ - ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1271_cmd_join(wl); if (ret < 0) goto out_sleep; @@ -672,8 +671,7 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw, memcpy(wl->ssid, conf->ssid, wl->ssid_len); if (wl->bss_type != BSS_TYPE_IBSS) { - /* FIXME: replace the magic numbers with proper definitions */ - ret = wl1271_cmd_join(wl, wl->bss_type, 5, 100, 1); + ret = wl1271_cmd_join(wl); if (ret < 0) goto out_sleep; } @@ -696,8 +694,7 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; - /* FIXME: replace the magic numbers with proper definitions */ - ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1271_cmd_join(wl); if (ret < 0) goto out_sleep; @@ -738,8 +735,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) u8 old_channel = wl->channel; wl->channel = channel; - /* FIXME: use beacon interval provided by mac80211 */ - ret = wl1271_cmd_join(wl, wl->bss_type, 1, 100, 0); + ret = wl1271_cmd_join(wl); if (ret < 0) { wl->channel = old_channel; goto out_sleep; @@ -1016,8 +1012,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { + wl->beacon_int = bss_conf->beacon_int; + wl->dtim_period = bss_conf->dtim_period; wl->aid = bss_conf->aid; + ret = wl1271_cmd_join(wl); + if (ret < 0) { + wl1271_warning("Association configuration " + "failed %d", ret); + goto out_sleep; + } + ret = wl1271_cmd_build_ps_poll(wl, wl->aid); if (ret < 0) goto out_sleep; @@ -1033,7 +1038,14 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; } + } else { + /* use defaults when not associated */ + wl->beacon_int = WL1271_DEFAULT_BEACON_INT; + wl->dtim_period = WL1271_DEFAULT_DTIM_PERIOD; + wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; + wl->aid = 0; } + } if (changed & BSS_CHANGED_ERP_SLOT) { @@ -1066,13 +1078,20 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BASIC_RATES) { - u32 enabled_rates = wl1271_enabled_rates_get( + wl->basic_rate_set = wl1271_enabled_rates_get( wl, bss_conf->basic_rates); - ret = wl1271_acx_rate_policies(wl, enabled_rates); + ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set); + if (ret < 0) { wl1271_warning("Set rate policies failed %d", ret); goto out_sleep; } + ret = wl1271_cmd_join(wl); + if (ret < 0) { + wl1271_warning("Join with new basic rate " + "set failed %d", ret); + goto out_sleep; + } } out_sleep: @@ -1269,6 +1288,9 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->psm_requested = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; + wl->beacon_int = WL1271_DEFAULT_BEACON_INT; + wl->dtim_period = WL1271_DEFAULT_DTIM_PERIOD; + wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; wl->band = IEEE80211_BAND_2GHZ; /* We use the default power on sleep time until we know which chip -- cgit v1.2.3 From be7078c21d826fbaab77f88440958019aab969af Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:26 +0300 Subject: wl1271: Corrections to TX path Corrections to the TX path - use correct number of maximum descriptors (32 instead of 16) and correct checking and setting of excessive retries on completion. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 4 +++- drivers/net/wireless/wl12xx/wl1271_acx.h | 1 - drivers/net/wireless/wl12xx/wl1271_main.c | 4 +--- drivers/net/wireless/wl12xx/wl1271_tx.c | 8 +++----- 4 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 05eb29c847c6..0b4744db22ef 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -123,6 +123,8 @@ enum { #define WL1271_DEFAULT_BEACON_INT 100 #define WL1271_DEFAULT_DTIM_PERIOD 1 +#define ACX_TX_DESCRIPTORS 32 + enum wl1271_state { WL1271_STATE_OFF, WL1271_STATE_ON, @@ -346,7 +348,7 @@ struct wl1271 { struct work_struct filter_work; /* Pending TX frames */ - struct sk_buff *tx_frames[16]; + struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; /* Security sequence number counters */ u8 tx_security_last_seq; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 55850eb809ea..c1773459bf55 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -170,7 +170,6 @@ enum { #define DP_RX_PACKET_RING_CHUNK_NUM 2 #define DP_TX_PACKET_RING_CHUNK_NUM 2 #define DP_TX_COMPLETE_TIME_OUT 20 -#define FW_TX_CMPLT_BLOCK_SIZE 16 #define TX_MSDU_LIFETIME_MIN 0 #define TX_MSDU_LIFETIME_MAX 3000 diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 6e35fcf37e4f..0a0f2eacf400 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1293,9 +1293,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; wl->band = IEEE80211_BAND_2GHZ; - /* We use the default power on sleep time until we know which chip - * we're using */ - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + for (i = 0; i < ACX_TX_DESCRIPTORS; i++) wl->tx_frames[i] = NULL; spin_lock_init(&wl->wl_lock); diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 1ad1bc3f152e..5d3aa4b26cf3 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -33,8 +33,7 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) { int i; - - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + for (i = 0; i < ACX_TX_DESCRIPTORS; i++) if (wl->tx_frames[i] == NULL) { wl->tx_frames[i] = skb; return i; @@ -262,14 +261,13 @@ out: static void wl1271_tx_complete_packet(struct wl1271 *wl, struct wl1271_tx_hw_res_descr *result) { - struct ieee80211_tx_info *info; struct sk_buff *skb; u16 seq; int id = result->id; /* check for id legality */ - if (id >= TX_HW_RESULT_QUEUE_LEN || wl->tx_frames[id] == NULL) { + if (id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL) { wl1271_warning("TX result illegal id: %d", id); return; } @@ -382,7 +380,7 @@ void wl1271_tx_flush(struct wl1271 *wl) ieee80211_tx_status(wl->hw, skb); } - for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) + for (i = 0; i < ACX_TX_DESCRIPTORS; i++) if (wl->tx_frames[i] != NULL) { skb = wl->tx_frames[i]; info = IEEE80211_SKB_CB(skb); -- cgit v1.2.3 From 2f0187250041afc765df51e2cce653e8a5b9c1b6 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 8 Oct 2009 21:56:27 +0300 Subject: wl1271: added Juuso Oikarinen as module author Add Juuso as one of the module authors, since he's working heavily on this module as well. Cc: Juuso Oikarinen Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 0a0f2eacf400..1a0491a01baa 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1449,3 +1449,4 @@ module_exit(wl1271_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Juuso Oikarinen "); -- cgit v1.2.3 From 64a7f67287c75f5bb28018a6ff2750a59ee1195a Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 8 Oct 2009 21:56:28 +0300 Subject: wl1271: hack to disable filters This is a hack to disable all filters in the join command. This is based on Kalle Valo's patch for wl1251. Cc: Kalle Valo Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 35a6e67f7ae4..ac93efd53f2a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -208,6 +208,15 @@ int wl1271_cmd_join(struct wl1271 *wl) join->rx_config_options = wl->rx_config; join->rx_filter_options = wl->rx_filter; + /* + * FIXME: disable temporarily all filters because after commit + * 9cef8737 "mac80211: fix managed mode BSSID handling" broke + * association. The filter logic needs to be implemented properly + * and once that is done, this hack can be removed. + */ + join->rx_config_options = 0; + join->rx_filter_options = WL1271_DEFAULT_RX_FILTER; + join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; -- cgit v1.2.3 From a64b07e8c6ff8394cd8c5a505b9f04d945f9f30f Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:29 +0300 Subject: wl1271: use workqueue provided by mac80211 instead of the default Use the workqueue provided by the mac80211 stack instead of the system default queue. Modified to use new ieee_queue_work() as required by changes in the stack. Signed-off-by: Juuso Oikarinen Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 1a0491a01baa..d1042305abcc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -107,7 +107,7 @@ static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status) /* if more blocks are available now, schedule some tx work */ if (total && !skb_queue_empty(&wl->tx_queue)) - schedule_work(&wl->tx_work); + ieee80211_queue_work(wl->hw, &wl->tx_work); /* update the host-chipset time offset */ wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime; @@ -205,7 +205,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) wl->elp_compl = NULL; } - schedule_work(&wl->irq_work); + ieee80211_queue_work(wl->hw, &wl->irq_work); spin_unlock_irqrestore(&wl->wl_lock, flags); return IRQ_HANDLED; @@ -480,7 +480,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * before that, the tx_work will not be initialized! */ - schedule_work(&wl->tx_work); + ieee80211_queue_work(wl->hw, &wl->tx_work); /* * The workqueue is slow to process the tx_queue and we need stop -- cgit v1.2.3 From 66497dc3bd569e05a5bcb729d495eebad47aa46a Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:30 +0300 Subject: wl1271: Clear probe-request template after scan Clear the probe-request template on the firmware after scan. Unless cleared, the firmware can independently send probe requests to the AP and interfere with the mac80211 logic. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_event.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index f3afd4a6ff33..87055f7996bc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -26,6 +26,7 @@ #include "wl1271_spi.h" #include "wl1271_event.h" #include "wl1271_ps.h" +#include "wl12xx_80211.h" static int wl1271_event_scan_complete(struct wl1271 *wl, struct event_mailbox *mbox) @@ -34,6 +35,9 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, mbox->scheduled_scan_status); if (wl->scanning) { + int size = sizeof(struct wl12xx_probe_req_template); + wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, + size); mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); -- cgit v1.2.3 From c87dec9f189b884df215756e285b9281cf065206 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:31 +0300 Subject: wl1271: Multicast filtering configuration Enable multicast filtering. This way by default no multicast frames will reach the host, and when needed, only required multicast frames can be passed from the WLAN chipset to the host. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 7 +- drivers/net/wireless/wl12xx/wl1271_acx.c | 9 ++- drivers/net/wireless/wl12xx/wl1271_acx.h | 8 +- drivers/net/wireless/wl12xx/wl1271_init.c | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 121 ++++++++++++++++++++++++++---- 5 files changed, 120 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 0b4744db22ef..34a52b33bf5d 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -97,7 +97,8 @@ enum { } while (0) #define WL1271_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ - CFG_BSSID_FILTER_EN) + CFG_BSSID_FILTER_EN | \ + CFG_MC_FILTER_EN) #define WL1271_DEFAULT_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \ CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ @@ -123,7 +124,7 @@ enum { #define WL1271_DEFAULT_BEACON_INT 100 #define WL1271_DEFAULT_DTIM_PERIOD 1 -#define ACX_TX_DESCRIPTORS 32 +#define ACX_TX_DESCRIPTORS 32 enum wl1271_state { WL1271_STATE_OFF, @@ -345,7 +346,9 @@ struct wl1271 { bool tx_queue_stopped; struct work_struct tx_work; + struct work_struct filter_work; + struct wl1271_filter_params *filter_params; /* Pending TX frames */ struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 2ae1081ed627..a457123442a7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -300,7 +300,8 @@ out: return ret; } -int wl1271_acx_group_address_tbl(struct wl1271 *wl) +int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, + void *mc_list, u32 mc_list_len) { struct acx_dot11_grp_addr_tbl *acx; int ret; @@ -314,9 +315,9 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl) } /* MAC filtering */ - acx->enabled = 0; - acx->num_groups = 0; - memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); + acx->enabled = enable; + acx->num_groups = mc_list_len; + memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, acx, sizeof(*acx)); diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index c1773459bf55..dae1fed66b30 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -301,8 +301,8 @@ struct acx_slot { } __attribute__ ((packed)); -#define ADDRESS_GROUP_MAX (8) -#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) +#define ACX_MC_ADDRESS_GROUP_MAX (8) +#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX) struct acx_dot11_grp_addr_tbl { struct acx_header header; @@ -313,7 +313,6 @@ struct acx_dot11_grp_addr_tbl { u8 mac_table[ADDRESS_GROUP_MAX_LEN]; } __attribute__ ((packed)); - #define RX_TIMEOUT_PS_POLL_MIN 0 #define RX_TIMEOUT_PS_POLL_MAX (200000) #define RX_TIMEOUT_PS_POLL_DEF (15) @@ -1193,7 +1192,8 @@ int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time); int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter); int wl1271_acx_pd_threshold(struct wl1271 *wl); int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); -int wl1271_acx_group_address_tbl(struct wl1271 *wl); +int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, + void *mc_list, u32 mc_list_len); int wl1271_acx_service_period_timeout(struct wl1271 *wl); int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); int wl1271_acx_beacon_filter_opt(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index eb6b91ab968a..49ff4071c0bc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -117,7 +117,7 @@ static int wl1271_init_phy_config(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_group_address_tbl(wl); + ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d1042305abcc..09fe9686977a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -379,12 +379,39 @@ out: return ret; } +struct wl1271_filter_params { + unsigned int filters; + unsigned int changed; + int mc_list_length; + u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; +}; + +#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | \ + FIF_OTHER_BSS) + static void wl1271_filter_work(struct work_struct *work) { struct wl1271 *wl = container_of(work, struct wl1271, filter_work); + struct wl1271_filter_params *fp; + unsigned long flags; + bool enabled = true; int ret; + /* first, get the filter parameters */ + spin_lock_irqsave(&wl->wl_lock, flags); + fp = wl->filter_params; + wl->filter_params = NULL; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + if (!fp) + return; + + /* then, lock the mutex without risk of lock-up */ mutex_lock(&wl->mutex); if (wl->state == WL1271_STATE_OFF) @@ -394,6 +421,20 @@ static void wl1271_filter_work(struct work_struct *work) if (ret < 0) goto out; + /* configure the mc filter regardless of the changed flags */ + if (fp->filters & FIF_ALLMULTI) + enabled = false; + + ret = wl1271_acx_group_address_tbl(wl, enabled, + fp->mc_list, fp->mc_list_length); + if (ret < 0) + goto out_sleep; + + /* determine, whether supported filter values have changed */ + if (fp->changed == 0) + goto out; + + /* apply configured filters */ ret = wl1271_cmd_join(wl); if (ret < 0) goto out_sleep; @@ -403,6 +444,7 @@ out_sleep: out: mutex_unlock(&wl->mutex); + kfree(fp); } int wl1271_plt_start(struct wl1271 *wl) @@ -544,12 +586,20 @@ out: static void wl1271_op_stop(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; + unsigned long flags; int i; wl1271_info("down"); wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); + /* complete/cancel ongoing work */ + cancel_work_sync(&wl->filter_work); + spin_lock_irqsave(&wl->wl_lock, flags); + kfree(wl->filter_params); + wl->filter_params = NULL; + spin_unlock_irqrestore(&wl->wl_lock, flags); + mutex_lock(&wl->mutex); WARN_ON(wl->state != WL1271_STATE_ON); @@ -784,16 +834,52 @@ out: return ret; } -#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ - FIF_FCSFAIL | \ - FIF_BCN_PRBRESP_PROMISC | \ - FIF_CONTROL | \ - FIF_OTHER_BSS) +static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, + struct dev_addr_list *mc_list) +{ + struct wl1271 *wl = hw->priv; + struct wl1271_filter_params *fp; + unsigned long flags; + int i; + + /* + * FIXME: we should return a hash that will be passed to + * configure_filter() instead of saving everything in the context. + */ + + fp = kzalloc(sizeof(*fp), GFP_KERNEL); + if (!fp) { + wl1271_error("Out of memory setting filters."); + return 0; + } + + /* update multicast filtering parameters */ + if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) { + mc_count = 0; + fp->filters |= FIF_ALLMULTI; + } + + fp->mc_list_length = 0; + for (i = 0; i < mc_count; i++) { + if (mc_list->da_addrlen == ETH_ALEN) { + memcpy(fp->mc_list[fp->mc_list_length], + mc_list->da_addr, ETH_ALEN); + fp->mc_list_length++; + } else + wl1271_warning("Unknown mc address length."); + } + + spin_lock_irqsave(&wl->wl_lock, flags); + kfree(wl->filter_params); + wl->filter_params = fp; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + return 1; +} static void wl1271_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *total,u64 multicast) + unsigned int *total, u64 multicast) { struct wl1271 *wl = hw->priv; @@ -802,19 +888,21 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, *total &= WL1271_SUPPORTED_FILTERS; changed &= WL1271_SUPPORTED_FILTERS; - if (changed == 0) + if (!multicast) return; - /* FIXME: wl->rx_config and wl->rx_filter are not protected */ - wl->rx_config = WL1271_DEFAULT_RX_CONFIG; - wl->rx_filter = WL1271_DEFAULT_RX_FILTER; - /* - * FIXME: workqueues need to be properly cancelled on stop(), for - * now let's just disable changing the filter settings. They will - * be updated any on config(). + * FIXME: for now we are still using a workqueue for filter + * configuration, but with the new mac80211, this is not needed, + * since configure_filter can now sleep. We now have + * prepare_multicast, which needs to be atomic instead. */ - /* schedule_work(&wl->filter_work); */ + + /* store current filter config */ + wl->filter_params->filters = *total; + wl->filter_params->changed = changed; + + ieee80211_queue_work(wl->hw, &wl->filter_work); } static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -1177,6 +1265,7 @@ static const struct ieee80211_ops wl1271_ops = { .remove_interface = wl1271_op_remove_interface, .config = wl1271_op_config, /* .config_interface = wl1271_op_config_interface, */ + .prepare_multicast = wl1271_op_prepare_multicast, .configure_filter = wl1271_op_configure_filter, .tx = wl1271_op_tx, .set_key = wl1271_op_set_key, -- cgit v1.2.3 From 1fba49741dc50d13d2fe6cf04f5a547e6c5c81f6 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:32 +0300 Subject: wl1271: Use vmalloc to allocate memory for firmware Use vmalloc to allocate memory for the firmware image, and use a smaller linear buffer for the actual transfer of the firmware to the chipset. This patch is an adaptation of a similar patch for wl1251 by Kalle Valo. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_boot.c | 16 ++++++++++++---- drivers/net/wireless/wl12xx/wl1271_main.c | 5 +++-- 2 files changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index 8228ef474a7e..7640313c45c1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -94,7 +94,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, size_t fw_data_len, u32 dest) { int addr, chunk_num, partition_limit; - u8 *p; + u8 *p, *chunk; /* whal_FwCtrl_LoadFwImageSm() */ @@ -103,12 +103,17 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, wl1271_debug(DEBUG_BOOT, "fw_data_len %zd chunk_size %d", fw_data_len, CHUNK_SIZE); - if ((fw_data_len % 4) != 0) { wl1271_error("firmware length not multiple of four"); return -EIO; } + chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL); + if (!buf) { + wl1271_error("allocation for firmware upload chunk failed"); + return -ENOMEM; + } + wl1271_set_partition(wl, dest, part_table[PART_DOWN].mem.size, part_table[PART_DOWN].reg.start, @@ -137,9 +142,10 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, /* 10.3 upload the chunk */ addr = dest + chunk_num * CHUNK_SIZE; p = buf + chunk_num * CHUNK_SIZE; + memcpy(chunk, p, CHUNK_SIZE); wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", p, addr); - wl1271_spi_mem_write(wl, addr, p, CHUNK_SIZE); + wl1271_spi_mem_write(wl, addr, chunk, CHUNK_SIZE); chunk_num++; } @@ -147,10 +153,12 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, /* 10.4 upload the last chunk */ addr = dest + chunk_num * CHUNK_SIZE; p = buf + chunk_num * CHUNK_SIZE; + memcpy(chunk, p, fw_data_len % CHUNK_SIZE); wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); - wl1271_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + wl1271_spi_mem_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE); + kfree(chunk); return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 09fe9686977a..d22de23f0bce 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "wl1271.h" @@ -231,7 +232,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) } wl->fw_len = fw->size; - wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); + wl->fw = vmalloc(wl->fw_len); if (!wl->fw) { wl1271_error("could not allocate memory for the firmware"); @@ -1484,7 +1485,7 @@ static int __devexit wl1271_remove(struct spi_device *spi) platform_device_unregister(&wl1271_device); free_irq(wl->irq, wl); kfree(wl->target_mem_map); - kfree(wl->fw); + vfree(wl->fw); wl->fw = NULL; kfree(wl->nvs); wl->nvs = NULL; -- cgit v1.2.3 From 344152361e6d14ade61d7f43678db7418cb445db Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:33 +0300 Subject: wl1271: Add connection monitoring configuration Add configuration for connection monitor (number of allowed beacons, and timeout after last received beacon.) Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.c | 30 ++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_acx.h | 11 +++++++++++ drivers/net/wireless/wl12xx/wl1271_init.c | 6 ++++++ 3 files changed, 47 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index a457123442a7..4b5fd94921c9 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -442,6 +442,36 @@ out: return ret; } +int wl1271_acx_conn_monit_params(struct wl1271 *wl) +{ + struct acx_conn_monit_params *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx connection monitor parameters"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD; + acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT; + + ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set connection monitor " + "parameters: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + + int wl1271_acx_sg_enable(struct wl1271 *wl) { struct acx_bt_wlan_coex *pta; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index dae1fed66b30..bb21bcbe1638 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -406,6 +406,16 @@ struct acx_beacon_filter_ie_table { u8 pad[3]; } __attribute__ ((packed)); +#define SYNCH_FAIL_DEFAULT_THRESHOLD 5 /* number of beacons */ +#define NO_BEACON_DEFAULT_TIMEOUT (100) /* TU */ + +struct acx_conn_monit_params { + struct acx_header header; + + u32 synch_fail_thold; /* number of beacons missed */ + u32 bss_lose_timeout; /* number of TU's from synch fail */ +}; + enum { SG_ENABLE = 0, SG_DISABLE, @@ -1198,6 +1208,7 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl); int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); int wl1271_acx_beacon_filter_opt(struct wl1271 *wl); int wl1271_acx_beacon_filter_table(struct wl1271 *wl); +int wl1271_acx_conn_monit_params(struct wl1271 *wl); int wl1271_acx_sg_enable(struct wl1271 *wl); int wl1271_acx_sg_cfg(struct wl1271 *wl); int wl1271_acx_cca_threshold(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 49ff4071c0bc..d3db3fba41d4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -323,6 +323,11 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + /* Initialize connection monitoring thresholds */ + ret = wl1271_acx_conn_monit_params(wl); + if (ret < 0) + goto out_free_memmap; + /* Beacon filtering */ ret = wl1271_init_beacon_filter(wl); if (ret < 0) @@ -392,6 +397,7 @@ int wl1271_hw_init(struct wl1271 *wl) out_free_memmap: kfree(wl->target_mem_map); + wl->target_mem_map = NULL; return ret; } -- cgit v1.2.3 From b771eee583343782c8b44d2b78cf53c29d0f3303 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:34 +0300 Subject: wl1271: Enable beacon filtering with the stack Enable beacon filtering with the mac80211 stack. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 2 ++ drivers/net/wireless/wl12xx/wl1271_event.c | 14 ++++++++------ drivers/net/wireless/wl12xx/wl1271_main.c | 12 ++++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 34a52b33bf5d..96a581316941 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -420,6 +420,8 @@ struct wl1271 { struct wl1271_fw_status *fw_status; struct wl1271_tx_hw_res_if *tx_res_if; + + struct ieee80211_vif *vif; }; int wl1271_plt_start(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 87055f7996bc..f32927650af4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -70,14 +70,16 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) return ret; } - if (vector & BSS_LOSE_EVENT_ID) { + /* + * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon + * filtering) is enabled. Without PSM, the stack will receive all + * beacons and can detect beacon loss by itself. + */ + if (vector & BSS_LOSE_EVENT_ID && wl->psm) { wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); - if (wl->psm_requested && wl->psm) { - ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); - if (ret < 0) - return ret; - } + /* indicate to the stack, that beacons have been lost */ + ieee80211_beacon_loss(wl->vif); } return 0; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d22de23f0bce..e6f9e9b57037 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -665,6 +665,12 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, conf->type, conf->mac_addr); mutex_lock(&wl->mutex); + if (wl->vif) { + ret = -EBUSY; + goto out; + } + + wl->vif = conf->vif; switch (conf->type) { case NL80211_IFTYPE_STATION: @@ -688,7 +694,12 @@ out: static void wl1271_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { + struct wl1271 *wl = hw->priv; + + mutex_lock(&wl->mutex); wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); + wl->vif = NULL; + mutex_unlock(&wl->mutex); } #if 0 @@ -1382,6 +1393,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->dtim_period = WL1271_DEFAULT_DTIM_PERIOD; wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; wl->band = IEEE80211_BAND_2GHZ; + wl->vif = NULL; for (i = 0; i < ACX_TX_DESCRIPTORS; i++) wl->tx_frames[i] = NULL; -- cgit v1.2.3 From 1922167b9de575d9d1a56be9b80f0fa3b22785f9 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:35 +0300 Subject: wl1271: Configure beacon filtering on if PSM used Enable beacon filtering when PSM is enabled Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.c | 11 +++++++---- drivers/net/wireless/wl12xx/wl1271_acx.h | 7 ++++++- drivers/net/wireless/wl12xx/wl1271_init.c | 3 ++- drivers/net/wireless/wl12xx/wl1271_main.c | 3 ++- drivers/net/wireless/wl12xx/wl1271_ps.c | 11 +++++++++++ 5 files changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 4b5fd94921c9..b9dfa094f049 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -386,7 +386,7 @@ out: return ret; } -int wl1271_acx_beacon_filter_opt(struct wl1271 *wl) +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) { struct acx_beacon_filter_option *beacon_filter; int ret; @@ -399,7 +399,7 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl) goto out; } - beacon_filter->enable = 0; + beacon_filter->enable = enable_filter; beacon_filter->max_num_beacons = 0; ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, @@ -417,6 +417,7 @@ out: int wl1271_acx_beacon_filter_table(struct wl1271 *wl) { struct acx_beacon_filter_ie_table *ie_table; + int idx = 0; int ret; wl1271_debug(DEBUG_ACX, "acx beacon filter table"); @@ -427,8 +428,10 @@ int wl1271_acx_beacon_filter_table(struct wl1271 *wl) goto out; } - ie_table->num_ie = 0; - memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); + /* configure default beacon pass-through rules */ + ie_table->num_ie = 1; + ie_table->table[idx++] = BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN; + ie_table->table[idx++] = BEACON_RULE_PASS_ON_APPEARANCE; ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, ie_table, sizeof(*ie_table)); diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index bb21bcbe1638..0c2a10734493 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -398,6 +398,11 @@ struct acx_beacon_filter_option { (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) +#define BEACON_RULE_PASS_ON_CHANGE BIT(0) +#define BEACON_RULE_PASS_ON_APPEARANCE BIT(1) + +#define BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN (37) + struct acx_beacon_filter_ie_table { struct acx_header header; @@ -1206,7 +1211,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, void *mc_list, u32 mc_list_len); int wl1271_acx_service_period_timeout(struct wl1271 *wl); int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); -int wl1271_acx_beacon_filter_opt(struct wl1271 *wl); +int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); int wl1271_acx_beacon_filter_table(struct wl1271 *wl); int wl1271_acx_conn_monit_params(struct wl1271 *wl); int wl1271_acx_sg_enable(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index d3db3fba41d4..bf4d0e18fb81 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -136,7 +136,8 @@ static int wl1271_init_beacon_filter(struct wl1271 *wl) { int ret; - ret = wl1271_acx_beacon_filter_opt(wl); + /* disable beacon filtering at this stage */ + ret = wl1271_acx_beacon_filter_opt(wl, false); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index e6f9e9b57037..3662715c0313 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1319,7 +1319,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->channel_change_time = 10000; wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; + IEEE80211_HW_NOISE_DBM | + IEEE80211_HW_BEACON_FILTER; wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wl->hw->wiphy->max_scan_ssids = 1; diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index 0f6ea16cae83..5580e53d103a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -129,6 +129,12 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) switch (mode) { case STATION_POWER_SAVE_MODE: wl1271_debug(DEBUG_PSM, "entering psm"); + + /* enable beacon filtering */ + ret = wl1271_acx_beacon_filter_opt(wl, true); + if (ret < 0) + return ret; + ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); if (ret < 0) return ret; @@ -146,6 +152,11 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) if (ret < 0) return ret; + /* disable beacon filtering */ + ret = wl1271_acx_beacon_filter_opt(wl, false); + if (ret < 0) + return ret; + ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE); if (ret < 0) return ret; -- cgit v1.2.3 From be823e5b2d71d367b5e27496e2b19d453e21936e Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 8 Oct 2009 21:56:36 +0300 Subject: wl1271: Mask unneeded events from firmware to conserve power Currently several events are enabled from the firmware for which there is no handling. This wakes up the host unnecessarily. Mask those unneeded events. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_boot.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index 7640313c45c1..140e94348bc1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -390,8 +390,9 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) /* enable gpio interrupts */ wl1271_boot_enable_interrupts(wl); - /* unmask all mbox events */ - wl->event_mask = 0xffffffff; + /* unmask required mbox events */ + wl->event_mask = BSS_LOSE_EVENT_ID | + SCAN_COMPLETE_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { -- cgit v1.2.3 From c0bbd57679efc2350703a1c0f3fc624cbcaba55f Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 8 Oct 2009 19:38:45 -0700 Subject: libertas: Check return status of command functions Return status of lbs_prepare_and_send_command and lbs_cmd_with_response functions is not checked at some places. Those checks are added. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/debugfs.c | 27 ++++++++++++++++++--------- drivers/net/wireless/libertas/main.c | 2 ++ drivers/net/wireless/libertas/scan.c | 11 +++++++---- drivers/net/wireless/libertas/wext.c | 10 +++++++--- 4 files changed, 34 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 893a55ca344a..587b0cb0088d 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -451,10 +451,12 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, CMD_MAC_REG_ACCESS, 0, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); - pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n", + if (!ret) { + pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n", priv->mac_offset, priv->offsetvalue.value); - ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + } free_page(addr); return ret; } @@ -514,7 +516,8 @@ static ssize_t lbs_wrmac_write(struct file *file, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); - res = count; + if (!res) + res = count; out_unlock: free_page(addr); return res; @@ -539,10 +542,12 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf, CMD_BBP_REG_ACCESS, 0, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); - pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n", + if (!ret) { + pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n", priv->bbp_offset, priv->offsetvalue.value); - ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + } free_page(addr); return ret; @@ -603,7 +608,8 @@ static ssize_t lbs_wrbbp_write(struct file *file, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); - res = count; + if (!res) + res = count; out_unlock: free_page(addr); return res; @@ -628,10 +634,12 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf, CMD_RF_REG_ACCESS, 0, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); - pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n", + if (!ret) { + pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n", priv->rf_offset, priv->offsetvalue.value); - ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + } free_page(addr); return ret; @@ -692,7 +700,8 @@ static ssize_t lbs_wrrf_write(struct file *file, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); - res = count; + if (!res) + res = count; out_unlock: free_page(addr); return res; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 87bfd17b9c8c..b7363236cc53 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1089,6 +1089,8 @@ static void auto_deepsleep_timer_fn(unsigned long data) ret = lbs_prepare_and_send_command(priv, CMD_802_11_DEEP_SLEEP, 0, 0, 0, NULL); + if (ret) + lbs_pr_err("Enter Deep Sleep command failed\n"); } } mod_timer(&priv->auto_deepsleep_timer , jiffies + diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 6c95af3023cc..d8fc2b8b3027 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -1022,9 +1022,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, return -EAGAIN; /* Update RSSI if current BSS is a locally created ad-hoc BSS */ - if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) - lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, - CMD_OPTION_WAITFORRSP, 0, NULL); + if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) { + err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, + CMD_OPTION_WAITFORRSP, 0, NULL); + if (err) + goto out; + } mutex_lock(&priv->lock); list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { @@ -1058,7 +1061,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, dwrq->length = (ev - extra); dwrq->flags = 0; - +out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err); return err; } diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 69dd19bf9558..4594841cd4af 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -832,7 +832,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) u32 rssi_qual; u32 tx_qual; u32 quality = 0; - int stats_valid = 0; + int ret, stats_valid = 0; u8 rssi; u32 tx_retries; struct cmd_ds_802_11_get_log log; @@ -881,7 +881,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) memset(&log, 0, sizeof(log)); log.hdr.size = cpu_to_le16(sizeof(log)); - lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log); + ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log); + if (ret) + goto out; tx_retries = le32_to_cpu(log.retry); @@ -909,8 +911,10 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) stats_valid = 1; /* update stats asynchronously for future calls */ - lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, 0, 0, NULL); + if (ret) + lbs_pr_err("RSSI command failed\n"); out: if (!stats_valid) { priv->wstats.miss.beacon = 0; -- cgit v1.2.3 From 332c556633b8c5fb4e890b1783122f2315526590 Mon Sep 17 00:00:00 2001 From: Sujith Date: Fri, 9 Oct 2009 09:51:28 +0530 Subject: ath9k: Fix TX hang poll routine When TX is hung, the chip is reset. Ensure that the chip is awake by using the PS wrappers. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index a8620b1d091b..2a4efcbced60 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2079,7 +2079,9 @@ static void ath_tx_complete_poll_work(struct work_struct *work) if (needreset) { ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, "tx hung, resetting the chip\n"); + ath9k_ps_wakeup(sc); ath_reset(sc, false); + ath9k_ps_restore(sc); } ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, -- cgit v1.2.3 From 899110fe4e1b26f7a13e639c57e2a047d21bffa2 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 9 Oct 2009 20:30:10 +0200 Subject: b43/legacy: Fix usage of host_pci pointer We must check the bustype before using the host_pci pointer. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 4 ++-- drivers/net/wireless/b43legacy/main.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index df6b26a0c05e..751017b4c3d3 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4671,7 +4671,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) { struct b43_wl *wl = dev->wl; struct ssb_bus *bus = dev->dev->bus; - struct pci_dev *pdev = bus->host_pci; + struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL; int err; bool have_2ghz_phy = 0, have_5ghz_phy = 0; u32 tmp; @@ -4804,7 +4804,7 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) if (!list_empty(&wl->devlist)) { /* We are not the first core on this chip. */ - pdev = dev->bus->host_pci; + pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL; /* Only special chips support more than one wireless * core, although some of the other chips have more than * one wireless core as well. Check for this and diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 1d9223b3d4c4..0983406f4630 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3592,7 +3592,7 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) { struct b43legacy_wl *wl = dev->wl; struct ssb_bus *bus = dev->dev->bus; - struct pci_dev *pdev = bus->host_pci; + struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL; int err; int have_bphy = 0; int have_gphy = 0; @@ -3706,7 +3706,7 @@ static int b43legacy_one_core_attach(struct ssb_device *dev, if (!list_empty(&wl->devlist)) { /* We are not the first core on this chip. */ - pdev = dev->bus->host_pci; + pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL; /* Only special chips support more than one wireless * core, although some of the other chips have more than * one wireless core as well. Check for this and -- cgit v1.2.3 From 40b93ad6e97a1d412c4b86f4717fee9b4bc830e1 Mon Sep 17 00:00:00 2001 From: matthieu castet Date: Fri, 9 Oct 2009 22:12:25 +0200 Subject: airo : allow supend with card without power management Some airo card don't support power Management [1]. Don't abort suspend with those cards. 00:06.0 Network controller: AIRONET Wireless Communications PC4800 (rev 01) Flags: medium devsel, IRQ 17 Memory at dffffe00 (32-bit, non-prefetchable) [size=128] I/O ports at d000 [size=128] I/O ports at cc00 [size=64] Kernel driver in use: airo Signed-off-by: Matthieu CASTET Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 7116a1aa20ce..e265ba14054b 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5660,7 +5660,8 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); pci_save_state(pdev); - return pci_set_power_state(pdev, pci_choose_state(pdev, state)); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; } static int airo_pci_resume(struct pci_dev *pdev) -- cgit v1.2.3 From f33269b8968d1c64772a9221e2c9c42d07a9b5ae Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:19 -0700 Subject: iwl3945: update iwl3945_apm_init() Update iwl3945_apm_init() to set up device registers in sequence most recently recommended by factory. Add resets for APMG interrupts and radio chip, formerly done only in iwl3945_apm_reset(); moving them here assures that apm_init() will do a complete job of preparing hardware not only after platform boot, but also after apm_stop() has executed (due to rfkill, ifconfig down, driver unload, etc.). This is in preparation to completely remove apm_reset(). Add some comments. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 42 ++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 4115672e2338..89f82396a13a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -982,23 +982,45 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) return rc; } +/* + * Start up NIC's basic functionality after it has been reset + * (e.g. after platform boot, or shutdown via iwl3945_apm_stop()) + * NOTE: This does not load uCode nor start the embedded processor + */ static int iwl3945_apm_init(struct iwl_priv *priv) { int ret; iwl_power_initialize(priv); + /* Configure chip clock phase-lock-loop */ + iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL); + + /* + * Disable L0S exit timer (platform NMI Work/Around) + * (does this do anything on 3945, or just 4965 and beyond?) + */ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */ + /* Disable L0s without affecting L1; don't wait for ICH (L0s bug W/A) */ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - /* set "initialization complete" bit to move adapter - * D0U* --> D0A* state */ + /* Set FH wait threshold to maximum (HW error during stress W/A) */ + iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); + + /* + * Set "initialization complete" bit to move adapter from + * D0U* --> D0A* (powered-up active) state. + */ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + /* + * Wait for clock stabilization; once stabilized, access to + * device-internal resources is supported, e.g. iwl_write_prph() + * and accesses to uCode SRAM. + */ ret = iwl_poll_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); @@ -1007,13 +1029,21 @@ static int iwl3945_apm_init(struct iwl_priv *priv) goto out; } - /* enable DMA */ + /* Enable DMA and BSM clocks, wait for them to stabilize */ iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); - udelay(20); - /* disable L1-Active */ + /* Clear APMG (NIC's internal power management) interrupts */ + iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); + iwl_write_prph(priv, APMG_RTC_INT_STT_REG, 0xFFFFFFFF); + + /* Reset radio chip */ + iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); + udelay(5); + iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); + + /* Disable L1-Active */ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); -- cgit v1.2.3 From 4d2ccdb94847248a4075414169108d8f929c153c Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:20 -0700 Subject: iwlwifi: turn off device when not used. In some cases (e.g. when mac80211 calls iwl_mac_stop() for suspend or user no longer wants device active), device has not been going into low power state via __iwl_down(). apm_ops.reset() does not put device into low power state; instead it resets the device, then puts it into a powered-up state ready to be re-loaded with uCode and re-started. This has needlessly warmed up user's laptops and drained batteries. With current architecture in which mac80211 controls device up/down (including resetting device after firmware errors), there is no need for apm_ops.reset() any more; apm_ops.reset() is basically a combination of apm_ops.stop() and apm_ops.init(). Instead, __iwl_down() now unconditionally places the device into a low-power state via apm_ops.stop(). Device may be re-started via __iwl_up() calling apm_ops.init() as soon as it may be needed (e.g. quickly for firmware errors), but in the meantime, device will stop wasting energy. Note that, even in this low power state, if driver re-enables interrupts, the device retains the ability to sense the hardware RF-KILL switch, and (except for 3945) interrupt the host when it changes. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 +++----- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 ++---- 2 files changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8d7bc38fe005..0878b34ee586 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1899,11 +1899,9 @@ static void __iwl_down(struct iwl_priv *priv) udelay(5); - /* FIXME: apm_ops.suspend(priv) */ - if (exit_pending) - priv->cfg->ops->lib->apm_ops.stop(priv); - else - priv->cfg->ops->lib->apm_ops.reset(priv); + /* Stop the device, and put it in low power state */ + priv->cfg->ops->lib->apm_ops.stop(priv); + exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c347d6631d85..adf4ebe6bb78 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2576,10 +2576,8 @@ static void __iwl3945_down(struct iwl_priv *priv) udelay(5); - if (exit_pending) - priv->cfg->ops->lib->apm_ops.stop(priv); - else - priv->cfg->ops->lib->apm_ops.reset(priv); + /* Stop the device, and put it in low power state */ + priv->cfg->ops->lib->apm_ops.stop(priv); exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); -- cgit v1.2.3 From 278d84051d1944080d4cfdba205af5f5ce4f4064 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:21 -0700 Subject: iwl3945: remove unnecessary call to apm_ops.reset() Now that we're unconditionally using apm_ops.stop() to reset and power-down the device in __iwl3945_down(), the apm_ops.reset() is redundant. Removing this call will also allow us to remove iwl3945_apm_reset(). Remove unneeded iwl_clear_bit(CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ) because this bit will be set again very soon in iwl3945_hw_txq_ctx_stop() and other following calls. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index adf4ebe6bb78..ab4c4bae7600 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2563,11 +2563,6 @@ static void __iwl3945_down(struct iwl_priv *priv) test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; - priv->cfg->ops->lib->apm_ops.reset(priv); - spin_lock_irqsave(&priv->lock, flags); - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - spin_unlock_irqrestore(&priv->lock, flags); - iwl3945_hw_txq_ctx_stop(priv); iwl3945_hw_rxq_stop(priv); -- cgit v1.2.3 From b660d3adb8dd4ead54744c9269bae9338163020a Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:22 -0700 Subject: iwlagn, iwl3945: remove apm_reset() functions Clean up device-specific apm_reset() functions and library infrastructure, now that these reset() functions are no longer being used. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 - drivers/net/wireless/iwlwifi/iwl-3945.c | 42 ------------------------------ drivers/net/wireless/iwlwifi/iwl-4965.c | 41 ------------------------------ drivers/net/wireless/iwlwifi/iwl-5000.c | 45 --------------------------------- drivers/net/wireless/iwlwifi/iwl-6000.c | 1 - drivers/net/wireless/iwlwifi/iwl-core.h | 1 - drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 7 files changed, 132 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 679a67ff76eb..1fc38142a491 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -111,7 +111,6 @@ static struct iwl_lib_ops iwl1000_lib = { .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, - .reset = iwl5000_apm_reset, .stop = iwl_apm_stop, .config = iwl1000_nic_config, .set_pwr_src = iwl_set_pwr_src, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 89f82396a13a..f8ce96c94c6b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1198,47 +1198,6 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) iwl3945_hw_txq_ctx_free(priv); } -static int iwl3945_apm_reset(struct iwl_priv *priv) -{ - iwl_apm_stop_master(priv); - - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - udelay(10); - - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - - iwl_write_prph(priv, APMG_CLK_CTRL_REG, - APMG_CLK_VAL_BSM_CLK_RQT); - - iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); - iwl_write_prph(priv, APMG_RTC_INT_STT_REG, - 0xFFFFFFFF); - - /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); - udelay(10); - - iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); - udelay(5); - iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); - - /* Clear the 'host command active' bit... */ - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - - wake_up_interruptible(&priv->wait_command_queue); - - return 0; -} - /** * iwl3945_hw_reg_adjust_power_by_temp * return index delta into power gain settings table @@ -2833,7 +2792,6 @@ static struct iwl_lib_ops iwl3945_lib = { .dump_nic_error_log = iwl3945_dump_nic_error_log, .apm_ops = { .init = iwl3945_apm_init, - .reset = iwl3945_apm_reset, .stop = iwl_apm_stop, .config = iwl3945_nic_config, .set_pwr_src = iwl3945_set_pwr_src, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index f8eed9a4abc1..782a36198f38 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -397,46 +397,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static int iwl4965_apm_reset(struct iwl_priv *priv) -{ - int ret = 0; - - iwl_apm_stop_master(priv); - - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - - udelay(10); - - /* FIXME: put here L1A -L0S w/a */ - - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret < 0) - goto out; - - udelay(10); - - /* Enable DMA and BSM Clock */ - iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); - - udelay(10); - - /* disable L1A */ - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - -out: - return ret; -} - /* Reset differential Rx gains in NIC to prepare for chain noise calibration. * Called after every association, but this runs only once! * ... once chain noise is calibrated the first time, it's good forever. */ @@ -2273,7 +2233,6 @@ static struct iwl_lib_ops iwl4965_lib = { .dump_nic_error_log = iwl_dump_nic_error_log, .apm_ops = { .init = iwl4965_apm_init, - .reset = iwl4965_apm_reset, .stop = iwl_apm_stop, .config = iwl4965_nic_config, .set_pwr_src = iwl_set_pwr_src, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 8cc3d50e7f59..33b38aa0d8c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -118,49 +118,6 @@ int iwl5000_apm_init(struct iwl_priv *priv) return ret; } -int iwl5000_apm_reset(struct iwl_priv *priv) -{ - int ret = 0; - - iwl_apm_stop_master(priv); - - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - - udelay(10); - - - /* FIXME: put here L1A -L0S w/a */ - - if (priv->cfg->need_pll_cfg) - iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); - - /* set "initialization complete" bit to move adapter - * D0U* --> D0A* state */ - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret < 0) { - IWL_DEBUG_INFO(priv, "Failed to init the card\n"); - goto out; - } - - /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); - - udelay(20); - - /* disable L1-Active */ - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); -out: - - return ret; -} - - /* NIC configuration for 5000 series */ void iwl5000_nic_config(struct iwl_priv *priv) { @@ -1522,7 +1479,6 @@ struct iwl_lib_ops iwl5000_lib = { .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, - .reset = iwl5000_apm_reset, .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -1574,7 +1530,6 @@ static struct iwl_lib_ops iwl5150_lib = { .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, - .reset = iwl5000_apm_reset, .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index d1f0b0b4ad0c..46af74b86a83 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -192,7 +192,6 @@ static struct iwl_lib_ops iwl6000_lib = { .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, - .reset = iwl5000_apm_reset, .stop = iwl_apm_stop, .config = iwl6000_nic_config, .set_pwr_src = iwl_set_pwr_src, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 6688b6944200..447eb64e1f69 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -109,7 +109,6 @@ struct iwl_hcmd_utils_ops { struct iwl_apm_ops { int (*init)(struct iwl_priv *priv); - int (*reset)(struct iwl_priv *priv); void (*stop)(struct iwl_priv *priv); void (*config)(struct iwl_priv *priv); int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 72946c144be7..9da0b0343b99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -86,7 +86,6 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, extern int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp); extern int iwl5000_apm_init(struct iwl_priv *priv); -extern int iwl5000_apm_reset(struct iwl_priv *priv); extern void iwl5000_nic_config(struct iwl_priv *priv); extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv); extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, -- cgit v1.2.3 From bd35f150823c21000f4c0f029abb258bc1ae3b5f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 9 Oct 2009 13:20:23 -0700 Subject: iwlwifi: remove duplicated/unused definition "IWL_CMD_QUEUE_NUM" is being defined in multiple places and used by all the devices. move it to iwl-dev.h file and shared by all the devices. Remove "IWL_CMD_FIFO_NUM", replaced by "IWL49_CMD_FIFO_NUM" and IWL50_CMD_FIFO_NUM" Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 3 --- drivers/net/wireless/iwlwifi/iwl-dev.h | 6 ++++++ 3 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 16772780c5b0..ccdac69838dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -71,12 +71,6 @@ #include "iwl-eeprom.h" -/* - * uCode queue management definitions ... - * Queue #4 is the command queue for 3945 and 4965. - */ -#define IWL_CMD_QUEUE_NUM 4 - /* Time constants */ #define SHORT_SLOT_TIME 9 #define LONG_SLOT_TIME 20 diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index b34322a32458..c606366b582c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -76,12 +76,9 @@ /* * uCode queue management definitions ... - * Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4. * The first queue used for block-ack aggregation is #7 (4965 only). * All block-ack aggregation queues should map to Tx DMA/FIFO channel 7. */ -#define IWL_CMD_QUEUE_NUM 4 -#define IWL_CMD_FIFO_NUM 4 #define IWL49_FIRST_AMPDU_QUEUE 7 /* Time constants */ diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9da0b0343b99..394402afaa57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -323,6 +323,12 @@ struct iwl_channel_info { * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */ #define IWL_MIN_NUM_QUEUES 10 +/* + * uCode queue management definitions ... + * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00. + */ +#define IWL_CMD_QUEUE_NUM 4 + /* Power management (not Tx power) structures */ enum iwl_pwr_src { -- cgit v1.2.3 From 55036d6602679fb88dd7b1c19bb7203a0213b684 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 9 Oct 2009 13:20:24 -0700 Subject: iwlwifi: additional items in sensitivity range table Add more items to sensitivity range table to avoid using hardcoded values. Initialize the table per device since unique per device information is required to perform sensitivity calibration. additional items in sensitivity range table: .barker_corr_th_min: Barker correlation threshold minimum .barker_corr_th_min_mrc: Barker correlation threshold minimum for MRC .nrg_th_cca: Energy threshold for Clear Channel Assessment Barker codes are a technique used in WLAN encoding for transmission. MRC is "Maximal Ratio Combining", a technique for optimally combining the signals from 2 or more receivers to achieve a better signal. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-5000.c | 8 ++++++++ drivers/net/wireless/iwlwifi/iwl-6000.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-calib.c | 9 ++++++--- drivers/net/wireless/iwlwifi/iwl-commands.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-dev.h | 8 ++++++++ 6 files changed, 30 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 782a36198f38..966858587e25 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -678,6 +678,10 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = { .nrg_th_cck = 100, .nrg_th_ofdm = 100, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, }; static void iwl4965_set_ct_threshold(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 33b38aa0d8c3..a9d1aa3ad57b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -329,6 +329,10 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = { .auto_corr_max_cck_mrc = 400, .nrg_th_cck = 95, .nrg_th_ofdm = 95, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, }; static struct iwl_sensitivity_ranges iwl5150_sensitivity = { @@ -351,6 +355,10 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = { .auto_corr_max_cck_mrc = 400, .nrg_th_cck = 95, .nrg_th_ofdm = 95, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, }; const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 46af74b86a83..dda1dd6ed40a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -121,6 +121,10 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { .auto_corr_max_cck_mrc = 310, .nrg_th_cck = 97, .nrg_th_ofdm = 100, + + .barker_corr_th_min = 190, + .barker_corr_th_min_mrc = 390, + .nrg_th_cca = 62, }; static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 69a80d7c2e44..1f801eb9fbff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -447,11 +447,11 @@ static int iwl_sensitivity_write(struct iwl_priv *priv) cpu_to_le16((u16)data->nrg_th_ofdm); cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] = - cpu_to_le16(190); + cpu_to_le16(data->barker_corr_th_min); cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] = - cpu_to_le16(390); + cpu_to_le16(data->barker_corr_th_min_mrc); cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] = - cpu_to_le16(62); + cpu_to_le16(data->nrg_th_cca); IWL_DEBUG_CALIB(priv, "ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n", data->auto_corr_ofdm, data->auto_corr_ofdm_mrc, @@ -524,6 +524,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv) data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc; data->nrg_th_cck = ranges->nrg_th_cck; data->nrg_th_ofdm = ranges->nrg_th_ofdm; + data->barker_corr_th_min = ranges->barker_corr_th_min; + data->barker_corr_th_min_mrc = ranges->barker_corr_th_min_mrc; + data->nrg_th_cca = ranges->nrg_th_cca; data->last_bad_plcp_cnt_ofdm = 0; data->last_fa_cnt_ofdm = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index ba3e4c837d87..2e8a55ed7de5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3247,12 +3247,6 @@ struct iwl_missed_beacon_notif { * Lower values mean higher energy; this means making sure that the value * in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy". * - * Driver should set the following entries to fixed values: - * - * HD_MIN_ENERGY_OFDM_DET_INDEX 100 - * HD_BARKER_CORR_TH_ADD_MIN_INDEX 190 - * HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX 390 - * HD_OFDM_ENERGY_TH_IN_INDEX 62 */ /* diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 394402afaa57..c1b07e2045e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -629,6 +629,10 @@ struct iwl_sensitivity_ranges { u16 auto_corr_max_cck_mrc; u16 auto_corr_min_cck; u16 auto_corr_min_cck_mrc; + + u16 barker_corr_th_min; + u16 barker_corr_th_min_mrc; + u16 nrg_th_cca; }; @@ -850,6 +854,10 @@ struct iwl_sensitivity_data { s32 nrg_auto_corr_silence_diff; u32 num_in_cck_no_fa; u32 nrg_th_ofdm; + + u16 barker_corr_th_min; + u16 barker_corr_th_min_mrc; + u16 nrg_th_cca; }; /* Chain noise (differential Rx gain) calib data */ -- cgit v1.2.3 From 1a34c043802a213e719420ece395cf25c85cc7c5 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 9 Oct 2009 13:20:25 -0700 Subject: iwlwifi: fix userspace setting of sleep_level_override The sleep_level_override debugfs file is used by the user to request a static power index instead of the dynamic sleep values. Users are expected to provide value from 1 to 5 as an index or -1 to disable it. The problem at the moment is that users can also provide 0 to this file which, together with the value 1, is translated to index 1. This is confusing and even more so when users write 0 to sleep_level_override and then read 1 from it afterwards. Modify checking to treat 0 as invalid. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 1794b9c4e6ac..aa62357c9151 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -801,7 +801,9 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, * valid here. However, let's not confuse them and present * IWL_POWER_INDEX_1 as "1", not "0". */ - if (value > 0) + if (value == 0) + return -EINVAL; + else if (value > 0) value -= 1; if (value != -1 && (value < 0 || value >= IWL_POWER_NUM)) -- cgit v1.2.3 From 743cdf1b65656faf1e6f1f74278c52b89a0b7360 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:26 -0700 Subject: iwl3945: streamline iwl3945_rfkill_poll() iwl3945_rfkill_poll() has been silently calling wiphy_rfkill_set_hw_state() every 2 seconds, regardless of whether hardware RF KILL switch changed state. Call wiphy_rfkill_set_hw_state() only when RFKILL switch changes. Add IWL_DEBUG_RF_KILL log message and documentation. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index ab4c4bae7600..2406b73e9093 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2717,19 +2717,34 @@ static void iwl3945_bg_alive_start(struct work_struct *data) mutex_unlock(&priv->mutex); } +/* + * 3945 cannot interrupt driver when hardware rf kill switch toggles; + * driver must poll CSR_GP_CNTRL_REG register for change. This register + * *is* readable even when device has been SW_RESET into low power mode + * (e.g. during RF KILL). + */ static void iwl3945_rfkill_poll(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, rfkill_poll.work); + bool old_rfkill = test_bit(STATUS_RF_KILL_HW, &priv->status); + bool new_rfkill = !(iwl_read32(priv, CSR_GP_CNTRL) + & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); - if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) - clear_bit(STATUS_RF_KILL_HW, &priv->status); - else - set_bit(STATUS_RF_KILL_HW, &priv->status); + if (new_rfkill != old_rfkill) { + if (new_rfkill) + set_bit(STATUS_RF_KILL_HW, &priv->status); + else + clear_bit(STATUS_RF_KILL_HW, &priv->status); - wiphy_rfkill_set_hw_state(priv->hw->wiphy, - test_bit(STATUS_RF_KILL_HW, &priv->status)); + wiphy_rfkill_set_hw_state(priv->hw->wiphy, new_rfkill); + + IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", + new_rfkill ? "disable radio" : "enable radio"); + } + /* Keep this running, even if radio now enabled. This will be + * cancelled in mac_start() if system decides to start again */ queue_delayed_work(priv->workqueue, &priv->rfkill_poll, round_jiffies_relative(2 * HZ)); -- cgit v1.2.3 From 008a9e3e3c37abd7f56d2478fe92d5874de3630a Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 9 Oct 2009 13:20:27 -0700 Subject: iwl3945: move iwl_power_initialize() iwl_power_initialize() initializes driver data (not device hardware), and does not need to execute more than once (when the driver initializes). Therefore, it does not belong in iwl3945_apm_init(), which initializes hardware, and may run more than once. Move it to iwl3945_pci_probe(), where it will run only once. This agrees with similar placement in iwl-agn.c's iwl_pci_probe(), although placement under "services" seemed more appropriate than under "mac80211". Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 -- drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index f8ce96c94c6b..4e15a8e20d09 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -991,8 +991,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv) { int ret; - iwl_power_initialize(priv); - /* Configure chip clock phase-lock-loop */ iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2406b73e9093..e0e566c932c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4064,6 +4064,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e &priv->bands[IEEE80211_BAND_2GHZ].channels[5]); iwl3945_setup_deferred_work(priv); iwl3945_setup_rx_handlers(priv); + iwl_power_initialize(priv); /********************************* * 8. Setup and Register mac80211 -- cgit v1.2.3 From 88804e2b33b6ab3974ff2330cd045ca53d6750c5 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 9 Oct 2009 13:20:28 -0700 Subject: iwlwifi: dynamic allocate tx queue structure Instead of always allocate the max number of tx queue structure, use dynamic allocation based on the number of queues in device configuration. With these changes, device does not have to allocate more memory than the h/w can support. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 4 +++ drivers/net/wireless/iwlwifi/iwl-3945.c | 23 +++++++++++----- drivers/net/wireless/iwlwifi/iwl-4965.c | 33 ++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-5000.c | 42 ++++++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-6000.c | 36 ++++++++++++++++++------- drivers/net/wireless/iwlwifi/iwl-core.c | 21 +++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 5 +++- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 12 +++++++-- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +-- drivers/net/wireless/iwlwifi/iwl-tx.c | 22 ++++++++++----- drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 - 11 files changed, 144 insertions(+), 59 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 1fc38142a491..a00f947bd59c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -158,6 +158,8 @@ struct iwl_cfg iwl1000_bgn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_1000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, @@ -179,6 +181,8 @@ struct iwl_cfg iwl1000_bg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_1000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 4e15a8e20d09..314cae773646 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -958,6 +958,11 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) iwl3945_hw_txq_ctx_free(priv); + /* allocate tx queue structure */ + rc = iwl_alloc_txq_mem(priv); + if (rc) + return rc; + /* Tx CMD queue */ rc = iwl3945_tx_reset(priv); if (rc) @@ -1170,12 +1175,16 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv) int txq_id; /* Tx queues */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - if (txq_id == IWL_CMD_QUEUE_NUM) - iwl_cmd_queue_free(priv); - else - iwl_tx_queue_free(priv, txq_id); + if (priv->txq) + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; + txq_id++) + if (txq_id == IWL_CMD_QUEUE_NUM) + iwl_cmd_queue_free(priv); + else + iwl_tx_queue_free(priv, txq_id); + /* free tx queue structure */ + iwl_free_txq_mem(priv); } void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) @@ -2503,7 +2512,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) } /* Assign number of Usable TX queues */ - priv->hw_params.max_txq_num = IWL39_NUM_QUEUES; + priv->hw_params.max_txq_num = priv->cfg->num_of_queues; priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; @@ -2838,6 +2847,7 @@ static struct iwl_cfg iwl3945_bg_cfg = { .eeprom_size = IWL3945_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, + .num_of_queues = IWL39_NUM_QUEUES, .mod_params = &iwl3945_mod_params, .use_isr_legacy = true, .ht_greenfield_support = false, @@ -2853,6 +2863,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { .eeprom_size = IWL3945_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_3945_EEPROM_VERSION, .ops = &iwl3945_ops, + .num_of_queues = IWL39_NUM_QUEUES, .mod_params = &iwl3945_mod_params, .use_isr_legacy = true, .ht_greenfield_support = false, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 966858587e25..c9d90169ab1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -62,8 +62,6 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv); /* module parameters */ static struct iwl_mod_params iwl4965_mod_params = { - .num_of_queues = IWL49_NUM_QUEUES, - .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, .amsdu_size_8K = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -698,19 +696,16 @@ static void iwl4965_set_ct_threshold(struct iwl_priv *priv) */ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) { + if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && + priv->cfg->mod_params->num_of_queues <= IWL49_NUM_QUEUES) + priv->cfg->num_of_queues = + priv->cfg->mod_params->num_of_queues; - if ((priv->cfg->mod_params->num_of_queues > IWL49_NUM_QUEUES) || - (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { - IWL_ERR(priv, - "invalid queues_num, should be between %d and %d\n", - IWL_MIN_NUM_QUEUES, IWL49_NUM_QUEUES); - return -EINVAL; - } - - priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->num_of_queues; priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM; priv->hw_params.scd_bc_tbls_size = - IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl); + priv->cfg->num_of_queues * + sizeof(struct iwl4965_scd_bc_tbl); priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.max_stations = IWL4965_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; @@ -1739,11 +1734,13 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || - (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { + (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues + <= txq_id)) { IWL_WARN(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWL49_FIRST_AMPDU_QUEUE, - IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1); + IWL49_FIRST_AMPDU_QUEUE + + priv->cfg->num_of_ampdu_queues - 1); return -EINVAL; } @@ -1804,11 +1801,13 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, u16 ra_tid; if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || - (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { + (IWL49_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues + <= txq_id)) { IWL_WARN(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWL49_FIRST_AMPDU_QUEUE, - IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1); + IWL49_FIRST_AMPDU_QUEUE + + priv->cfg->num_of_ampdu_queues - 1); return -EINVAL; } @@ -2286,6 +2285,8 @@ struct iwl_cfg iwl4965_agn_cfg = { .eeprom_ver = EEPROM_4965_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, + .num_of_queues = IWL49_NUM_QUEUES, + .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, .mod_params = &iwl4965_mod_params, .use_isr_legacy = true, .ht_greenfield_support = false, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a9d1aa3ad57b..ab5b9d8d66be 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -749,18 +749,16 @@ int iwl5000_alive_notify(struct iwl_priv *priv) int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { - if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || - (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { - IWL_ERR(priv, - "invalid queues_num, should be between %d and %d\n", - IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES); - return -EINVAL; - } + if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && + priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES) + priv->cfg->num_of_queues = + priv->cfg->mod_params->num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; priv->hw_params.scd_bc_tbls_size = - IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); + priv->cfg->num_of_queues * + sizeof(struct iwl5000_scd_bc_tbl); priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; @@ -912,11 +910,13 @@ int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, u16 ra_tid; if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || - (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { + (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues + <= txq_id)) { IWL_WARN(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWL50_FIRST_AMPDU_QUEUE, - IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1); + IWL50_FIRST_AMPDU_QUEUE + + priv->cfg->num_of_ampdu_queues - 1); return -EINVAL; } @@ -970,11 +970,13 @@ int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || - (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { + (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues + <= txq_id)) { IWL_ERR(priv, "queue number out of range: %d, must be %d to %d\n", txq_id, IWL50_FIRST_AMPDU_QUEUE, - IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1); + IWL50_FIRST_AMPDU_QUEUE + + priv->cfg->num_of_ampdu_queues - 1); return -EINVAL; } @@ -1584,8 +1586,6 @@ static struct iwl_ops iwl5150_ops = { }; struct iwl_mod_params iwl50_mod_params = { - .num_of_queues = IWL50_NUM_QUEUES, - .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .amsdu_size_8K = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -1602,6 +1602,8 @@ struct iwl_cfg iwl5300_agn_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, @@ -1621,6 +1623,8 @@ struct iwl_cfg iwl5100_bg_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, @@ -1640,6 +1644,8 @@ struct iwl_cfg iwl5100_abg_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, @@ -1659,6 +1665,8 @@ struct iwl_cfg iwl5100_agn_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, @@ -1678,6 +1686,8 @@ struct iwl_cfg iwl5350_agn_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, @@ -1697,6 +1707,8 @@ struct iwl_cfg iwl5150_agn_cfg = { .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index dda1dd6ed40a..bdc1c74b6820 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -129,18 +129,16 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) { - if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || - (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) { - IWL_ERR(priv, - "invalid queues_num, should be between %d and %d\n", - IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES); - return -EINVAL; - } + if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && + priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES) + priv->cfg->num_of_queues = + priv->cfg->mod_params->num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; + priv->hw_params.max_txq_num = priv->cfg->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; priv->hw_params.scd_bc_tbls_size = - IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); + priv->cfg->num_of_queues * + sizeof(struct iwl5000_scd_bc_tbl); priv->hw_params.tfd_size = sizeof(struct iwl_tfd); priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; @@ -248,6 +246,8 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, @@ -272,6 +272,8 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, @@ -295,6 +297,8 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, @@ -321,6 +325,8 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, @@ -345,6 +351,8 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, @@ -368,6 +376,8 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, @@ -391,6 +401,8 @@ struct iwl_cfg iwl6050_2agn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, @@ -415,6 +427,8 @@ struct iwl_cfg iwl6050_2abg_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, @@ -438,6 +452,8 @@ struct iwl_cfg iwl6000_3agn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, @@ -462,6 +478,8 @@ struct iwl_cfg iwl6050_3agn_cfg = { .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index dc7fd87bed98..c40c7e2dacf8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2826,6 +2826,27 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) } EXPORT_SYMBOL(iwl_mac_reset_tsf); +int iwl_alloc_txq_mem(struct iwl_priv *priv) +{ + if (!priv->txq) + priv->txq = kzalloc( + sizeof(struct iwl_tx_queue) * priv->cfg->num_of_queues, + GFP_KERNEL); + if (!priv->txq) { + IWL_ERR(priv, "Not enough memory for txq \n"); + return -ENOMEM; + } + return 0; +} +EXPORT_SYMBOL(iwl_alloc_txq_mem); + +void iwl_free_txq_mem(struct iwl_priv *priv) +{ + kfree(priv->txq); + priv->txq = NULL; +} +EXPORT_SYMBOL(iwl_free_txq_mem); + #ifdef CONFIG_IWLWIFI_DEBUGFS #define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 447eb64e1f69..3679c2ced04d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -204,7 +204,6 @@ struct iwl_mod_params { int sw_crypto; /* def: 0 = using hardware encryption */ int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ - int num_of_ampdu_queues;/* def: HW dependent */ int disable_11n; /* def: 0 = 11n capabilities enabled */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ @@ -257,6 +256,8 @@ struct iwl_cfg { int eeprom_size; u16 eeprom_ver; u16 eeprom_calib_ver; + int num_of_queues; /* def: HW dependent */ + int num_of_ampdu_queues;/* def: HW dependent */ const struct iwl_ops *ops; const struct iwl_mod_params *mod_params; u8 valid_tx_ant; @@ -326,6 +327,8 @@ void iwl_config_ap(struct iwl_priv *priv); int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); void iwl_mac_reset_tsf(struct ieee80211_hw *hw); +int iwl_alloc_txq_mem(struct iwl_priv *priv); +void iwl_free_txq_mem(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_alloc_traffic_mem(struct iwl_priv *priv); void iwl_free_traffic_mem(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index aa62357c9151..028d4bf8dcd8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -884,10 +884,14 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, struct iwl_rx_queue *rxq = &priv->rxq; char *buf; int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) + - (IWL_MAX_NUM_QUEUES * 32 * 8) + 400; + (priv->cfg->num_of_queues * 32 * 8) + 400; const u8 *ptr; ssize_t ret; + if (!priv->txq) { + IWL_ERR(priv, "txq not ready\n"); + return -EAGAIN; + } buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) { IWL_ERR(priv, "Can not allocate buffer\n"); @@ -979,8 +983,12 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, int pos = 0; int cnt; int ret; - const size_t bufsz = sizeof(char) * 60 * IWL_MAX_NUM_QUEUES; + const size_t bufsz = sizeof(char) * 60 * priv->cfg->num_of_queues; + if (!priv->txq) { + IWL_ERR(priv, "txq not ready\n"); + return -EAGAIN; + } buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c1b07e2045e6..6d7c2350d8c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -974,8 +974,6 @@ struct traffic_stats { }; #endif -#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ - struct iwl_priv { /* ieee device used by generic ieee processing code */ @@ -1103,7 +1101,7 @@ struct iwl_priv { /* Rx and Tx DMA processing queues */ struct iwl_rx_queue rxq; - struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES]; + struct iwl_tx_queue *txq; unsigned long txq_ctx_active_msk; struct iwl_dma_ptr kw; /* keep warm address */ struct iwl_dma_ptr scd_bc_tbls; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index c832ba085dba..625da63d01ee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -405,15 +405,19 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv) int txq_id; /* Tx queues */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - if (txq_id == IWL_CMD_QUEUE_NUM) - iwl_cmd_queue_free(priv); - else - iwl_tx_queue_free(priv, txq_id); - + if (priv->txq) + for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; + txq_id++) + if (txq_id == IWL_CMD_QUEUE_NUM) + iwl_cmd_queue_free(priv); + else + iwl_tx_queue_free(priv, txq_id); iwl_free_dma_ptr(priv, &priv->kw); iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); + + /* free tx queue structure */ + iwl_free_txq_mem(priv); } EXPORT_SYMBOL(iwl_hw_txq_ctx_free); @@ -445,6 +449,12 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) IWL_ERR(priv, "Keep Warm allocation failed\n"); goto error_kw; } + + /* allocate tx queue structure */ + ret = iwl_alloc_txq_mem(priv); + if (ret) + goto error; + spin_lock_irqsave(&priv->lock, flags); /* Turn off all Tx DMA fifos */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e0e566c932c5..66da441fe366 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -88,7 +88,6 @@ MODULE_LICENSE("GPL"); /* module parameters */ struct iwl_mod_params iwl3945_mod_params = { - .num_of_queues = IWL39_NUM_QUEUES, /* Not used */ .sw_crypto = 1, .restart_fw = 1, /* the rest are 0 by default */ -- cgit v1.2.3 From 92a35bda792cf9295b1d399f7c937d4560292b1e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 9 Oct 2009 13:20:29 -0700 Subject: iwlwifi: showing accumulative ucode statistics counters Adding accumulative statistics counters in iwlwifi driver. Statistics counters are reported by uCode every beacon interval; but can be reset by uCode when needed. The accumulative statistics counters is maintained by driver to keep track of the history of all the counters. Update the ucode stats files in debugfs to display both latest and accumulative counters. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 - drivers/net/wireless/iwlwifi/iwl-debugfs.c | 629 ++++++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 41 ++ 4 files changed, 447 insertions(+), 229 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 314cae773646..cee03e7fc2da 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -361,8 +361,6 @@ void iwl3945_hw_rx_statistics(struct iwl_priv *priv, memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39)); iwl_leds_background(priv); - - priv->last_statistics_time = jiffies; } /****************************************************************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 028d4bf8dcd8..2cd11ba96370 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1079,10 +1079,10 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, sizeof(struct statistics_rx_non_phy) * 20 + sizeof(struct statistics_rx_ht_phy) * 20 + 400; ssize_t ret; - struct statistics_rx_phy *ofdm; - struct statistics_rx_phy *cck; - struct statistics_rx_non_phy *general; - struct statistics_rx_ht_phy *ht; + struct statistics_rx_phy *ofdm, *accum_ofdm; + struct statistics_rx_phy *cck, *accum_cck; + struct statistics_rx_non_phy *general, *accum_general; + struct statistics_rx_ht_phy *ht, *accum_ht; if (!iwl_is_alive(priv)) return -EAGAIN; @@ -1111,155 +1111,268 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, cck = &priv->statistics.rx.cck; general = &priv->statistics.rx.general; ht = &priv->statistics.rx.ofdm_ht; + accum_ofdm = &priv->accum_statistics.rx.ofdm; + accum_cck = &priv->accum_statistics.rx.cck; + accum_general = &priv->accum_statistics.rx.general; + accum_ht = &priv->accum_statistics.rx.ofdm_ht; pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM:\n"); - pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n", - le32_to_cpu(ofdm->ina_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n", - le32_to_cpu(ofdm->fina_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", - le32_to_cpu(ofdm->plcp_err)); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", - le32_to_cpu(ofdm->crc32_err)); - pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", - le32_to_cpu(ofdm->overrun_err)); - pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", - le32_to_cpu(ofdm->early_overrun_err)); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", - le32_to_cpu(ofdm->crc32_good)); - pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n", - le32_to_cpu(ofdm->false_alarm_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n", - le32_to_cpu(ofdm->fina_sync_err_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n", - le32_to_cpu(ofdm->sfd_timeout)); - pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n", - le32_to_cpu(ofdm->fina_timeout)); - pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n", - le32_to_cpu(ofdm->unresponded_rts)); - pos += scnprintf(buf + pos, bufsz - pos, - "rxe_frame_limit_overrun: %u\n", - le32_to_cpu(ofdm->rxe_frame_limit_overrun)); - pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", - le32_to_cpu(ofdm->sent_ack_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", - le32_to_cpu(ofdm->sent_cts_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", - le32_to_cpu(ofdm->sent_ba_rsp_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", - le32_to_cpu(ofdm->dsp_self_kill)); - pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", - le32_to_cpu(ofdm->mh_format_err)); - pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", - le32_to_cpu(ofdm->re_acq_main_rssi_sum)); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->ina_cnt), accum_ofdm->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + "overrun_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->overrun_err), + accum_ofdm->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + "early_overrun_err:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->early_overrun_err), + accum_ofdm->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->crc32_good), + accum_ofdm->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + "false_alarm_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->false_alarm_cnt), + accum_ofdm->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_sync_err_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->fina_sync_err_cnt), + accum_ofdm->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sfd_timeout:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->sfd_timeout), + accum_ofdm->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_timeout:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->fina_timeout), + accum_ofdm->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "unresponded_rts:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->unresponded_rts), + accum_ofdm->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->rxe_frame_limit_overrun), + accum_ofdm->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ack_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->sent_ack_cnt), + accum_ofdm->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_cts_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->sent_cts_cnt), + accum_ofdm->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ba_rsp_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->sent_ba_rsp_cnt), + accum_ofdm->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "dsp_self_kill:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->dsp_self_kill), + accum_ofdm->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + "mh_format_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->mh_format_err), + accum_ofdm->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + "re_acq_main_rssi_sum:\t%u\t\t\t%u\n", + le32_to_cpu(ofdm->re_acq_main_rssi_sum), + accum_ofdm->re_acq_main_rssi_sum); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - CCK:\n"); - pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt: %u\n", - le32_to_cpu(cck->ina_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt: %u\n", - le32_to_cpu(cck->fina_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", - le32_to_cpu(cck->plcp_err)); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", - le32_to_cpu(cck->crc32_err)); - pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", - le32_to_cpu(cck->overrun_err)); - pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", - le32_to_cpu(cck->early_overrun_err)); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", - le32_to_cpu(cck->crc32_good)); - pos += scnprintf(buf + pos, bufsz - pos, "false_alarm_cnt: %u\n", - le32_to_cpu(cck->false_alarm_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "fina_sync_err_cnt: %u\n", - le32_to_cpu(cck->fina_sync_err_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "sfd_timeout: %u\n", - le32_to_cpu(cck->sfd_timeout)); - pos += scnprintf(buf + pos, bufsz - pos, "fina_timeout: %u\n", - le32_to_cpu(cck->fina_timeout)); - pos += scnprintf(buf + pos, bufsz - pos, "unresponded_rts: %u\n", - le32_to_cpu(cck->unresponded_rts)); - pos += scnprintf(buf + pos, bufsz - pos, - "rxe_frame_limit_overrun: %u\n", - le32_to_cpu(cck->rxe_frame_limit_overrun)); - pos += scnprintf(buf + pos, bufsz - pos, "sent_ack_cnt: %u\n", - le32_to_cpu(cck->sent_ack_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "sent_cts_cnt: %u\n", - le32_to_cpu(cck->sent_cts_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "sent_ba_rsp_cnt: %u\n", - le32_to_cpu(cck->sent_ba_rsp_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "dsp_self_kill: %u\n", - le32_to_cpu(cck->dsp_self_kill)); - pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", - le32_to_cpu(cck->mh_format_err)); - pos += scnprintf(buf + pos, bufsz - pos, "re_acq_main_rssi_sum: %u\n", - le32_to_cpu(cck->re_acq_main_rssi_sum)); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "ina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "fina_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->plcp_err), accum_cck->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->crc32_err), accum_cck->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + "overrun_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->overrun_err), + accum_cck->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + "early_overrun_err:\t%u\t\t\t%u\n", + le32_to_cpu(cck->early_overrun_err), + accum_cck->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->crc32_good), accum_cck->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + "false_alarm_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(cck->false_alarm_cnt), + accum_cck->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_sync_err_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(cck->fina_sync_err_cnt), + accum_cck->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sfd_timeout:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->sfd_timeout), + accum_cck->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "fina_timeout:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->fina_timeout), + accum_cck->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "unresponded_rts:\t%u\t\t\t%u\n", + le32_to_cpu(cck->unresponded_rts), + accum_cck->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + "rxe_frame_lmt_ovrun:\t%u\t\t\t%u\n", + le32_to_cpu(cck->rxe_frame_limit_overrun), + accum_cck->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ack_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->sent_ack_cnt), + accum_cck->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_cts_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->sent_cts_cnt), + accum_cck->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "sent_ba_rsp_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(cck->sent_ba_rsp_cnt), + accum_cck->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "dsp_self_kill:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->dsp_self_kill), + accum_cck->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + "mh_format_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(cck->mh_format_err), + accum_cck->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + "re_acq_main_rssi_sum:\t%u\t\t\t%u\n", + le32_to_cpu(cck->re_acq_main_rssi_sum), + accum_cck->re_acq_main_rssi_sum); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - GENERAL:\n"); - pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts: %u\n", - le32_to_cpu(general->bogus_cts)); - pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack: %u\n", - le32_to_cpu(general->bogus_ack)); - pos += scnprintf(buf + pos, bufsz - pos, "non_bssid_frames: %u\n", - le32_to_cpu(general->non_bssid_frames)); - pos += scnprintf(buf + pos, bufsz - pos, "filtered_frames: %u\n", - le32_to_cpu(general->filtered_frames)); - pos += scnprintf(buf + pos, bufsz - pos, "non_channel_beacons: %u\n", - le32_to_cpu(general->non_channel_beacons)); - pos += scnprintf(buf + pos, bufsz - pos, "channel_beacons: %u\n", - le32_to_cpu(general->channel_beacons)); - pos += scnprintf(buf + pos, bufsz - pos, "num_missed_bcon: %u\n", - le32_to_cpu(general->num_missed_bcon)); - pos += scnprintf(buf + pos, bufsz - pos, - "adc_rx_saturation_time: %u\n", - le32_to_cpu(general->adc_rx_saturation_time)); - pos += scnprintf(buf + pos, bufsz - pos, - "ina_detection_search_time: %u\n", - le32_to_cpu(general->ina_detection_search_time)); - pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_a: %u\n", - le32_to_cpu(general->beacon_silence_rssi_a)); - pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_b: %u\n", - le32_to_cpu(general->beacon_silence_rssi_b)); - pos += scnprintf(buf + pos, bufsz - pos, "beacon_silence_rssi_c: %u\n", - le32_to_cpu(general->beacon_silence_rssi_c)); - pos += scnprintf(buf + pos, bufsz - pos, - "interference_data_flag: %u\n", - le32_to_cpu(general->interference_data_flag)); - pos += scnprintf(buf + pos, bufsz - pos, "channel_load: %u\n", - le32_to_cpu(general->channel_load)); - pos += scnprintf(buf + pos, bufsz - pos, "dsp_false_alarms: %u\n", - le32_to_cpu(general->dsp_false_alarms)); - pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_a: %u\n", - le32_to_cpu(general->beacon_rssi_a)); - pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_b: %u\n", - le32_to_cpu(general->beacon_rssi_b)); - pos += scnprintf(buf + pos, bufsz - pos, "beacon_rssi_c: %u\n", - le32_to_cpu(general->beacon_rssi_c)); - pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_a: %u\n", - le32_to_cpu(general->beacon_energy_a)); - pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_b: %u\n", - le32_to_cpu(general->beacon_energy_b)); - pos += scnprintf(buf + pos, bufsz - pos, "beacon_energy_c: %u\n", - le32_to_cpu(general->beacon_energy_c)); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_cts:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->bogus_cts), + accum_general->bogus_cts); + pos += scnprintf(buf + pos, bufsz - pos, "bogus_ack:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->bogus_ack), + accum_general->bogus_ack); + pos += scnprintf(buf + pos, bufsz - pos, + "non_bssid_frames:\t%u\t\t\t%u\n", + le32_to_cpu(general->non_bssid_frames), + accum_general->non_bssid_frames); + pos += scnprintf(buf + pos, bufsz - pos, + "filtered_frames:\t%u\t\t\t%u\n", + le32_to_cpu(general->filtered_frames), + accum_general->filtered_frames); + pos += scnprintf(buf + pos, bufsz - pos, + "non_channel_beacons:\t%u\t\t\t%u\n", + le32_to_cpu(general->non_channel_beacons), + accum_general->non_channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + "channel_beacons:\t%u\t\t\t%u\n", + le32_to_cpu(general->channel_beacons), + accum_general->channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + "num_missed_bcon:\t%u\t\t\t%u\n", + le32_to_cpu(general->num_missed_bcon), + accum_general->num_missed_bcon); + pos += scnprintf(buf + pos, bufsz - pos, + "adc_rx_saturation_time:\t%u\t\t\t%u\n", + le32_to_cpu(general->adc_rx_saturation_time), + accum_general->adc_rx_saturation_time); + pos += scnprintf(buf + pos, bufsz - pos, + "ina_detect_search_tm:\t%u\t\t\t%u\n", + le32_to_cpu(general->ina_detection_search_time), + accum_general->ina_detection_search_time); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_silence_rssi_a:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_silence_rssi_a), + accum_general->beacon_silence_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_silence_rssi_b:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_silence_rssi_b), + accum_general->beacon_silence_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_silence_rssi_c:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_silence_rssi_c), + accum_general->beacon_silence_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + "interference_data_flag:\t%u\t\t\t%u\n", + le32_to_cpu(general->interference_data_flag), + accum_general->interference_data_flag); + pos += scnprintf(buf + pos, bufsz - pos, + "channel_load:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->channel_load), + accum_general->channel_load); + pos += scnprintf(buf + pos, bufsz - pos, + "dsp_false_alarms:\t%u\t\t\t%u\n", + le32_to_cpu(general->dsp_false_alarms), + accum_general->dsp_false_alarms); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_rssi_a:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_rssi_a), + accum_general->beacon_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_rssi_b:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_rssi_b), + accum_general->beacon_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_rssi_c:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_rssi_c), + accum_general->beacon_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_energy_a:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_energy_a), + accum_general->beacon_energy_a); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_energy_b:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_energy_b), + accum_general->beacon_energy_b); + pos += scnprintf(buf + pos, bufsz - pos, + "beacon_energy_c:\t%u\t\t\t%u\n", + le32_to_cpu(general->beacon_energy_c), + accum_general->beacon_energy_c); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n"); - pos += scnprintf(buf + pos, bufsz - pos, "plcp_err: %u\n", - le32_to_cpu(ht->plcp_err)); - pos += scnprintf(buf + pos, bufsz - pos, "overrun_err: %u\n", - le32_to_cpu(ht->overrun_err)); - pos += scnprintf(buf + pos, bufsz - pos, "early_overrun_err: %u\n", - le32_to_cpu(ht->early_overrun_err)); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_good: %u\n", - le32_to_cpu(ht->crc32_good)); - pos += scnprintf(buf + pos, bufsz - pos, "crc32_err: %u\n", - le32_to_cpu(ht->crc32_err)); - pos += scnprintf(buf + pos, bufsz - pos, "mh_format_err: %u\n", - le32_to_cpu(ht->mh_format_err)); - pos += scnprintf(buf + pos, bufsz - pos, "agg_crc32_good: %u\n", - le32_to_cpu(ht->agg_crc32_good)); - pos += scnprintf(buf + pos, bufsz - pos, "agg_mpdu_cnt: %u\n", - le32_to_cpu(ht->agg_mpdu_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt: %u\n", - le32_to_cpu(ht->agg_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "plcp_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->plcp_err), accum_ht->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + "overrun_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->overrun_err), accum_ht->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + "early_overrun_err:\t%u\t\t\t%u\n", + le32_to_cpu(ht->early_overrun_err), + accum_ht->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_good:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->crc32_good), accum_ht->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, "crc32_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->crc32_err), accum_ht->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + "mh_format_err:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->mh_format_err), + accum_ht->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + "agg_crc32_good:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->agg_crc32_good), + accum_ht->agg_crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + "agg_mpdu_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->agg_mpdu_cnt), + accum_ht->agg_mpdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -1275,7 +1388,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, char *buf; int bufsz = (sizeof(struct statistics_tx) * 24) + 250; ssize_t ret; - struct statistics_tx *tx; + struct statistics_tx *tx, *accum_tx; if (!iwl_is_alive(priv)) return -EAGAIN; @@ -1301,62 +1414,107 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, * might not reflect the current uCode activity */ tx = &priv->statistics.tx; + accum_tx = &priv->accum_statistics.tx; pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Tx:\n"); - pos += scnprintf(buf + pos, bufsz - pos, "preamble: %u\n", - le32_to_cpu(tx->preamble_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "rx_detected_cnt: %u\n", - le32_to_cpu(tx->rx_detected_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_defer_cnt: %u\n", - le32_to_cpu(tx->bt_prio_defer_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "bt_prio_kill_cnt: %u\n", - le32_to_cpu(tx->bt_prio_kill_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "few_bytes_cnt: %u\n", - le32_to_cpu(tx->few_bytes_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout: %u\n", - le32_to_cpu(tx->cts_timeout)); - pos += scnprintf(buf + pos, bufsz - pos, "ack_timeout: %u\n", - le32_to_cpu(tx->ack_timeout)); - pos += scnprintf(buf + pos, bufsz - pos, "expected_ack_cnt: %u\n", - le32_to_cpu(tx->expected_ack_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "actual_ack_cnt: %u\n", - le32_to_cpu(tx->actual_ack_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "dump_msdu_cnt: %u\n", - le32_to_cpu(tx->dump_msdu_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, - "burst_abort_next_frame_mismatch_cnt: %u\n", - le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, - "burst_abort_missing_next_frame_cnt: %u\n", - le32_to_cpu(tx->burst_abort_missing_next_frame_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "cts_timeout_collision: %u\n", - le32_to_cpu(tx->cts_timeout_collision)); - pos += scnprintf(buf + pos, bufsz - pos, - "ack_or_ba_timeout_collision: %u\n", - le32_to_cpu(tx->ack_or_ba_timeout_collision)); - pos += scnprintf(buf + pos, bufsz - pos, "agg ba_timeout: %u\n", - le32_to_cpu(tx->agg.ba_timeout)); - pos += scnprintf(buf + pos, bufsz - pos, - "agg ba_reschedule_frames: %u\n", - le32_to_cpu(tx->agg.ba_reschedule_frames)); - pos += scnprintf(buf + pos, bufsz - pos, - "agg scd_query_agg_frame_cnt: %u\n", - le32_to_cpu(tx->agg.scd_query_agg_frame_cnt)); - pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_no_agg: %u\n", - le32_to_cpu(tx->agg.scd_query_no_agg)); - pos += scnprintf(buf + pos, bufsz - pos, "agg scd_query_agg: %u\n", - le32_to_cpu(tx->agg.scd_query_agg)); - pos += scnprintf(buf + pos, bufsz - pos, - "agg scd_query_mismatch: %u\n", - le32_to_cpu(tx->agg.scd_query_mismatch)); - pos += scnprintf(buf + pos, bufsz - pos, "agg frame_not_ready: %u\n", - le32_to_cpu(tx->agg.frame_not_ready)); - pos += scnprintf(buf + pos, bufsz - pos, "agg underrun: %u\n", - le32_to_cpu(tx->agg.underrun)); - pos += scnprintf(buf + pos, bufsz - pos, "agg bt_prio_kill: %u\n", - le32_to_cpu(tx->agg.bt_prio_kill)); - pos += scnprintf(buf + pos, bufsz - pos, "agg rx_ba_rsp_cnt: %u\n", - le32_to_cpu(tx->agg.rx_ba_rsp_cnt)); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "preamble:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->preamble_cnt), + accum_tx->preamble_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "rx_detected_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->rx_detected_cnt), + accum_tx->rx_detected_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "bt_prio_defer_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->bt_prio_defer_cnt), + accum_tx->bt_prio_defer_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "bt_prio_kill_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->bt_prio_kill_cnt), + accum_tx->bt_prio_kill_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "few_bytes_cnt:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->few_bytes_cnt), + accum_tx->few_bytes_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "cts_timeout:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "ack_timeout:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->ack_timeout), + accum_tx->ack_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "expected_ack_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->expected_ack_cnt), + accum_tx->expected_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "actual_ack_cnt:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->actual_ack_cnt), + accum_tx->actual_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "dump_msdu_cnt:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->dump_msdu_cnt), + accum_tx->dump_msdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "abort_nxt_frame_mismatch:" + "\t%u\t\t\t%u\n", + le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), + accum_tx->burst_abort_next_frame_mismatch_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "abort_missing_nxt_frame:" + "\t%u\t\t\t%u\n", + le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), + accum_tx->burst_abort_missing_next_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "cts_timeout_collision:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->cts_timeout_collision), + accum_tx->cts_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + "ack_ba_timeout_collision:\t%u\t\t\t%u\n", + le32_to_cpu(tx->ack_or_ba_timeout_collision), + accum_tx->ack_or_ba_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + "agg ba_timeout:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.ba_timeout), + accum_tx->agg.ba_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + "agg ba_resched_frames:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.ba_reschedule_frames), + accum_tx->agg.ba_reschedule_frames); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_agg_frame:\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), + accum_tx->agg.scd_query_agg_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_no_agg:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.scd_query_no_agg), + accum_tx->agg.scd_query_no_agg); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_agg:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.scd_query_agg), + accum_tx->agg.scd_query_agg); + pos += scnprintf(buf + pos, bufsz - pos, + "agg scd_query_mismatch:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.scd_query_mismatch), + accum_tx->agg.scd_query_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, + "agg frame_not_ready:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.frame_not_ready), + accum_tx->agg.frame_not_ready); + pos += scnprintf(buf + pos, bufsz - pos, + "agg underrun:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.underrun), + accum_tx->agg.underrun); + pos += scnprintf(buf + pos, bufsz - pos, + "agg bt_prio_kill:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.bt_prio_kill), + accum_tx->agg.bt_prio_kill); + pos += scnprintf(buf + pos, bufsz - pos, + "agg rx_ba_rsp_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(tx->agg.rx_ba_rsp_cnt), + accum_tx->agg.rx_ba_rsp_cnt); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); @@ -1372,9 +1530,9 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, char *buf; int bufsz = sizeof(struct statistics_general) * 4 + 250; ssize_t ret; - struct statistics_general *general; - struct statistics_dbg *dbg; - struct statistics_div *div; + struct statistics_general *general, *accum_general; + struct statistics_dbg *dbg, *accum_dbg; + struct statistics_div *div, *accum_div; if (!iwl_is_alive(priv)) return -EAGAIN; @@ -1402,34 +1560,53 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, general = &priv->statistics.general; dbg = &priv->statistics.general.dbg; div = &priv->statistics.general.div; + accum_general = &priv->accum_statistics.general; + accum_dbg = &priv->accum_statistics.general.dbg; + accum_div = &priv->accum_statistics.general.div; pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz); pos += scnprintf(buf + pos, bufsz - pos, "Statistics_General:\n"); - pos += scnprintf(buf + pos, bufsz - pos, "temperature: %u\n", + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, "temperature:\t\t\t%u\n", le32_to_cpu(general->temperature)); - pos += scnprintf(buf + pos, bufsz - pos, "temperature_m: %u\n", + pos += scnprintf(buf + pos, bufsz - pos, "temperature_m:\t\t\t%u\n", le32_to_cpu(general->temperature_m)); - pos += scnprintf(buf + pos, bufsz - pos, "burst_check: %u\n", - le32_to_cpu(dbg->burst_check)); - pos += scnprintf(buf + pos, bufsz - pos, "burst_count: %u\n", - le32_to_cpu(dbg->burst_count)); - pos += scnprintf(buf + pos, bufsz - pos, "sleep_time: %u\n", - le32_to_cpu(general->sleep_time)); - pos += scnprintf(buf + pos, bufsz - pos, "slots_out: %u\n", - le32_to_cpu(general->slots_out)); - pos += scnprintf(buf + pos, bufsz - pos, "slots_idle: %u\n", - le32_to_cpu(general->slots_idle)); - pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp: %u\n", + pos += scnprintf(buf + pos, bufsz - pos, + "burst_check:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(dbg->burst_check), + accum_dbg->burst_check); + pos += scnprintf(buf + pos, bufsz - pos, + "burst_count:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(dbg->burst_count), + accum_dbg->burst_count); + pos += scnprintf(buf + pos, bufsz - pos, + "sleep_time:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(general->sleep_time), + accum_general->sleep_time); + pos += scnprintf(buf + pos, bufsz - pos, + "slots_out:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(general->slots_out), + accum_general->slots_out); + pos += scnprintf(buf + pos, bufsz - pos, + "slots_idle:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(general->slots_idle), + accum_general->slots_idle); + pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n", le32_to_cpu(general->ttl_timestamp)); - pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a: %u\n", - le32_to_cpu(div->tx_on_a)); - pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b: %u\n", - le32_to_cpu(div->tx_on_b)); - pos += scnprintf(buf + pos, bufsz - pos, "exec_time: %u\n", - le32_to_cpu(div->exec_time)); - pos += scnprintf(buf + pos, bufsz - pos, "probe_time: %u\n", - le32_to_cpu(div->probe_time)); - pos += scnprintf(buf + pos, bufsz - pos, "rx_enable_counter: %u\n", - le32_to_cpu(general->rx_enable_counter)); + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_a:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->tx_on_a), accum_div->tx_on_a); + pos += scnprintf(buf + pos, bufsz - pos, "tx_on_b:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->tx_on_b), accum_div->tx_on_b); + pos += scnprintf(buf + pos, bufsz - pos, + "exec_time:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->exec_time), accum_div->exec_time); + pos += scnprintf(buf + pos, bufsz - pos, + "probe_time:\t\t\t%u\t\t\t%u\n", + le32_to_cpu(div->probe_time), accum_div->probe_time); + pos += scnprintf(buf + pos, bufsz - pos, + "rx_enable_counter:\t\t%u\t\t\t%u\n", + le32_to_cpu(general->rx_enable_counter), + accum_general->rx_enable_counter); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 6d7c2350d8c9..8d087f0455de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1124,7 +1124,9 @@ struct iwl_priv { struct iwl_tt_mgmt thermal_throttle; struct iwl_notif_statistics statistics; - unsigned long last_statistics_time; +#ifdef CONFIG_IWLWIFI_DEBUG + struct iwl_notif_statistics accum_statistics; +#endif /* context information */ u16 rates_mask; diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 493626bcd3ec..7ad327ef9cb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -548,6 +548,44 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv) priv->last_rx_noise); } +#ifdef CONFIG_IWLWIFI_DEBUG +/* + * based on the assumption of all statistics counter are in DWORD + * FIXME: This function is for debugging, do not deal with + * the case of counters roll-over. + */ +static void iwl_accumulative_statistics(struct iwl_priv *priv, + __le32 *stats) +{ + int i; + __le32 *prev_stats; + u32 *accum_stats; + + prev_stats = (__le32 *)&priv->statistics; + accum_stats = (u32 *)&priv->accum_statistics; + + for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics); + i += sizeof(__le32), stats++, prev_stats++, accum_stats++) + if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) + *accum_stats += (le32_to_cpu(*stats) - + le32_to_cpu(*prev_stats)); + + /* reset accumulative statistics for "no-counter" type statistics */ + priv->accum_statistics.general.temperature = + priv->statistics.general.temperature; + priv->accum_statistics.general.temperature_m = + priv->statistics.general.temperature_m; + priv->accum_statistics.general.ttl_timestamp = + priv->statistics.general.ttl_timestamp; + priv->accum_statistics.tx.tx_power.ant_a = + priv->statistics.tx.tx_power.ant_a; + priv->accum_statistics.tx.tx_power.ant_b = + priv->statistics.tx.tx_power.ant_b; + priv->accum_statistics.tx.tx_power.ant_c = + priv->statistics.tx.tx_power.ant_c; +} +#endif + #define REG_RECALIB_PERIOD (60) void iwl_rx_statistics(struct iwl_priv *priv, @@ -566,6 +604,9 @@ void iwl_rx_statistics(struct iwl_priv *priv, STATISTICS_REPLY_FLG_HT40_MODE_MSK) != (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); +#ifdef CONFIG_IWLWIFI_DEBUG + iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); +#endif memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); set_bit(STATUS_STATISTICS, &priv->status); -- cgit v1.2.3 From 37dc70fea870ced8fbd9ae786701529e7ce48f03 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 9 Oct 2009 13:20:30 -0700 Subject: iwlwifi/iwl3945: unify rts_tx_cmd_flag 3945 and 4965 share the functionality for setting RTS and CTS to the tx_cmd. Unify these functions and move the common functionality to core. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 1 + drivers/net/wireless/iwlwifi/iwl-4965.c | 14 +------------- drivers/net/wireless/iwlwifi/iwl-core.c | 17 +++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 9 +-------- 5 files changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index cee03e7fc2da..1372ce4a407c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2826,6 +2826,7 @@ static struct iwl_lib_ops iwl3945_lib = { static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { .get_hcmd_size = iwl3945_get_hcmd_size, .build_addsta_hcmd = iwl3945_build_addsta_hcmd, + .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag, }; static struct iwl_ops iwl3945_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index c9d90169ab1a..6d77039b4ed2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -484,18 +484,6 @@ static void iwl4965_gain_computation(struct iwl_priv *priv, data->beacon_count = 0; } -static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info, - __le32 *tx_flags) -{ - if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { - *tx_flags |= TX_CMD_FLG_RTS_MSK; - *tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - *tx_flags &= ~TX_CMD_FLG_RTS_MSK; - *tx_flags |= TX_CMD_FLG_CTS_MSK; - } -} - static void iwl4965_bg_txpower_work(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, @@ -2212,7 +2200,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .build_addsta_hcmd = iwl4965_build_addsta_hcmd, .chain_noise_reset = iwl4965_chain_noise_reset, .gain_computation = iwl4965_gain_computation, - .rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag, + .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag, .calc_rssi = iwl4965_calc_rssi, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c40c7e2dacf8..1e0021f9681c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -604,6 +604,23 @@ void iwlcore_free_geos(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_free_geos); +/* + * iwlcore_rts_tx_cmd_flag: Set rts/cts. 3945 and 4965 only share this + * function. + */ +void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info, + __le32 *tx_flags) +{ + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { + *tx_flags |= TX_CMD_FLG_RTS_MSK; + *tx_flags &= ~TX_CMD_FLG_CTS_MSK; + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + *tx_flags &= ~TX_CMD_FLG_RTS_MSK; + *tx_flags |= TX_CMD_FLG_CTS_MSK; + } +} +EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag); + static bool is_single_rx_stream(struct iwl_priv *priv) { return !priv->current_ht_config.is_ht || diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3679c2ced04d..cec673badf0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -329,6 +329,8 @@ int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, void iwl_mac_reset_tsf(struct ieee80211_hw *hw); int iwl_alloc_txq_mem(struct iwl_priv *priv); void iwl_free_txq_mem(struct iwl_priv *priv); +void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info, + __le32 *tx_flags); #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_alloc_traffic_mem(struct iwl_priv *priv); void iwl_free_traffic_mem(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 66da441fe366..f4d43531bfa4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -408,7 +408,6 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; __le32 tx_flags = tx->tx_flags; __le16 fc = hdr->frame_control; - u8 rc_flags = info->control.rates[0].flags; tx->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { @@ -435,13 +434,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - tx_flags |= TX_CMD_FLG_RTS_MSK; - tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx_flags |= TX_CMD_FLG_CTS_MSK; - } + priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags); if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK)) tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; -- cgit v1.2.3 From 9744c91f91e9e467b38473a8b673324ae658ca88 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 9 Oct 2009 13:20:31 -0700 Subject: iwl3945: rename tx to tx_cmd Rename iwl3945_tx_cmd variable tx to tx_cmd for better readability. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 20 +++++------ drivers/net/wireless/iwlwifi/iwl3945-base.c | 54 ++++++++++++++--------------- 2 files changed, 37 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 1372ce4a407c..a6944bc53fec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -785,10 +785,10 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, u8 data_retry_limit; __le32 tx_flags; __le16 fc = hdr->frame_control; - struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; + struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload; rate = iwl3945_rates[rate_index].plcp; - tx_flags = tx->tx_flags; + tx_flags = tx_cmd->tx_flags; /* We need to figure out how to get the sta->supp_rates while * in this running context */ @@ -825,22 +825,22 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, } } - tx->rts_retry_limit = rts_retry_limit; - tx->data_retry_limit = data_retry_limit; - tx->rate = rate; - tx->tx_flags = tx_flags; + tx_cmd->rts_retry_limit = rts_retry_limit; + tx_cmd->data_retry_limit = data_retry_limit; + tx_cmd->rate = rate; + tx_cmd->tx_flags = tx_flags; /* OFDM */ - tx->supp_rates[0] = + tx_cmd->supp_rates[0] = ((rate_mask & IWL_OFDM_RATES_MASK) >> IWL_FIRST_OFDM_RATE) & 0xFF; /* CCK */ - tx->supp_rates[1] = (rate_mask & 0xF); + tx_cmd->supp_rates[1] = (rate_mask & 0xF); IWL_DEBUG_RATE(priv, "Tx sta id: %d, rate: %d (plcp), flags: 0x%4X " "cck/ofdm mask: 0x%x/0x%x\n", sta_id, - tx->rate, le32_to_cpu(tx->tx_flags), - tx->supp_rates[1], tx->supp_rates[0]); + tx_cmd->rate, le32_to_cpu(tx_cmd->tx_flags), + tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]); } u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index f4d43531bfa4..03612b394591 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -365,13 +365,13 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct sk_buff *skb_frag, int sta_id) { - struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; + struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload; struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: - tx->sec_ctl = TX_CMD_SEC_CCM; - memcpy(tx->key, keyinfo->key, keyinfo->keylen); + tx_cmd->sec_ctl = TX_CMD_SEC_CCM; + memcpy(tx_cmd->key, keyinfo->key, keyinfo->keylen); IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n"); break; @@ -379,13 +379,13 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, break; case ALG_WEP: - tx->sec_ctl = TX_CMD_SEC_WEP | + tx_cmd->sec_ctl = TX_CMD_SEC_WEP | (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; if (keyinfo->keylen == 13) - tx->sec_ctl |= TX_CMD_SEC_KEY128; + tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; - memcpy(&tx->key[3], keyinfo->key, keyinfo->keylen); + memcpy(&tx_cmd->key[3], keyinfo->key, keyinfo->keylen); IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption " "with key %d\n", info->control.hw_key->hw_key_idx); @@ -405,11 +405,11 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, u8 std_id) { - struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; - __le32 tx_flags = tx->tx_flags; + struct iwl3945_tx_cmd *tx_cmd = (struct iwl3945_tx_cmd *)cmd->cmd.payload; + __le32 tx_flags = tx_cmd->tx_flags; __le16 fc = hdr->frame_control; - tx->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { tx_flags |= TX_CMD_FLG_ACK_MSK; if (ieee80211_is_mgmt(fc)) @@ -422,13 +422,13 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - tx->sta_id = std_id; + tx_cmd->sta_id = std_id; if (ieee80211_has_morefrags(fc)) tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; if (ieee80211_is_data_qos(fc)) { u8 *qc = ieee80211_get_qos_ctl(hdr); - tx->tid_tspec = qc[0] & 0xf; + tx_cmd->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } else { tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; @@ -442,16 +442,16 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv, tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK); if (ieee80211_is_mgmt(fc)) { if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) - tx->timeout.pm_frame_timeout = cpu_to_le16(3); + tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3); else - tx->timeout.pm_frame_timeout = cpu_to_le16(2); + tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2); } else { - tx->timeout.pm_frame_timeout = 0; + tx_cmd->timeout.pm_frame_timeout = 0; } - tx->driver_txop = 0; - tx->tx_flags = tx_flags; - tx->next_frame_len = 0; + tx_cmd->driver_txop = 0; + tx_cmd->tx_flags = tx_flags; + tx_cmd->next_frame_len = 0; } /* @@ -461,7 +461,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct iwl3945_tx_cmd *tx; + struct iwl3945_tx_cmd *tx_cmd; struct iwl_tx_queue *txq = NULL; struct iwl_queue *q = NULL; struct iwl_device_cmd *out_cmd; @@ -560,9 +560,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Init first empty entry in queue's array of Tx/cmd buffers */ out_cmd = txq->cmd[idx]; out_meta = &txq->meta[idx]; - tx = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload; + tx_cmd = (struct iwl3945_tx_cmd *)out_cmd->cmd.payload; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); - memset(tx, 0, sizeof(*tx)); + memset(tx_cmd, 0, sizeof(*tx_cmd)); /* * Set up the Tx-command (not MAC!) header. @@ -575,7 +575,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) INDEX_TO_SEQ(q->write_ptr))); /* Copy MAC header from skb into command buffer */ - memcpy(tx->hdr, hdr, hdr_len); + memcpy(tx_cmd->hdr, hdr, hdr_len); if (info->control.hw_key) @@ -589,12 +589,12 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Total # bytes to be transmitted */ len = (u16)skb->len; - tx->len = cpu_to_le16(len); + tx_cmd->len = cpu_to_le16(len); iwl_dbg_log_tx_data_frame(priv, len, hdr); iwl_update_stats(priv, true, fc, len); - tx->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; - tx->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; + tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; + tx_cmd->tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; @@ -607,9 +607,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", le16_to_cpu(out_cmd->hdr.sequence)); - IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags)); - iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx)); - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr, + IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags)); + iwl_print_hex_dump(priv, IWL_DL_TX, tx_cmd, sizeof(*tx_cmd)); + iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, ieee80211_hdrlen(fc)); /* -- cgit v1.2.3 From 1f0436f4702b7cdda22a38689cc1903822694a17 Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 9 Oct 2009 13:20:32 -0700 Subject: iwlwifi/iwl3945: remove data_retry_limit Remove the ununsed variable data_retry_limit from priv. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 3 --- drivers/net/wireless/iwlwifi/iwl-core.c | 1 - drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - drivers/net/wireless/iwlwifi/iwl-tx.c | 4 +--- drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 - 5 files changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index a6944bc53fec..eb874e08ba53 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -806,9 +806,6 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, } else data_retry_limit = IWL_DEFAULT_TX_RETRY; - if (priv->data_retry_limit != -1) - data_retry_limit = priv->data_retry_limit; - if (ieee80211_is_mgmt(fc)) { switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { case cpu_to_le16(IEEE80211_STYPE_AUTH): diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1e0021f9681c..2ae168af0f2c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1524,7 +1524,6 @@ int iwl_init_drv(struct iwl_priv *priv) /* Clear the driver's (not device's) station table */ iwl_clear_stations_table(priv); - priv->data_retry_limit = -1; priv->ieee_channels = NULL; priv->ieee_rates = NULL; priv->band = IEEE80211_BAND_2GHZ; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 8d087f0455de..451aa65b1a56 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1092,7 +1092,6 @@ struct iwl_priv { u8 last_phy_res[100]; /* Rate scaling data */ - s8 data_retry_limit; u8 retry_rate; wait_queue_head_t wait_command_queue; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 625da63d01ee..d0bd7cd024ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -591,9 +591,7 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, u8 rate_plcp; /* Set retry limit on DATA packets and Probe Responses*/ - if (priv->data_retry_limit != -1) - data_retry_limit = priv->data_retry_limit; - else if (ieee80211_is_probe_resp(fc)) + if (ieee80211_is_probe_resp(fc)) data_retry_limit = 3; else data_retry_limit = IWL_DEFAULT_TX_RETRY; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 03612b394591..515f29b8a7a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3797,7 +3797,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) /* Clear the driver's (not device's) station table */ iwl_clear_stations_table(priv); - priv->data_retry_limit = -1; priv->ieee_channels = NULL; priv->ieee_rates = NULL; priv->band = IEEE80211_BAND_2GHZ; -- cgit v1.2.3 From 768db9829d0d45d57204714f18b54f7fc0561ddf Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 9 Oct 2009 13:20:33 -0700 Subject: iwl3945: rearrange the code. Rearrange the code and groups setting of retry_limit and data_retry_limits code together. Make 'data_retry_limit' setting similar to iwlwifi for better readability. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index eb874e08ba53..8012381d3717 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -794,17 +794,22 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, * in this running context */ rate_mask = IWL_RATES_MASK; + + /* Set retry limit on DATA packets and Probe Responses*/ + if (ieee80211_is_probe_resp(fc)) + data_retry_limit = 3; + else + data_retry_limit = IWL_DEFAULT_TX_RETRY; + tx_cmd->data_retry_limit = data_retry_limit; + if (tx_id >= IWL_CMD_QUEUE_NUM) rts_retry_limit = 3; else rts_retry_limit = 7; - if (ieee80211_is_probe_resp(fc)) { - data_retry_limit = 3; - if (data_retry_limit < rts_retry_limit) - rts_retry_limit = data_retry_limit; - } else - data_retry_limit = IWL_DEFAULT_TX_RETRY; + if (data_retry_limit < rts_retry_limit) + rts_retry_limit = data_retry_limit; + tx_cmd->rts_retry_limit = rts_retry_limit; if (ieee80211_is_mgmt(fc)) { switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { @@ -822,8 +827,6 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, } } - tx_cmd->rts_retry_limit = rts_retry_limit; - tx_cmd->data_retry_limit = data_retry_limit; tx_cmd->rate = rate; tx_cmd->tx_flags = tx_flags; -- cgit v1.2.3 From e57f14895bf6bc7f16df760963427ac6ee6ff7e1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 9 Oct 2009 13:20:34 -0700 Subject: iwlwifi: update channel switch command API Channel switch host command has different data structure for different devices. Adding additional structures to support 5000 and 6000 NICs. unlike 4965, starting with 5000 series, the tx power is managed by uCode, there is no tx power db information need to be passing from driver to uCode; but the space needs to be reserved to match uCode expection. 1000 NIC do not support channel switch operation since it is 'bgn' device, there is no need to have data structure defined for it. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 47 ++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 2e8a55ed7de5..cc4e9122709e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -353,6 +353,9 @@ struct iwl3945_power_per_rate { #define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 #define POWER_TABLE_CCK_ENTRY 32 +#define IWL_PWR_NUM_HT_OFDM_ENTRIES 24 +#define IWL_PWR_CCK_ENTRIES 2 + /** * union iwl4965_tx_power_dual_stream * @@ -803,7 +806,7 @@ struct iwl3945_channel_switch_cmd { struct iwl3945_power_per_rate power[IWL_MAX_RATES]; } __attribute__ ((packed)); -struct iwl_channel_switch_cmd { +struct iwl4965_channel_switch_cmd { u8 band; u8 expect_beacon; __le16 channel; @@ -813,6 +816,48 @@ struct iwl_channel_switch_cmd { struct iwl4965_tx_power_db tx_power; } __attribute__ ((packed)); +/** + * struct iwl5000_channel_switch_cmd + * @band: 0- 5.2GHz, 1- 2.4GHz + * @expect_beacon: 0- resume transmits after channel switch + * 1- wait for beacon to resume transmits + * @channel: new channel number + * @rxon_flags: Rx on flags + * @rxon_filter_flags: filtering parameters + * @switch_time: switch time in extended beacon format + * @reserved: reserved bytes + */ +struct iwl5000_channel_switch_cmd { + u8 band; + u8 expect_beacon; + __le16 channel; + __le32 rxon_flags; + __le32 rxon_filter_flags; + __le32 switch_time; + __le32 reserved[2][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES]; +} __attribute__ ((packed)); + +/** + * struct iwl6000_channel_switch_cmd + * @band: 0- 5.2GHz, 1- 2.4GHz + * @expect_beacon: 0- resume transmits after channel switch + * 1- wait for beacon to resume transmits + * @channel: new channel number + * @rxon_flags: Rx on flags + * @rxon_filter_flags: filtering parameters + * @switch_time: switch time in extended beacon format + * @reserved: reserved bytes + */ +struct iwl6000_channel_switch_cmd { + u8 band; + u8 expect_beacon; + __le16 channel; + __le32 rxon_flags; + __le32 rxon_filter_flags; + __le32 switch_time; + __le32 reserved[3][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES]; +} __attribute__ ((packed)); + /* * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) */ -- cgit v1.2.3 From 25a7dc6d22adda590be4932ebc772ea35914880c Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 12 Oct 2009 15:08:42 +0300 Subject: wl1271: implement cmd_disconnect This patch implements the CMD_DISCONNECT command, which should be sent to the firmware when we are disassociated. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 32 +++++++++++++++++++++++++++++++- drivers/net/wireless/wl12xx/wl1271_cmd.h | 27 +++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index ac93efd53f2a..d09ad1211977 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -191,7 +191,6 @@ int wl1271_cmd_join(struct wl1271 *wl) do_cal = false; } - join = kzalloc(sizeof(*join), GFP_KERNEL); if (!join) { ret = -ENOMEM; @@ -825,3 +824,34 @@ out: return ret; } + +int wl1271_cmd_disconnect(struct wl1271 *wl) +{ + struct wl1271_cmd_disconnect *cmd; + int ret = 0; + + wl1271_debug(DEBUG_CMD, "cmd disconnect"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + cmd->rx_config_options = wl->rx_config; + cmd->rx_filter_options = wl->rx_filter; + /* disconnect reason is not used in immediate disconnections */ + cmd->type = DISCONNECT_IMMEDIATE; + + ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd)); + if (ret < 0) { + wl1271_error("failed to send disconnect command"); + goto out_free; + } + +out_free: + kfree(cmd); + +out: + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 63bc4417deb8..0219664765ec 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -50,6 +50,7 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, const u8 *addr, u32 tx_seq_32, u16 tx_seq_16); +int wl1271_cmd_disconnect(struct wl1271 *wl); enum wl1271_commands { CMD_INTERROGATE = 1, /*use this to read information elements*/ @@ -461,4 +462,30 @@ struct wl1271_cmd_cal_p2g { u8 padding2; } __attribute__ ((packed)); + +/* + * There are three types of disconnections: + * + * DISCONNECT_IMMEDIATE: the fw doesn't send any frames + * DISCONNECT_DEAUTH: the fw generates a DEAUTH request with the reason + * we have passed + * DISCONNECT_DISASSOC: the fw generates a DESASSOC request with the reason + * we have passed + */ +enum wl1271_disconnect_type { + DISCONNECT_IMMEDIATE, + DISCONNECT_DEAUTH, + DISCONNECT_DISASSOC +}; + +struct wl1271_cmd_disconnect { + u32 rx_config_options; + u32 rx_filter_options; + + u16 reason; + u8 type; + + u8 padding; +} __attribute__ ((packed)); + #endif /* __WL1271_CMD_H__ */ -- cgit v1.2.3 From d6e19d135dadb1895296668914d0a15bc3cafcbf Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 12 Oct 2009 15:08:43 +0300 Subject: wl1271: workaround to send a disconnect before rejoining We don't get any indication from the stack when we have disassociated. In wl1271, it is important to send a CMD_DISCONNECT before joining again, because the firmware cleans some things up. So we check if we're already joined and disconnect if that's the case. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 3 +++ drivers/net/wireless/wl12xx/wl1271_cmd.c | 15 +++++++++++++++ drivers/net/wireless/wl12xx/wl1271_main.c | 3 +++ 3 files changed, 21 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 96a581316941..858bf6b160a1 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -422,6 +422,9 @@ struct wl1271 { struct wl1271_tx_hw_res_if *tx_res_if; struct ieee80211_vif *vif; + + /* Used for a workaround to send disconnect before rejoining */ + bool joined; }; int wl1271_plt_start(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index d09ad1211977..ef92834e0e8f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -191,6 +191,19 @@ int wl1271_cmd_join(struct wl1271 *wl) do_cal = false; } + /* FIXME: This is a workaround, because with the current stack, we + * cannot know when we have disassociated. So, if we have already + * joined, we disconnect before joining again. */ + if (wl->joined) { + ret = wl1271_cmd_disconnect(wl); + if (ret < 0) { + wl1271_error("failed to disconnect before rejoining"); + goto out; + } + + wl->joined = false; + } + join = kzalloc(sizeof(*join), GFP_KERNEL); if (!join) { ret = -ENOMEM; @@ -245,6 +258,8 @@ int wl1271_cmd_join(struct wl1271 *wl) goto out_free; } + wl->joined = true; + /* * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to * simplify locking we just sleep instead, for now diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 3662715c0313..b9f20918a25d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -648,6 +648,8 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->tx_security_seq_32 = 0; wl->time_offset = 0; wl->session_counter = 0; + wl->joined = false; + for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_blocks_freed[i] = 0; @@ -1395,6 +1397,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; wl->band = IEEE80211_BAND_2GHZ; wl->vif = NULL; + wl->joined = false; for (i = 0; i < ACX_TX_DESCRIPTORS; i++) wl->tx_frames[i] = NULL; -- cgit v1.2.3 From ac78403e149cae56efa75ba025e7e717c4ad01ed Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 12 Oct 2009 15:08:44 +0300 Subject: wl1271: add workaround to avoid distortion due to excessive tx power We still don't have proper calibration for our devices, so we are using way too much power for TX, which causes a lot of distortion. This hack hardcodes the txpower to 7dBm. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index b9dfa094f049..d5dac5753ae2 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -137,7 +137,12 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power) goto out; } - acx->current_tx_power = power * 10; + /* + * FIXME: This is a workaround needed while we don't the correct + * calibration, to avoid distortions + */ + /* acx->current_tx_power = power * 10; */ + acx->current_tx_power = 70; ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); if (ret < 0) { -- cgit v1.2.3 From 37079a831d8194e138c03663b7cab281ab1dc181 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 12 Oct 2009 15:08:45 +0300 Subject: wl1271: enable HW_AVAILABLE interrupt to fix ELP We need to listen to HW_AVAILABLE interrupts when using ELP with firmware revision 6.1.0.0.241. Add WL1271_ACX_INTR_HW_AVAILABLE to the interrupts that are enabled by default. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 0c2a10734493..07256d280e51 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -61,8 +61,9 @@ WL1271_ACX_INTR_HW_AVAILABLE | \ WL1271_ACX_INTR_DATA) -#define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \ - WL1271_ACX_INTR_EVENT_B | \ +#define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \ + WL1271_ACX_INTR_EVENT_B | \ + WL1271_ACX_INTR_HW_AVAILABLE | \ WL1271_ACX_INTR_DATA) /* Target's information element */ -- cgit v1.2.3 From 451de97adb4d0f101f3befc881a548adb47c467a Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 12 Oct 2009 15:08:46 +0300 Subject: wl1271: Update memory mapping for firmware revision 6.1.0.0.241 Update the memory regions and memory mapping to support firmware revision 6.1.0.0.241. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 7 +- drivers/net/wireless/wl12xx/wl1271_boot.c | 67 +++++------ drivers/net/wireless/wl12xx/wl1271_main.c | 10 +- drivers/net/wireless/wl12xx/wl1271_spi.c | 178 +++++++++++------------------- drivers/net/wireless/wl12xx/wl1271_spi.h | 15 ++- 5 files changed, 116 insertions(+), 161 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 858bf6b160a1..b2bc7b59d645 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -148,6 +148,8 @@ struct wl1271_partition { struct wl1271_partition_set { struct wl1271_partition mem; struct wl1271_partition reg; + struct wl1271_partition mem2; + struct wl1271_partition mem3; }; struct wl1271; @@ -302,10 +304,7 @@ struct wl1271 { enum wl1271_state state; struct mutex mutex; - int physical_mem_addr; - int physical_reg_addr; - int virtual_mem_addr; - int virtual_reg_addr; + struct wl1271_partition_set part; struct wl1271_chip chip; diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index 140e94348bc1..2eb7836c9ac1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -39,6 +39,14 @@ static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { .start = REGISTERS_BASE, .size = 0x00008800 }, + .mem2 = { + .start = 0x00000000, + .size = 0x00000000 + }, + .mem3 = { + .start = 0x00000000, + .size = 0x00000000 + }, }, [PART_WORK] = { @@ -48,7 +56,15 @@ static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { }, .reg = { .start = REGISTERS_BASE, - .size = 0x0000b000 + .size = 0x0000a000 + }, + .mem2 = { + .start = 0x003004f8, + .size = 0x00000004 + }, + .mem3 = { + .start = 0x00040404, + .size = 0x00000000 }, }, @@ -60,6 +76,14 @@ static struct wl1271_partition_set part_table[PART_TABLE_LEN] = { .reg = { .start = DRPW_BASE, .size = 0x00006000 + }, + .mem2 = { + .start = 0x00000000, + .size = 0x00000000 + }, + .mem3 = { + .start = 0x00000000, + .size = 0x00000000 } } }; @@ -93,6 +117,7 @@ static void wl1271_boot_fw_version(struct wl1271 *wl) static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, size_t fw_data_len, u32 dest) { + struct wl1271_partition_set partition; int addr, chunk_num, partition_limit; u8 *p, *chunk; @@ -114,10 +139,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, return -ENOMEM; } - wl1271_set_partition(wl, dest, - part_table[PART_DOWN].mem.size, - part_table[PART_DOWN].reg.start, - part_table[PART_DOWN].reg.size); + memcpy(&partition, &part_table[PART_DOWN], sizeof(partition)); + partition.mem.start = dest; + wl1271_set_partition(wl, &partition); /* 10.1 set partition limit and chunk num */ chunk_num = 0; @@ -130,13 +154,8 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, addr = dest + chunk_num * CHUNK_SIZE; partition_limit = chunk_num * CHUNK_SIZE + part_table[PART_DOWN].mem.size; - - /* FIXME: Over 80 chars! */ - wl1271_set_partition(wl, - addr, - part_table[PART_DOWN].mem.size, - part_table[PART_DOWN].reg.start, - part_table[PART_DOWN].reg.size); + partition.mem.start = addr; + wl1271_set_partition(wl, &partition); } /* 10.3 upload the chunk */ @@ -261,11 +280,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) /* FIXME: The driver sets the partition here, but this is not needed, since it sets to the same one as currently in use */ /* Now we must set the partition correctly */ - wl1271_set_partition(wl, - part_table[PART_WORK].mem.start, - part_table[PART_WORK].mem.size, - part_table[PART_WORK].reg.start, - part_table[PART_WORK].reg.size); + wl1271_set_partition(wl, &part_table[PART_WORK]); /* Copy the NVS tables to a new block to ensure alignment */ nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); @@ -371,11 +386,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) wl->event_box_addr = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); /* set the working partition to its "running" mode offset */ - wl1271_set_partition(wl, - part_table[PART_WORK].mem.start, - part_table[PART_WORK].mem.size, - part_table[PART_WORK].reg.start, - part_table[PART_WORK].reg.size); + wl1271_set_partition(wl, &part_table[PART_WORK]); wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x", wl->cmd_box_addr, wl->event_box_addr); @@ -469,11 +480,7 @@ int wl1271_boot(struct wl1271 *wl) wl1271_reg_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); udelay(500); - wl1271_set_partition(wl, - part_table[PART_DRPW].mem.start, - part_table[PART_DRPW].mem.size, - part_table[PART_DRPW].reg.start, - part_table[PART_DRPW].reg.size); + wl1271_set_partition(wl, &part_table[PART_DRPW]); /* Read-modify-write DRPW_SCRATCH_START register (see next state) to be used by DRPw FW. The RTRIM value will be added by the FW @@ -488,11 +495,7 @@ int wl1271_boot(struct wl1271 *wl) clk |= (REF_CLOCK << 1) << 4; wl1271_reg_write32(wl, DRPW_SCRATCH_START, clk); - wl1271_set_partition(wl, - part_table[PART_WORK].mem.start, - part_table[PART_WORK].mem.size, - part_table[PART_WORK].reg.start, - part_table[PART_WORK].reg.size); + wl1271_set_partition(wl, &part_table[PART_WORK]); /* Disable interrupts */ wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index b9f20918a25d..22d44ba2e969 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -315,6 +315,7 @@ static int wl1271_setup(struct wl1271 *wl) static int wl1271_chip_wakeup(struct wl1271 *wl) { + struct wl1271_partition_set partition; int ret = 0; wl1271_power_on(wl); @@ -324,11 +325,10 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) /* We don't need a real memory partition here, because we only want * to use the registers at this point. */ - wl1271_set_partition(wl, - 0x00000000, - 0x00000000, - REGISTERS_BASE, - REGISTERS_DOWN_SIZE); + memset(&partition, 0, sizeof(partition)); + partition.reg.start = REGISTERS_BASE; + partition.reg.size = REGISTERS_DOWN_SIZE; + wl1271_set_partition(wl, &partition); /* ELP module wake up */ wl1271_fw_wakeup(wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 504991acb052..367f2d3319ac 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -30,17 +30,29 @@ #include "wl12xx_80211.h" #include "wl1271_spi.h" -static int wl1271_translate_reg_addr(struct wl1271 *wl, int addr) +static int wl1271_translate_addr(struct wl1271 *wl, int addr) { - return addr - wl->physical_reg_addr + wl->virtual_reg_addr; -} - -static int wl1271_translate_mem_addr(struct wl1271 *wl, int addr) -{ - return addr - wl->physical_mem_addr + wl->virtual_mem_addr; + /* + * To translate, first check to which window of addresses the + * particular address belongs. Then subtract the starting address + * of that window from the address. Then, add offset of the + * translated region. + * + * The translated regions occur next to each other in physical device + * memory, so just add the sizes of the preceeding address regions to + * get the offset to the new region. + * + * Currently, only the two first regions are addressed, and the + * assumption is that all addresses will fall into either of those + * two. + */ + if ((addr >= wl->part.reg.start) && + (addr < wl->part.reg.start + wl->part.reg.size)) + return addr - wl->part.reg.start + wl->part.mem.size; + else + return addr - wl->part.mem.start; } - void wl1271_spi_reset(struct wl1271 *wl) { u8 *cmd; @@ -123,123 +135,61 @@ void wl1271_spi_init(struct wl1271 *wl) /* Set the SPI partitions to access the chip addresses * - * There are two VIRTUAL (SPI) partitions (the memory partition and the - * registers partition), which are mapped to two different areas of the - * PHYSICAL (hardware) memory. This function also makes other checks to - * ensure that the partitions are not overlapping. In the diagram below, the - * memory partition comes before the register partition, but the opposite is - * also supported. + * To simplify driver code, a fixed (virtual) memory map is defined for + * register and memory addresses. Because in the chipset, in different stages + * of operation, those addresses will move around, an address translation + * mechanism is required. * - * PHYSICAL address + * There are four partitions (three memory and one register partition), + * which are mapped to two different areas of the hardware memory. + * + * Virtual address * space * * | | - * ...+----+--> mem_start - * VIRTUAL address ... | | + * ...+----+--> mem.start + * Physical address ... | | * space ... | | [PART_0] * ... | | - * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size + * 00000000 <--+----+... ...+----+--> mem.start + mem.size * | | ... | | * |MEM | ... | | * | | ... | | - * part_size <--+----+... | | {unused area) + * mem.size <--+----+... | | {unused area) * | | ... | | * |REG | ... | | - * part_size | | ... | | - * + <--+----+... ...+----+--> reg_start - * reg_size ... | | - * ... | | [PART_1] - * ... | | - * ...+----+--> reg_start + reg_size + * mem.size | | ... | | + * + <--+----+... ...+----+--> reg.start + * reg.size | | ... | | + * |MEM2| ... | | [PART_1] + * | | ... | | + * ...+----+--> reg.start + reg.size * | | * */ int wl1271_set_partition(struct wl1271 *wl, - u32 mem_start, u32 mem_size, - u32 reg_start, u32 reg_size) + struct wl1271_partition_set *p) { - struct wl1271_partition *partition; - struct spi_transfer t; - struct spi_message m; - size_t len, cmd_len; - u32 *cmd; - int addr; - - cmd_len = sizeof(u32) + 2 * sizeof(struct wl1271_partition); - cmd = kzalloc(cmd_len, GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - spi_message_init(&m); - memset(&t, 0, sizeof(t)); - - partition = (struct wl1271_partition *) (cmd + 1); - addr = HW_ACCESS_PART0_SIZE_ADDR; - len = 2 * sizeof(struct wl1271_partition); - - *cmd |= WSPI_CMD_WRITE; - *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH; - *cmd |= addr & WSPI_CMD_BYTE_ADDR; + /* copy partition info */ + memcpy(&wl->part, p, sizeof(*p)); wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); + p->mem.start, p->mem.size); wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - - /* Make sure that the two partitions together don't exceed the - * address range */ - if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { - wl1271_debug(DEBUG_SPI, "Total size exceeds maximum virtual" - " address range. Truncating partition[0]."); - mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; - wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - if ((mem_start < reg_start) && - ((mem_start + mem_size) > reg_start)) { - /* Guarantee that the memory partition doesn't overlap the - * registers partition */ - wl1271_debug(DEBUG_SPI, "End of partition[0] is " - "overlapping partition[1]. Adjusted."); - mem_size = reg_start - mem_start; - wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } else if ((reg_start < mem_start) && - ((reg_start + reg_size) > mem_start)) { - /* Guarantee that the register partition doesn't overlap the - * memory partition */ - wl1271_debug(DEBUG_SPI, "End of partition[1] is" - " overlapping partition[0]. Adjusted."); - reg_size = mem_start - reg_start; - wl1271_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", - mem_start, mem_size); - wl1271_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", - reg_start, reg_size); - } - - partition[0].start = mem_start; - partition[0].size = mem_size; - partition[1].start = reg_start; - partition[1].size = reg_size; - - wl->physical_mem_addr = mem_start; - wl->physical_reg_addr = reg_start; - - wl->virtual_mem_addr = 0; - wl->virtual_reg_addr = mem_size; - - t.tx_buf = cmd; - t.len = cmd_len; - spi_message_add_tail(&t, &m); - - spi_sync(wl->spi, &m); - - kfree(cmd); + p->reg.start, p->reg.size); + wl1271_debug(DEBUG_SPI, "mem2_start %08X mem2_size %08X", + p->mem2.start, p->mem2.size); + wl1271_debug(DEBUG_SPI, "mem3_start %08X mem3_size %08X", + p->mem3.start, p->mem3.size); + + /* write partition info to the chipset */ + wl1271_write32(wl, HW_PART0_START_ADDR, p->mem.start); + wl1271_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); + wl1271_write32(wl, HW_PART1_START_ADDR, p->reg.start); + wl1271_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); + wl1271_write32(wl, HW_PART2_START_ADDR, p->mem2.start); + wl1271_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); + wl1271_write32(wl, HW_PART3_START_ADDR, p->mem3.start); return 0; } @@ -391,7 +341,7 @@ void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, { int physical; - physical = wl1271_translate_mem_addr(wl, addr); + physical = wl1271_translate_addr(wl, addr); wl1271_spi_read(wl, physical, buf, len, false); } @@ -401,7 +351,7 @@ void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, { int physical; - physical = wl1271_translate_mem_addr(wl, addr); + physical = wl1271_translate_addr(wl, addr); wl1271_spi_write(wl, physical, buf, len, false); } @@ -411,7 +361,7 @@ void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, { int physical; - physical = wl1271_translate_reg_addr(wl, addr); + physical = wl1271_translate_addr(wl, addr); wl1271_spi_read(wl, physical, buf, len, fixed); } @@ -421,27 +371,27 @@ void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, { int physical; - physical = wl1271_translate_reg_addr(wl, addr); + physical = wl1271_translate_addr(wl, addr); wl1271_spi_write(wl, physical, buf, len, fixed); } u32 wl1271_mem_read32(struct wl1271 *wl, int addr) { - return wl1271_read32(wl, wl1271_translate_mem_addr(wl, addr)); + return wl1271_read32(wl, wl1271_translate_addr(wl, addr)); } void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val) { - wl1271_write32(wl, wl1271_translate_mem_addr(wl, addr), val); + wl1271_write32(wl, wl1271_translate_addr(wl, addr), val); } u32 wl1271_reg_read32(struct wl1271 *wl, int addr) { - return wl1271_read32(wl, wl1271_translate_reg_addr(wl, addr)); + return wl1271_read32(wl, wl1271_translate_addr(wl, addr)); } void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val) { - wl1271_write32(wl, wl1271_translate_reg_addr(wl, addr), val); + wl1271_write32(wl, wl1271_translate_addr(wl, addr), val); } diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h index 2c9968458646..c58e02724d02 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.h +++ b/drivers/net/wireless/wl12xx/wl1271_spi.h @@ -29,10 +29,14 @@ #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 -#define HW_ACCESS_PART0_SIZE_ADDR 0x1FFC0 -#define HW_ACCESS_PART0_START_ADDR 0x1FFC4 -#define HW_ACCESS_PART1_SIZE_ADDR 0x1FFC8 -#define HW_ACCESS_PART1_START_ADDR 0x1FFCC +#define HW_PARTITION_REGISTERS_ADDR 0x1ffc0 +#define HW_PART0_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR) +#define HW_PART0_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 4) +#define HW_PART1_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 8) +#define HW_PART1_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 12) +#define HW_PART2_SIZE_ADDR (HW_PARTITION_REGISTERS_ADDR + 16) +#define HW_PART2_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 20) +#define HW_PART3_START_ADDR (HW_PARTITION_REGISTERS_ADDR + 24) #define HW_ACCESS_REGISTER_SIZE 4 @@ -92,8 +96,7 @@ void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val); void wl1271_spi_reset(struct wl1271 *wl); void wl1271_spi_init(struct wl1271 *wl); int wl1271_set_partition(struct wl1271 *wl, - u32 part_start, u32 part_size, - u32 reg_start, u32 reg_size); + struct wl1271_partition_set *p); static inline u32 wl1271_read32(struct wl1271 *wl, int addr) { -- cgit v1.2.3 From 732a1ad93e820768bb14732b8365493dbd69ecc8 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 12 Oct 2009 15:08:47 +0300 Subject: wl1271: Remove RX workaround Remove RX workaround which is not needed with newer firmware revisions. This will reduce one SPI register transaction per RX packet. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_reg.h | 1 - drivers/net/wireless/wl12xx/wl1271_rx.c | 4 ---- 2 files changed, 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h index f8ed4a4fc691..bd12615e4caf 100644 --- a/drivers/net/wireless/wl12xx/wl1271_reg.h +++ b/drivers/net/wireless/wl12xx/wl1271_reg.h @@ -213,7 +213,6 @@ ==============================================*/ #define ACX_REG_INTERRUPT_ACK (REGISTERS_BASE + 0x04F0) -#define RX_DRIVER_DUMMY_WRITE_ADDRESS (REGISTERS_BASE + 0x0534) #define RX_DRIVER_COUNTER_ADDRESS (REGISTERS_BASE + 0x0538) /* Device Configuration registers*/ diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 5d8d40158981..1d9865371f17 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -187,8 +187,4 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) } wl1271_reg_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); - - /* This is a workaround for some problems in the chip */ - wl1271_reg_write32(wl, RX_DRIVER_DUMMY_WRITE_ADDRESS, 0x1); - } -- cgit v1.2.3 From e8768eeb5993bf9695adb4afe4118b7fd5e307a3 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 12 Oct 2009 15:08:48 +0300 Subject: wl1271: Add top-register access functions Add top register access function. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_boot.c | 27 ++---------------- drivers/net/wireless/wl12xx/wl1271_boot.h | 15 +--------- drivers/net/wireless/wl12xx/wl1271_spi.c | 46 +++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_spi.h | 16 +++++++++++ 4 files changed, 66 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index 2eb7836c9ac1..1a3084cca9b8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -419,34 +419,13 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) { - u32 polarity, status, i; + u32 polarity; - wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY); - wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ); - - /* Wait until the command is complete (ie. bit 18 is set) */ - for (i = 0; i < OCP_CMD_LOOP; i++) { - polarity = wl1271_reg_read32(wl, OCP_DATA_READ); - if (polarity & OCP_READY_MASK) - break; - } - if (i == OCP_CMD_LOOP) { - wl1271_error("OCP command timeout!"); - return -EIO; - } - - status = polarity & OCP_STATUS_MASK; - if (status != OCP_STATUS_OK) { - wl1271_error("OCP command failed (%d)", status); - return -EIO; - } + polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY); /* We use HIGH polarity, so unset the LOW bit */ polarity &= ~POLARITY_LOW; - - wl1271_reg_write32(wl, OCP_POR_CTR, OCP_REG_POLARITY); - wl1271_reg_write32(wl, OCP_DATA_WRITE, polarity); - wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE); + wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity); return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h index b0d8fb46a439..4501653fb52a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.h +++ b/drivers/net/wireless/wl12xx/wl1271_boot.h @@ -50,20 +50,7 @@ struct wl1271_static_data { #define WU_COUNTER_PAUSE_VAL 0x3FF #define WELP_ARM_COMMAND_VAL 0x4 -#define OCP_CMD_LOOP 32 - -#define OCP_CMD_WRITE 0x1 -#define OCP_CMD_READ 0x2 - -#define OCP_READY_MASK BIT(18) -#define OCP_STATUS_MASK (BIT(16) | BIT(17)) - -#define OCP_STATUS_NO_RESP 0x00000 -#define OCP_STATUS_OK 0x10000 -#define OCP_STATUS_REQ_FAILED 0x20000 -#define OCP_STATUS_RESP_ERROR 0x30000 - -#define OCP_REG_POLARITY 0x30032 +#define OCP_REG_POLARITY 0x0064 #define CMD_MBOX_ADDRESS 0x407B4 diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 367f2d3319ac..7a7890b77b89 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -395,3 +395,49 @@ void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val) { wl1271_write32(wl, wl1271_translate_addr(wl, addr), val); } + +void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val) +{ + /* write address >> 1 + 0x30000 to OCP_POR_CTR */ + addr = (addr >> 1) + 0x30000; + wl1271_reg_write32(wl, OCP_POR_CTR, addr); + + /* write value to OCP_POR_WDATA */ + wl1271_reg_write32(wl, OCP_DATA_WRITE, val); + + /* write 1 to OCP_CMD */ + wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE); +} + +u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) +{ + u32 val; + int timeout = OCP_CMD_LOOP; + + /* write address >> 1 + 0x30000 to OCP_POR_CTR */ + addr = (addr >> 1) + 0x30000; + wl1271_reg_write32(wl, OCP_POR_CTR, addr); + + /* write 2 to OCP_CMD */ + wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ); + + /* poll for data ready */ + do { + val = wl1271_reg_read32(wl, OCP_DATA_READ); + timeout--; + } while (!(val & OCP_READY_MASK) && timeout); + + if (!timeout) { + wl1271_warning("Top register access timed out."); + return 0xffff; + } + + /* check data status and return if OK */ + if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) + return val & 0xffff; + else { + wl1271_warning("Top register access returned error."); + return 0xffff; + } +} + diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h index c58e02724d02..4f1608e99c29 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.h +++ b/drivers/net/wireless/wl12xx/wl1271_spi.h @@ -71,6 +71,18 @@ ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32)) #define HW_ACCESS_WSPI_INIT_CMD_MASK 0 +#define OCP_CMD_LOOP 32 + +#define OCP_CMD_WRITE 0x1 +#define OCP_CMD_READ 0x2 + +#define OCP_READY_MASK BIT(18) +#define OCP_STATUS_MASK (BIT(16) | BIT(17)) + +#define OCP_STATUS_NO_RESP 0x00000 +#define OCP_STATUS_OK 0x10000 +#define OCP_STATUS_REQ_FAILED 0x20000 +#define OCP_STATUS_RESP_ERROR 0x30000 /* Raw target IO, address is not translated */ void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, @@ -92,6 +104,10 @@ void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, u32 wl1271_reg_read32(struct wl1271 *wl, int addr); void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val); +/* Top Register IO */ +void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val); +u16 wl1271_top_reg_read(struct wl1271 *wl, int addr); + /* INIT and RESET words */ void wl1271_spi_reset(struct wl1271 *wl); void wl1271_spi_init(struct wl1271 *wl); -- cgit v1.2.3 From 284134eb6f928f6cdbfe95ab79f8e46233a22c98 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 12 Oct 2009 15:08:49 +0300 Subject: wl1271: RefClk configuration Updated RefClk configuration based on reference sources. Apparently this change will improve RF performance. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_boot.c | 20 ++++++++++++++++++-- drivers/net/wireless/wl12xx/wl1271_boot.h | 9 ++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index 1a3084cca9b8..b58657750716 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -435,13 +435,29 @@ int wl1271_boot(struct wl1271 *wl) int ret = 0; u32 tmp, clk, pause; - if (REF_CLOCK == 0 || REF_CLOCK == 2) - /* ref clk: 19.2/38.4 */ + if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4) + /* ref clk: 19.2/38.4/38.4-XTAL */ clk = 0x3; else if (REF_CLOCK == 1 || REF_CLOCK == 3) /* ref clk: 26/52 */ clk = 0x5; + if (REF_CLOCK != 0) { + u16 val; + /* Set clock type */ + val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); + val &= FREF_CLK_TYPE_BITS; + val |= CLK_REQ_PRCM; + wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val); + } else { + u16 val; + /* Set clock polarity */ + val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY); + val &= FREF_CLK_POLARITY_BITS; + val |= CLK_REQ_OUTN_SEL; + wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); + } + wl1271_reg_write32(wl, PLL_PARAMETERS, clk); pause = wl1271_reg_read32(wl, PLL_PARAMETERS); diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.h b/drivers/net/wireless/wl12xx/wl1271_boot.h index 4501653fb52a..412443ee655a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.h +++ b/drivers/net/wireless/wl12xx/wl1271_boot.h @@ -50,10 +50,17 @@ struct wl1271_static_data { #define WU_COUNTER_PAUSE_VAL 0x3FF #define WELP_ARM_COMMAND_VAL 0x4 -#define OCP_REG_POLARITY 0x0064 +#define OCP_REG_POLARITY 0x0064 +#define OCP_REG_CLK_TYPE 0x0448 +#define OCP_REG_CLK_POLARITY 0x0cb2 #define CMD_MBOX_ADDRESS 0x407B4 #define POLARITY_LOW BIT(1) +#define FREF_CLK_TYPE_BITS 0xfffffe7f +#define CLK_REQ_PRCM 0x100 +#define FREF_CLK_POLARITY_BITS 0xfffff8ff +#define CLK_REQ_OUTN_SEL 0x700 + #endif -- cgit v1.2.3 From c15f63bffabb996f90b9c24c62fb0614c5a4f676 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 12 Oct 2009 15:08:50 +0300 Subject: wl1271: Update interrupt handling by removing an extra SPI read Remove separate interrupt register reading from the interrupt handling routine. This will slightly improve interrupt performance. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 74 +++++++++++++------------------ drivers/net/wireless/wl12xx/wl1271_reg.h | 2 +- 2 files changed, 31 insertions(+), 45 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 22d44ba2e969..8ac9bc1b9445 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -76,20 +76,14 @@ static void wl1271_power_on(struct wl1271 *wl) wl->set_power(true); } -static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status) +static void wl1271_fw_status(struct wl1271 *wl, + struct wl1271_fw_status *status) { u32 total = 0; int i; - /* - * FIXME: Reading the FW status directly from the registers seems to - * be the right thing to do, but it doesn't work. And in the - * reference driver, there is a workaround called - * USE_SDIO_24M_WORKAROUND, which reads the status from memory - * instead, so we do the same here. - */ - - wl1271_spi_mem_read(wl, STATUS_MEM_ADDRESS, status, sizeof(*status)); + wl1271_spi_reg_read(wl, FW_STATUS_ADDR, status, + sizeof(*status), false); wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " "drv_rx_counter = %d, tx_results_counter = %d)", @@ -114,11 +108,10 @@ static void wl1271_fw_status(struct wl1271 *wl, struct wl1271_fw_status *status) wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime; } -#define WL1271_IRQ_MAX_LOOPS 10 static void wl1271_irq_work(struct work_struct *work) { - u32 intr, ctr = WL1271_IRQ_MAX_LOOPS; int ret; + u32 intr; struct wl1271 *wl = container_of(work, struct wl1271, irq_work); @@ -135,7 +128,8 @@ static void wl1271_irq_work(struct work_struct *work) wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); - intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + wl1271_fw_status(wl, wl->fw_status); + intr = wl->fw_status->intr; if (!intr) { wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); goto out_sleep; @@ -143,43 +137,35 @@ static void wl1271_irq_work(struct work_struct *work) intr &= WL1271_INTR_MASK; - do { - wl1271_fw_status(wl, wl->fw_status); - - - if (intr & (WL1271_ACX_INTR_EVENT_A | - WL1271_ACX_INTR_EVENT_B)) { - wl1271_debug(DEBUG_IRQ, - "WL1271_ACX_INTR_EVENT (0x%x)", intr); - if (intr & WL1271_ACX_INTR_EVENT_A) - wl1271_event_handle(wl, 0); - else - wl1271_event_handle(wl, 1); - } + if (intr & (WL1271_ACX_INTR_EVENT_A | + WL1271_ACX_INTR_EVENT_B)) { + wl1271_debug(DEBUG_IRQ, + "WL1271_ACX_INTR_EVENT (0x%x)", intr); + if (intr & WL1271_ACX_INTR_EVENT_A) + wl1271_event_handle(wl, 0); + else + wl1271_event_handle(wl, 1); + } - if (intr & WL1271_ACX_INTR_INIT_COMPLETE) - wl1271_debug(DEBUG_IRQ, - "WL1271_ACX_INTR_INIT_COMPLETE"); + if (intr & WL1271_ACX_INTR_INIT_COMPLETE) + wl1271_debug(DEBUG_IRQ, + "WL1271_ACX_INTR_INIT_COMPLETE"); - if (intr & WL1271_ACX_INTR_HW_AVAILABLE) - wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); + if (intr & WL1271_ACX_INTR_HW_AVAILABLE) + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); - if (intr & WL1271_ACX_INTR_DATA) { - u8 tx_res_cnt = wl->fw_status->tx_results_counter - - wl->tx_results_count; + if (intr & WL1271_ACX_INTR_DATA) { + u8 tx_res_cnt = wl->fw_status->tx_results_counter - + wl->tx_results_count; - wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); - /* check for tx results */ - if (tx_res_cnt) - wl1271_tx_complete(wl, tx_res_cnt); + /* check for tx results */ + if (tx_res_cnt) + wl1271_tx_complete(wl, tx_res_cnt); - wl1271_rx(wl, wl->fw_status); - } - - intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - intr &= WL1271_INTR_MASK; - } while (intr && --ctr); + wl1271_rx(wl, wl->fw_status); + } out_sleep: wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h index bd12615e4caf..6af87b5573ba 100644 --- a/drivers/net/wireless/wl12xx/wl1271_reg.h +++ b/drivers/net/wireless/wl12xx/wl1271_reg.h @@ -34,7 +34,7 @@ #define REGISTERS_WORK_SIZE 0x0000b000 #define HW_ACCESS_ELP_CTRL_REG_ADDR 0x1FFFC -#define STATUS_MEM_ADDRESS 0x40400 +#define FW_STATUS_ADDR (0x14FC0 + 0xA000) /* ELP register commands */ #define ELPCTRL_WAKE_UP 0x1 -- cgit v1.2.3 From 5d0af498c08b43566733d5c5fb8293ce3b109eab Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 12 Oct 2009 15:08:51 +0300 Subject: wl1271: Enable ELP The new firmware has fixed a firmware crash problem related to ELP entry. Enable ELP to conserve power. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_ps.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index 5580e53d103a..fb821c988661 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -39,12 +39,7 @@ void wl1271_elp_work(struct work_struct *work) mutex_lock(&wl->mutex); - /* - * FIXME: below, by means of the "true", ELP has been disabled for now - * to work around a firmware bug. To be enabled upon receiving a new - * firmware version. - */ - if (true || wl->elp || !wl->psm) + if (wl->elp || !wl->psm) goto out; wl1271_debug(DEBUG_PSM, "chip to elp"); -- cgit v1.2.3 From 3cfd6cf960b2b030ccae1144a5c0dcd91c7c56a8 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 12 Oct 2009 15:08:52 +0300 Subject: wl1271: Enable smart reflex Enable and configure smart reflex. This should have a reducing impact on power consumption. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.c | 72 +++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_acx.h | 23 ++++++++++ drivers/net/wireless/wl12xx/wl1271_init.c | 5 +++ 3 files changed, 100 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index d5dac5753ae2..6c2989002218 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -998,3 +998,75 @@ out: kfree(rx_conf); return ret; } + +int wl1271_acx_smart_reflex(struct wl1271 *wl) +{ + struct acx_smart_reflex_state *sr_state = NULL; + struct acx_smart_reflex_config_params *sr_param = NULL; + int ret; + + wl1271_debug(DEBUG_ACX, "acx smart reflex"); + + sr_param = kzalloc(sizeof(*sr_param), GFP_KERNEL); + if (!sr_param) { + ret = -ENOMEM; + goto out; + } + + /* set cryptic smart reflex parameters - source TI reference code */ + sr_param->error_table[0].len = 0x07; + sr_param->error_table[0].upper_limit = 0x03; + sr_param->error_table[0].values[0] = 0x18; + sr_param->error_table[0].values[1] = 0x10; + sr_param->error_table[0].values[2] = 0x05; + sr_param->error_table[0].values[3] = 0xfb; + sr_param->error_table[0].values[4] = 0xf0; + sr_param->error_table[0].values[5] = 0xe8; + + sr_param->error_table[1].len = 0x07; + sr_param->error_table[1].upper_limit = 0x03; + sr_param->error_table[1].values[0] = 0x18; + sr_param->error_table[1].values[1] = 0x10; + sr_param->error_table[1].values[2] = 0x05; + sr_param->error_table[1].values[3] = 0xf6; + sr_param->error_table[1].values[4] = 0xf0; + sr_param->error_table[1].values[5] = 0xe8; + + sr_param->error_table[2].len = 0x07; + sr_param->error_table[2].upper_limit = 0x03; + sr_param->error_table[2].values[0] = 0x18; + sr_param->error_table[2].values[1] = 0x10; + sr_param->error_table[2].values[2] = 0x05; + sr_param->error_table[2].values[3] = 0xfb; + sr_param->error_table[2].values[4] = 0xf0; + sr_param->error_table[2].values[5] = 0xe8; + + ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS, + sr_param, sizeof(*sr_param)); + if (ret < 0) { + wl1271_warning("failed to set smart reflex params: %d", ret); + goto out; + } + + sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL); + if (!sr_state) { + ret = -ENOMEM; + goto out; + } + + /* enable smart reflex */ + sr_state->enable = 1; + + ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE, + sr_state, sizeof(*sr_state)); + if (ret < 0) { + wl1271_warning("failed to set smart reflex params: %d", ret); + goto out; + } + +out: + kfree(sr_state); + kfree(sr_param); + return ret; + +} diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 07256d280e51..0c704af1953c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -445,6 +445,25 @@ struct acx_bt_wlan_coex { u8 pad[3]; } __attribute__ ((packed)); +struct acx_smart_reflex_state { + struct acx_header header; + + u8 enable; + u8 padding[3]; +}; + +struct smart_reflex_err_table { + u8 len; + s8 upper_limit; + s8 values[14]; +}; + +struct acx_smart_reflex_config_params { + struct acx_header header; + + struct smart_reflex_err_table error_table[3]; +}; + #define PTA_ANTENNA_TYPE_DEF (0) #define PTA_BT_HP_MAXTIME_DEF (2000) #define PTA_WLAN_HP_MAX_TIME_DEF (5000) @@ -1184,6 +1203,9 @@ enum { ACX_PEER_HT_CAP = 0x0057, ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0059, + ACX_SET_SMART_REFLEX_DEBUG = 0x005A, + ACX_SET_SMART_REFLEX_STATE = 0x005B, + ACX_SET_SMART_REFLEX_PARAMS = 0x005F, DOT11_RX_MSDU_LIFE_TIME = 0x1004, DOT11_CUR_TX_PWR = 0x100D, DOT11_RX_DOT11_MODE = 0x1012, @@ -1233,5 +1255,6 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl); int wl1271_acx_mem_cfg(struct wl1271 *wl); int wl1271_acx_init_mem_config(struct wl1271 *wl); int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); +int wl1271_acx_smart_reflex(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index bf4d0e18fb81..f9315f601bd6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -394,6 +394,11 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + /* Configure smart reflex */ + ret = wl1271_acx_smart_reflex(wl); + if (ret < 0) + goto out_free_memmap; + return 0; out_free_memmap: -- cgit v1.2.3 From 207347e498cbe25fa2a8369edd49df43e56000be Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 12 Oct 2009 15:08:53 +0300 Subject: wl1271: Update TX path block calucation algo Update the TX path block calculation algorithm based on TI reference. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_tx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 5d3aa4b26cf3..56a7f36380b7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -57,8 +57,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra) /* approximate the number of blocks required for this packet in the firmware */ /* FIXME: try to figure out what is done here and make it cleaner */ - total_blocks = (total_len) >> TX_HW_BLOCK_SHIFT_DIV; - excluded = (total_blocks << 2) + (skb->len & 0xff) + 34; + total_blocks = (total_len + 20) >> TX_HW_BLOCK_SHIFT_DIV; + excluded = (total_blocks << 2) + ((total_len + 20) & 0xff) + 34; total_blocks += (excluded > 252) ? 2 : 1; total_blocks += TX_HW_BLOCK_SPARE; -- cgit v1.2.3 From 746214178774bc7f9adbeaef7d43a634570eb870 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 12 Oct 2009 15:08:54 +0300 Subject: wl1271: Remove outdated SPI functions With the change to the new firmware, there was a change to firmware memory partitioning. Along with that change, the translation of all partitions was unified, and separate functions for reg and mem access became unnecessary. Cleanup the unnecessary functions. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_boot.c | 63 +++++++++++----------- drivers/net/wireless/wl12xx/wl1271_cmd.c | 19 +++---- drivers/net/wireless/wl12xx/wl1271_event.c | 8 +-- drivers/net/wireless/wl12xx/wl1271_main.c | 12 ++--- drivers/net/wireless/wl12xx/wl1271_ps.c | 4 +- drivers/net/wireless/wl12xx/wl1271_rx.c | 10 ++-- drivers/net/wireless/wl12xx/wl1271_spi.c | 85 ++++++++++-------------------- drivers/net/wireless/wl12xx/wl1271_spi.h | 36 ++++++------- drivers/net/wireless/wl12xx/wl1271_tx.c | 10 ++-- 9 files changed, 107 insertions(+), 140 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index b58657750716..a27601dc9c0d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -93,19 +93,19 @@ static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) u32 cpu_ctrl; /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wl1271_reg_read32(wl, ACX_REG_ECPU_CONTROL); + cpu_ctrl = wl1271_spi_read32(wl, ACX_REG_ECPU_CONTROL); /* 10.5.1 run the firmware (II) */ cpu_ctrl |= flag; - wl1271_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); + wl1271_spi_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl); } static void wl1271_boot_fw_version(struct wl1271 *wl) { struct wl1271_static_data static_data; - wl1271_spi_mem_read(wl, wl->cmd_box_addr, - &static_data, sizeof(static_data)); + wl1271_spi_read(wl, wl->cmd_box_addr, + &static_data, sizeof(static_data), false); strncpy(wl->chip.fw_ver, static_data.fw_version, sizeof(wl->chip.fw_ver)); @@ -164,7 +164,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, memcpy(chunk, p, CHUNK_SIZE); wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", p, addr); - wl1271_spi_mem_write(wl, addr, chunk, CHUNK_SIZE); + wl1271_spi_write(wl, addr, chunk, CHUNK_SIZE, false); chunk_num++; } @@ -175,7 +175,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, memcpy(chunk, p, fw_data_len % CHUNK_SIZE); wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); - wl1271_spi_mem_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE); + wl1271_spi_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); kfree(chunk); return 0; @@ -262,7 +262,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "nvs burst write 0x%x: 0x%x", dest_addr, val); - wl1271_reg_write32(wl, dest_addr, val); + wl1271_spi_write32(wl, dest_addr, val); nvs_ptr += 4; dest_addr += 4; @@ -289,7 +289,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) /* FIXME: In wl1271, we upload everything at once. No endianness handling needed here?! The ref driver doesn't do anything about it at this point */ - wl1271_spi_mem_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len); + wl1271_spi_write(wl, CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, false); kfree(nvs_aligned); return 0; @@ -298,9 +298,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) static void wl1271_boot_enable_interrupts(struct wl1271 *wl) { enable_irq(wl->irq); - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); - wl1271_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL); + wl1271_spi_write32(wl, HI_CFG, HI_CFG_DEF_VAL); } static int wl1271_boot_soft_reset(struct wl1271 *wl) @@ -309,12 +309,13 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl) u32 boot_data; /* perform soft reset */ - wl1271_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + wl1271_spi_write32(wl, ACX_REG_SLV_SOFT_RESET, + ACX_SLV_SOFT_RESET_BIT); /* SOFT_RESET is self clearing */ timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); while (1) { - boot_data = wl1271_reg_read32(wl, ACX_REG_SLV_SOFT_RESET); + boot_data = wl1271_spi_read32(wl, ACX_REG_SLV_SOFT_RESET); wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) break; @@ -330,10 +331,10 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl) } /* disable Rx/Tx */ - wl1271_reg_write32(wl, ENABLE, 0x0); + wl1271_spi_write32(wl, ENABLE, 0x0); /* disable auto calibration on start*/ - wl1271_reg_write32(wl, SPARE_A2, 0xffff); + wl1271_spi_write32(wl, SPARE_A2, 0xffff); return 0; } @@ -345,7 +346,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); - chip_id = wl1271_reg_read32(wl, CHIP_ID_B); + chip_id = wl1271_spi_read32(wl, CHIP_ID_B); wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); @@ -358,7 +359,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) loop = 0; while (loop++ < INIT_LOOP) { udelay(INIT_LOOP_DELAY); - interrupt = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + interrupt = wl1271_spi_read32(wl, + ACX_REG_INTERRUPT_NO_CLEAR); if (interrupt == 0xffffffff) { wl1271_error("error reading hardware complete " @@ -367,7 +369,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) } /* check that ACX_INTR_INIT_COMPLETE is enabled */ else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) { - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK, WL1271_ACX_INTR_INIT_COMPLETE); break; } @@ -380,10 +382,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) } /* get hardware config command mail box */ - wl->cmd_box_addr = wl1271_reg_read32(wl, REG_COMMAND_MAILBOX_PTR); + wl->cmd_box_addr = wl1271_spi_read32(wl, REG_COMMAND_MAILBOX_PTR); /* get hardware config event mail box */ - wl->event_box_addr = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->event_box_addr = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR); /* set the working partition to its "running" mode offset */ wl1271_set_partition(wl, &part_table[PART_WORK]); @@ -458,9 +460,9 @@ int wl1271_boot(struct wl1271 *wl) wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); } - wl1271_reg_write32(wl, PLL_PARAMETERS, clk); + wl1271_spi_write32(wl, PLL_PARAMETERS, clk); - pause = wl1271_reg_read32(wl, PLL_PARAMETERS); + pause = wl1271_spi_read32(wl, PLL_PARAMETERS); wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); @@ -469,10 +471,10 @@ int wl1271_boot(struct wl1271 *wl) * 0x3ff (magic number ). How does * this work?! */ pause |= WU_COUNTER_PAUSE_VAL; - wl1271_reg_write32(wl, WU_COUNTER_PAUSE, pause); + wl1271_spi_write32(wl, WU_COUNTER_PAUSE, pause); /* Continue the ELP wake up sequence */ - wl1271_reg_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + wl1271_spi_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); udelay(500); wl1271_set_partition(wl, &part_table[PART_DRPW]); @@ -482,18 +484,18 @@ int wl1271_boot(struct wl1271 *wl) before taking DRPw out of reset */ wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START); - clk = wl1271_reg_read32(wl, DRPW_SCRATCH_START); + clk = wl1271_spi_read32(wl, DRPW_SCRATCH_START); wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); /* 2 */ clk |= (REF_CLOCK << 1) << 4; - wl1271_reg_write32(wl, DRPW_SCRATCH_START, clk); + wl1271_spi_write32(wl, DRPW_SCRATCH_START, clk); wl1271_set_partition(wl, &part_table[PART_WORK]); /* Disable interrupts */ - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); ret = wl1271_boot_soft_reset(wl); if (ret < 0) @@ -508,21 +510,22 @@ int wl1271_boot(struct wl1271 *wl) * ACX_EEPROMLESS_IND_REG */ wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); - wl1271_reg_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG); + wl1271_spi_write32(wl, ACX_EEPROMLESS_IND_REG, + ACX_EEPROMLESS_IND_REG); - tmp = wl1271_reg_read32(wl, CHIP_ID_B); + tmp = wl1271_spi_read32(wl, CHIP_ID_B); wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); /* 6. read the EEPROM parameters */ - tmp = wl1271_reg_read32(wl, SCR_PAD2); + tmp = wl1271_spi_read32(wl, SCR_PAD2); ret = wl1271_boot_write_irq_polarity(wl); if (ret < 0) goto out; /* FIXME: Need to check whether this is really what we want */ - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR); /* WL1271: The reference driver skips steps 7 to 10 (jumps directly diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index ef92834e0e8f..f727744dcff7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -55,13 +55,13 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) WARN_ON(len % 4 != 0); - wl1271_spi_mem_write(wl, wl->cmd_box_addr, buf, len); + wl1271_spi_write(wl, wl->cmd_box_addr, buf, len, false); - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); - intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); @@ -71,10 +71,10 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) msleep(1); - intr = wl1271_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); + intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); } - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_ACK, + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); out: @@ -302,7 +302,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) * The answer would be a wl1271_command, where the * parameter array contains the actual answer. */ - wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len); + wl1271_spi_read(wl, wl->cmd_box_addr, buf, buf_len, false); cmd_answer = buf; @@ -341,7 +341,7 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) } /* the interrogate command got in, we can read the answer */ - wl1271_spi_mem_read(wl, wl->cmd_box_addr, buf, len); + wl1271_spi_read(wl, wl->cmd_box_addr, buf, len, false); acx = buf; if (acx->cmd.status != CMD_STATUS_SUCCESS) @@ -496,7 +496,7 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, } /* the read command got in, we can now read the answer */ - wl1271_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); + wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd), false); if (cmd->header.status != CMD_STATUS_SUCCESS) wl1271_error("error in read command result: %d", @@ -591,7 +591,8 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, goto out; } - wl1271_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); + wl1271_spi_read(wl, wl->cmd_box_addr, params, sizeof(*params), + false); if (params->header.status != CMD_STATUS_SUCCESS) { wl1271_error("Scan command error: %d", diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index f32927650af4..4189e97ca805 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -98,7 +98,7 @@ int wl1271_event_unmask(struct wl1271 *wl) void wl1271_event_mbox_config(struct wl1271 *wl) { - wl->mbox_ptr[0] = wl1271_reg_read32(wl, REG_EVENT_MAILBOX_PTR); + wl->mbox_ptr[0] = wl1271_spi_read32(wl, REG_EVENT_MAILBOX_PTR); wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); wl1271_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x", @@ -116,8 +116,8 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) return -EINVAL; /* first we read the mbox descriptor */ - wl1271_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox, - sizeof(struct event_mailbox)); + wl1271_spi_read(wl, wl->mbox_ptr[mbox_num], &mbox, + sizeof(struct event_mailbox), false); /* process the descriptor */ ret = wl1271_event_process(wl, &mbox); @@ -125,7 +125,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) return ret; /* then we let the firmware know it can go on...*/ - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 8ac9bc1b9445..5ef0bd53af66 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -82,8 +82,8 @@ static void wl1271_fw_status(struct wl1271 *wl, u32 total = 0; int i; - wl1271_spi_reg_read(wl, FW_STATUS_ADDR, status, - sizeof(*status), false); + wl1271_spi_read(wl, FW_STATUS_ADDR, status, + sizeof(*status), false); wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " "drv_rx_counter = %d, tx_results_counter = %d)", @@ -126,7 +126,7 @@ static void wl1271_irq_work(struct work_struct *work) if (ret < 0) goto out; - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); wl1271_fw_status(wl, wl->fw_status); intr = wl->fw_status->intr; @@ -168,7 +168,7 @@ static void wl1271_irq_work(struct work_struct *work) } out_sleep: - wl1271_reg_write32(wl, ACX_REG_INTERRUPT_MASK, + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); wl1271_ps_elp_sleep(wl); @@ -279,7 +279,7 @@ static void wl1271_fw_wakeup(struct wl1271 *wl) u32 elp_reg; elp_reg = ELPCTRL_WAKE_UP; - wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); + wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); } static int wl1271_setup(struct wl1271 *wl) @@ -322,7 +322,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) /* whal_FwCtrl_BootSm() */ /* 0. read chip id from CHIP_ID */ - wl->chip.id = wl1271_reg_read32(wl, CHIP_ID_B); + wl->chip.id = wl1271_spi_read32(wl, CHIP_ID_B); /* 1. check if chip id is valid */ diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index fb821c988661..bb8745d9bd64 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -43,7 +43,7 @@ void wl1271_elp_work(struct work_struct *work) goto out; wl1271_debug(DEBUG_PSM, "chip to elp"); - wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); + wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); wl->elp = true; out: @@ -86,7 +86,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) wl->elp_compl = &compl; spin_unlock_irqrestore(&wl->wl_lock, flags); - wl1271_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); + wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP); if (!pending) { ret = wait_for_completion_timeout( diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 1d9865371f17..7979b69ec52d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -132,7 +132,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) } buf = skb_put(skb, length); - wl1271_spi_reg_read(wl, WL1271_SLV_MEM_DATA, buf, length, true); + wl1271_spi_read(wl, WL1271_SLV_MEM_DATA, buf, length, true); /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) buf; @@ -176,9 +176,9 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) wl->rx_mem_pool_addr.addr + 4; /* Choose the block we want to read */ - wl1271_spi_reg_write(wl, WL1271_SLV_REG_DATA, - &wl->rx_mem_pool_addr, - sizeof(wl->rx_mem_pool_addr), false); + wl1271_spi_write(wl, WL1271_SLV_REG_DATA, + &wl->rx_mem_pool_addr, + sizeof(wl->rx_mem_pool_addr), false); wl1271_rx_handle_data(wl, buf_size); @@ -186,5 +186,5 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; } - wl1271_reg_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); + wl1271_spi_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); } diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 7a7890b77b89..4800fdfd2373 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -183,13 +183,13 @@ int wl1271_set_partition(struct wl1271 *wl, p->mem3.start, p->mem3.size); /* write partition info to the chipset */ - wl1271_write32(wl, HW_PART0_START_ADDR, p->mem.start); - wl1271_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); - wl1271_write32(wl, HW_PART1_START_ADDR, p->reg.start); - wl1271_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); - wl1271_write32(wl, HW_PART2_START_ADDR, p->mem2.start); - wl1271_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); - wl1271_write32(wl, HW_PART3_START_ADDR, p->mem3.start); + wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); + wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); + wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); + wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); + wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); + wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); + wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); return 0; } @@ -257,8 +257,8 @@ void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len) wl1271_error("SPI read busy-word timeout!\n"); } -void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) +void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) { struct spi_transfer t[3]; struct spi_message m; @@ -302,8 +302,8 @@ void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); } -void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) +void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, + size_t len, bool fixed) { struct spi_transfer t[2]; struct spi_message m; @@ -336,77 +336,47 @@ void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len); } -void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, - size_t len) +void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed) { int physical; physical = wl1271_translate_addr(wl, addr); - wl1271_spi_read(wl, physical, buf, len, false); + wl1271_spi_raw_read(wl, physical, buf, len, fixed); } -void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, - size_t len) +void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed) { int physical; physical = wl1271_translate_addr(wl, addr); - wl1271_spi_write(wl, physical, buf, len, false); + wl1271_spi_raw_write(wl, physical, buf, len, fixed); } -void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, - bool fixed) +u32 wl1271_spi_read32(struct wl1271 *wl, int addr) { - int physical; - - physical = wl1271_translate_addr(wl, addr); - - wl1271_spi_read(wl, physical, buf, len, fixed); -} - -void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, - bool fixed) -{ - int physical; - - physical = wl1271_translate_addr(wl, addr); - - wl1271_spi_write(wl, physical, buf, len, fixed); + return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr)); } -u32 wl1271_mem_read32(struct wl1271 *wl, int addr) +void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val) { - return wl1271_read32(wl, wl1271_translate_addr(wl, addr)); -} - -void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val) -{ - wl1271_write32(wl, wl1271_translate_addr(wl, addr), val); -} - -u32 wl1271_reg_read32(struct wl1271 *wl, int addr) -{ - return wl1271_read32(wl, wl1271_translate_addr(wl, addr)); -} - -void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val) -{ - wl1271_write32(wl, wl1271_translate_addr(wl, addr), val); + wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val); } void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val) { /* write address >> 1 + 0x30000 to OCP_POR_CTR */ addr = (addr >> 1) + 0x30000; - wl1271_reg_write32(wl, OCP_POR_CTR, addr); + wl1271_spi_write32(wl, OCP_POR_CTR, addr); /* write value to OCP_POR_WDATA */ - wl1271_reg_write32(wl, OCP_DATA_WRITE, val); + wl1271_spi_write32(wl, OCP_DATA_WRITE, val); /* write 1 to OCP_CMD */ - wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_WRITE); + wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_WRITE); } u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) @@ -416,14 +386,14 @@ u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) /* write address >> 1 + 0x30000 to OCP_POR_CTR */ addr = (addr >> 1) + 0x30000; - wl1271_reg_write32(wl, OCP_POR_CTR, addr); + wl1271_spi_write32(wl, OCP_POR_CTR, addr); /* write 2 to OCP_CMD */ - wl1271_reg_write32(wl, OCP_CMD, OCP_CMD_READ); + wl1271_spi_write32(wl, OCP_CMD, OCP_CMD_READ); /* poll for data ready */ do { - val = wl1271_reg_read32(wl, OCP_DATA_READ); + val = wl1271_spi_read32(wl, OCP_DATA_READ); timeout--; } while (!(val & OCP_READY_MASK) && timeout); @@ -440,4 +410,3 @@ u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) return 0xffff; } } - diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h index 4f1608e99c29..cb7df1c56314 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.h +++ b/drivers/net/wireless/wl12xx/wl1271_spi.h @@ -85,24 +85,18 @@ #define OCP_STATUS_RESP_ERROR 0x30000 /* Raw target IO, address is not translated */ -void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, +void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed); -void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, +void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed); -/* Memory target IO, address is tranlated to partition 0 */ -void wl1271_spi_mem_read(struct wl1271 *wl, int addr, void *buf, size_t len); -void wl1271_spi_mem_write(struct wl1271 *wl, int addr, void *buf, size_t len); -u32 wl1271_mem_read32(struct wl1271 *wl, int addr); -void wl1271_mem_write32(struct wl1271 *wl, int addr, u32 val); - -/* Registers IO */ -void wl1271_spi_reg_read(struct wl1271 *wl, int addr, void *buf, size_t len, - bool fixed); -void wl1271_spi_reg_write(struct wl1271 *wl, int addr, void *buf, size_t len, - bool fixed); -u32 wl1271_reg_read32(struct wl1271 *wl, int addr); -void wl1271_reg_write32(struct wl1271 *wl, int addr, u32 val); +/* Translated target IO */ +void wl1271_spi_read(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed); +void wl1271_spi_write(struct wl1271 *wl, int addr, void *buf, size_t len, + bool fixed); +u32 wl1271_spi_read32(struct wl1271 *wl, int addr); +void wl1271_spi_write32(struct wl1271 *wl, int addr, u32 val); /* Top Register IO */ void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val); @@ -114,19 +108,19 @@ void wl1271_spi_init(struct wl1271 *wl); int wl1271_set_partition(struct wl1271 *wl, struct wl1271_partition_set *p); -static inline u32 wl1271_read32(struct wl1271 *wl, int addr) +static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) { - wl1271_spi_read(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); + wl1271_spi_raw_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); return wl->buffer_32; } -static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) +static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) { wl->buffer_32 = val; - wl1271_spi_write(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); + wl1271_spi_raw_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); } #endif /* __WL1271_SPI_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 56a7f36380b7..4560458a6d60 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -154,11 +154,11 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb, len = WL1271_TX_ALIGN(skb->len); /* perform a fixed address block write with the packet */ - wl1271_spi_reg_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); + wl1271_spi_write(wl, WL1271_SLV_MEM_DATA, skb->data, len, true); /* write packet new counter into the write access register */ wl->tx_packets_count++; - wl1271_reg_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); + wl1271_spi_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); desc = (struct wl1271_tx_hw_descr *) skb->data; wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)", @@ -331,8 +331,8 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count) wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); /* read the tx results from the chipset */ - wl1271_spi_mem_read(wl, memmap->tx_result, - wl->tx_res_if, sizeof(*wl->tx_res_if)); + wl1271_spi_read(wl, memmap->tx_result, + wl->tx_res_if, sizeof(*wl->tx_res_if), false); /* verify that the result buffer is not getting overrun */ if (count > TX_HW_RESULT_QUEUE_LEN) { @@ -353,7 +353,7 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count) } /* write host counter to chipset (to ack) */ - wl1271_mem_write32(wl, memmap->tx_result + + wl1271_spi_write32(wl, memmap->tx_result + offsetof(struct wl1271_tx_hw_res_if, tx_result_host_counter), wl->tx_res_if->tx_result_fw_counter); -- cgit v1.2.3 From 8bcfcb125b036e978b1bd478d3f68278b05bcfd6 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 12 Oct 2009 15:08:55 +0300 Subject: wl1271: Update boot time configuration for the new firmware Update the magic values of the wl1271 boot time config according to the new reference driver. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index f9315f601bd6..e45af075e671 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -202,7 +202,7 @@ static int wl1271_init_general_parms(struct wl1271 *wl) gen_parms->clk_valid_on_wakeup = 0; gen_parms->dc2dcmode = 0; gen_parms->single_dual_band = 0; - gen_parms->tx_bip_fem_autodetect = 1; + gen_parms->tx_bip_fem_autodetect = 0; gen_parms->tx_bip_fem_manufacturer = 1; gen_parms->settings = 1; -- cgit v1.2.3 From 0535d9f4f07df9a592b77fe75f66faee66a851e8 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 12 Oct 2009 15:08:56 +0300 Subject: wl1271: use acx_rx_config instead of join when updating filters We shouldn't use a join command to change the filter settings while associated. The right way to do it is to use ACX_RX_CFG. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 5ef0bd53af66..fc0d03fd24cb 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -422,7 +422,7 @@ static void wl1271_filter_work(struct work_struct *work) goto out; /* apply configured filters */ - ret = wl1271_cmd_join(wl); + ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); if (ret < 0) goto out_sleep; @@ -869,6 +869,8 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, wl1271_warning("Unknown mc address length."); } + /* FIXME: We still need to set our filters properly */ + spin_lock_irqsave(&wl->wl_lock, flags); kfree(wl->filter_params); wl->filter_params = fp; -- cgit v1.2.3 From ae751bab9f55c3152ebf713c89a4fb6f439c2575 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 12 Oct 2009 15:08:57 +0300 Subject: wl1271: remove unnecessary joins and join only when the bssid changes We were using the join command to change some settings when the stack asked us to do it. In many cases they were not needed (and could cause potential problems), so they were removed. In other cases there are ACX commands that can be used instead of using join to reconfigure. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 4 -- drivers/net/wireless/wl12xx/wl1271_cmd.c | 4 +- drivers/net/wireless/wl12xx/wl1271_main.c | 61 +++++++++++-------------------- 3 files changed, 24 insertions(+), 45 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index b2bc7b59d645..aa9bb2ea8554 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -378,10 +378,6 @@ struct wl1271 { /* Our association ID */ u16 aid; - /* Beacon parameters */ - u16 beacon_int; - u8 dtim_period; - /* currently configured rate set */ u32 basic_rate_set; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index f727744dcff7..eaa1de97339c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -232,8 +232,8 @@ int wl1271_cmd_join(struct wl1271 *wl) join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; - join->beacon_interval = wl->beacon_int; - join->dtim_interval = wl->dtim_period; + join->beacon_interval = WL1271_DEFAULT_BEACON_INT; + join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; join->bss_type = wl->bss_type; join->channel = wl->channel; join->ssid_len = wl->ssid_len; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index fc0d03fd24cb..821a7752adfe 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -710,7 +710,15 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw, if (ret < 0) goto out; - memcpy(wl->bssid, conf->bssid, ETH_ALEN); + if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) { + wl1271_debug(DEBUG_MAC80211, "bssid changed"); + + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + + ret = wl1271_cmd_join(wl); + if (ret < 0) + goto out_sleep; + } ret = wl1271_cmd_build_null_data(wl); if (ret < 0) @@ -720,12 +728,6 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw, if (wl->ssid_len) memcpy(wl->ssid, conf->ssid, wl->ssid_len); - if (wl->bss_type != BSS_TYPE_IBSS) { - ret = wl1271_cmd_join(wl); - if (ret < 0) - goto out_sleep; - } - if (conf->changed & IEEE80211_IFCC_BEACON) { beacon = ieee80211_beacon_get(hw, vif); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, @@ -741,11 +743,6 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw, dev_kfree_skb(beacon); - if (ret < 0) - goto out_sleep; - - ret = wl1271_cmd_join(wl); - if (ret < 0) goto out_sleep; } @@ -782,14 +779,13 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) goto out; if (channel != wl->channel) { - u8 old_channel = wl->channel; + /* + * We assume that the stack will configure the right channel + * before associating, so we don't need to send a join + * command here. We will join the right channel when the + * BSSID changes + */ wl->channel = channel; - - ret = wl1271_cmd_join(wl); - if (ret < 0) { - wl->channel = old_channel; - goto out_sleep; - } } ret = wl1271_cmd_build_null_data(wl); @@ -1102,17 +1098,14 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { - wl->beacon_int = bss_conf->beacon_int; - wl->dtim_period = bss_conf->dtim_period; wl->aid = bss_conf->aid; - ret = wl1271_cmd_join(wl); - if (ret < 0) { - wl1271_warning("Association configuration " - "failed %d", ret); - goto out_sleep; - } - + /* + * with wl1271, we don't need to update the + * beacon_int and dtim_period, because the firmware + * updates it by itself when the first beacon is + * received after a join. + */ ret = wl1271_cmd_build_ps_poll(wl, wl->aid); if (ret < 0) goto out_sleep; @@ -1130,8 +1123,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } else { /* use defaults when not associated */ - wl->beacon_int = WL1271_DEFAULT_BEACON_INT; - wl->dtim_period = WL1271_DEFAULT_DTIM_PERIOD; wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; wl->aid = 0; } @@ -1170,18 +1161,12 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BASIC_RATES) { wl->basic_rate_set = wl1271_enabled_rates_get( wl, bss_conf->basic_rates); - ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set); + ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set); if (ret < 0) { wl1271_warning("Set rate policies failed %d", ret); goto out_sleep; } - ret = wl1271_cmd_join(wl); - if (ret < 0) { - wl1271_warning("Join with new basic rate " - "set failed %d", ret); - goto out_sleep; - } } out_sleep: @@ -1380,8 +1365,6 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->psm_requested = false; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; - wl->beacon_int = WL1271_DEFAULT_BEACON_INT; - wl->dtim_period = WL1271_DEFAULT_DTIM_PERIOD; wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; wl->band = IEEE80211_BAND_2GHZ; wl->vif = NULL; -- cgit v1.2.3 From 2f301227a1ede57504694e1f64839839f5737cac Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 9 Oct 2009 17:19:45 +0800 Subject: iwlwifi: use paged Rx This switches the iwlwifi driver to use paged skb from linear skb for Rx buffer. So that it relieves some Rx buffer allocation pressure for the memory subsystem. Currently iwlwifi (4K for 3945) requests 8K bytes for Rx buffer. Due to the trailing skb_shared_info in the skb->data, alloc_skb() will do the next order allocation, which is 16K bytes. This is suboptimal and more likely to fail when the system is under memory usage pressure. Switching to paged Rx skb lets us allocate the RXB directly by alloc_pages(), so that only order 1 allocation is required. It also adjusts the area spin_lock (with IRQ disabled) protected in the tasklet because tasklet guarentees to run only on one CPU and the new unprotected code can be preempted by the IRQ handler. This saves us from spawning another workqueue to make skb_linearize/__pskb_pull_tail happy (which cannot be called in hard irq context). Finally, mac80211 doesn't support paged Rx yet. So we linearize the skb for all the management frames and software decryption or defragmentation required data frames before handed to mac80211. For all the other frames, we __pskb_pull_tail 64 bytes in the linear area of the skb for mac80211 to handle them properly. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 67 ++++++++++----- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-5000.c | 4 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 42 +++++----- drivers/net/wireless/iwlwifi/iwl-commands.h | 10 +++ drivers/net/wireless/iwlwifi/iwl-core.c | 13 ++- drivers/net/wireless/iwlwifi/iwl-core.h | 2 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 27 +++--- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 21 ++--- drivers/net/wireless/iwlwifi/iwl-rx.c | 122 +++++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-scan.c | 20 ++--- drivers/net/wireless/iwlwifi/iwl-spectrum.c | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 62 ++++++-------- drivers/net/wireless/iwlwifi/iwl-tx.c | 10 +-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 120 ++++++++++++++------------- 15 files changed, 284 insertions(+), 240 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8012381d3717..b188a026637a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -293,7 +293,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv, static void iwl3945_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); @@ -353,7 +353,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv, void iwl3945_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(struct iwl3945_notif_statistics), le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); @@ -543,14 +543,17 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); 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); + u16 len = le16_to_cpu(rx_hdr->len); + struct sk_buff *skb; + int ret; /* We received data from the HW, so stop the watchdog */ - if (unlikely((len + IWL39_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) { + if (unlikely(len + IWL39_RX_FRAME_SIZE > + PAGE_SIZE << priv->hw_params.rx_page_order)) { IWL_DEBUG_DROP(priv, "Corruption detected!\n"); return; } @@ -562,20 +565,45 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, return; } - skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt); - /* Set the size of the skb to the size of the frame */ - skb_put(rxb->skb, le16_to_cpu(rx_hdr->len)); + skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC); + if (!skb) { + IWL_ERR(priv, "alloc_skb failed\n"); + return; + } if (!iwl3945_mod_params.sw_crypto) iwl_set_decrypted_flag(priv, - (struct ieee80211_hdr *)rxb->skb->data, + (struct ieee80211_hdr *)rxb_addr(rxb), le32_to_cpu(rx_end->status), stats); + skb_add_rx_frag(skb, 0, rxb->page, + (void *)rx_hdr->payload - (void *)pkt, len); + + /* mac80211 currently doesn't support paged SKB. Convert it to + * linear SKB for management frame and data frame requires + * software decryption or software defragementation. */ + if (ieee80211_is_mgmt(hdr->frame_control) || + ieee80211_has_protected(hdr->frame_control) || + ieee80211_has_morefrags(hdr->frame_control) || + le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) + ret = skb_linearize(skb); + else + ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ? + 0 : -ENOMEM; + + if (ret) { + kfree_skb(skb); + goto out; + } + iwl_update_stats(priv, false, hdr->frame_control, len); - memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); - ieee80211_rx_irqsafe(priv->hw, rxb->skb); - rxb->skb = NULL; + memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); + ieee80211_rx(priv->hw, skb); + + out: + priv->alloc_rxb_page--; + rxb->page = NULL; } #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) @@ -585,7 +613,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, { struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status; - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); @@ -1811,7 +1839,7 @@ int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) { int rc = 0; - struct iwl_rx_packet *res = NULL; + struct iwl_rx_packet *pkt; struct iwl3945_rxon_assoc_cmd rxon_assoc; struct iwl_host_cmd cmd = { .id = REPLY_RXON_ASSOC, @@ -1840,14 +1868,14 @@ static int iwl3945_send_rxon_assoc(struct iwl_priv *priv) if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.reply_skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_RXON_ASSOC command\n"); rc = -EIO; } - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.reply_skb); + priv->alloc_rxb_page--; + free_pages(cmd.reply_page, priv->hw_params.rx_page_order); return rc; } @@ -2513,8 +2541,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_txq_num = priv->cfg->num_of_queues; priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; - priv->hw_params.max_pkt_size = 2342; + priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_3K); priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; priv->hw_params.max_stations = IWL3945_STATION_COUNT; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 6d77039b4ed2..1a622aa5a160 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1999,7 +1999,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, static void iwl4965_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ab5b9d8d66be..17555c7c1d67 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -423,7 +423,7 @@ static int iwl5000_send_calib_cfg(struct iwl_priv *priv) static void iwl5000_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; int index; @@ -1143,7 +1143,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, static void iwl5000_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0878b34ee586..fc7a51144f0c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -524,7 +524,7 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv, static void iwl_rx_reply_alive(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_alive_resp *palive; struct delayed_work *pwork; @@ -610,7 +610,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl4965_beacon_notif *beacon = (struct iwl4965_beacon_notif *)pkt->u.raw; u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); @@ -634,7 +634,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv, static void iwl_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; @@ -786,10 +786,10 @@ void iwl_rx_handle(struct iwl_priv *priv) rxq->queue[i] = NULL; - pci_unmap_single(priv->pci_dev, rxb->real_dma_addr, - priv->hw_params.rx_buf_size + 256, - PCI_DMA_FROMDEVICE); - pkt = (struct iwl_rx_packet *)rxb->skb->data; + pci_unmap_page(priv->pci_dev, rxb->page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + pkt = rxb_addr(rxb); trace_iwlwifi_dev_rx(priv, pkt, le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); @@ -825,10 +825,10 @@ void iwl_rx_handle(struct iwl_priv *priv) } if (reclaim) { - /* Invoke any callbacks, transfer the skb to caller, and - * fire off the (possibly) blocking iwl_send_cmd() + /* Invoke any callbacks, transfer the buffer to caller, + * and fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ - if (rxb && rxb->skb) + if (rxb && rxb->page) iwl_tx_cmd_complete(priv, rxb); else IWL_WARN(priv, "Claim null rxb?\n"); @@ -837,10 +837,10 @@ void iwl_rx_handle(struct iwl_priv *priv) /* For now we just don't re-use anything. We can tweak this * later to try and re-use notification packets and SKBs that * fail to Rx correctly */ - if (rxb->skb != NULL) { - priv->alloc_rxb_skb--; - dev_kfree_skb_any(rxb->skb); - rxb->skb = NULL; + if (rxb->page != NULL) { + priv->alloc_rxb_page--; + __free_pages(rxb->page, priv->hw_params.rx_page_order); + rxb->page = NULL; } spin_lock_irqsave(&rxq->lock, flags); @@ -907,6 +907,8 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) } #endif + spin_unlock_irqrestore(&priv->lock, flags); + /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not * atomic, make sure that inta covers all the interrupts that * we've discovered, even if FH interrupt came in just after @@ -928,8 +930,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) handled |= CSR_INT_BIT_HW_ERR; - spin_unlock_irqrestore(&priv->lock, flags); - return; } @@ -1056,7 +1056,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); } #endif - spin_unlock_irqrestore(&priv->lock, flags); } /* tasklet for iwlagn interrupt */ @@ -1086,6 +1085,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) inta, inta_mask); } #endif + + spin_unlock_irqrestore(&priv->lock, flags); + /* saved interrupt in inta variable now we can reset priv->inta */ priv->inta = 0; @@ -1101,8 +1103,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) handled |= CSR_INT_BIT_HW_ERR; - spin_unlock_irqrestore(&priv->lock, flags); - return; } @@ -1242,14 +1242,10 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) inta & ~priv->inta_mask); } - /* Re-enable all interrupts */ /* only Re-enable if diabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_enable_interrupts(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - } diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index cc4e9122709e..7d4f131708f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3544,6 +3544,16 @@ struct iwl_wimax_coex_cmd { *****************************************************************************/ struct iwl_rx_packet { + /* + * The first 4 bytes of the RX frame header contain both the RX frame + * size and some flags. + * Bit fields: + * 31: flag flush RB request + * 30: flag ignore TC (terminal counter) request + * 29: flag fast IRQ request + * 28-14: Reserved + * 13-00: RX frame size + */ __le32 len_n_flags; struct iwl_cmd_header hdr; union { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2ae168af0f2c..3e6ce5ce36aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1281,7 +1281,7 @@ static void iwl_set_rate(struct iwl_priv *priv) void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; struct iwl_csa_notification *csa = &(pkt->u.csa_notif); IWL_DEBUG_11H(priv, "CSA notif: channel %d, status %d\n", @@ -1492,10 +1492,9 @@ int iwl_set_hw_params(struct iwl_priv *priv) priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; if (priv->cfg->mod_params->amsdu_size_8K) - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K; + priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K); else - priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K; - priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256; + priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K); priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL; @@ -2176,7 +2175,7 @@ void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", sleep->pm_sleep_mode, sleep->pm_wakeup_src); @@ -2187,7 +2186,7 @@ EXPORT_SYMBOL(iwl_rx_pm_sleep_notif); void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " "notification for %s:\n", len, @@ -2199,7 +2198,7 @@ EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); void iwl_rx_reply_error(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) " "seq 0x%04X ser 0x%08X\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index cec673badf0e..b877f8893fdf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -531,7 +531,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, void (*callback)(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb)); + struct iwl_rx_packet *pkt)); int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 451aa65b1a56..35d579455c3c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -146,12 +146,13 @@ extern void iwl5000_temperature(struct iwl_priv *priv); #define DEFAULT_LONG_RETRY_LIMIT 4U struct iwl_rx_mem_buffer { - dma_addr_t real_dma_addr; - dma_addr_t aligned_dma_addr; - struct sk_buff *skb; + dma_addr_t page_dma; + struct page *page; struct list_head list; }; +#define rxb_addr(r) page_address(r->page) + /* defined below */ struct iwl_device_cmd; @@ -167,7 +168,7 @@ struct iwl_cmd_meta { */ void (*callback)(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb); + struct iwl_rx_packet *pkt); /* The CMD_SIZE_HUGE flag bit indicates that the command * structure is stored at the end of the shared queue memory. */ @@ -366,6 +367,13 @@ enum { #define IWL_CMD_MAX_PAYLOAD 320 +/* + * IWL_LINK_HDR_MAX should include ieee80211_hdr, radiotap header, + * SNAP header and alignment. It should also be big enough for 802.11 + * control frames. + */ +#define IWL_LINK_HDR_MAX 64 + /** * struct iwl_device_cmd * @@ -390,10 +398,10 @@ struct iwl_device_cmd { struct iwl_host_cmd { const void *data; - struct sk_buff *reply_skb; + unsigned long reply_page; void (*callback)(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb); + struct iwl_rx_packet *pkt); u32 flags; u16 len; u8 id; @@ -650,7 +658,7 @@ struct iwl_sensitivity_ranges { * @valid_tx/rx_ant: usable antennas * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) * @max_rxq_log: Log-base-2 of max_rxq_size - * @rx_buf_size: Rx buffer size + * @rx_page_order: Rx buffer page order * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR * @max_stations: * @bcast_sta_id: @@ -673,9 +681,8 @@ struct iwl_hw_params { u8 valid_rx_ant; u16 max_rxq_size; u16 max_rxq_log; - u32 rx_buf_size; + u32 rx_page_order; u32 rx_wrt_ptr_reg; - u32 max_pkt_size; u8 max_stations; u8 bcast_sta_id; u8 ht40_channel; @@ -987,7 +994,7 @@ struct iwl_priv { int frames_count; enum ieee80211_band band; - int alloc_rxb_skb; + int alloc_rxb_page; void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 532c8d6cd8da..22a21a1c7f49 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -103,17 +103,8 @@ EXPORT_SYMBOL(get_cmd_string); static void iwl_generic_cmd_callback(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb) + struct iwl_rx_packet *pkt) { - struct iwl_rx_packet *pkt = NULL; - - if (!skb) { - IWL_ERR(priv, "Error: Response NULL in %s.\n", - get_cmd_string(cmd->hdr.cmd)); - return; - } - - pkt = (struct iwl_rx_packet *)skb->data; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from %s (0x%08X)\n", get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); @@ -215,7 +206,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ret = -EIO; goto fail; } - if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_skb) { + if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) { IWL_ERR(priv, "Error: Response NULL in '%s'\n", get_cmd_string(cmd->id)); ret = -EIO; @@ -237,9 +228,9 @@ cancel: ~CMD_WANT_SKB; } fail: - if (cmd->reply_skb) { - dev_kfree_skb_any(cmd->reply_skb); - cmd->reply_skb = NULL; + if (cmd->reply_page) { + free_pages(cmd->reply_page, priv->hw_params.rx_page_order); + cmd->reply_page = 0; } out: clear_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status); @@ -272,7 +263,7 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, const void *data, void (*callback)(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb)) + struct iwl_rx_packet *pkt)) { struct iwl_host_cmd cmd = { .id = id, diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 7ad327ef9cb5..0a407f79de01 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -200,7 +200,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) list_del(element); /* Point to Rx buffer via next RBD in circular buffer */ - rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->aligned_dma_addr); + rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->page_dma); rxq->queue[rxq->write] = rxb; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->free_count--; @@ -239,7 +239,7 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl_rx_mem_buffer *rxb; - struct sk_buff *skb; + struct page *page; unsigned long flags; while (1) { @@ -252,29 +252,34 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) if (rxq->free_count > RX_LOW_WATERMARK) priority |= __GFP_NOWARN; - /* Alloc a new receive buffer */ - skb = alloc_skb(priv->hw_params.rx_buf_size + 256, - priority); - if (!skb) { + if (priv->hw_params.rx_page_order > 0) + priority |= __GFP_COMP; + + /* Alloc a new receive buffer */ + page = alloc_pages(priority, priv->hw_params.rx_page_order); + if (!page) { if (net_ratelimit()) - IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n"); + IWL_DEBUG_INFO(priv, "alloc_pages failed, " + "order: %d\n", + priv->hw_params.rx_page_order); + if ((rxq->free_count <= RX_LOW_WATERMARK) && net_ratelimit()) - IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n", + IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n", priority == GFP_ATOMIC ? "GFP_ATOMIC" : "GFP_KERNEL", rxq->free_count); /* We don't reschedule replenish work here -- we will * call the restock method and if it still needs * more buffers it will schedule replenish */ - break; + return; } spin_lock_irqsave(&rxq->lock, flags); if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); - dev_kfree_skb_any(skb); + __free_pages(page, priv->hw_params.rx_page_order); return; } element = rxq->rx_used.next; @@ -283,24 +288,21 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) spin_unlock_irqrestore(&rxq->lock, flags); - rxb->skb = skb; - /* Get physical address of RB/SKB */ - rxb->real_dma_addr = pci_map_single( - priv->pci_dev, - rxb->skb->data, - priv->hw_params.rx_buf_size + 256, - PCI_DMA_FROMDEVICE); + rxb->page = page; + /* Get physical address of the RB */ + rxb->page_dma = pci_map_page(priv->pci_dev, page, 0, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); /* dma address must be no more than 36 bits */ - BUG_ON(rxb->real_dma_addr & ~DMA_BIT_MASK(36)); + BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); /* and also 256 byte aligned! */ - rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256); - skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr); + BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); spin_lock_irqsave(&rxq->lock, flags); list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; - priv->alloc_rxb_skb++; + priv->alloc_rxb_page++; spin_unlock_irqrestore(&rxq->lock, flags); } @@ -336,12 +338,14 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) { int i; for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].real_dma_addr, - priv->hw_params.rx_buf_size + 256, - PCI_DMA_FROMDEVICE); - dev_kfree_skb(rxq->pool[i].skb); + if (rxq->pool[i].page != NULL) { + pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + __free_pages(rxq->pool[i].page, + priv->hw_params.rx_page_order); + rxq->pool[i].page = NULL; + priv->alloc_rxb_page--; } } @@ -405,14 +409,14 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { /* In the reset function, these buffers may have been allocated * to an SKB, so we need to unmap and free potential storage */ - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].real_dma_addr, - priv->hw_params.rx_buf_size + 256, - PCI_DMA_FROMDEVICE); - priv->alloc_rxb_skb--; - dev_kfree_skb(rxq->pool[i].skb); - rxq->pool[i].skb = NULL; + if (rxq->pool[i].page != NULL) { + pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + priv->alloc_rxb_page--; + __free_pages(rxq->pool[i].page, + priv->hw_params.rx_page_order); + rxq->pool[i].page = NULL; } list_add_tail(&rxq->pool[i].list, &rxq->rx_used); } @@ -491,7 +495,7 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_missed_beacon_notif *missed_beacon; missed_beacon = &pkt->u.missed_beacon; @@ -592,7 +596,7 @@ void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { int change; - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", (int)sizeof(priv->statistics), @@ -919,6 +923,9 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) { + struct sk_buff *skb; + int ret = 0; + /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { IWL_DEBUG_DROP_LIMIT(priv, @@ -931,15 +938,38 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; - /* Resize SKB from mac header to end of packet */ - skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data); - skb_put(rxb->skb, len); + skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC); + if (!skb) { + IWL_ERR(priv, "alloc_skb failed\n"); + return; + } + + skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); + + /* mac80211 currently doesn't support paged SKB. Convert it to + * linear SKB for management frame and data frame requires + * software decryption or software defragementation. */ + if (ieee80211_is_mgmt(hdr->frame_control) || + ieee80211_has_protected(hdr->frame_control) || + ieee80211_has_morefrags(hdr->frame_control) || + le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) + ret = skb_linearize(skb); + else + ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ? + 0 : -ENOMEM; + + if (ret) { + kfree_skb(skb); + goto out; + } iwl_update_stats(priv, false, hdr->frame_control, len); - memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); - ieee80211_rx_irqsafe(priv->hw, rxb->skb); - priv->alloc_rxb_skb--; - rxb->skb = NULL; + memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); + + ieee80211_rx(priv->hw, skb); + out: + priv->alloc_rxb_page--; + rxb->page = NULL; } /* This is necessary only for a number of statistics, see the caller. */ @@ -967,7 +997,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, { struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status; - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_phy_res *phy_res; __le32 rx_pkt_status; struct iwl4965_rx_mpdu_res_start *amsdu; @@ -1128,7 +1158,7 @@ EXPORT_SYMBOL(iwl_rx_reply_rx); void iwl_rx_reply_rx_phy(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); priv->last_phy_res[0] = 1; memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), sizeof(struct iwl_rx_phy_res)); diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 41f9a0621250..4fca65a2fe9c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -111,7 +111,7 @@ EXPORT_SYMBOL(iwl_scan_cancel_timeout); static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret = 0; - struct iwl_rx_packet *res; + struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .flags = CMD_WANT_SKB, @@ -131,21 +131,21 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) return ret; } - res = (struct iwl_rx_packet *)cmd.reply_skb->data; - if (res->u.status != CAN_ABORT_STATUS) { + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be * due to simply not being in an active scan which * can occur if we send the scan abort before we * the microcode has notified us that a scan is * completed. */ - IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", res->u.status); + IWL_DEBUG_INFO(priv, "SCAN_ABORT returned %d.\n", pkt->u.status); clear_bit(STATUS_SCAN_ABORTING, &priv->status); clear_bit(STATUS_SCAN_HW, &priv->status); } - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.reply_skb); + priv->alloc_rxb_page--; + free_pages(cmd.reply_page, priv->hw_params.rx_page_order); return ret; } @@ -155,7 +155,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scanreq_notification *notif = (struct iwl_scanreq_notification *)pkt->u.raw; @@ -167,7 +167,7 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv, static void iwl_rx_scan_start_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scanstart_notification *notif = (struct iwl_scanstart_notification *)pkt->u.raw; priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); @@ -186,7 +186,7 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scanresults_notification *notif = (struct iwl_scanresults_notification *)pkt->u.raw; @@ -213,7 +213,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c index 022bcf115731..1ea5cd345fe8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.c +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c @@ -177,7 +177,7 @@ static int iwl_get_measurement(struct iwl_priv *priv, static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); if (!report->state) { diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index c6633fec8216..dc74c16d36a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -99,32 +99,25 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) static void iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb) + struct iwl_rx_packet *pkt) { - struct iwl_rx_packet *res = NULL; struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)cmd->cmd.payload; u8 sta_id = addsta->sta.sta_id; - if (!skb) { - IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n"); - return; - } - - res = (struct iwl_rx_packet *)skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", - res->hdr.flags); + pkt->hdr.flags); return; } - switch (res->u.add_sta.status) { + switch (pkt->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: iwl_sta_ucode_activate(priv, sta_id); /* fall through */ default: IWL_DEBUG_HC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", - res->u.add_sta.status); + pkt->u.add_sta.status); break; } } @@ -132,7 +125,7 @@ static void iwl_add_sta_callback(struct iwl_priv *priv, int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags) { - struct iwl_rx_packet *res = NULL; + struct iwl_rx_packet *pkt = NULL; int ret = 0; u8 data[sizeof(*sta)]; struct iwl_host_cmd cmd = { @@ -152,15 +145,15 @@ int iwl_send_add_sta(struct iwl_priv *priv, if (ret || (flags & CMD_ASYNC)) return ret; - res = (struct iwl_rx_packet *)cmd.reply_skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", - res->hdr.flags); + pkt->hdr.flags); ret = -EIO; } if (ret == 0) { - switch (res->u.add_sta.status) { + switch (pkt->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: iwl_sta_ucode_activate(priv, sta->sta.sta_id); IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); @@ -172,8 +165,8 @@ int iwl_send_add_sta(struct iwl_priv *priv, } } - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.reply_skb); + priv->alloc_rxb_page--; + free_pages(cmd.reply_page, priv->hw_params.rx_page_order); return ret; } @@ -324,26 +317,19 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) static void iwl_remove_sta_callback(struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct sk_buff *skb) + struct iwl_rx_packet *pkt) { - struct iwl_rx_packet *res = NULL; struct iwl_rem_sta_cmd *rm_sta = - (struct iwl_rem_sta_cmd *)cmd->cmd.payload; + (struct iwl_rem_sta_cmd *)cmd->cmd.payload; const char *addr = rm_sta->addr; - if (!skb) { - IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n"); - return; - } - - res = (struct iwl_rx_packet *)skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", - res->hdr.flags); + pkt->hdr.flags); return; } - switch (res->u.rem_sta.status) { + switch (pkt->u.rem_sta.status) { case REM_STA_SUCCESS_MSK: iwl_sta_ucode_deactivate(priv, addr); break; @@ -356,7 +342,7 @@ static void iwl_remove_sta_callback(struct iwl_priv *priv, static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, u8 flags) { - struct iwl_rx_packet *res = NULL; + struct iwl_rx_packet *pkt; int ret; struct iwl_rem_sta_cmd rm_sta_cmd; @@ -381,15 +367,15 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, if (ret || (flags & CMD_ASYNC)) return ret; - res = (struct iwl_rx_packet *)cmd.reply_skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", - res->hdr.flags); + pkt->hdr.flags); ret = -EIO; } if (!ret) { - switch (res->u.rem_sta.status) { + switch (pkt->u.rem_sta.status) { case REM_STA_SUCCESS_MSK: iwl_sta_ucode_deactivate(priv, addr); IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); @@ -401,8 +387,8 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, } } - priv->alloc_rxb_skb--; - dev_kfree_skb_any(cmd.reply_skb); + priv->alloc_rxb_page--; + free_pages(cmd.reply_page, priv->hw_params.rx_page_order); return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index d0bd7cd024ad..5c43d7c43b30 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1153,7 +1153,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, */ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); @@ -1180,10 +1180,10 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { - meta->source->reply_skb = rxb->skb; - rxb->skb = NULL; + meta->source->reply_page = (unsigned long)rxb_addr(rxb); + rxb->page = NULL; } else if (meta->callback) - meta->callback(priv, cmd, rxb->skb); + meta->callback(priv, cmd, pkt); iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); @@ -1442,7 +1442,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; struct iwl_tx_queue *txq = NULL; struct iwl_ht_agg *agg; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 515f29b8a7a7..5977a57a234c 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -745,7 +745,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, u8 type) { struct iwl_spectrum_cmd spectrum; - struct iwl_rx_packet *res; + struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = REPLY_SPECTRUM_MEASUREMENT_CMD, .data = (void *)&spectrum, @@ -790,18 +790,18 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.reply_skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_RX_ON_ASSOC command\n"); rc = -EIO; } - spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); + spectrum_resp_status = le16_to_cpu(pkt->u.spectrum.status); switch (spectrum_resp_status) { case 0: /* Command will be handled */ - if (res->u.spectrum.id != 0xff) { + if (pkt->u.spectrum.id != 0xff) { IWL_DEBUG_INFO(priv, "Replaced existing measurement: %d\n", - res->u.spectrum.id); + pkt->u.spectrum.id); priv->measurement_status &= ~MEASUREMENT_READY; } priv->measurement_status |= MEASUREMENT_ACTIVE; @@ -813,7 +813,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, break; } - dev_kfree_skb_any(cmd.reply_skb); + free_pages(cmd.reply_page, priv->hw_params.rx_page_order); return rc; } @@ -822,7 +822,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv, static void iwl3945_rx_reply_alive(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_alive_resp *palive; struct delayed_work *pwork; @@ -859,7 +859,7 @@ static void iwl3945_rx_reply_add_sta(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); #endif IWL_DEBUG_RX(priv, "Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); @@ -895,7 +895,7 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status); u8 rate = beacon->beacon_notify_hdr.rate; @@ -918,7 +918,7 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv, static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; @@ -1082,7 +1082,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv) list_del(element); /* Point to Rx buffer via next RBD in circular buffer */ - rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->real_dma_addr); + rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->page_dma); rxq->queue[rxq->write] = rxb; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->free_count--; @@ -1122,7 +1122,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) struct iwl_rx_queue *rxq = &priv->rxq; struct list_head *element; struct iwl_rx_mem_buffer *rxb; - struct sk_buff *skb; + struct page *page; unsigned long flags; while (1) { @@ -1136,9 +1136,13 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) if (rxq->free_count > RX_LOW_WATERMARK) priority |= __GFP_NOWARN; + + if (priv->hw_params.rx_page_order > 0) + priority |= __GFP_COMP; + /* Alloc a new receive buffer */ - skb = alloc_skb(priv->hw_params.rx_buf_size, priority); - if (!skb) { + page = alloc_pages(priority, priv->hw_params.rx_page_order); + if (!page) { if (net_ratelimit()) IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n"); if ((rxq->free_count <= RX_LOW_WATERMARK) && @@ -1155,7 +1159,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) spin_lock_irqsave(&rxq->lock, flags); if (list_empty(&rxq->rx_used)) { spin_unlock_irqrestore(&rxq->lock, flags); - dev_kfree_skb_any(skb); + __free_pages(page, priv->hw_params.rx_page_order); return; } element = rxq->rx_used.next; @@ -1163,26 +1167,18 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) list_del(element); spin_unlock_irqrestore(&rxq->lock, flags); - rxb->skb = skb; - - /* If radiotap head is required, reserve some headroom here. - * The physical head count is a variable rx_stats->phy_count. - * We reserve 4 bytes here. Plus these extra bytes, the - * headroom of the physical head should be enough for the - * radiotap head that iwl3945 supported. See iwl3945_rt. - */ - skb_reserve(rxb->skb, 4); - + rxb->page = page; /* Get physical address of RB/SKB */ - rxb->real_dma_addr = pci_map_single(priv->pci_dev, - rxb->skb->data, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); + rxb->page_dma = pci_map_page(priv->pci_dev, page, 0, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &rxq->rx_free); - priv->alloc_rxb_skb++; rxq->free_count++; + priv->alloc_rxb_page++; + spin_unlock_irqrestore(&rxq->lock, flags); } } @@ -1198,14 +1194,14 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { /* In the reset function, these buffers may have been allocated * to an SKB, so we need to unmap and free potential storage */ - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].real_dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - priv->alloc_rxb_skb--; - dev_kfree_skb(rxq->pool[i].skb); - rxq->pool[i].skb = NULL; + if (rxq->pool[i].page != NULL) { + pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + priv->alloc_rxb_page--; + __free_pages(rxq->pool[i].page, + priv->hw_params.rx_page_order); + rxq->pool[i].page = NULL; } list_add_tail(&rxq->pool[i].list, &rxq->rx_used); } @@ -1213,8 +1209,8 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* Set us so that we have processed and used all buffers, but have * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; - rxq->free_count = 0; rxq->write_actual = 0; + rxq->free_count = 0; spin_unlock_irqrestore(&rxq->lock, flags); } @@ -1247,12 +1243,14 @@ static void iwl3945_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rx { int i; for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { - if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, - rxq->pool[i].real_dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - dev_kfree_skb(rxq->pool[i].skb); + if (rxq->pool[i].page != NULL) { + pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + __free_pages(rxq->pool[i].page, + priv->hw_params.rx_page_order); + rxq->pool[i].page = NULL; + priv->alloc_rxb_page--; } } @@ -1388,10 +1386,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) rxq->queue[i] = NULL; - pci_unmap_single(priv->pci_dev, rxb->real_dma_addr, - priv->hw_params.rx_buf_size, - PCI_DMA_FROMDEVICE); - pkt = (struct iwl_rx_packet *)rxb->skb->data; + pci_unmap_page(priv->pci_dev, rxb->page_dma, + PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + pkt = rxb_addr(rxb); trace_iwlwifi_dev_rx(priv, pkt, le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); @@ -1416,16 +1414,17 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; } else { /* No handling needed */ - IWL_DEBUG_RX(priv, "r %d i %d No handler needed for %s, 0x%02x\n", + IWL_DEBUG_RX(priv, + "r %d i %d No handler needed for %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); } if (reclaim) { - /* Invoke any callbacks, transfer the skb to caller, and - * fire off the (possibly) blocking iwl_send_cmd() + /* Invoke any callbacks, transfer the buffer to caller, + * and fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ - if (rxb && rxb->skb) + if (rxb && rxb->page) iwl_tx_cmd_complete(priv, rxb); else IWL_WARN(priv, "Claim null rxb?\n"); @@ -1434,10 +1433,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) /* For now we just don't re-use anything. We can tweak this * later to try and re-use notification packets and SKBs that * fail to Rx correctly */ - if (rxb->skb != NULL) { - priv->alloc_rxb_skb--; - dev_kfree_skb_any(rxb->skb); - rxb->skb = NULL; + if (rxb->page != NULL) { + priv->alloc_rxb_page--; + __free_pages(rxb->page, priv->hw_params.rx_page_order); + rxb->page = NULL; } spin_lock_irqsave(&rxq->lock, flags); @@ -1678,6 +1677,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) } #endif + spin_unlock_irqrestore(&priv->lock, flags); + /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not * atomic, make sure that inta covers all the interrupts that * we've discovered, even if FH interrupt came in just after @@ -1699,8 +1700,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) handled |= CSR_INT_BIT_HW_ERR; - spin_unlock_irqrestore(&priv->lock, flags); - return; } @@ -1792,7 +1791,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags); } #endif - spin_unlock_irqrestore(&priv->lock, flags); } static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, -- cgit v1.2.3 From 2cc8d4db9dd7df9dd12d86f2e37d1b4760d3dd98 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:38 +0300 Subject: wl1271: Workaround for reference clock setting on boot. If the 38.4MHz reference clock is configured to the firmware, it crashes on boot. Configuring an experimental 38.4MHz in XTAL mode allows the firmware to boot, and everything appears to work. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_init.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index e45af075e671..9abe062f1876 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -196,7 +196,14 @@ static int wl1271_init_general_parms(struct wl1271 *wl) gen_parms->id = TEST_CMD_INI_FILE_GENERAL_PARAM; - gen_parms->ref_clk = REF_CLK_38_4_E; + /* + * FIXME: The firmware crashes on boot with REF_CLK_38_4_E as clock. + * according to TI engineers, ref clk 5 is an unofficial + * 38.4 XTAL clock config, which seems to boot the device. + * Restore correct value once the real problem source is + * identified. + */ + gen_parms->ref_clk = 5; /* REF_CLK_38_4_E; */ /* FIXME: magic numbers */ gen_parms->settling_time = 5; gen_parms->clk_valid_on_wakeup = 0; -- cgit v1.2.3 From 2b60100bf04aba28133ccb24efd85f72fb1a5494 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:39 +0300 Subject: wl1271: Add structure for firmware configuration values In order to make the firmware configuration more manageable, collect hardcoded configuration values into one data structure, and set default values there. Add the SoftGemini BT/WLAN coex paramters into the config structure. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 5 + drivers/net/wireless/wl12xx/wl1271_acx.c | 40 ++----- drivers/net/wireless/wl12xx/wl1271_acx.h | 136 +++-------------------- drivers/net/wireless/wl12xx/wl1271_cmd.c | 6 +- drivers/net/wireless/wl12xx/wl1271_cmd.h | 5 - drivers/net/wireless/wl12xx/wl1271_conf.h | 178 ++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_main.c | 84 ++++++++++---- drivers/net/wireless/wl12xx/wl1271_reg.h | 44 -------- 8 files changed, 274 insertions(+), 224 deletions(-) create mode 100644 drivers/net/wireless/wl12xx/wl1271_conf.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index aa9bb2ea8554..64a327009f2e 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -32,6 +32,8 @@ #include #include +#include "wl1271_conf.h" + #define DRIVER_NAME "wl1271" #define DRIVER_PREFIX DRIVER_NAME ": " @@ -420,6 +422,9 @@ struct wl1271 { /* Used for a workaround to send disconnect before rejoining */ bool joined; + + /* Current chipset configuration */ + struct conf_drv_settings conf; }; int wl1271_plt_start(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 6c2989002218..d19d8605b9d2 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -509,6 +509,7 @@ out: int wl1271_acx_sg_cfg(struct wl1271 *wl) { struct acx_bt_wlan_coex_param *param; + struct conf_sg_settings *c = &wl->conf.sg; int ret; wl1271_debug(DEBUG_ACX, "acx sg cfg"); @@ -520,34 +521,17 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl) } /* BT-WLAN coext parameters */ - param->min_rate = RATE_INDEX_24MBPS; - param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF; - param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF; - param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF; - param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF; - param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF; - param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF; - param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF; - param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF; - param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF; - param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF; - param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF; - param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF; - param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF; - param->antenna_type = PTA_ANTENNA_TYPE_DEF; - param->signal_type = PTA_SIGNALING_TYPE_DEF; - param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF; - param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF; - param->max_cts = PTA_MAX_NUM_CTS_DEF; - param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF; - param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF; - param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF; - param->wlan_elp_hp = PTA_ELP_HP_DEF; - param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF; - param->ack_mode_dual_ant = PTA_ACK_MODE_DEF; - param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF; - param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF; - param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF; + param->per_threshold = c->per_threshold; + param->max_scan_compensation_time = c->max_scan_compensation_time; + param->nfs_sample_interval = c->nfs_sample_interval; + param->load_ratio = c->load_ratio; + param->auto_ps_mode = c->auto_ps_mode; + param->probe_req_compensation = c->probe_req_compensation; + param->scan_window_compensation = c->scan_window_compensation; + param->antenna_config = c->antenna_config; + param->beacon_miss_threshold = c->beacon_miss_threshold; + param->rate_adaptation_threshold = c->rate_adaptation_threshold; + param->rate_adaptation_snr = c->rate_adaptation_snr; ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 0c704af1953c..8e3b97cff794 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -496,126 +496,18 @@ struct acx_smart_reflex_config_params { struct acx_bt_wlan_coex_param { struct acx_header header; - /* - * The minimum rate of a received WLAN packet in the STA, - * during protective mode, of which a new BT-HP request - * during this Rx will always be respected and gain the antenna. - */ - u32 min_rate; - - /* Max time the BT HP will be respected. */ - u16 bt_hp_max_time; - - /* Max time the WLAN HP will be respected. */ - u16 wlan_hp_max_time; - - /* - * The time between the last BT activity - * and the moment when the sense mode returns - * to SENSE_INACTIVE. - */ - u16 sense_disable_timer; - - /* Time before the next BT HP instance */ - u16 rx_time_bt_hp; - u16 tx_time_bt_hp; - - /* range: 10-20000 default: 1500 */ - u16 rx_time_bt_hp_fast; - u16 tx_time_bt_hp_fast; - - /* range: 2000-65535 default: 8700 */ - u16 wlan_cycle_fast; - - /* range: 0 - 15000 (Msec) default: 1000 */ - u16 bt_anti_starvation_period; - - /* range 400-10000(Usec) default: 3000 */ - u16 next_bt_lp_packet; - - /* Deafult: worst case for BT DH5 traffic */ - u16 wake_up_beacon; - - /* range: 0-50000(Usec) default: 1050 */ - u16 hp_dm_max_guard_time; - - /* - * This is to prevent both BT & WLAN antenna - * starvation. - * Range: 100-50000(Usec) default:2550 - */ - u16 next_wlan_packet; - - /* 0 -> shared antenna */ - u8 antenna_type; - - /* - * 0 -> TI legacy - * 1 -> Palau - */ - u8 signal_type; - - /* - * BT AFH status - * 0 -> no AFH - * 1 -> from dedicated GPIO - * 2 -> AFH on (from host) - */ - u8 afh_leverage_on; - - /* - * The number of cycles during which no - * TX will be sent after 1 cycle of RX - * transaction in protective mode - */ - u8 quiet_cycle_num; - - /* - * The maximum number of CTSs that will - * be sent for receiving RX packet in - * protective mode - */ - u8 max_cts; - - /* - * The number of WLAN packets - * transferred in common mode before - * switching to BT. - */ - u8 wlan_packets_num; - - /* - * The number of BT packets - * transferred in common mode before - * switching to WLAN. - */ - u8 bt_packets_num; - - /* range: 1-255 default: 5 */ - u8 missed_rx_avalanche; - - /* range: 0-1 default: 1 */ - u8 wlan_elp_hp; - - /* range: 0 - 15 default: 4 */ - u8 bt_anti_starvation_cycles; - - u8 ack_mode_dual_ant; - - /* - * Allow PA_SD assertion/de-assertion - * during enabled BT activity. - */ - u8 pa_sd_enable; - - /* - * Enable/Disable PTA in auto mode: - * Support Both Active & P.S modes - */ - u8 pta_auto_mode_enable; - - /* range: 0 - 20 default: 1 */ - u8 bt_hp_respected_num; + u32 per_threshold; + u32 max_scan_compensation_time; + u16 nfs_sample_interval; + u8 load_ratio; + u8 auto_ps_mode; + u8 probe_req_compensation; + u8 scan_window_compensation; + u8 antenna_config; + u8 beacon_miss_threshold; + u32 rate_adaptation_threshold; + s8 rate_adaptation_snr; + u8 padding[3]; } __attribute__ ((packed)); #define CCA_THRSH_ENABLE_ENERGY_D 0x140A @@ -690,6 +582,10 @@ struct acx_event_mask { #define SCAN_TRIGGERED BIT(2) #define SCAN_PRIORITY_HIGH BIT(3) +/* When set, disable HW encryption */ +#define DF_ENCRYPTION_DISABLE 0x01 +#define DF_SNIFF_MODE_ENABLE 0x80 + struct acx_feature_config { struct acx_header header; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index eaa1de97339c..c7a8a64d18dd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -229,8 +229,8 @@ int wl1271_cmd_join(struct wl1271 *wl) join->rx_config_options = 0; join->rx_filter_options = WL1271_DEFAULT_RX_FILTER; - join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | - RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; + join->basic_rate_set = CONF_HW_BIT_RATE_1MBPS | CONF_HW_BIT_RATE_2MBPS | + CONF_HW_BIT_RATE_5_5MBPS | CONF_HW_BIT_RATE_11MBPS; join->beacon_interval = WL1271_DEFAULT_BEACON_INT; join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; @@ -538,7 +538,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, params->params.num_channels = num_channels; params->params.num_probe_requests = probe_requests; - params->params.tx_rate = cpu_to_le32(RATE_MASK_2MBPS); + params->params.tx_rate = cpu_to_le32(CONF_HW_BIT_RATE_2MBPS); params->params.tid_trigger = 0; params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 0219664765ec..91430871c8fd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -288,11 +288,6 @@ struct wl1271_cmd_ps_params { #define NUM_ACCESS_CATEGORIES_COPY 4 #define MAX_KEY_SIZE 32 -/* When set, disable HW encryption */ -#define DF_ENCRYPTION_DISABLE 0x01 -/* When set, disable HW decryption */ -#define DF_SNIFF_MODE_ENABLE 0x80 - enum wl1271_cmd_key_action { KEY_ADD_OR_REPLACE = 1, KEY_REMOVE = 2, diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h new file mode 100644 index 000000000000..1d6a44bec1cb --- /dev/null +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -0,0 +1,178 @@ +/* + * This file is part of wl1271 + * + * Copyright (C) 2009 Nokia Corporation + * + * Contact: Luciano Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __WL1271_CONF_H__ +#define __WL1271_CONF_H__ + +enum { + CONF_HW_BIT_RATE_1MBPS = BIT(0), + CONF_HW_BIT_RATE_2MBPS = BIT(1), + CONF_HW_BIT_RATE_5_5MBPS = BIT(2), + CONF_HW_BIT_RATE_6MBPS = BIT(3), + CONF_HW_BIT_RATE_9MBPS = BIT(4), + CONF_HW_BIT_RATE_11MBPS = BIT(5), + CONF_HW_BIT_RATE_12MBPS = BIT(6), + CONF_HW_BIT_RATE_18MBPS = BIT(7), + CONF_HW_BIT_RATE_22MBPS = BIT(8), + CONF_HW_BIT_RATE_24MBPS = BIT(9), + CONF_HW_BIT_RATE_36MBPS = BIT(10), + CONF_HW_BIT_RATE_48MBPS = BIT(11), + CONF_HW_BIT_RATE_54MBPS = BIT(12), + CONF_HW_BIT_RATE_MCS_0 = BIT(13), + CONF_HW_BIT_RATE_MCS_1 = BIT(14), + CONF_HW_BIT_RATE_MCS_2 = BIT(15), + CONF_HW_BIT_RATE_MCS_3 = BIT(16), + CONF_HW_BIT_RATE_MCS_4 = BIT(17), + CONF_HW_BIT_RATE_MCS_5 = BIT(18), + CONF_HW_BIT_RATE_MCS_6 = BIT(19), + CONF_HW_BIT_RATE_MCS_7 = BIT(20) +}; + +enum { + CONF_HW_RATE_INDEX_1MBPS = 0, + CONF_HW_RATE_INDEX_2MBPS = 1, + CONF_HW_RATE_INDEX_5_5MBPS = 2, + CONF_HW_RATE_INDEX_6MBPS = 3, + CONF_HW_RATE_INDEX_9MBPS = 4, + CONF_HW_RATE_INDEX_11MBPS = 5, + CONF_HW_RATE_INDEX_12MBPS = 6, + CONF_HW_RATE_INDEX_18MBPS = 7, + CONF_HW_RATE_INDEX_22MBPS = 8, + CONF_HW_RATE_INDEX_24MBPS = 9, + CONF_HW_RATE_INDEX_36MBPS = 10, + CONF_HW_RATE_INDEX_48MBPS = 11, + CONF_HW_RATE_INDEX_54MBPS = 12, + CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS, +}; + +struct conf_sg_settings { + /* + * Defines the PER threshold in PPM of the BT voice of which reaching + * this value will trigger raising the priority of the BT voice by + * the BT IP until next NFS sample interval time as defined in + * nfs_sample_interval. + * + * Unit: PER value in PPM (parts per million) + * #Error_packets / #Total_packets + + * Range: u32 + */ + u32 per_threshold; + + /* + * This value is an absolute time in micro-seconds to limit the + * maximum scan duration compensation while in SG + */ + u32 max_scan_compensation_time; + + /* Defines the PER threshold of the BT voice of which reaching this + * value will trigger raising the priority of the BT voice until next + * NFS sample interval time as defined in sample_interval. + * + * Unit: msec + * Range: 1-65000 + */ + u16 nfs_sample_interval; + + /* + * Defines the load ratio for the BT. + * The WLAN ratio is: 100 - load_ratio + * + * Unit: Percent + * Range: 0-100 + */ + u8 load_ratio; + + /* + * true - Co-ex is allowed to enter/exit P.S automatically and + * transparently to the host + * + * false - Co-ex is disallowed to enter/exit P.S and will trigger an + * event to the host to notify for the need to enter/exit P.S + * due to BT change state + * + */ + u8 auto_ps_mode; + + /* + * This parameter defines the compensation percentage of num of probe + * requests in case scan is initiated during BT voice/BT ACL + * guaranteed link. + * + * Unit: Percent + * Range: 0-255 (0 - No compensation) + */ + u8 probe_req_compensation; + + /* + * This parameter defines the compensation percentage of scan window + * size in case scan is initiated during BT voice/BT ACL Guaranteed + * link. + * + * Unit: Percent + * Range: 0-255 (0 - No compensation) + */ + u8 scan_window_compensation; + + /* + * Defines the antenna configuration. + * + * Range: 0 - Single Antenna; 1 - Dual Antenna + */ + u8 antenna_config; + + /* + * The percent out of the Max consecutive beacon miss roaming trigger + * which is the threshold for raising the priority of beacon + * reception. + * + * Range: 1-100 + * N = MaxConsecutiveBeaconMiss + * P = coexMaxConsecutiveBeaconMissPrecent + * Threshold = MIN( N-1, round(N * P / 100)) + */ + u8 beacon_miss_threshold; + + /* + * The RX rate threshold below which rate adaptation is assumed to be + * occurring at the AP which will raise priority for ACTIVE_RX and RX + * SP. + * + * Range: HW_BIT_RATE_* + */ + u32 rate_adaptation_threshold; + + /* + * The SNR above which the RX rate threshold indicating AP rate + * adaptation is valid + * + * Range: -128 - 127 + */ + s8 rate_adaptation_snr; +}; + +struct conf_drv_settings { + struct conf_sg_settings sg; +}; + +#endif diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 821a7752adfe..69bc929e1859 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -46,6 +46,39 @@ #include "wl1271_cmd.h" #include "wl1271_boot.h" +static void wl1271_conf_init(struct wl1271 *wl) +{ + struct conf_drv_settings conf = { + .sg = { + .per_threshold = 7500, + .max_scan_compensation_time = 120000, + .nfs_sample_interval = 400, + .load_ratio = 50, + .auto_ps_mode = 0, + .probe_req_compensation = 170, + .scan_window_compensation = 50, + .antenna_config = 0, + .beacon_miss_threshold = 60, + .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS, + .rate_adaptation_snr = 0 + } + }; + + /* + * This function applies the default configuration to the driver. This + * function is invoked upon driver load (spi probe.) + * + * The configuration is stored in a run-time structure in order to + * facilitate for run-time adjustment of any of the parameters. Making + * changes to the configuration structure will apply the new values on + * the next interface up (wl1271_op_start.) + */ + + /* apply driver default configuration */ + memcpy(&wl->conf, &conf, sizeof(conf)); +} + + static int wl1271_plt_init(struct wl1271 *wl) { int ret; @@ -1180,44 +1213,44 @@ out: /* can't be const, mac80211 writes to this */ static struct ieee80211_rate wl1271_rates[] = { { .bitrate = 10, - .hw_value = 0x1, - .hw_value_short = 0x1, }, + .hw_value = CONF_HW_BIT_RATE_1MBPS, + .hw_value_short = CONF_HW_BIT_RATE_1MBPS, }, { .bitrate = 20, - .hw_value = 0x2, - .hw_value_short = 0x2, + .hw_value = CONF_HW_BIT_RATE_2MBPS, + .hw_value_short = CONF_HW_BIT_RATE_2MBPS, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, { .bitrate = 55, - .hw_value = 0x4, - .hw_value_short = 0x4, + .hw_value = CONF_HW_BIT_RATE_5_5MBPS, + .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, { .bitrate = 110, - .hw_value = 0x20, - .hw_value_short = 0x20, + .hw_value = CONF_HW_BIT_RATE_11MBPS, + .hw_value_short = CONF_HW_BIT_RATE_11MBPS, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, { .bitrate = 60, - .hw_value = 0x8, - .hw_value_short = 0x8, }, + .hw_value = CONF_HW_BIT_RATE_6MBPS, + .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, { .bitrate = 90, - .hw_value = 0x10, - .hw_value_short = 0x10, }, + .hw_value = CONF_HW_BIT_RATE_9MBPS, + .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, { .bitrate = 120, - .hw_value = 0x40, - .hw_value_short = 0x40, }, + .hw_value = CONF_HW_BIT_RATE_12MBPS, + .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, { .bitrate = 180, - .hw_value = 0x80, - .hw_value_short = 0x80, }, + .hw_value = CONF_HW_BIT_RATE_18MBPS, + .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, { .bitrate = 240, - .hw_value = 0x200, - .hw_value_short = 0x200, }, + .hw_value = CONF_HW_BIT_RATE_24MBPS, + .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, { .bitrate = 360, - .hw_value = 0x400, - .hw_value_short = 0x400, }, + .hw_value = CONF_HW_BIT_RATE_36MBPS, + .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, { .bitrate = 480, - .hw_value = 0x800, - .hw_value_short = 0x800, }, + .hw_value = CONF_HW_BIT_RATE_48MBPS, + .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, { .bitrate = 540, - .hw_value = 0x1000, - .hw_value_short = 0x1000, }, + .hw_value = CONF_HW_BIT_RATE_54MBPS, + .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, }; /* can't be const, mac80211 writes to this */ @@ -1433,6 +1466,9 @@ static int __devinit wl1271_probe(struct spi_device *spi) } dev_set_drvdata(&wl1271_device.dev, wl); + /* Apply default driver configuration. */ + wl1271_conf_init(wl); + ret = wl1271_init_ieee80211(wl); if (ret) goto out_platform; diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h index 6af87b5573ba..1f237389d1c7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_reg.h +++ b/drivers/net/wireless/wl12xx/wl1271_reg.h @@ -613,50 +613,6 @@ enum { MAX_RADIO_BANDS = 0xFF }; -enum { - NO_RATE = 0, - RATE_1MBPS = 0x0A, - RATE_2MBPS = 0x14, - RATE_5_5MBPS = 0x37, - RATE_6MBPS = 0x0B, - RATE_9MBPS = 0x0F, - RATE_11MBPS = 0x6E, - RATE_12MBPS = 0x0A, - RATE_18MBPS = 0x0E, - RATE_22MBPS = 0xDC, - RATE_24MBPS = 0x09, - RATE_36MBPS = 0x0D, - RATE_48MBPS = 0x08, - RATE_54MBPS = 0x0C -}; - -enum { - RATE_INDEX_1MBPS = 0, - RATE_INDEX_2MBPS = 1, - RATE_INDEX_5_5MBPS = 2, - RATE_INDEX_6MBPS = 3, - RATE_INDEX_9MBPS = 4, - RATE_INDEX_11MBPS = 5, - RATE_INDEX_12MBPS = 6, - RATE_INDEX_18MBPS = 7, - RATE_INDEX_22MBPS = 8, - RATE_INDEX_24MBPS = 9, - RATE_INDEX_36MBPS = 10, - RATE_INDEX_48MBPS = 11, - RATE_INDEX_54MBPS = 12, - RATE_INDEX_MAX = RATE_INDEX_54MBPS, - MAX_RATE_INDEX, - INVALID_RATE_INDEX = MAX_RATE_INDEX, - RATE_INDEX_ENUM_MAX_SIZE = 0x7FFFFFFF -}; - -enum { - RATE_MASK_1MBPS = 0x1, - RATE_MASK_2MBPS = 0x2, - RATE_MASK_5_5MBPS = 0x4, - RATE_MASK_11MBPS = 0x20, -}; - #define SHORT_PREAMBLE_BIT BIT(0) /* CCK or Barker depending on the rate */ #define OFDM_RATE_BIT BIT(6) #define PBCC_RATE_BIT BIT(7) -- cgit v1.2.3 From 8793f9bb19c00b26532e37f1f516e1d9c7bc0476 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:40 +0300 Subject: wl1271: Add config structure for RX path parameters Add a configuration structure for RX path parameters, and set default configuration values there. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.c | 20 ++++---- drivers/net/wireless/wl12xx/wl1271_acx.h | 43 +--------------- drivers/net/wireless/wl12xx/wl1271_conf.h | 85 +++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_init.c | 4 +- drivers/net/wireless/wl12xx/wl1271_main.c | 12 +++++ 5 files changed, 110 insertions(+), 54 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index d19d8605b9d2..63aa64618e1b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -198,7 +198,7 @@ int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, return 0; } -int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time) +int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl) { struct acx_rx_msdu_lifetime *acx; int ret; @@ -211,7 +211,7 @@ int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time) goto out; } - acx->lifetime = life_time; + acx->lifetime = wl->conf.rx.rx_msdu_life_time; ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, acx, sizeof(*acx)); if (ret < 0) { @@ -265,7 +265,7 @@ int wl1271_acx_pd_threshold(struct wl1271 *wl) goto out; } - /* FIXME: threshold value not set */ + pd->threshold = wl->conf.rx.packet_detection_threshold; ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); if (ret < 0) { @@ -349,8 +349,8 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl) wl1271_debug(DEBUG_ACX, "acx service period timeout"); - rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF; - rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF; + rx_timeout->ps_poll_timeout = wl->conf.rx.ps_poll_timeout; + rx_timeout->upsd_timeout = wl->conf.rx.upsd_timeout; ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, rx_timeout, sizeof(*rx_timeout)); @@ -557,7 +557,7 @@ int wl1271_acx_cca_threshold(struct wl1271 *wl) goto out; } - detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D; + detection->rx_cca_threshold = wl->conf.rx.rx_cca_threshold; detection->tx_energy_detection = 0; ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, @@ -966,10 +966,10 @@ int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) goto out; } - rx_conf->threshold = WL1271_RX_INTR_THRESHOLD_DEF; - rx_conf->timeout = WL1271_RX_INTR_TIMEOUT_DEF; - rx_conf->mblk_threshold = USHORT_MAX; /* Disabled */ - rx_conf->queue_type = RX_QUEUE_TYPE_RX_LOW_PRIORITY; + rx_conf->threshold = wl->conf.rx.irq_pkt_threshold; + rx_conf->timeout = wl->conf.rx.irq_timeout; + rx_conf->mblk_threshold = wl->conf.rx.irq_blk_threshold; + rx_conf->queue_type = wl->conf.rx.queue_type; ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, sizeof(*rx_conf)); diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 8e3b97cff794..1fbd4e5fcc44 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -314,35 +314,13 @@ struct acx_dot11_grp_addr_tbl { u8 mac_table[ADDRESS_GROUP_MAX_LEN]; } __attribute__ ((packed)); -#define RX_TIMEOUT_PS_POLL_MIN 0 -#define RX_TIMEOUT_PS_POLL_MAX (200000) -#define RX_TIMEOUT_PS_POLL_DEF (15) -#define RX_TIMEOUT_UPSD_MIN 0 -#define RX_TIMEOUT_UPSD_MAX (200000) -#define RX_TIMEOUT_UPSD_DEF (15) - struct acx_rx_timeout { struct acx_header header; - /* - * The longest time the STA will wait to receive - * traffic from the AP after a PS-poll has been - * transmitted. - */ u16 ps_poll_timeout; - - /* - * The longest time the STA will wait to receive - * traffic from the AP after a frame has been sent - * from an UPSD enabled queue. - */ u16 upsd_timeout; } __attribute__ ((packed)); -#define RTS_THRESHOLD_MIN 0 -#define RTS_THRESHOLD_MAX 4096 -#define RTS_THRESHOLD_DEF 2347 - struct acx_rts_threshold { struct acx_header header; @@ -510,9 +488,6 @@ struct acx_bt_wlan_coex_param { u8 padding[3]; } __attribute__ ((packed)); -#define CCA_THRSH_ENABLE_ENERGY_D 0x140A -#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF - struct acx_energy_detection { struct acx_header header; @@ -1017,22 +992,6 @@ struct wl1271_acx_mem_map { void *tx_ctrl; } __attribute__ ((packed)); -enum wl1271_acx_rx_queue_type { - RX_QUEUE_TYPE_RX_LOW_PRIORITY, /* All except the high priority */ - RX_QUEUE_TYPE_RX_HIGH_PRIORITY, /* Management and voice packets */ - RX_QUEUE_TYPE_NUM, - RX_QUEUE_TYPE_MAX = USHORT_MAX -}; - -#define WL1271_RX_INTR_THRESHOLD_DEF 0 /* no pacing, send interrupt on - * every event */ -#define WL1271_RX_INTR_THRESHOLD_MIN 0 -#define WL1271_RX_INTR_THRESHOLD_MAX 15 - -#define WL1271_RX_INTR_TIMEOUT_DEF 5 -#define WL1271_RX_INTR_TIMEOUT_MIN 1 -#define WL1271_RX_INTR_TIMEOUT_MAX 100 - struct wl1271_acx_rx_config_opt { struct acx_header header; @@ -1122,7 +1081,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power); int wl1271_acx_feature_cfg(struct wl1271 *wl); int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, size_t len); -int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl, u32 life_time); +int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl); int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter); int wl1271_acx_pd_threshold(struct wl1271 *wl); int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 1d6a44bec1cb..8bf8bff54b59 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -171,8 +171,93 @@ struct conf_sg_settings { s8 rate_adaptation_snr; }; +enum conf_rx_queue_type { + CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */ + CONF_RX_QUEUE_TYPE_HIGH_PRIORITY, /* Management and voice packets */ +}; + +struct conf_rx_settings { + /* + * The maximum amount of time, in TU, before the + * firmware discards the MSDU. + * + * Range: 0 - 0xFFFFFFFF + */ + u32 rx_msdu_life_time; + + /* + * Packet detection threshold in the PHY. + * + * FIXME: details unknown. + */ + u32 packet_detection_threshold; + + /* + * The longest time the STA will wait to receive traffic from the AP + * after a PS-poll has been transmitted. + * + * Range: 0 - 200000 + */ + u16 ps_poll_timeout; + /* + * The longest time the STA will wait to receive traffic from the AP + * after a frame has been sent from an UPSD enabled queue. + * + * Range: 0 - 200000 + */ + u16 upsd_timeout; + + /* + * The number of octets in an MPDU, below which an RTS/CTS + * handshake is not performed. + * + * Range: 0 - 4096 + */ + u16 rts_threshold; + + /* + * The RX Clear Channel Assessment threshold in the PHY + * (the energy threshold). + * + * Range: ENABLE_ENERGY_D == 0x140A + * DISABLE_ENERGY_D == 0xFFEF + */ + u16 rx_cca_threshold; + + /* + * Occupied Rx mem-blocks number which requires interrupting the host + * (0 = no buffering, 0xffff = disabled). + * + * Range: u16 + */ + u16 irq_blk_threshold; + + /* + * Rx packets number which requires interrupting the host + * (0 = no buffering). + * + * Range: u16 + */ + u16 irq_pkt_threshold; + + /* + * Max time in msec the FW may delay RX-Complete interrupt. + * + * Range: 1 - 100 + */ + u16 irq_timeout; + + /* + * The RX queue type. + * + * Range: RX_QUEUE_TYPE_RX_LOW_PRIORITY, RX_QUEUE_TYPE_RX_HIGH_PRIORITY, + */ + u8 queue_type; +}; + struct conf_drv_settings { struct conf_sg_settings sg; + struct conf_rx_settings rx; }; #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 9abe062f1876..57382631c1ad 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -94,7 +94,7 @@ static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) { int ret; - ret = wl1271_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF); + ret = wl1271_acx_rx_msdu_life_time(wl); if (ret < 0) return ret; @@ -125,7 +125,7 @@ static int wl1271_init_phy_config(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_rts_threshold(wl, RTS_THRESHOLD_DEF); + ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 69bc929e1859..d04706de7f49 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -61,6 +61,18 @@ static void wl1271_conf_init(struct wl1271 *wl) .beacon_miss_threshold = 60, .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS, .rate_adaptation_snr = 0 + }, + .rx = { + .rx_msdu_life_time = 512000, + .packet_detection_threshold = 0, + .ps_poll_timeout = 15, + .upsd_timeout = 15, + .rts_threshold = 2347, + .rx_cca_threshold = 0xFFEF, + .irq_blk_threshold = 0, + .irq_pkt_threshold = USHORT_MAX, + .irq_timeout = 5, + .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, } }; -- cgit v1.2.3 From 45b531a86f93c82d8e390e19a6258111b3627bb0 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:41 +0300 Subject: wl1271: Add config structure for TX path parameters Add a configuration structure for TX path parameters, and set defalt configuration values there. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 2 +- drivers/net/wireless/wl12xx/wl1271_acx.c | 54 ++++----- drivers/net/wireless/wl12xx/wl1271_acx.h | 37 +----- drivers/net/wireless/wl12xx/wl1271_cmd.c | 6 +- drivers/net/wireless/wl12xx/wl1271_conf.h | 187 ++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_init.c | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 103 ++++++++++++++++ 7 files changed, 321 insertions(+), 70 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 64a327009f2e..985e8964c2f7 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -107,7 +107,7 @@ enum { CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) -#define WL1271_DEFAULT_BASIC_RATE_SET (ACX_RATE_MASK_ALL) +#define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL) #define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin" diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 63aa64618e1b..038203bcf447 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -558,7 +558,7 @@ int wl1271_acx_cca_threshold(struct wl1271 *wl) } detection->rx_cca_threshold = wl->conf.rx.rx_cca_threshold; - detection->tx_energy_detection = 0; + detection->tx_energy_detection = wl->conf.tx.tx_energy_detection; ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, detection, sizeof(*detection)); @@ -729,6 +729,7 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) { struct acx_rate_policy *acx; + struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf; int ret = 0; wl1271_debug(DEBUG_ACX, "acx rate policies"); @@ -743,9 +744,9 @@ int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) /* configure one default (one-size-fits-all) rate class */ acx->rate_class_cnt = 1; acx->rate_class[0].enabled_rates = enabled_rates; - acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; - acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; - acx->rate_class[0].aflags = 0; + acx->rate_class[0].short_retry_limit = c->short_retry_limit; + acx->rate_class[0].long_retry_limit = c->long_retry_limit; + acx->rate_class[0].aflags = c->aflags; ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); if (ret < 0) { @@ -772,22 +773,14 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl) goto out; } - /* - * FIXME: Configure each AC with appropriate values (most suitable - * values will probably be different for each AC. - */ - for (i = 0; i < WL1271_ACX_AC_COUNT; i++) { - acx->ac = i; - - /* - * FIXME: The following default values originate from - * the TI reference driver. What do they mean? - */ - acx->cw_min = 15; - acx->cw_max = 63; - acx->aifsn = 3; + for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { + struct conf_tx_ac_category *c = &(wl->conf.tx.ac_conf[i]); + acx->ac = c->ac; + acx->cw_min = c->cw_min; + acx->cw_max = c->cw_max; + acx->aifsn = c->aifsn; acx->reserved = 0; - acx->tx_op_limit = 0; + acx->tx_op_limit = c->tx_op_limit; ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); if (ret < 0) { @@ -816,12 +809,15 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl) goto out; } - /* FIXME: configure each TID with a different AC reference */ - for (i = 0; i < WL1271_ACX_TID_COUNT; i++) { - acx->queue_id = i; - acx->tsid = WL1271_ACX_AC_BE; - acx->ps_scheme = WL1271_ACX_PS_SCHEME_LEGACY; - acx->ack_policy = WL1271_ACX_ACK_POLICY_LEGACY; + for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { + struct conf_tx_tid *c = &(wl->conf.tx.tid_conf[i]); + acx->queue_id = c->queue_id; + acx->channel_type = c->channel_type; + acx->tsid = c->tsid; + acx->ps_scheme = c->ps_scheme; + acx->ack_policy = c->ack_policy; + acx->apsd_conf[0] = c->apsd_conf[0]; + acx->apsd_conf[1] = c->apsd_conf[1]; ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); if (ret < 0) { @@ -849,7 +845,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl) goto out; } - acx->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; + acx->frag_threshold = wl->conf.tx.frag_threshold; ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("Setting of frag threshold failed: %d", ret); @@ -875,8 +871,8 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl) goto out; } - acx->tx_compl_timeout = WL1271_ACX_TX_COMPL_TIMEOUT; - acx->tx_compl_threshold = WL1271_ACX_TX_COMPL_THRESHOLD; + acx->tx_compl_timeout = wl->conf.tx.tx_compl_timeout; + acx->tx_compl_threshold = wl->conf.tx.tx_compl_threshold; ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("Setting of tx options failed: %d", ret); @@ -929,7 +925,7 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl) return ret; wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map), - GFP_KERNEL); + GFP_KERNEL); if (!wl->target_mem_map) { wl1271_error("couldn't allocate target memory map"); return -ENOMEM; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 1fbd4e5fcc44..63cddceb39a4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -850,11 +850,6 @@ struct acx_statistics { struct acx_rxpipe_statistics rxpipe; } __attribute__ ((packed)); -#define ACX_MAX_RATE_CLASSES 8 -#define ACX_RATE_MASK_UNSPECIFIED 0 -#define ACX_RATE_MASK_ALL 0x1eff -#define ACX_RATE_RETRY_LIMIT 10 - struct acx_rate_class { u32 enabled_rates; u8 short_retry_limit; @@ -867,11 +862,9 @@ struct acx_rate_policy { struct acx_header header; u32 rate_class_cnt; - struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES]; + struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES]; } __attribute__ ((packed)); -#define WL1271_ACX_AC_COUNT 4 - struct acx_ac_cfg { struct acx_header header; u8 ac; @@ -882,31 +875,6 @@ struct acx_ac_cfg { u16 tx_op_limit; } __attribute__ ((packed)); -enum wl1271_acx_ac { - WL1271_ACX_AC_BE = 0, - WL1271_ACX_AC_BK = 1, - WL1271_ACX_AC_VI = 2, - WL1271_ACX_AC_VO = 3, - WL1271_ACX_AC_CTS2SELF = 4, - WL1271_ACX_AC_ANY_TID = 0x1F, - WL1271_ACX_AC_INVALID = 0xFF, -}; - -enum wl1271_acx_ps_scheme { - WL1271_ACX_PS_SCHEME_LEGACY = 0, - WL1271_ACX_PS_SCHEME_UPSD_TRIGGER = 1, - WL1271_ACX_PS_SCHEME_LEGACY_PSPOLL = 2, - WL1271_ACX_PS_SCHEME_SAPSD = 3, -}; - -enum wl1271_acx_ack_policy { - WL1271_ACX_ACK_POLICY_LEGACY = 0, - WL1271_ACX_ACK_POLICY_NO_ACK = 1, - WL1271_ACX_ACK_POLICY_BLOCK = 2, -}; - -#define WL1271_ACX_TID_COUNT 7 - struct acx_tid_config { struct acx_header header; u8 queue_id; @@ -924,9 +892,6 @@ struct acx_frag_threshold { u8 padding[2]; } __attribute__ ((packed)); -#define WL1271_ACX_TX_COMPL_TIMEOUT 5 -#define WL1271_ACX_TX_COMPL_THRESHOLD 5 - struct acx_tx_config_options { struct acx_header header; u16 tx_compl_timeout; /* msec */ diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index c7a8a64d18dd..f05bd7797fb7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -626,9 +626,9 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, cmd->len = cpu_to_le16(buf_len); cmd->template_type = template_id; - cmd->enabled_rates = ACX_RATE_MASK_UNSPECIFIED; - cmd->short_retry_limit = ACX_RATE_RETRY_LIMIT; - cmd->long_retry_limit = ACX_RATE_RETRY_LIMIT; + cmd->enabled_rates = wl->conf.tx.rc_conf.enabled_rates; + cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; + cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; if (buf) memcpy(cmd->template_data, buf, buf_len); diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 8bf8bff54b59..3c5ce3100e6e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -255,9 +255,196 @@ struct conf_rx_settings { u8 queue_type; }; +#define CONF_TX_MAX_RATE_CLASSES 8 + +#define CONF_TX_RATE_MASK_UNSPECIFIED 0 +#define CONF_TX_RATE_MASK_ALL 0x1eff +#define CONF_TX_RATE_RETRY_LIMIT 10 + +struct conf_tx_rate_class { + + /* + * The rates enabled for this rate class. + * + * Range: CONF_HW_BIT_RATE_* bit mask + */ + u32 enabled_rates; + + /* + * The dot11 short retry limit used for TX retries. + * + * Range: u8 + */ + u8 short_retry_limit; + + /* + * The dot11 long retry limit used for TX retries. + * + * Range: u8 + */ + u8 long_retry_limit; + + /* + * Flags controlling the attributes of TX transmission. + * + * Range: bit 0: Truncate - when set, FW attempts to send a frame stop + * when the total valid per-rate attempts have + * been exhausted; otherwise transmissions + * will continue at the lowest available rate + * until the appropriate one of the + * short_retry_limit, long_retry_limit, + * dot11_max_transmit_msdu_life_time, or + * max_tx_life_time, is exhausted. + * 1: Preamble Override - indicates if the preamble type + * should be used in TX. + * 2: Preamble Type - the type of the preamble to be used by + * the policy (0 - long preamble, 1 - short preamble. + */ + u8 aflags; +}; + +#define CONF_TX_MAX_AC_COUNT 4 + +/* Slot number setting to start transmission at PIFS interval */ +#define CONF_TX_AIFS_PIFS 1 +/* Slot number setting to start transmission at DIFS interval normal + * DCF access */ +#define CONF_TX_AIFS_DIFS 2 + + +enum conf_tx_ac { + CONF_TX_AC_BE = 0, /* best effort / legacy */ + CONF_TX_AC_BK = 1, /* background */ + CONF_TX_AC_VI = 2, /* video */ + CONF_TX_AC_VO = 3, /* voice */ + CONF_TX_AC_CTS2SELF = 4, /* fictious AC, follows AC_VO */ + CONF_TX_AC_ANY_TID = 0x1f +}; + +struct conf_tx_ac_category { + /* + * The AC class identifier. + * + * Range: enum conf_tx_ac + */ + u8 ac; + + /* + * The contention window minimum size (in slots) for the access + * class. + * + * Range: u8 + */ + u8 cw_min; + + /* + * The contention window maximum size (in slots) for the access + * class. + * + * Range: u8 + */ + u16 cw_max; + + /* + * The AIF value (in slots) for the access class. + * + * Range: u8 + */ + u8 aifsn; + + /* + * The TX Op Limit (in microseconds) for the access class. + * + * Range: u16 + */ + u16 tx_op_limit; +}; + +#define CONF_TX_MAX_TID_COUNT 7 + +enum { + CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ + CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/ + CONF_CHANNEL_TYPE_HCCA = 2, /* HCCA*/ +}; + +enum { + CONF_PS_SCHEME_LEGACY = 0, + CONF_PS_SCHEME_UPSD_TRIGGER = 1, + CONF_PS_SCHEME_LEGACY_PSPOLL = 2, + CONF_PS_SCHEME_SAPSD = 3, +}; + +enum { + CONF_ACK_POLICY_LEGACY = 0, + CONF_ACK_POLICY_NO_ACK = 1, + CONF_ACK_POLICY_BLOCK = 2, +}; + + +struct conf_tx_tid { + u8 queue_id; + u8 channel_type; + u8 tsid; + u8 ps_scheme; + u8 ack_policy; + u32 apsd_conf[2]; +}; + +struct conf_tx_settings { + /* + * The TX ED value for TELEC Enable/Disable. + * + * Range: 0, 1 + */ + u8 tx_energy_detection; + + /* + * Configuration for rate classes for TX (currently only one + * rate class supported.) + */ + struct conf_tx_rate_class rc_conf; + + /* + * Configuration for access categories for TX rate control. + */ + u8 ac_conf_count; + struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT]; + + /* + * Configuration for TID parameters. + */ + u8 tid_conf_count; + struct conf_tx_tid tid_conf[CONF_TX_MAX_TID_COUNT]; + + /* + * The TX fragmentation threshold. + * + * Range: u16 + */ + u16 frag_threshold; + + /* + * Max time in msec the FW may delay frame TX-Complete interrupt. + * + * Range: u16 + */ + u16 tx_compl_timeout; + + /* + * Completed TX packet count which requires to issue the TX-Complete + * interrupt. + * + * Range: u16 + */ + u16 tx_compl_threshold; + +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; + struct conf_tx_settings tx; }; #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 57382631c1ad..a3fc4c97c518 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -382,7 +382,7 @@ int wl1271_hw_init(struct wl1271 *wl) goto out_free_memmap; /* Configure TX rate classes */ - ret = wl1271_acx_rate_policies(wl, ACX_RATE_MASK_ALL); + ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_ALL); if (ret < 0) goto out_free_memmap; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d04706de7f49..35d0b7efb680 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -73,6 +73,109 @@ static void wl1271_conf_init(struct wl1271 *wl) .irq_pkt_threshold = USHORT_MAX, .irq_timeout = 5, .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, + }, + .tx = { + .tx_energy_detection = 0, + .rc_conf = { + .enabled_rates = + CONF_TX_RATE_MASK_UNSPECIFIED, + .short_retry_limit = 10, + .long_retry_limit = 10, + .aflags = 0 + }, + .ac_conf_count = 4, + .ac_conf = { + [0] = { + .ac = CONF_TX_AC_BE, + .cw_min = 15, + .cw_max = 63, + .aifsn = 3, + .tx_op_limit = 0, + }, + [1] = { + .ac = CONF_TX_AC_BK, + .cw_min = 15, + .cw_max = 63, + .aifsn = 7, + .tx_op_limit = 0, + }, + [2] = { + .ac = CONF_TX_AC_VI, + .cw_min = 15, + .cw_max = 63, + .aifsn = CONF_TX_AIFS_PIFS, + .tx_op_limit = 3008, + }, + [3] = { + .ac = CONF_TX_AC_VO, + .cw_min = 15, + .cw_max = 63, + .aifsn = CONF_TX_AIFS_PIFS, + .tx_op_limit = 1504, + }, + }, + .tid_conf_count = 7, + .tid_conf = { + [0] = { + .queue_id = 0, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [1] = { + .queue_id = 1, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [2] = { + .queue_id = 2, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [3] = { + .queue_id = 3, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [4] = { + .queue_id = 4, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [5] = { + .queue_id = 5, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [6] = { + .queue_id = 6, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + } + }, + .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, + .tx_compl_timeout = 5, + .tx_compl_threshold = 5 } }; -- cgit v1.2.3 From 51f2be24328957f9e2acf116b1b1d2dfd10bf41f Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:42 +0300 Subject: wl1271: Add config structure for connection management parameters Add a configuration structure for connection management parameters, and set default configuration values there. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 1 - drivers/net/wireless/wl12xx/wl1271_acx.c | 63 ++++++-- drivers/net/wireless/wl12xx/wl1271_acx.h | 24 +-- drivers/net/wireless/wl12xx/wl1271_cmd.c | 3 +- drivers/net/wireless/wl12xx/wl1271_conf.h | 251 ++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_main.c | 50 +++++- 6 files changed, 348 insertions(+), 44 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 985e8964c2f7..648223f67b54 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -323,7 +323,6 @@ struct wl1271 { u8 bss_type; u8 ssid[IW_ESSID_MAX_SIZE + 1]; u8 ssid_len; - u8 listen_int; int channel; struct wl1271_acx_mem_map *target_mem_map; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 038203bcf447..d0036860ab60 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -34,8 +34,7 @@ #include "wl1271_spi.h" #include "wl1271_ps.h" -int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event, - u8 listen_interval) +int wl1271_acx_wake_up_conditions(struct wl1271 *wl) { struct acx_wake_up_condition *wake_up; int ret; @@ -48,8 +47,8 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event, goto out; } - wake_up->wake_up_event = wake_up_event; - wake_up->listen_interval = listen_interval; + wake_up->wake_up_event = wl->conf.conn.wake_up_event; + wake_up->listen_interval = wl->conf.conn.listen_interval; ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS, wake_up, sizeof(*wake_up)); @@ -393,11 +392,15 @@ out: int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) { - struct acx_beacon_filter_option *beacon_filter; - int ret; + struct acx_beacon_filter_option *beacon_filter = NULL; + int ret = 0; wl1271_debug(DEBUG_ACX, "acx beacon filter opt"); + if (enable_filter && + wl->conf.conn.bcn_filt_mode == CONF_BCN_FILT_MODE_DISABLED) + goto out; + beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL); if (!beacon_filter) { ret = -ENOMEM; @@ -405,6 +408,11 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) } beacon_filter->enable = enable_filter; + + /* + * When set to zero, and the filter is enabled, beacons + * without the unicast TIM bit set are dropped. + */ beacon_filter->max_num_beacons = 0; ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_OPT, @@ -422,8 +430,9 @@ out: int wl1271_acx_beacon_filter_table(struct wl1271 *wl) { struct acx_beacon_filter_ie_table *ie_table; - int idx = 0; + int i, idx = 0; int ret; + bool vendor_spec = false; wl1271_debug(DEBUG_ACX, "acx beacon filter table"); @@ -434,9 +443,31 @@ int wl1271_acx_beacon_filter_table(struct wl1271 *wl) } /* configure default beacon pass-through rules */ - ie_table->num_ie = 1; - ie_table->table[idx++] = BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN; - ie_table->table[idx++] = BEACON_RULE_PASS_ON_APPEARANCE; + ie_table->num_ie = 0; + for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { + struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); + ie_table->table[idx++] = r->ie; + ie_table->table[idx++] = r->rule; + + if (r->ie == WLAN_EID_VENDOR_SPECIFIC) { + /* only one vendor specific ie allowed */ + if (vendor_spec) + continue; + + /* for vendor specific rules configure the + additional fields */ + memcpy(&(ie_table->table[idx]), r->oui, + CONF_BCN_IE_OUI_LEN); + idx += CONF_BCN_IE_OUI_LEN; + ie_table->table[idx++] = r->type; + memcpy(&(ie_table->table[idx]), r->version, + CONF_BCN_IE_VER_LEN); + idx += CONF_BCN_IE_VER_LEN; + vendor_spec = true; + } + + ie_table->num_ie++; + } ret = wl1271_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, ie_table, sizeof(*ie_table)); @@ -463,8 +494,8 @@ int wl1271_acx_conn_monit_params(struct wl1271 *wl) goto out; } - acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD; - acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT; + acx->synch_fail_thold = wl->conf.conn.synch_fail_thold; + acx->bss_lose_timeout = wl->conf.conn.bss_lose_timeout; ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, acx, sizeof(*acx)); @@ -585,10 +616,10 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) goto out; } - bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE; - bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE; - bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE; - bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF; + bb->beacon_rx_timeout = wl->conf.conn.beacon_rx_timeout; + bb->broadcast_timeout = wl->conf.conn.broadcast_timeout; + bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; + bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold; ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb)); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 63cddceb39a4..73ef2bdf3b74 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -377,11 +377,6 @@ struct acx_beacon_filter_option { (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) -#define BEACON_RULE_PASS_ON_CHANGE BIT(0) -#define BEACON_RULE_PASS_ON_APPEARANCE BIT(1) - -#define BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN (37) - struct acx_beacon_filter_ie_table { struct acx_header header; @@ -390,9 +385,6 @@ struct acx_beacon_filter_ie_table { u8 pad[3]; } __attribute__ ((packed)); -#define SYNCH_FAIL_DEFAULT_THRESHOLD 5 /* number of beacons */ -#define NO_BEACON_DEFAULT_TIMEOUT (100) /* TU */ - struct acx_conn_monit_params { struct acx_header header; @@ -497,11 +489,6 @@ struct acx_energy_detection { u8 pad; } __attribute__ ((packed)); -#define BCN_RX_TIMEOUT_DEF_VALUE 10000 -#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000 -#define RX_BROADCAST_IN_PS_DEF_VALUE 1 -#define CONSECUTIVE_PS_POLL_FAILURE_DEF 4 - struct acx_beacon_broadcast { struct acx_header header; @@ -575,14 +562,6 @@ struct acx_current_tx_power { u8 padding[3]; } __attribute__ ((packed)); -enum acx_wake_up_event { - WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/ - WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/ - WAKE_UP_EVENT_N_DTIM_BITMAP = 0x04, /* Wake on every Nth DTIM */ - WAKE_UP_EVENT_N_BEACONS_BITMAP = 0x08, /* Wake on every Nth Beacon */ - WAKE_UP_EVENT_BITS_MASK = 0x0F -}; - struct acx_wake_up_condition { struct acx_header header; @@ -1038,8 +1017,7 @@ enum { }; -int wl1271_acx_wake_up_conditions(struct wl1271 *wl, u8 wake_up_event, - u8 listen_interval); +int wl1271_acx_wake_up_conditions(struct wl1271 *wl); int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth); int wl1271_acx_fw_version(struct wl1271 *wl, char *buf, size_t len); int wl1271_acx_tx_power(struct wl1271 *wl, int power); diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index f05bd7797fb7..f38e3e0e2d66 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -436,8 +436,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) int ret = 0; /* FIXME: this should be in ps.c */ - ret = wl1271_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, - wl->listen_int); + ret = wl1271_acx_wake_up_conditions(wl); if (ret < 0) { wl1271_error("couldn't set wake up conditions"); goto out; diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 3c5ce3100e6e..f08e509bd69f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -441,10 +441,261 @@ struct conf_tx_settings { }; +enum { + CONF_WAKE_UP_EVENT_BEACON = 0x01, /* Wake on every Beacon*/ + CONF_WAKE_UP_EVENT_DTIM = 0x02, /* Wake on every DTIM*/ + CONF_WAKE_UP_EVENT_N_DTIM = 0x04, /* Wake every Nth DTIM */ + CONF_WAKE_UP_EVENT_N_BEACONS = 0x08, /* Wake every Nth beacon */ + CONF_WAKE_UP_EVENT_BITS_MASK = 0x0F +}; + +#define CONF_MAX_BCN_FILT_IE_COUNT 32 + +#define CONF_BCN_RULE_PASS_ON_CHANGE BIT(0) +#define CONF_BCN_RULE_PASS_ON_APPEARANCE BIT(1) + +#define CONF_BCN_IE_OUI_LEN 3 +#define CONF_BCN_IE_VER_LEN 2 + +struct conf_bcn_filt_rule { + /* + * IE number to which to associate a rule. + * + * Range: u8 + */ + u8 ie; + + /* + * Rule to associate with the specific ie. + * + * Range: CONF_BCN_RULE_PASS_ON_* + */ + u8 rule; + + /* + * OUI for the vendor specifie IE (221) + */ + u8 oui[CONF_BCN_IE_OUI_LEN]; + + /* + * Type for the vendor specifie IE (221) + */ + u8 type; + + /* + * Version for the vendor specifie IE (221) + */ + u8 version[CONF_BCN_IE_VER_LEN]; +}; + +#define CONF_MAX_RSSI_SNR_TRIGGERS 8 + +enum { + CONF_TRIG_METRIC_RSSI_BEACON = 0, + CONF_TRIG_METRIC_RSSI_DATA, + CONF_TRIG_METRIC_SNR_BEACON, + CONF_TRIG_METRIC_SNR_DATA +}; + +enum { + CONF_TRIG_EVENT_TYPE_LEVEL = 0, + CONF_TRIG_EVENT_TYPE_EDGE +}; + +enum { + CONF_TRIG_EVENT_DIR_LOW = 0, + CONF_TRIG_EVENT_DIR_HIGH, + CONF_TRIG_EVENT_DIR_BIDIR +}; + + +struct conf_sig_trigger { + /* + * The RSSI / SNR threshold value. + * + * FIXME: what is the range? + */ + s16 threshold; + + /* + * Minimum delay between two trigger events for this trigger in ms. + * + * Range: 0 - 60000 + */ + u16 pacing; + + /* + * The measurement data source for this trigger. + * + * Range: CONF_TRIG_METRIC_* + */ + u8 metric; + + /* + * The trigger type of this trigger. + * + * Range: CONF_TRIG_EVENT_TYPE_* + */ + u8 type; + + /* + * The direction of the trigger. + * + * Range: CONF_TRIG_EVENT_DIR_* + */ + u8 direction; + + /* + * Hysteresis range of the trigger around the threshold (in dB) + * + * Range: u8 + */ + u8 hysteresis; + + /* + * Index of the trigger rule. + * + * Range: 0 - CONF_MAX_RSSI_SNR_TRIGGERS-1 + */ + u8 index; + + /* + * Enable / disable this rule (to use for clearing rules.) + * + * Range: 1 - Enabled, 2 - Not enabled + */ + u8 enable; +}; + +struct conf_sig_weights { + + /* + * RSSI from beacons average weight. + * + * Range: u8 + */ + u8 rssi_bcn_avg_weight; + + /* + * RSSI from data average weight. + * + * Range: u8 + */ + u8 rssi_pkt_avg_weight; + + /* + * SNR from beacons average weight. + * + * Range: u8 + */ + u8 snr_bcn_avg_weight; + + /* + * SNR from data average weight. + * + * Range: u8 + */ + u8 snr_pkt_avg_weight; +}; + +enum conf_bcn_filt_mode { + CONF_BCN_FILT_MODE_DISABLED = 0, + CONF_BCN_FILT_MODE_ENABLED = 1 +}; + +struct conf_conn_settings { + /* + * Firmware wakeup conditions configuration. The host may set only + * one bit. + * + * Range: CONF_WAKE_UP_EVENT_* + */ + u8 wake_up_event; + + /* + * Listen interval for beacons or Dtims. + * + * Range: 0 for beacon and Dtim wakeup + * 1-10 for x Dtims + * 1-255 for x beacons + */ + u8 listen_interval; + + /* + * Enable or disable the beacon filtering. + * + * Range: CONF_BCN_FILT_MODE_* + */ + enum conf_bcn_filt_mode bcn_filt_mode; + + /* + * Configure Beacon filter pass-thru rules. + */ + u8 bcn_filt_ie_count; + struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT]; + + /* + * The number of consequtive beacons to lose, before the firmware + * becomes out of synch. + * + * Range: u32 + */ + u32 synch_fail_thold; + + /* + * After out-of-synch, the number of TU's to wait without a further + * received beacon (or probe response) before issuing the BSS_EVENT_LOSE + * event. + * + * Range: u32 + */ + u32 bss_lose_timeout; + + /* + * Beacon receive timeout. + * + * Range: u32 + */ + u32 beacon_rx_timeout; + + /* + * Broadcast receive timeout. + * + * Range: u32 + */ + u32 broadcast_timeout; + + /* + * Enable/disable reception of broadcast packets in power save mode + * + * Range: 1 - enable, 0 - disable + */ + u8 rx_broadcast_in_ps; + + /* + * Consequtive PS Poll failures before sending event to driver + * + * Range: u8 + */ + u8 ps_poll_threshold; + + /* + * Configuration of signal (rssi/snr) triggers. + */ + u8 sig_trigger_count; + struct conf_sig_trigger sig_trigger[CONF_MAX_RSSI_SNR_TRIGGERS]; + + /* + * Configuration of signal average weights. + */ + struct conf_sig_weights sig_weights; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; struct conf_tx_settings tx; + struct conf_conn_settings conn; }; #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 35d0b7efb680..a559a1536534 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -176,6 +176,54 @@ static void wl1271_conf_init(struct wl1271 *wl) .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, .tx_compl_timeout = 5, .tx_compl_threshold = 5 + }, + .conn = { + .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, + .listen_interval = 0, + .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, + .bcn_filt_ie_count = 1, + .bcn_filt_ie = { + [0] = { + .ie = WLAN_EID_CHANNEL_SWITCH, + .rule = + CONF_BCN_RULE_PASS_ON_APPEARANCE, + } + }, + .synch_fail_thold = 5, + .bss_lose_timeout = 100, + .beacon_rx_timeout = 10000, + .broadcast_timeout = 20000, + .rx_broadcast_in_ps = 1, + .ps_poll_threshold = 4, + .sig_trigger_count = 2, + .sig_trigger = { + [0] = { + .threshold = -75, + .pacing = 500, + .metric = CONF_TRIG_METRIC_RSSI_BEACON, + .type = CONF_TRIG_EVENT_TYPE_EDGE, + .direction = CONF_TRIG_EVENT_DIR_LOW, + .hysteresis = 2, + .index = 0, + .enable = 1 + }, + [1] = { + .threshold = -75, + .pacing = 500, + .metric = CONF_TRIG_METRIC_RSSI_BEACON, + .type = CONF_TRIG_EVENT_TYPE_EDGE, + .direction = CONF_TRIG_EVENT_DIR_HIGH, + .hysteresis = 2, + .index = 1, + .enable = 1 + } + }, + .sig_weights = { + .rssi_bcn_avg_weight = 10, + .rssi_pkt_avg_weight = 10, + .snr_bcn_avg_weight = 10, + .snr_pkt_avg_weight = 10 + } } }; @@ -765,7 +813,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) memset(wl->bssid, 0, ETH_ALEN); memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1); wl->ssid_len = 0; - wl->listen_int = 1; wl->bss_type = MAX_BSS_TYPE; wl->band = IEEE80211_BAND_2GHZ; @@ -1504,7 +1551,6 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->channel = WL1271_DEFAULT_CHANNEL; wl->scanning = false; wl->default_key = 0; - wl->listen_int = 1; wl->rx_counter = 0; wl->rx_config = WL1271_DEFAULT_RX_CONFIG; wl->rx_filter = WL1271_DEFAULT_RX_FILTER; -- cgit v1.2.3 From 47fab7d589d46d87a5dbfd7f2ddd53deccfad504 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:43 +0300 Subject: wl1271: Add config structure for FW init parameters Add a configuration structure for RX path parameters, and set default configuration values there. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.c | 39 ++----- drivers/net/wireless/wl12xx/wl1271_conf.h | 182 ++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_init.c | 128 ++++++++++----------- drivers/net/wireless/wl12xx/wl1271_init.h | 51 ++++----- drivers/net/wireless/wl12xx/wl1271_main.c | 103 +++++++++++++++++ 5 files changed, 376 insertions(+), 127 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index d0036860ab60..880c82894f63 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -1014,7 +1014,7 @@ int wl1271_acx_smart_reflex(struct wl1271 *wl) { struct acx_smart_reflex_state *sr_state = NULL; struct acx_smart_reflex_config_params *sr_param = NULL; - int ret; + int i, ret; wl1271_debug(DEBUG_ACX, "acx smart reflex"); @@ -1024,33 +1024,14 @@ int wl1271_acx_smart_reflex(struct wl1271 *wl) goto out; } - /* set cryptic smart reflex parameters - source TI reference code */ - sr_param->error_table[0].len = 0x07; - sr_param->error_table[0].upper_limit = 0x03; - sr_param->error_table[0].values[0] = 0x18; - sr_param->error_table[0].values[1] = 0x10; - sr_param->error_table[0].values[2] = 0x05; - sr_param->error_table[0].values[3] = 0xfb; - sr_param->error_table[0].values[4] = 0xf0; - sr_param->error_table[0].values[5] = 0xe8; - - sr_param->error_table[1].len = 0x07; - sr_param->error_table[1].upper_limit = 0x03; - sr_param->error_table[1].values[0] = 0x18; - sr_param->error_table[1].values[1] = 0x10; - sr_param->error_table[1].values[2] = 0x05; - sr_param->error_table[1].values[3] = 0xf6; - sr_param->error_table[1].values[4] = 0xf0; - sr_param->error_table[1].values[5] = 0xe8; - - sr_param->error_table[2].len = 0x07; - sr_param->error_table[2].upper_limit = 0x03; - sr_param->error_table[2].values[0] = 0x18; - sr_param->error_table[2].values[1] = 0x10; - sr_param->error_table[2].values[2] = 0x05; - sr_param->error_table[2].values[3] = 0xfb; - sr_param->error_table[2].values[4] = 0xf0; - sr_param->error_table[2].values[5] = 0xe8; + for (i = 0; i < CONF_SR_ERR_TBL_COUNT; i++) { + struct conf_mart_reflex_err_table *e = + &(wl->conf.init.sr_err_tbl[i]); + + sr_param->error_table[i].len = e->len; + sr_param->error_table[i].upper_limit = e->upper_limit; + memcpy(sr_param->error_table[i].values, e->values, e->len); + } ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS, sr_param, sizeof(*sr_param)); @@ -1066,7 +1047,7 @@ int wl1271_acx_smart_reflex(struct wl1271 *wl) } /* enable smart reflex */ - sr_state->enable = 1; + sr_state->enable = wl->conf.init.sr_enable; ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE, sr_state, sizeof(*sr_state)); diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index f08e509bd69f..5333a2731254 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -691,11 +691,193 @@ struct conf_conn_settings { struct conf_sig_weights sig_weights; }; +#define CONF_SR_ERR_TBL_MAX_VALUES 14 + +struct conf_mart_reflex_err_table { + /* + * Length of the error table values table. + * + * Range: 0 - CONF_SR_ERR_TBL_MAX_VALUES + */ + u8 len; + + /* + * Smart Reflex error table upper limit. + * + * Range: s8 + */ + s8 upper_limit; + + /* + * Smart Reflex error table values. + * + * Range: s8 + */ + s8 values[CONF_SR_ERR_TBL_MAX_VALUES]; +}; + +enum { + CONF_REF_CLK_19_2_E, + CONF_REF_CLK_26_E, + CONF_REF_CLK_38_4_E, + CONF_REF_CLK_52_E +}; + +struct conf_general_parms { + /* + * RF Reference Clock type / speed + * + * Range: CONF_REF_CLK_* + */ + u8 ref_clk; + + /* + * Settling time of the reference clock after boot. + * + * Range: u8 + */ + u8 settling_time; + + /* + * Flag defining whether clock is valid on wakeup. + * + * Range: 0 - not valid on wakeup, 1 - valid on wakeup + */ + u8 clk_valid_on_wakeup; + + /* + * DC-to-DC mode. + * + * Range: Unknown + */ + u8 dc2dcmode; + + /* + * Flag defining whether used as single or dual-band. + * + * Range: Unknown + */ + u8 single_dual_band; + + /* + * TX bip fem autodetect flag. + * + * Range: Unknown + */ + u8 tx_bip_fem_autodetect; + + /* + * TX bip gem manufacturer. + * + * Range: Unknown + */ + u8 tx_bip_fem_manufacturer; + + /* + * Settings flags. + * + * Range: Unknown + */ + u8 settings; +}; + +#define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15 +#define CONF_NUMBER_OF_SUB_BANDS_5 7 +#define CONF_NUMBER_OF_RATE_GROUPS 6 +#define CONF_NUMBER_OF_CHANNELS_2_4 14 +#define CONF_NUMBER_OF_CHANNELS_5 35 + +struct conf_radio_parms { + /* + * Static radio parameters for 2.4GHz + * + * Range: unknown + */ + u8 rx_trace_loss; + u8 tx_trace_loss; + s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; + + /* + * Static radio parameters for 5GHz + * + * Range: unknown + */ + u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; + + /* + * Dynamic radio parameters for 2.4GHz + * + * Range: unknown + */ + s16 tx_ref_pd_voltage; + s8 tx_ref_power; + s8 tx_offset_db; + + s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; + + s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; + s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; + s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS]; + + u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; + u8 rx_fem_insertion_loss; + + /* + * Dynamic radio parameters for 5GHz + * + * Range: unknown + */ + s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; + + s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; + + s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; + s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; + + /* FIXME: this is inconsistent with the types for 2.4GHz */ + s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; +}; + +#define CONF_SR_ERR_TBL_COUNT 3 + +struct conf_init_settings { + /* + * Configure Smart Reflex error table values. + */ + struct conf_mart_reflex_err_table sr_err_tbl[CONF_SR_ERR_TBL_COUNT]; + + /* + * Smart Reflex enable flag. + * + * Range: 1 - Smart Reflex enabled, 0 - Smart Reflex disabled + */ + u8 sr_enable; + + /* + * Configure general parameters. + */ + struct conf_general_parms genparam; + + /* + * Configure radio parameters. + */ + struct conf_radio_parms radioparam; + +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; struct conf_tx_settings tx; struct conf_conn_settings conn; + struct conf_init_settings init; }; #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index a3fc4c97c518..5c2cf1e00ac7 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -188,6 +188,7 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl) static int wl1271_init_general_parms(struct wl1271 *wl) { struct wl1271_general_parms *gen_parms; + struct conf_general_parms *g = &wl->conf.init.genparam; int ret; gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); @@ -196,22 +197,14 @@ static int wl1271_init_general_parms(struct wl1271 *wl) gen_parms->id = TEST_CMD_INI_FILE_GENERAL_PARAM; - /* - * FIXME: The firmware crashes on boot with REF_CLK_38_4_E as clock. - * according to TI engineers, ref clk 5 is an unofficial - * 38.4 XTAL clock config, which seems to boot the device. - * Restore correct value once the real problem source is - * identified. - */ - gen_parms->ref_clk = 5; /* REF_CLK_38_4_E; */ - /* FIXME: magic numbers */ - gen_parms->settling_time = 5; - gen_parms->clk_valid_on_wakeup = 0; - gen_parms->dc2dcmode = 0; - gen_parms->single_dual_band = 0; - gen_parms->tx_bip_fem_autodetect = 0; - gen_parms->tx_bip_fem_manufacturer = 1; - gen_parms->settings = 1; + gen_parms->ref_clk = g->ref_clk; + gen_parms->settling_time = g->settling_time; + gen_parms->clk_valid_on_wakeup = g->clk_valid_on_wakeup; + gen_parms->dc2dcmode = g->dc2dcmode; + gen_parms->single_dual_band = g->single_dual_band; + gen_parms->tx_bip_fem_autodetect = g->tx_bip_fem_autodetect; + gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer; + gen_parms->settings = g->settings; ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); if (ret < 0) { @@ -225,32 +218,9 @@ static int wl1271_init_general_parms(struct wl1271 *wl) static int wl1271_init_radio_parms(struct wl1271 *wl) { - /* - * FIXME: All these magic numbers should be moved to some place where - * they can be configured (separate file?) - */ - struct wl1271_radio_parms *radio_parms; - int ret; - u8 compensation[] = { 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, 0xfc, 0x00, - 0x08, 0x10, 0xf0, 0xf8, 0x00, 0x0a, 0x14 }; - - u8 tx_rate_limits_normal[] = { 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 }; - u8 tx_rate_limits_degraded[] = { 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 }; - - u8 tx_channel_limits_11b[] = { 0x22, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x22, 0x50, - 0x22, 0x50 }; - - u8 tx_channel_limits_ofdm[] = { 0x20, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x20, 0x50, - 0x20, 0x50 }; - - u8 tx_pdv_rate_offsets[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - u8 tx_ibias[] = { 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }; + struct conf_radio_parms *r = &wl->conf.init.radioparam; + int i, ret; radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); if (!radio_parms) @@ -259,33 +229,59 @@ static int wl1271_init_radio_parms(struct wl1271 *wl) radio_parms->id = TEST_CMD_INI_FILE_RADIO_PARAM; /* Static radio parameters */ - radio_parms->rx_trace_loss = 10; - radio_parms->tx_trace_loss = 10; - memcpy(radio_parms->rx_rssi_and_proc_compens, compensation, - sizeof(compensation)); - - /* We don't set the 5GHz -- N/A */ + radio_parms->rx_trace_loss = r->rx_trace_loss; + radio_parms->tx_trace_loss = r->tx_trace_loss; + memcpy(radio_parms->rx_rssi_and_proc_compens, + r->rx_rssi_and_proc_compens, + CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE); + + memcpy(radio_parms->rx_trace_loss_5, r->rx_trace_loss_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->tx_trace_loss_5, r->tx_trace_loss_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->rx_rssi_and_proc_compens_5, + r->rx_rssi_and_proc_compens_5, + CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE); /* Dynamic radio parameters */ - radio_parms->tx_ref_pd_voltage = cpu_to_le16(0x24e); - radio_parms->tx_ref_power = 0x78; - radio_parms->tx_offset_db = 0x0; - - memcpy(radio_parms->tx_rate_limits_normal, tx_rate_limits_normal, - sizeof(tx_rate_limits_normal)); - memcpy(radio_parms->tx_rate_limits_degraded, tx_rate_limits_degraded, - sizeof(tx_rate_limits_degraded)); - - memcpy(radio_parms->tx_channel_limits_11b, tx_channel_limits_11b, - sizeof(tx_channel_limits_11b)); - memcpy(radio_parms->tx_channel_limits_ofdm, tx_channel_limits_ofdm, - sizeof(tx_channel_limits_ofdm)); - memcpy(radio_parms->tx_pdv_rate_offsets, tx_pdv_rate_offsets, - sizeof(tx_pdv_rate_offsets)); - memcpy(radio_parms->tx_ibias, tx_ibias, - sizeof(tx_ibias)); - - radio_parms->rx_fem_insertion_loss = 0x14; + radio_parms->tx_ref_pd_voltage = cpu_to_le16(r->tx_ref_pd_voltage); + radio_parms->tx_ref_power = r->tx_ref_power; + radio_parms->tx_offset_db = r->tx_offset_db; + + memcpy(radio_parms->tx_rate_limits_normal, r->tx_rate_limits_normal, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded, + CONF_NUMBER_OF_RATE_GROUPS); + + memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b, + CONF_NUMBER_OF_CHANNELS_2_4); + memcpy(radio_parms->tx_channel_limits_ofdm, r->tx_channel_limits_ofdm, + CONF_NUMBER_OF_CHANNELS_2_4); + memcpy(radio_parms->tx_pdv_rate_offsets, r->tx_pdv_rate_offsets, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS); + + radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss; + + for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++) + radio_parms->tx_ref_pd_voltage_5[i] = + cpu_to_le16(r->tx_ref_pd_voltage_5[i]); + memcpy(radio_parms->tx_ref_power_5, r->tx_ref_power_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->tx_offset_db_5, r->tx_offset_db_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->tx_rate_limits_normal_5, + r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_rate_limits_degraded_5, + r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_channel_limits_ofdm_5, + r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5); + memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_ibias_5, r->tx_ibias_5, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->rx_fem_insertion_loss_5, + r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5); ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h index bd8ff0fa2272..513d0cb1866b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.h +++ b/drivers/net/wireless/wl12xx/wl1271_init.h @@ -48,19 +48,6 @@ struct wl1271_general_parms { u8 settings; } __attribute__ ((packed)); -enum ref_clk_enum { - REF_CLK_19_2_E, - REF_CLK_26_E, - REF_CLK_38_4_E, - REF_CLK_52_E -}; - -#define RSSI_AND_PROCESS_COMPENSATION_SIZE 15 -#define NUMBER_OF_SUB_BANDS_5 7 -#define NUMBER_OF_RATE_GROUPS 6 -#define NUMBER_OF_CHANNELS_2_4 14 -#define NUMBER_OF_CHANNELS_5 35 - struct wl1271_radio_parms { u8 id; u8 padding[3]; @@ -69,12 +56,12 @@ struct wl1271_radio_parms { /* 2.4GHz */ u8 rx_trace_loss; u8 tx_trace_loss; - s8 rx_rssi_and_proc_compens[RSSI_AND_PROCESS_COMPENSATION_SIZE]; + s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; /* 5GHz */ - u8 rx_trace_loss_5[NUMBER_OF_SUB_BANDS_5]; - u8 tx_trace_loss_5[NUMBER_OF_SUB_BANDS_5]; - s8 rx_rssi_and_proc_compens_5[RSSI_AND_PROCESS_COMPENSATION_SIZE]; + u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; /* Dynamic radio parameters */ /* 2.4GHz */ @@ -82,32 +69,32 @@ struct wl1271_radio_parms { s8 tx_ref_power; s8 tx_offset_db; - s8 tx_rate_limits_normal[NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_degraded[NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_channel_limits_11b[NUMBER_OF_CHANNELS_2_4]; - s8 tx_channel_limits_ofdm[NUMBER_OF_CHANNELS_2_4]; - s8 tx_pdv_rate_offsets[NUMBER_OF_RATE_GROUPS]; + s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; + s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; + s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS]; - u8 tx_ibias[NUMBER_OF_RATE_GROUPS]; + u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; u8 rx_fem_insertion_loss; u8 padding2; /* 5GHz */ - s16 tx_ref_pd_voltage_5[NUMBER_OF_SUB_BANDS_5]; - s8 tx_ref_power_5[NUMBER_OF_SUB_BANDS_5]; - s8 tx_offset_db_5[NUMBER_OF_SUB_BANDS_5]; + s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; - s8 tx_rate_limits_normal_5[NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_degraded_5[NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_channel_limits_ofdm_5[NUMBER_OF_CHANNELS_5]; - s8 tx_pdv_rate_offsets_5[NUMBER_OF_RATE_GROUPS]; + s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; + s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; /* FIXME: this is inconsistent with the types for 2.4GHz */ - s8 tx_ibias_5[NUMBER_OF_RATE_GROUPS]; - s8 rx_fem_insertion_loss_5[NUMBER_OF_SUB_BANDS_5]; + s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; u8 padding3[2]; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index a559a1536534..0b17b056f3f3 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -224,6 +224,109 @@ static void wl1271_conf_init(struct wl1271 *wl) .snr_bcn_avg_weight = 10, .snr_pkt_avg_weight = 10 } + }, + .init = { + .sr_err_tbl = { + [0] = { + .len = 7, + .upper_limit = 0x03, + .values = { + 0x18, 0x10, 0x05, 0xfb, + 0xf0, 0xe8, 0x00 } + }, + [1] = { + .len = 7, + .upper_limit = 0x03, + .values = { + 0x18, 0x10, 0x05, 0xf6, + 0xf0, 0xe8, 0x00 } + }, + [2] = { + .len = 7, + .upper_limit = 0x03, + .values = { + 0x18, 0x10, 0x05, 0xfb, + 0xf0, 0xe8, 0x00 } + } + }, + .sr_enable = 1, + .genparam = { + /* + * FIXME: The correct value CONF_REF_CLK_38_4_E + * causes the firmware to crash on boot. + * The value 5 apparently is an + * unnoficial XTAL configuration of the + * same frequency, which appears to work. + */ + .ref_clk = 5, + .settling_time = 5, + .clk_valid_on_wakeup = 0, + .dc2dcmode = 0, + .single_dual_band = 0, + .tx_bip_fem_autodetect = 0, + .tx_bip_fem_manufacturer = 1, + .settings = 1, + }, + .radioparam = { + /* FIXME: 5GHz values unset! */ + .rx_trace_loss = 10, + .tx_trace_loss = 10, + .rx_rssi_and_proc_compens = { + 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, + 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8, + 0x00, 0x0a, 0x14 }, + .rx_trace_loss_5 = { + 0, 0, 0, 0, 0, 0, 0 }, + .tx_trace_loss_5 = { + 0, 0, 0, 0, 0, 0, 0 }, + .rx_rssi_and_proc_compens_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 }, + .tx_ref_pd_voltage = 0x24e, + .tx_ref_power = 0x78, + .tx_offset_db = 0x0, + .tx_rate_limits_normal = { + 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 }, + .tx_rate_limits_degraded = { + 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 }, + .tx_channel_limits_11b = { + 0x22, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x22, 0x50, + 0x22, 0x50 }, + .tx_channel_limits_ofdm = { + 0x20, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x20, 0x50, + 0x20, 0x50 }, + .tx_pdv_rate_offsets = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .tx_ibias = { + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }, + .rx_fem_insertion_loss = 0x14, + .tx_ref_pd_voltage_5 = { + 0, 0, 0, 0, 0, 0, 0 }, + .tx_ref_power_5 = { + 0, 0, 0, 0, 0, 0, 0 }, + .tx_offset_db_5 = { + 0, 0, 0, 0, 0, 0, 0 }, + .tx_rate_limits_normal_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .tx_rate_limits_degraded_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .tx_channel_limits_ofdm_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00}, + .tx_pdv_rate_offsets_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .tx_ibias_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .rx_fem_insertion_loss_5 = { + 0, 0, 0, 0, 0, 0, 0 } + } } }; -- cgit v1.2.3 From 8a08048a3722a6b52c2b34e070c4e6a32ad19e0d Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:44 +0300 Subject: wl1271: Move default FW config struct away from stack Move the default FW config into a module global static variable, instead of being a stack variable. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 535 +++++++++++++++--------------- 1 file changed, 264 insertions(+), 271 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 0b17b056f3f3..eba38dff871b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -46,289 +46,282 @@ #include "wl1271_cmd.h" #include "wl1271_boot.h" -static void wl1271_conf_init(struct wl1271 *wl) -{ - struct conf_drv_settings conf = { - .sg = { - .per_threshold = 7500, - .max_scan_compensation_time = 120000, - .nfs_sample_interval = 400, - .load_ratio = 50, - .auto_ps_mode = 0, - .probe_req_compensation = 170, - .scan_window_compensation = 50, - .antenna_config = 0, - .beacon_miss_threshold = 60, - .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS, - .rate_adaptation_snr = 0 - }, - .rx = { - .rx_msdu_life_time = 512000, - .packet_detection_threshold = 0, - .ps_poll_timeout = 15, - .upsd_timeout = 15, - .rts_threshold = 2347, - .rx_cca_threshold = 0xFFEF, - .irq_blk_threshold = 0, - .irq_pkt_threshold = USHORT_MAX, - .irq_timeout = 5, - .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, +static struct conf_drv_settings default_conf = { + .sg = { + .per_threshold = 7500, + .max_scan_compensation_time = 120000, + .nfs_sample_interval = 400, + .load_ratio = 50, + .auto_ps_mode = 0, + .probe_req_compensation = 170, + .scan_window_compensation = 50, + .antenna_config = 0, + .beacon_miss_threshold = 60, + .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS, + .rate_adaptation_snr = 0 + }, + .rx = { + .rx_msdu_life_time = 512000, + .packet_detection_threshold = 0, + .ps_poll_timeout = 15, + .upsd_timeout = 15, + .rts_threshold = 2347, + .rx_cca_threshold = 0xFFEF, + .irq_blk_threshold = 0, + .irq_pkt_threshold = USHORT_MAX, + .irq_timeout = 5, + .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, + }, + .tx = { + .tx_energy_detection = 0, + .rc_conf = { + .enabled_rates = CONF_TX_RATE_MASK_UNSPECIFIED, + .short_retry_limit = 10, + .long_retry_limit = 10, + .aflags = 0 }, - .tx = { - .tx_energy_detection = 0, - .rc_conf = { - .enabled_rates = - CONF_TX_RATE_MASK_UNSPECIFIED, - .short_retry_limit = 10, - .long_retry_limit = 10, - .aflags = 0 + .ac_conf_count = 4, + .ac_conf = { + [0] = { + .ac = CONF_TX_AC_BE, + .cw_min = 15, + .cw_max = 63, + .aifsn = 3, + .tx_op_limit = 0, + }, + [1] = { + .ac = CONF_TX_AC_BK, + .cw_min = 15, + .cw_max = 63, + .aifsn = 7, + .tx_op_limit = 0, }, - .ac_conf_count = 4, - .ac_conf = { - [0] = { - .ac = CONF_TX_AC_BE, - .cw_min = 15, - .cw_max = 63, - .aifsn = 3, - .tx_op_limit = 0, - }, - [1] = { - .ac = CONF_TX_AC_BK, - .cw_min = 15, - .cw_max = 63, - .aifsn = 7, - .tx_op_limit = 0, - }, - [2] = { - .ac = CONF_TX_AC_VI, - .cw_min = 15, - .cw_max = 63, - .aifsn = CONF_TX_AIFS_PIFS, - .tx_op_limit = 3008, - }, - [3] = { - .ac = CONF_TX_AC_VO, - .cw_min = 15, - .cw_max = 63, - .aifsn = CONF_TX_AIFS_PIFS, - .tx_op_limit = 1504, - }, + [2] = { + .ac = CONF_TX_AC_VI, + .cw_min = 15, + .cw_max = 63, + .aifsn = CONF_TX_AIFS_PIFS, + .tx_op_limit = 3008, }, - .tid_conf_count = 7, - .tid_conf = { - [0] = { - .queue_id = 0, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [1] = { - .queue_id = 1, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [2] = { - .queue_id = 2, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [3] = { - .queue_id = 3, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [4] = { - .queue_id = 4, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [5] = { - .queue_id = 5, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - }, - [6] = { - .queue_id = 6, - .channel_type = CONF_CHANNEL_TYPE_DCF, - .tsid = CONF_TX_AC_BE, - .ps_scheme = CONF_PS_SCHEME_LEGACY, - .ack_policy = CONF_ACK_POLICY_LEGACY, - .apsd_conf = {0, 0}, - } + [3] = { + .ac = CONF_TX_AC_VO, + .cw_min = 15, + .cw_max = 63, + .aifsn = CONF_TX_AIFS_PIFS, + .tx_op_limit = 1504, }, - .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, - .tx_compl_timeout = 5, - .tx_compl_threshold = 5 }, - .conn = { - .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, - .listen_interval = 0, - .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, - .bcn_filt_ie_count = 1, - .bcn_filt_ie = { - [0] = { - .ie = WLAN_EID_CHANNEL_SWITCH, - .rule = - CONF_BCN_RULE_PASS_ON_APPEARANCE, - } + .tid_conf_count = 7, + .tid_conf = { + [0] = { + .queue_id = 0, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [1] = { + .queue_id = 1, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, }, - .synch_fail_thold = 5, - .bss_lose_timeout = 100, - .beacon_rx_timeout = 10000, - .broadcast_timeout = 20000, - .rx_broadcast_in_ps = 1, - .ps_poll_threshold = 4, - .sig_trigger_count = 2, - .sig_trigger = { - [0] = { - .threshold = -75, - .pacing = 500, - .metric = CONF_TRIG_METRIC_RSSI_BEACON, - .type = CONF_TRIG_EVENT_TYPE_EDGE, - .direction = CONF_TRIG_EVENT_DIR_LOW, - .hysteresis = 2, - .index = 0, - .enable = 1 - }, - [1] = { - .threshold = -75, - .pacing = 500, - .metric = CONF_TRIG_METRIC_RSSI_BEACON, - .type = CONF_TRIG_EVENT_TYPE_EDGE, - .direction = CONF_TRIG_EVENT_DIR_HIGH, - .hysteresis = 2, - .index = 1, - .enable = 1 - } + [2] = { + .queue_id = 2, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, }, - .sig_weights = { - .rssi_bcn_avg_weight = 10, - .rssi_pkt_avg_weight = 10, - .snr_bcn_avg_weight = 10, - .snr_pkt_avg_weight = 10 + [3] = { + .queue_id = 3, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [4] = { + .queue_id = 4, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [5] = { + .queue_id = 5, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, + }, + [6] = { + .queue_id = 6, + .channel_type = CONF_CHANNEL_TYPE_DCF, + .tsid = CONF_TX_AC_BE, + .ps_scheme = CONF_PS_SCHEME_LEGACY, + .ack_policy = CONF_ACK_POLICY_LEGACY, + .apsd_conf = {0, 0}, } }, - .init = { - .sr_err_tbl = { - [0] = { - .len = 7, - .upper_limit = 0x03, - .values = { - 0x18, 0x10, 0x05, 0xfb, - 0xf0, 0xe8, 0x00 } - }, - [1] = { - .len = 7, - .upper_limit = 0x03, - .values = { - 0x18, 0x10, 0x05, 0xf6, - 0xf0, 0xe8, 0x00 } - }, - [2] = { - .len = 7, - .upper_limit = 0x03, - .values = { - 0x18, 0x10, 0x05, 0xfb, - 0xf0, 0xe8, 0x00 } - } + .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, + .tx_compl_timeout = 5, + .tx_compl_threshold = 5 + }, + .conn = { + .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, + .listen_interval = 0, + .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, + .bcn_filt_ie_count = 1, + .bcn_filt_ie = { + [0] = { + .ie = WLAN_EID_CHANNEL_SWITCH, + .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, + } + }, + .synch_fail_thold = 5, + .bss_lose_timeout = 100, + .beacon_rx_timeout = 10000, + .broadcast_timeout = 20000, + .rx_broadcast_in_ps = 1, + .ps_poll_threshold = 4, + .sig_trigger_count = 2, + .sig_trigger = { + [0] = { + .threshold = -75, + .pacing = 500, + .metric = CONF_TRIG_METRIC_RSSI_BEACON, + .type = CONF_TRIG_EVENT_TYPE_EDGE, + .direction = CONF_TRIG_EVENT_DIR_LOW, + .hysteresis = 2, + .index = 0, + .enable = 1 }, - .sr_enable = 1, - .genparam = { - /* - * FIXME: The correct value CONF_REF_CLK_38_4_E - * causes the firmware to crash on boot. - * The value 5 apparently is an - * unnoficial XTAL configuration of the - * same frequency, which appears to work. - */ - .ref_clk = 5, - .settling_time = 5, - .clk_valid_on_wakeup = 0, - .dc2dcmode = 0, - .single_dual_band = 0, - .tx_bip_fem_autodetect = 0, - .tx_bip_fem_manufacturer = 1, - .settings = 1, + [1] = { + .threshold = -75, + .pacing = 500, + .metric = CONF_TRIG_METRIC_RSSI_BEACON, + .type = CONF_TRIG_EVENT_TYPE_EDGE, + .direction = CONF_TRIG_EVENT_DIR_HIGH, + .hysteresis = 2, + .index = 1, + .enable = 1 + } + }, + .sig_weights = { + .rssi_bcn_avg_weight = 10, + .rssi_pkt_avg_weight = 10, + .snr_bcn_avg_weight = 10, + .snr_pkt_avg_weight = 10 + } + }, + .init = { + .sr_err_tbl = { + [0] = { + .len = 7, + .upper_limit = 0x03, + .values = { + 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8, + 0x00 } + }, + [1] = { + .len = 7, + .upper_limit = 0x03, + .values = { + 0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8, + 0x00 } }, - .radioparam = { - /* FIXME: 5GHz values unset! */ - .rx_trace_loss = 10, - .tx_trace_loss = 10, - .rx_rssi_and_proc_compens = { - 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, - 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8, - 0x00, 0x0a, 0x14 }, - .rx_trace_loss_5 = { - 0, 0, 0, 0, 0, 0, 0 }, - .tx_trace_loss_5 = { - 0, 0, 0, 0, 0, 0, 0 }, - .rx_rssi_and_proc_compens_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 }, - .tx_ref_pd_voltage = 0x24e, - .tx_ref_power = 0x78, - .tx_offset_db = 0x0, - .tx_rate_limits_normal = { - 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 }, - .tx_rate_limits_degraded = { - 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 }, - .tx_channel_limits_11b = { - 0x22, 0x50, 0x50, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x50, 0x50, 0x22, 0x50, - 0x22, 0x50 }, - .tx_channel_limits_ofdm = { - 0x20, 0x50, 0x50, 0x50, 0x50, 0x50, - 0x50, 0x50, 0x50, 0x50, 0x20, 0x50, - 0x20, 0x50 }, - .tx_pdv_rate_offsets = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - .tx_ibias = { - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }, - .rx_fem_insertion_loss = 0x14, - .tx_ref_pd_voltage_5 = { - 0, 0, 0, 0, 0, 0, 0 }, - .tx_ref_power_5 = { - 0, 0, 0, 0, 0, 0, 0 }, - .tx_offset_db_5 = { - 0, 0, 0, 0, 0, 0, 0 }, - .tx_rate_limits_normal_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - .tx_rate_limits_degraded_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - .tx_channel_limits_ofdm_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}, - .tx_pdv_rate_offsets_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - .tx_ibias_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - .rx_fem_insertion_loss_5 = { - 0, 0, 0, 0, 0, 0, 0 } + [2] = { + .len = 7, + .upper_limit = 0x03, + .values = { + 0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8, + 0x00 } } + }, + .sr_enable = 1, + .genparam = { + /* + * FIXME: The correct value CONF_REF_CLK_38_4_E + * causes the firmware to crash on boot. + * The value 5 apparently is an + * unnoficial XTAL configuration of the + * same frequency, which appears to work. + */ + .ref_clk = 5, + .settling_time = 5, + .clk_valid_on_wakeup = 0, + .dc2dcmode = 0, + .single_dual_band = 0, + .tx_bip_fem_autodetect = 0, + .tx_bip_fem_manufacturer = 1, + .settings = 1, + }, + .radioparam = { + /* FIXME: 5GHz values unset! */ + .rx_trace_loss = 10, + .tx_trace_loss = 10, + .rx_rssi_and_proc_compens = { + 0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, + 0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8, + 0x00, 0x0a, 0x14 }, + .rx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }, + .tx_trace_loss_5 = { 0, 0, 0, 0, 0, 0, 0 }, + .rx_rssi_and_proc_compens_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 }, + .tx_ref_pd_voltage = 0x24e, + .tx_ref_power = 0x78, + .tx_offset_db = 0x0, + .tx_rate_limits_normal = { + 0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 }, + .tx_rate_limits_degraded = { + 0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 }, + .tx_channel_limits_11b = { + 0x22, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x22, 0x50, + 0x22, 0x50 }, + .tx_channel_limits_ofdm = { + 0x20, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x20, 0x50, + 0x20, 0x50 }, + .tx_pdv_rate_offsets = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .tx_ibias = { + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }, + .rx_fem_insertion_loss = 0x14, + .tx_ref_pd_voltage_5 = { 0, 0, 0, 0, 0, 0, 0 }, + .tx_ref_power_5 = { 0, 0, 0, 0, 0, 0, 0 }, + .tx_offset_db_5 = {0, 0, 0, 0, 0, 0, 0 }, + .tx_rate_limits_normal_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .tx_rate_limits_degraded_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .tx_channel_limits_ofdm_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00}, + .tx_pdv_rate_offsets_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .tx_ibias_5 = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .rx_fem_insertion_loss_5 = { 0, 0, 0, 0, 0, 0, 0 } } - }; + } +}; + +static void wl1271_conf_init(struct wl1271 *wl) +{ /* * This function applies the default configuration to the driver. This @@ -341,7 +334,7 @@ static void wl1271_conf_init(struct wl1271 *wl) */ /* apply driver default configuration */ - memcpy(&wl->conf, &conf, sizeof(conf)); + memcpy(&wl->conf, &default_conf, sizeof(default_conf)); } -- cgit v1.2.3 From eb5b28d021a1b96050f7af46e9140eb0051cc6d8 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:45 +0300 Subject: wl1271: Fix IRQ enable handling on FW init failure Disable IRQ's after FW initialization failure - originally this was not done in all cases, and it resulted in a kernel warning if firmware initialization was tried again without reboot. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_boot.c | 6 ++--- drivers/net/wireless/wl12xx/wl1271_init.c | 4 +-- drivers/net/wireless/wl12xx/wl1271_main.c | 42 ++++++++++++++++++++++--------- 3 files changed, 35 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index a27601dc9c0d..b8a37a84842f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -400,9 +400,6 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) * ready to receive event from the command mailbox */ - /* enable gpio interrupts */ - wl1271_boot_enable_interrupts(wl); - /* unmask required mbox events */ wl->event_mask = BSS_LOSE_EVENT_ID | SCAN_COMPLETE_EVENT_ID; @@ -540,6 +537,9 @@ int wl1271_boot(struct wl1271 *wl) if (ret < 0) goto out; + /* Enable firmware interrupts now */ + wl1271_boot_enable_interrupts(wl); + /* set the wl1271 default filters */ wl->rx_config = WL1271_DEFAULT_RX_CONFIG; wl->rx_filter = WL1271_DEFAULT_RX_FILTER; diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 5c2cf1e00ac7..6f21eeae5246 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -315,8 +315,8 @@ int wl1271_hw_init(struct wl1271 *wl) /* RX config */ ret = wl1271_init_rx_config(wl, - RX_CFG_PROMISCUOUS | RX_CFG_TSF, - RX_FILTER_OPTION_DEF); + RX_CFG_PROMISCUOUS | RX_CFG_TSF, + RX_FILTER_OPTION_DEF); /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, RX_FILTER_OPTION_FILTER_ALL); */ if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index eba38dff871b..7f1093cd816c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -625,7 +625,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ret = wl1271_setup(wl); if (ret < 0) - goto out; + goto out_power_off; break; case CHIP_ID_1271_PG20: wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", @@ -633,27 +633,32 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) ret = wl1271_setup(wl); if (ret < 0) - goto out; + goto out_power_off; break; default: wl1271_error("unsupported chip id: 0x%x", wl->chip.id); ret = -ENODEV; - goto out; + goto out_power_off; } if (wl->fw == NULL) { ret = wl1271_fetch_firmware(wl); if (ret < 0) - goto out; + goto out_power_off; } /* No NVS from netlink, try to get it from the filesystem */ if (wl->nvs == NULL) { ret = wl1271_fetch_nvs(wl); if (ret < 0) - goto out; + goto out_power_off; } + goto out; + +out_power_off: + wl1271_power_off(wl); + out: return ret; } @@ -749,13 +754,21 @@ int wl1271_plt_start(struct wl1271 *wl) ret = wl1271_boot(wl); if (ret < 0) - goto out; + goto out_power_off; wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); ret = wl1271_plt_init(wl); if (ret < 0) - goto out; + goto out_irq_disable; + + goto out; + +out_irq_disable: + wl1271_disable_interrupts(wl); + +out_power_off: + wl1271_power_off(wl); out: mutex_unlock(&wl->mutex); @@ -843,20 +856,25 @@ static int wl1271_op_start(struct ieee80211_hw *hw) ret = wl1271_boot(wl); if (ret < 0) - goto out; + goto out_power_off; ret = wl1271_hw_init(wl); if (ret < 0) - goto out; + goto out_irq_disable; wl->state = WL1271_STATE_ON; wl1271_info("firmware booted (%s)", wl->chip.fw_ver); -out: - if (ret < 0) - wl1271_power_off(wl); + goto out; + +out_irq_disable: + wl1271_disable_interrupts(wl); +out_power_off: + wl1271_power_off(wl); + +out: mutex_unlock(&wl->mutex); return ret; -- cgit v1.2.3 From 11f70f9715f0d8f99eac42d69689e8df15283fea Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:46 +0300 Subject: wl1271: Implement beacon early termination support Add support to enable beacon early termination in the firmware. Early Beacon termination is a feature which allows the radio to be turned off after TIM IE to save power. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.c | 30 ++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_acx.h | 12 +++++++++++- drivers/net/wireless/wl12xx/wl1271_conf.h | 23 +++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_main.c | 4 +++- drivers/net/wireless/wl12xx/wl1271_ps.c | 10 ++++++++++ 5 files changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 880c82894f63..44a1237fa794 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -1062,3 +1062,33 @@ out: return ret; } + +int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable) +{ + struct wl1271_acx_bet_enable *acx = NULL; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx bet enable"); + + if (enable && wl->conf.conn.bet_enable == CONF_BET_MODE_DISABLE) + goto out; + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; + acx->max_consecutive = wl->conf.conn.bet_max_consecutive; + + ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx bet enable failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 73ef2bdf3b74..29fd3635e383 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -946,6 +946,15 @@ struct wl1271_acx_rx_config_opt { u8 reserved; } __attribute__ ((packed)); + +struct wl1271_acx_bet_enable { + struct acx_header header; + + u8 enable; + u8 max_consecutive; + u8 padding[2]; +} __attribute__ ((packed)); + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -1043,7 +1052,7 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid); int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask); int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); int wl1271_acx_cts_protect(struct wl1271 *wl, - enum acx_ctsprotect_type ctsprotect); + enum acx_ctsprotect_type ctsprotect); int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates); int wl1271_acx_ac_cfg(struct wl1271 *wl); @@ -1054,5 +1063,6 @@ int wl1271_acx_mem_cfg(struct wl1271 *wl); int wl1271_acx_init_mem_config(struct wl1271 *wl); int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); int wl1271_acx_smart_reflex(struct wl1271 *wl); +int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 5333a2731254..00ffa6679324 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -603,6 +603,11 @@ enum conf_bcn_filt_mode { CONF_BCN_FILT_MODE_ENABLED = 1 }; +enum conf_bet_mode { + CONF_BET_MODE_DISABLE = 0, + CONF_BET_MODE_ENABLE = 1, +}; + struct conf_conn_settings { /* * Firmware wakeup conditions configuration. The host may set only @@ -689,6 +694,24 @@ struct conf_conn_settings { * Configuration of signal average weights. */ struct conf_sig_weights sig_weights; + + /* + * Specifies if beacon early termination procedure is enabled or + * disabled. + * + * Range: CONF_BET_MODE_* + */ + u8 bet_enable; + + /* + * Specifies the maximum number of consecutive beacons that may be + * early terminated. After this number is reached at least one full + * beacon must be correctly received in FW before beacon ET + * resumes. + * + * Range 0 - 255 + */ + u8 bet_max_consecutive; }; #define CONF_SR_ERR_TBL_MAX_VALUES 14 diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7f1093cd816c..3d2e999ef15a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -219,7 +219,9 @@ static struct conf_drv_settings default_conf = { .rssi_pkt_avg_weight = 10, .snr_bcn_avg_weight = 10, .snr_pkt_avg_weight = 10 - } + }, + .bet_enable = CONF_BET_MODE_ENABLE, + .bet_max_consecutive = 100 }, .init = { .sr_err_tbl = { diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c index bb8745d9bd64..507cd91d7eed 100644 --- a/drivers/net/wireless/wl12xx/wl1271_ps.c +++ b/drivers/net/wireless/wl12xx/wl1271_ps.c @@ -130,6 +130,11 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) if (ret < 0) return ret; + /* enable beacon early termination */ + ret = wl1271_acx_bet_enable(wl, true); + if (ret < 0) + return ret; + ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE); if (ret < 0) return ret; @@ -147,6 +152,11 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) if (ret < 0) return ret; + /* disable beacon early termination */ + ret = wl1271_acx_bet_enable(wl, false); + if (ret < 0) + return ret; + /* disable beacon filtering */ ret = wl1271_acx_beacon_filter_opt(wl, false); if (ret < 0) -- cgit v1.2.3 From c6d5d06e455b9965e300ae40c34fa2337e1aad0f Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:47 +0300 Subject: wl1271: Remove busy-word checking Remove busy-word checking to work around an SPI bug. To reduce the chance of chipset-busy scenarios, increment the number of fixed busy words. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 6 ++++-- drivers/net/wireless/wl12xx/wl1271_spi.c | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 648223f67b54..e0ebb1fb2ada 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -115,9 +115,11 @@ enum { /* * FIXME: for the wl1271, a busy word count of 1 here will result in a more * optimal SPI interface. There is some SPI bug however, causing RXS time outs - * with this mode occasionally on boot, so lets have two for now. + * with this mode occasionally on boot, so lets have three for now. A value of + * three should make sure, that the chipset will always be ready, though this + * will impact throughput and latencies slightly. */ -#define WL1271_BUSY_WORD_CNT 2 +#define WL1271_BUSY_WORD_CNT 3 #define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32)) #define WL1271_ELP_HW_STATE_ASLEEP 0 diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 4800fdfd2373..3c5aa584574b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -294,9 +294,9 @@ void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, spi_sync(wl->spi, &m); - /* Check busy words */ - if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1)) - wl1271_spi_read_busy(wl, buf, len); + /* FIXME: Check busy words, removed due to SPI bug */ + /* if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1)) + wl1271_spi_read_busy(wl, buf, len); */ wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd)); wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len); -- cgit v1.2.3 From 1ebec3d750f2b5740e3c334dac06104d2f74a9b1 Mon Sep 17 00:00:00 2001 From: Teemu Paasikivi Date: Tue, 13 Oct 2009 12:47:48 +0300 Subject: wl1271: Added 5 GHz parameters for wl1273 Added data rate and frequency tables for 5 GHz band channels, 5 GHz radio configration parameters and configuration option to enable 802.11 support. Signed-off-by: Teemu Paasikivi Reviewed-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 14 ++++ drivers/net/wireless/wl12xx/wl1271_conf.h | 7 +- drivers/net/wireless/wl12xx/wl1271_main.c | 123 ++++++++++++++++++++++++++---- 3 files changed, 127 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index e0ebb1fb2ada..dc9957ee1ac3 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -112,6 +112,11 @@ enum { #define WL1271_FW_NAME "wl1271-fw.bin" #define WL1271_NVS_NAME "wl1271-nvs.bin" +/* + * Enable/disable 802.11a support for WL1273 + */ +#undef WL1271_80211A_ENABLED + /* * FIXME: for the wl1271, a busy word count of 1 here will result in a more * optimal SPI interface. There is some SPI bug however, causing RXS time outs @@ -442,4 +447,13 @@ int wl1271_plt_stop(struct wl1271 *wl); /* WL1271 needs a 200ms sleep after power on */ #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ +static inline bool wl1271_11a_enabled(void) +{ +#ifdef WL1271_80211A_ENABLED + return true; +#else + return false; +#endif +} + #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 00ffa6679324..061d47520a32 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -746,6 +746,11 @@ enum { CONF_REF_CLK_52_E }; +enum single_dual_band_enum { + CONF_SINGLE_BAND, + CONF_DUAL_BAND +}; + struct conf_general_parms { /* * RF Reference Clock type / speed @@ -778,7 +783,7 @@ struct conf_general_parms { /* * Flag defining whether used as single or dual-band. * - * Range: Unknown + * Range: CONF_SINGLE_BAND, CONF_DUAL_BAND */ u8 single_dual_band; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 3d2e999ef15a..9b1cc8db1ddd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -260,13 +260,12 @@ static struct conf_drv_settings default_conf = { .settling_time = 5, .clk_valid_on_wakeup = 0, .dc2dcmode = 0, - .single_dual_band = 0, + .single_dual_band = CONF_SINGLE_BAND, .tx_bip_fem_autodetect = 0, .tx_bip_fem_manufacturer = 1, .settings = 1, }, .radioparam = { - /* FIXME: 5GHz values unset! */ .rx_trace_loss = 10, .tx_trace_loss = 10, .rx_rssi_and_proc_compens = { @@ -299,25 +298,29 @@ static struct conf_drv_settings default_conf = { .tx_ibias = { 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }, .rx_fem_insertion_loss = 0x14, - .tx_ref_pd_voltage_5 = { 0, 0, 0, 0, 0, 0, 0 }, - .tx_ref_power_5 = { 0, 0, 0, 0, 0, 0, 0 }, - .tx_offset_db_5 = {0, 0, 0, 0, 0, 0, 0 }, - .tx_rate_limits_normal_5 = { + .tx_ref_pd_voltage_5 = { + 0x0190, 0x01a4, 0x01c3, 0x01d8, + 0x020a, 0x021c }, + .tx_ref_power_5 = { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, + .tx_offset_db_5 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .tx_rate_limits_normal_5 = { + 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, .tx_rate_limits_degraded_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + 0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, .tx_channel_limits_ofdm_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50 }, .tx_pdv_rate_offsets_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + 0x01, 0x02, 0x02, 0x02, 0x02, 0x00 }, .tx_ibias_5 = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - .rx_fem_insertion_loss_5 = { 0, 0, 0, 0, 0, 0, 0 } + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, + .rx_fem_insertion_loss_5 = { + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 } } } }; @@ -337,6 +340,9 @@ static void wl1271_conf_init(struct wl1271 *wl) /* apply driver default configuration */ memcpy(&wl->conf, &default_conf, sizeof(default_conf)); + + if (wl1271_11a_enabled()) + wl->conf.init.genparam.single_dual_band = CONF_DUAL_BAND; } @@ -1556,6 +1562,88 @@ static struct ieee80211_supported_band wl1271_band_2ghz = { .n_bitrates = ARRAY_SIZE(wl1271_rates), }; +/* 5 GHz data rates for WL1273 */ +static struct ieee80211_rate wl1271_rates_5ghz[] = { + { .bitrate = 60, + .hw_value = CONF_HW_BIT_RATE_6MBPS, + .hw_value_short = CONF_HW_BIT_RATE_6MBPS, }, + { .bitrate = 90, + .hw_value = CONF_HW_BIT_RATE_9MBPS, + .hw_value_short = CONF_HW_BIT_RATE_9MBPS, }, + { .bitrate = 120, + .hw_value = CONF_HW_BIT_RATE_12MBPS, + .hw_value_short = CONF_HW_BIT_RATE_12MBPS, }, + { .bitrate = 180, + .hw_value = CONF_HW_BIT_RATE_18MBPS, + .hw_value_short = CONF_HW_BIT_RATE_18MBPS, }, + { .bitrate = 240, + .hw_value = CONF_HW_BIT_RATE_24MBPS, + .hw_value_short = CONF_HW_BIT_RATE_24MBPS, }, + { .bitrate = 360, + .hw_value = CONF_HW_BIT_RATE_36MBPS, + .hw_value_short = CONF_HW_BIT_RATE_36MBPS, }, + { .bitrate = 480, + .hw_value = CONF_HW_BIT_RATE_48MBPS, + .hw_value_short = CONF_HW_BIT_RATE_48MBPS, }, + { .bitrate = 540, + .hw_value = CONF_HW_BIT_RATE_54MBPS, + .hw_value_short = CONF_HW_BIT_RATE_54MBPS, }, +}; + +/* 5 GHz band channels for WL1273 */ +static struct ieee80211_channel wl1271_channels_5ghz[] = { + { .hw_value = 183, .center_freq = 4915}, + { .hw_value = 184, .center_freq = 4920}, + { .hw_value = 185, .center_freq = 4925}, + { .hw_value = 187, .center_freq = 4935}, + { .hw_value = 188, .center_freq = 4940}, + { .hw_value = 189, .center_freq = 4945}, + { .hw_value = 192, .center_freq = 4960}, + { .hw_value = 196, .center_freq = 4980}, + { .hw_value = 7, .center_freq = 5035}, + { .hw_value = 8, .center_freq = 5040}, + { .hw_value = 9, .center_freq = 5045}, + { .hw_value = 11, .center_freq = 5055}, + { .hw_value = 12, .center_freq = 5060}, + { .hw_value = 16, .center_freq = 5080}, + { .hw_value = 34, .center_freq = 5170}, + { .hw_value = 36, .center_freq = 5180}, + { .hw_value = 38, .center_freq = 5190}, + { .hw_value = 40, .center_freq = 5200}, + { .hw_value = 42, .center_freq = 5210}, + { .hw_value = 44, .center_freq = 5220}, + { .hw_value = 46, .center_freq = 5230}, + { .hw_value = 48, .center_freq = 5240}, + { .hw_value = 52, .center_freq = 5260}, + { .hw_value = 56, .center_freq = 5280}, + { .hw_value = 60, .center_freq = 5300}, + { .hw_value = 64, .center_freq = 5320}, + { .hw_value = 100, .center_freq = 5500}, + { .hw_value = 104, .center_freq = 5520}, + { .hw_value = 108, .center_freq = 5540}, + { .hw_value = 112, .center_freq = 5560}, + { .hw_value = 116, .center_freq = 5580}, + { .hw_value = 120, .center_freq = 5600}, + { .hw_value = 124, .center_freq = 5620}, + { .hw_value = 128, .center_freq = 5640}, + { .hw_value = 132, .center_freq = 5660}, + { .hw_value = 136, .center_freq = 5680}, + { .hw_value = 140, .center_freq = 5700}, + { .hw_value = 149, .center_freq = 5745}, + { .hw_value = 153, .center_freq = 5765}, + { .hw_value = 157, .center_freq = 5785}, + { .hw_value = 161, .center_freq = 5805}, + { .hw_value = 165, .center_freq = 5825}, +}; + + +static struct ieee80211_supported_band wl1271_band_5ghz = { + .channels = wl1271_channels_5ghz, + .n_channels = ARRAY_SIZE(wl1271_channels_5ghz), + .bitrates = wl1271_rates_5ghz, + .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), +}; + static const struct ieee80211_ops wl1271_ops = { .start = wl1271_op_start, .stop = wl1271_op_stop, @@ -1612,6 +1700,9 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; + if (wl1271_11a_enabled()) + wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; + SET_IEEE80211_DEV(wl->hw, &wl->spi->dev); return 0; -- cgit v1.2.3 From 311494c47fb670a1fd74eea54fa4d02a56fcc2ad Mon Sep 17 00:00:00 2001 From: Teemu Paasikivi Date: Tue, 13 Oct 2009 12:47:49 +0300 Subject: wl1271: Scan only enabled channels Added checking of whether channel is enabled or disabled by mac80211 stack to scan. Disabled channels are not scanned. Signed-off-by: Teemu Paasikivi Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 33 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index f38e3e0e2d66..204e87218d8f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -515,12 +515,16 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, struct wl1271_cmd_trigger_scan_to *trigger = NULL; struct wl1271_cmd_scan *params = NULL; - int i, ret; + struct ieee80211_channel *channels; + int i, j, n_ch, ret; u16 scan_options = 0; if (wl->scanning) return -EINVAL; + channels = wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels; + n_ch = wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->n_channels; + params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; @@ -535,24 +539,29 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; params->params.scan_options = scan_options; - params->params.num_channels = num_channels; params->params.num_probe_requests = probe_requests; params->params.tx_rate = cpu_to_le32(CONF_HW_BIT_RATE_2MBPS); params->params.tid_trigger = 0; params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; - for (i = 0; i < num_channels; i++) { - params->channels[i].min_duration = - cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); - params->channels[i].max_duration = - cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); - memset(¶ms->channels[i].bssid_lsb, 0xff, 4); - memset(¶ms->channels[i].bssid_msb, 0xff, 2); - params->channels[i].early_termination = 0; - params->channels[i].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR; - params->channels[i].channel = i + 1; + for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) { + if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) { + params->channels[j].min_duration = + cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); + params->channels[j].max_duration = + cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); + memset(¶ms->channels[j].bssid_lsb, 0xff, 4); + memset(¶ms->channels[j].bssid_msb, 0xff, 2); + params->channels[j].early_termination = 0; + params->channels[j].tx_power_att = + WL1271_SCAN_CURRENT_TX_PWR; + params->channels[j].channel = channels[i].hw_value; + j++; + } } + params->params.num_channels = j; + if (len && ssid) { params->params.ssid_len = len; memcpy(params->params.ssid, ssid, len); -- cgit v1.2.3 From abb0b3bfb2d2411034b721df21c31964265b851e Mon Sep 17 00:00:00 2001 From: Teemu Paasikivi Date: Tue, 13 Oct 2009 12:47:50 +0300 Subject: wl1271: Added support to scan on 5 GHz band Added support to scan 802.11a access points on 5 GHz band when using wl1273 chip. Signed-off-by: Teemu Paasikivi Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 10 +++ drivers/net/wireless/wl12xx/wl1271_cmd.c | 121 +++++++++++++++++++++++------ drivers/net/wireless/wl12xx/wl1271_cmd.h | 8 +- drivers/net/wireless/wl12xx/wl1271_event.c | 37 +++++++-- drivers/net/wireless/wl12xx/wl1271_init.c | 8 ++ drivers/net/wireless/wl12xx/wl1271_main.c | 11 ++- drivers/net/wireless/wl12xx/wl1271_rx.c | 3 + 7 files changed, 160 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index dc9957ee1ac3..79a732443151 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -299,6 +299,15 @@ struct wl1271_rx_mem_pool_addr { u32 addr_extra; }; +struct wl1271_scan { + u8 state; + u8 ssid[IW_ESSID_MAX_SIZE+1]; + size_t ssid_len; + u8 active; + u8 high_prio; + u8 probe_requests; +}; + struct wl1271 { struct ieee80211_hw *hw; bool mac80211_registered; @@ -382,6 +391,7 @@ struct wl1271 { /* Are we currently scanning */ bool scanning; + struct wl1271_scan scan; /* Our association ID */ u16 aid; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 204e87218d8f..6d7a40c004f1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -509,7 +509,7 @@ out: } int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, - u8 active_scan, u8 high_prio, u8 num_channels, + u8 active_scan, u8 high_prio, u8 band, u8 probe_requests) { @@ -518,12 +518,25 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, struct ieee80211_channel *channels; int i, j, n_ch, ret; u16 scan_options = 0; + u8 ieee_band; + + if (band == WL1271_SCAN_BAND_2_4_GHZ) + ieee_band = IEEE80211_BAND_2GHZ; + else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) + ieee_band = IEEE80211_BAND_2GHZ; + else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) + ieee_band = IEEE80211_BAND_5GHZ; + else + return -EINVAL; - if (wl->scanning) + if (wl->hw->wiphy->bands[ieee_band]->channels == NULL) return -EINVAL; - channels = wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels; - n_ch = wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->n_channels; + channels = wl->hw->wiphy->bands[ieee_band]->channels; + n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels; + + if (wl->scanning) + return -EINVAL; params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) @@ -540,10 +553,16 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, params->params.scan_options = scan_options; params->params.num_probe_requests = probe_requests; - params->params.tx_rate = cpu_to_le32(CONF_HW_BIT_RATE_2MBPS); + /* Let the fw autodetect suitable tx_rate for probes */ + params->params.tx_rate = 0; params->params.tid_trigger = 0; params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; + if (band == WL1271_SCAN_BAND_DUAL) + params->params.band = WL1271_SCAN_BAND_2_4_GHZ; + else + params->params.band = band; + for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) { if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) { params->channels[j].min_duration = @@ -567,7 +586,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, memcpy(params->params.ssid, ssid, len); } - ret = wl1271_cmd_build_probe_req(wl, ssid, len); + ret = wl1271_cmd_build_probe_req(wl, ssid, len, ieee_band); if (ret < 0) { wl1271_error("PROBE request template failed"); goto out; @@ -592,6 +611,19 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); wl->scanning = true; + if (wl1271_11a_enabled()) { + wl->scan.state = band; + if (band == WL1271_SCAN_BAND_DUAL) { + wl->scan.active = active_scan; + wl->scan.high_prio = high_prio; + wl->scan.probe_requests = probe_requests; + if (len && ssid) { + wl->scan.ssid_len = len; + memcpy(wl->scan.ssid, ssid, len); + } else + wl->scan.ssid_len = 0; + } + } ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); if (ret < 0) { @@ -654,30 +686,62 @@ out: return ret; } -static int wl1271_build_basic_rates(char *rates) +static int wl1271_build_basic_rates(char *rates, u8 band) { u8 index = 0; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; - rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + if (band == IEEE80211_BAND_2GHZ) { + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; + } else if (band == IEEE80211_BAND_5GHZ) { + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; + } else { + wl1271_error("build_basic_rates invalid band: %d", band); + } return index; } -static int wl1271_build_extended_rates(char *rates) +static int wl1271_build_extended_rates(char *rates, u8 band) { u8 index = 0; - rates[index++] = IEEE80211_OFDM_RATE_6MB; - rates[index++] = IEEE80211_OFDM_RATE_9MB; - rates[index++] = IEEE80211_OFDM_RATE_12MB; - rates[index++] = IEEE80211_OFDM_RATE_18MB; - rates[index++] = IEEE80211_OFDM_RATE_24MB; - rates[index++] = IEEE80211_OFDM_RATE_36MB; - rates[index++] = IEEE80211_OFDM_RATE_48MB; - rates[index++] = IEEE80211_OFDM_RATE_54MB; + if (band == IEEE80211_BAND_2GHZ) { + rates[index++] = IEEE80211_OFDM_RATE_6MB; + rates[index++] = IEEE80211_OFDM_RATE_9MB; + rates[index++] = IEEE80211_OFDM_RATE_12MB; + rates[index++] = IEEE80211_OFDM_RATE_18MB; + rates[index++] = IEEE80211_OFDM_RATE_24MB; + rates[index++] = IEEE80211_OFDM_RATE_36MB; + rates[index++] = IEEE80211_OFDM_RATE_48MB; + rates[index++] = IEEE80211_OFDM_RATE_54MB; + } else if (band == IEEE80211_BAND_5GHZ) { + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; + rates[index++] = + IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; + } else { + wl1271_error("build_basic_rates invalid band: %d", band); + } return index; } @@ -720,12 +784,14 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) } -int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len) +int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len, + u8 band) { struct wl12xx_probe_req_template template; struct wl12xx_ie_rates *rates; char *ptr; u16 size; + int ret; ptr = (char *)&template; size = sizeof(struct ieee80211_header); @@ -747,20 +813,25 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len) /* Basic Rates */ rates = (struct wl12xx_ie_rates *)ptr; rates->header.id = WLAN_EID_SUPP_RATES; - rates->header.len = wl1271_build_basic_rates(rates->rates); + rates->header.len = wl1271_build_basic_rates(rates->rates, band); size += sizeof(struct wl12xx_ie_header) + rates->header.len; ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; /* Extended rates */ rates = (struct wl12xx_ie_rates *)ptr; rates->header.id = WLAN_EID_EXT_SUPP_RATES; - rates->header.len = wl1271_build_extended_rates(rates->rates); + rates->header.len = wl1271_build_extended_rates(rates->rates, band); size += sizeof(struct wl12xx_ie_header) + rates->header.len; wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); - return wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, - &template, size); + if (band == IEEE80211_BAND_2GHZ) + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, + &template, size); + else + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, + &template, size); + return ret; } int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 91430871c8fd..33089408e759 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -39,13 +39,14 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode); int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, size_t len); int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, - u8 active_scan, u8 high_prio, u8 num_channels, + u8 active_scan, u8 high_prio, u8 band, u8 probe_requests); int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, void *buf, size_t buf_len); int wl1271_cmd_build_null_data(struct wl1271 *wl); int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); -int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len); +int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len, + u8 band); int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, const u8 *addr, @@ -343,6 +344,9 @@ struct wl1271_cmd_set_keys { #define WL1271_SCAN_OPT_PRIORITY_HIGH 4 #define WL1271_SCAN_CHAN_MIN_DURATION 30000 /* TU */ #define WL1271_SCAN_CHAN_MAX_DURATION 60000 /* TU */ +#define WL1271_SCAN_BAND_2_4_GHZ 0 +#define WL1271_SCAN_BAND_5_GHZ 1 +#define WL1271_SCAN_BAND_DUAL 2 struct basic_scan_params { u32 rx_config_options; diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 4189e97ca805..e2d7758ba1c9 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -31,19 +31,40 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, struct event_mailbox *mbox) { + int size = sizeof(struct wl12xx_probe_req_template); wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); if (wl->scanning) { - int size = sizeof(struct wl12xx_probe_req_template); - wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, - size); - mutex_unlock(&wl->mutex); - ieee80211_scan_completed(wl->hw, false); - mutex_lock(&wl->mutex); - wl->scanning = false; + if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { + wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, + NULL, size); + /* 2.4 GHz band scanned, scan 5 GHz band, pretend + * to the wl1271_cmd_scan function that we are not + * scanning as it checks that. + */ + wl->scanning = false; + wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, + wl->scan.active, + wl->scan.high_prio, + WL1271_SCAN_BAND_5_GHZ, + wl->scan.probe_requests); + } else { + if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ) + wl1271_cmd_template_set(wl, + CMD_TEMPL_CFG_PROBE_REQ_2_4, + NULL, size); + else + wl1271_cmd_template_set(wl, + CMD_TEMPL_CFG_PROBE_REQ_5, + NULL, size); + + mutex_unlock(&wl->mutex); + ieee80211_scan_completed(wl->hw, false); + mutex_lock(&wl->mutex); + wl->scanning = false; + } } - return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 6f21eeae5246..417b4152feb1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -59,6 +59,14 @@ static int wl1271_init_templates_config(struct wl1271 *wl) if (ret < 0) return ret; + if (wl1271_11a_enabled()) { + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, + NULL, + sizeof(struct wl12xx_probe_req_template)); + if (ret < 0) + return ret; + } + ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, sizeof(struct wl12xx_null_data_template)); if (ret < 0) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 9b1cc8db1ddd..ae41a7095508 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1332,13 +1332,13 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, struct wl1271 *wl = hw->priv; int ret; u8 *ssid = NULL; - size_t ssid_len = 0; + size_t len = 0; wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan"); if (req->n_ssids) { ssid = req->ssids[0].ssid; - ssid_len = req->ssids[0].ssid_len; + len = req->ssids[0].ssid_len; } mutex_lock(&wl->mutex); @@ -1347,7 +1347,12 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1271_cmd_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); + if (wl1271_11a_enabled()) + ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0, + WL1271_SCAN_BAND_DUAL, 3); + else + ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0, + WL1271_SCAN_BAND_2_4_GHZ, 3); wl1271_ps_elp_sleep(wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 7979b69ec52d..66b83e922909 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -79,6 +79,9 @@ static void wl1271_rx_status(struct wl1271 *wl, if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) status->band = IEEE80211_BAND_2GHZ; + else if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == + WL1271_RX_DESC_BAND_A) + status->band = IEEE80211_BAND_5GHZ; else wl1271_warning("unsupported band 0x%x", desc->flags & WL1271_RX_DESC_BAND_MASK); -- cgit v1.2.3 From a410264553447ff90bf13e3662684e794e5ff83e Mon Sep 17 00:00:00 2001 From: Teemu Paasikivi Date: Tue, 13 Oct 2009 12:47:51 +0300 Subject: wl1271: Added 5 GHz support to join and rx Added support to assiociate and use connection on 5 GHz band (802.11a). Signed-off-by: Teemu Paasikivi Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 13 ++++++-- drivers/net/wireless/wl12xx/wl1271_cmd.h | 1 + drivers/net/wireless/wl12xx/wl1271_rx.c | 57 ++++++++++++++++++++++++++------ 3 files changed, 58 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 6d7a40c004f1..fe4f1e64512d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -219,6 +219,7 @@ int wl1271_cmd_join(struct wl1271 *wl) join->rx_config_options = wl->rx_config; join->rx_filter_options = wl->rx_filter; + join->bss_type = wl->bss_type; /* * FIXME: disable temporarily all filters because after commit @@ -229,12 +230,20 @@ int wl1271_cmd_join(struct wl1271 *wl) join->rx_config_options = 0; join->rx_filter_options = WL1271_DEFAULT_RX_FILTER; - join->basic_rate_set = CONF_HW_BIT_RATE_1MBPS | CONF_HW_BIT_RATE_2MBPS | + if (wl->band == IEEE80211_BAND_2GHZ) + join->basic_rate_set = + CONF_HW_BIT_RATE_1MBPS | CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | CONF_HW_BIT_RATE_11MBPS; + else { + join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; + join->basic_rate_set = + CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_12MBPS | + CONF_HW_BIT_RATE_24MBPS; + } join->beacon_interval = WL1271_DEFAULT_BEACON_INT; join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; - join->bss_type = wl->bss_type; + join->channel = wl->channel; join->ssid_len = wl->ssid_len; memcpy(join->ssid, wl->ssid, wl->ssid_len); diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 33089408e759..15254fa82f6a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -198,6 +198,7 @@ enum { #define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */ #define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 +#define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10 struct wl1271_cmd_join { struct wl1271_cmd_header header; diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 66b83e922909..1dd84582ef32 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -70,6 +70,36 @@ static u8 wl1271_rx_rate_to_idx[] = { 0 /* WL1271_RATE_1 */ }; +/* The values of this table must match the wl1271_rates[] array */ +static u8 wl1271_5_ghz_rx_rate_to_idx[] = { + /* MCS rates are used only with 11n */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */ + + 7, /* WL1271_RATE_54 */ + 6, /* WL1271_RATE_48 */ + 5, /* WL1271_RATE_36 */ + 4, /* WL1271_RATE_24 */ + + /* TI-specific rate */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22 */ + + 3, /* WL1271_RATE_18 */ + 2, /* WL1271_RATE_12 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_11 */ + 1, /* WL1271_RATE_9 */ + 0, /* WL1271_RATE_6 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_5_5 */ + WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_2 */ + WL1271_RX_RATE_UNSUPPORTED /* WL1271_RATE_1 */ +}; + static void wl1271_rx_status(struct wl1271 *wl, struct wl1271_rx_descriptor *desc, struct ieee80211_rx_status *status, @@ -77,15 +107,21 @@ static void wl1271_rx_status(struct wl1271 *wl, { memset(status, 0, sizeof(struct ieee80211_rx_status)); - if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) + if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == + WL1271_RX_DESC_BAND_BG) { status->band = IEEE80211_BAND_2GHZ; - else if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == - WL1271_RX_DESC_BAND_A) + status->rate_idx = wl1271_rx_rate_to_idx[desc->rate]; + } else if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == + WL1271_RX_DESC_BAND_A) { status->band = IEEE80211_BAND_5GHZ; - else + status->rate_idx = wl1271_5_ghz_rx_rate_to_idx[desc->rate]; + } else wl1271_warning("unsupported band 0x%x", desc->flags & WL1271_RX_DESC_BAND_MASK); + if (unlikely(status->rate_idx == WL1271_RX_RATE_UNSUPPORTED)) + wl1271_warning("unsupported rate"); + /* * FIXME: Add mactime handling. For IBSS (ad-hoc) we need to get the * timestamp from the beacon (acx_tsf_info). In BSS mode (infra) we @@ -108,15 +144,14 @@ static void wl1271_rx_status(struct wl1271 *wl, if (likely(!(desc->flags & WL1271_RX_DESC_DECRYPT_FAIL))) status->flag |= RX_FLAG_DECRYPTED; - + /* FIXME: Flag should be also set when using 5 GHz band. + * At the moment chip reports MIC failed on all packets, + * so flag is silently discarded. + */ if (unlikely(desc->flags & WL1271_RX_DESC_MIC_FAIL)) - status->flag |= RX_FLAG_MMIC_ERROR; + if (status->band != IEEE80211_BAND_5GHZ) + status->flag |= RX_FLAG_MMIC_ERROR; } - - status->rate_idx = wl1271_rx_rate_to_idx[desc->rate]; - - if (status->rate_idx == WL1271_RX_RATE_UNSUPPORTED) - wl1271_warning("unsupported rate"); } static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) -- cgit v1.2.3 From 5d07b668f28175a39e4ad06eccab75e8275266d1 Mon Sep 17 00:00:00 2001 From: Teemu Paasikivi Date: Tue, 13 Oct 2009 12:47:52 +0300 Subject: wl1271: Checking of rx descriptor status fixed Fixed checking of status of the received packet. On wl1251 status is in the flags field of the descriptor, on wl1271 there is a separate status field. Signed-off-by: Teemu Paasikivi Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_rx.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 1dd84582ef32..1ea3f41912a6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -142,15 +142,10 @@ static void wl1271_rx_status(struct wl1271 *wl, if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; - if (likely(!(desc->flags & WL1271_RX_DESC_DECRYPT_FAIL))) + if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL))) status->flag |= RX_FLAG_DECRYPTED; - /* FIXME: Flag should be also set when using 5 GHz band. - * At the moment chip reports MIC failed on all packets, - * so flag is silently discarded. - */ - if (unlikely(desc->flags & WL1271_RX_DESC_MIC_FAIL)) - if (status->band != IEEE80211_BAND_5GHZ) - status->flag |= RX_FLAG_MMIC_ERROR; + if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL)) + status->flag |= RX_FLAG_MMIC_ERROR; } } -- cgit v1.2.3 From 7444113017b9d5394dc8c4bdf577f9567502417b Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:53 +0300 Subject: wl1271: Fix multicast list handling Fixes bugs in the multicast list handling: - Use atomic memory allocation in non-sleepable context - Increment address pointer when iterating list of MC addresses Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index ae41a7095508..19dbdb1b38ab 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1160,7 +1160,7 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, * configure_filter() instead of saving everything in the context. */ - fp = kzalloc(sizeof(*fp), GFP_KERNEL); + fp = kzalloc(sizeof(*fp), GFP_ATOMIC); if (!fp) { wl1271_error("Out of memory setting filters."); return 0; @@ -1180,6 +1180,7 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, fp->mc_list_length++; } else wl1271_warning("Unknown mc address length."); + mc_list = mc_list->next; } /* FIXME: We still need to set our filters properly */ -- cgit v1.2.3 From 1fd2794f36913992798184c464fe8f85753b13e0 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:54 +0300 Subject: wl1271: Fix event handling mechanism The event handling mechanism could miss events if multiple events would occur simultaneously. Fix event handling mechanism to process all events. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_event.c | 6 ++++-- drivers/net/wireless/wl12xx/wl1271_event.h | 2 +- drivers/net/wireless/wl12xx/wl1271_main.c | 17 +++++++++-------- 3 files changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index e2d7758ba1c9..a4b11e43f0db 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -126,7 +126,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl) wl->mbox_ptr[0], wl->mbox_ptr[1]); } -int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) +int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack) { struct event_mailbox mbox; int ret; @@ -146,7 +146,9 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) return ret; /* then we let the firmware know it can go on...*/ - wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); + if (do_ack) + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, + INTR_TRIG_EVENT_ACK); return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h index 2cdce7c34bf0..adc4653b2616 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.h +++ b/drivers/net/wireless/wl12xx/wl1271_event.h @@ -105,6 +105,6 @@ struct event_mailbox { int wl1271_event_unmask(struct wl1271 *wl); void wl1271_event_mbox_config(struct wl1271 *wl); -int wl1271_event_handle(struct wl1271 *wl, u8 mbox); +int wl1271_event_handle(struct wl1271 *wl, u8 mbox, bool do_ack); #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 19dbdb1b38ab..d6d1a4c1b114 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -437,14 +437,15 @@ static void wl1271_irq_work(struct work_struct *work) intr &= WL1271_INTR_MASK; - if (intr & (WL1271_ACX_INTR_EVENT_A | - WL1271_ACX_INTR_EVENT_B)) { - wl1271_debug(DEBUG_IRQ, - "WL1271_ACX_INTR_EVENT (0x%x)", intr); - if (intr & WL1271_ACX_INTR_EVENT_A) - wl1271_event_handle(wl, 0); - else - wl1271_event_handle(wl, 1); + if (intr & WL1271_ACX_INTR_EVENT_A) { + bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true; + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); + wl1271_event_handle(wl, 0, do_ack); + } + + if (intr & WL1271_ACX_INTR_EVENT_B) { + wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); + wl1271_event_handle(wl, 1, true); } if (intr & WL1271_ACX_INTR_INIT_COMPLETE) -- cgit v1.2.3 From 01c09162cd6170f3671825d6d5f2c1ae7b27cbf3 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:55 +0300 Subject: wl1271: Support for IPv4 ARP filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for IPv4 ARP filtering in the driver. This will dramatically reduce the number of unnecessary interrupts by the device in conqested networks. This patch is based on a similar patch to wl1251 by Janne Ylälehto. Cc: Janne Ylälehto Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 2 + drivers/net/wireless/wl12xx/wl1271_acx.c | 38 ++++++++++++ drivers/net/wireless/wl12xx/wl1271_acx.h | 17 +++++ drivers/net/wireless/wl12xx/wl1271_main.c | 100 ++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 79a732443151..1e399a2a7f6b 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -441,6 +441,8 @@ struct wl1271 { /* Current chipset configuration */ struct conf_drv_settings conf; + + struct list_head list; }; int wl1271_plt_start(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 44a1237fa794..e891cd5bd25c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -1092,3 +1092,41 @@ out: kfree(acx); return ret; } + +int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address, + u8 version) +{ + struct wl1271_acx_arp_filter *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->version = version; + acx->enable = enable; + + if (enable == true) { + if (version == ACX_IPV4_VERSION) + memcpy(acx->address, address, ACX_IPV4_ADDR_SIZE); + else if (version == ACX_IPV6_VERSION) + memcpy(acx->address, address, sizeof(acx->address)); + else + wl1271_error("Invalid IP version"); + } + + ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("failed to set arp ip filter: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 29fd3635e383..15803146d509 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -955,6 +955,21 @@ struct wl1271_acx_bet_enable { u8 padding[2]; } __attribute__ ((packed)); +#define ACX_IPV4_VERSION 4 +#define ACX_IPV6_VERSION 6 +#define ACX_IPV4_ADDR_SIZE 4 +struct wl1271_acx_arp_filter { + struct acx_header header; + u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */ + u8 enable; /* 1 to enable ARP filtering, 0 to disable */ + u8 padding[2]; + u8 address[16]; /* The configured device IP address - all ARP + requests directed to this IP address will pass + through. For IPv4, the first four bytes are + used. */ +} __attribute__((packed)); + + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -1064,5 +1079,7 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl); int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); int wl1271_acx_smart_reflex(struct wl1271 *wl); int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); +int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address, + u8 version); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d6d1a4c1b114..7d70f4168b2f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "wl1271.h" #include "wl12xx_80211.h" @@ -325,6 +326,8 @@ static struct conf_drv_settings default_conf = { } }; +static LIST_HEAD(wl_list); + static void wl1271_conf_init(struct wl1271 *wl) { @@ -843,6 +846,93 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } +static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, + void *arg) +{ + struct net_device *dev; + struct wireless_dev *wdev; + struct wiphy *wiphy; + struct ieee80211_hw *hw; + struct wl1271 *wl; + struct wl1271 *wl_temp; + struct in_device *idev; + struct in_ifaddr *ifa = arg; + int ret = 0; + + /* FIXME: this ugly function should probably be implemented in the + * mac80211, and here should only be a simple callback handling actual + * setting of the filters. Now we need to dig up references to + * various structures to gain access to what we need. + * Also, because of this, there is no "initial" setting of the filter + * in "op_start", because we don't want to dig up struct net_device + * there - the filter will be set upon first change of the interface + * IP address. */ + + dev = ifa->ifa_dev->dev; + + wdev = dev->ieee80211_ptr; + if (wdev == NULL) + return -ENODEV; + + wiphy = wdev->wiphy; + if (wiphy == NULL) + return -ENODEV; + + hw = wiphy_priv(wiphy); + if (hw == NULL) + return -ENODEV; + + /* Check that the interface is one supported by this driver. */ + wl_temp = hw->priv; + list_for_each_entry(wl, &wl_list, list) { + if (wl == wl_temp) + break; + } + if (wl == NULL) + return -ENODEV; + + /* Get the interface IP address for the device. "ifa" will become + NULL if: + - there is no IPV4 protocol address configured + - there are multiple (virtual) IPV4 addresses configured + When "ifa" is NULL, filtering will be disabled. + */ + ifa = NULL; + idev = dev->ip_ptr; + if (idev) + ifa = idev->ifa_list; + + if (ifa && ifa->ifa_next) + ifa = NULL; + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + if (ifa) + ret = wl1271_acx_arp_ip_filter(wl, true, + (u8 *)&ifa->ifa_address, + ACX_IPV4_VERSION); + else + ret = wl1271_acx_arp_ip_filter(wl, false, NULL, + ACX_IPV4_VERSION); + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); + + return ret; +} + +static struct notifier_block wl1271_dev_notifier = { + .notifier_call = wl1271_dev_notify, +}; + + static int wl1271_op_start(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; @@ -886,6 +976,11 @@ out_power_off: out: mutex_unlock(&wl->mutex); + if (!ret) { + list_add(&wl->list, &wl_list); + register_inetaddr_notifier(&wl1271_dev_notifier); + } + return ret; } @@ -906,6 +1001,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->filter_params = NULL; spin_unlock_irqrestore(&wl->wl_lock, flags); + unregister_inetaddr_notifier(&wl1271_dev_notifier); + list_del(&wl->list); + mutex_lock(&wl->mutex); WARN_ON(wl->state != WL1271_STATE_ON); @@ -1754,6 +1852,8 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl = hw->priv; memset(wl, 0, sizeof(*wl)); + INIT_LIST_HEAD(&wl->list); + wl->hw = hw; dev_set_drvdata(&spi->dev, wl); wl->spi = spi; -- cgit v1.2.3 From a163acce485a9629418659ff74737b89ba2c1751 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:56 +0300 Subject: wl1271: Remove unnecessary rx_descriptor memory allocation Remove unnecessary RX descriptor memory allocation from the driver. The allocation was a remnant of the wl1251 driver. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 1 - drivers/net/wireless/wl12xx/wl1271_main.c | 13 ------------- 2 files changed, 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 1e399a2a7f6b..fca59687041e 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -429,7 +429,6 @@ struct wl1271 { u32 buffer_32; u32 buffer_cmd; u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; - struct wl1271_rx_descriptor *rx_descriptor; struct wl1271_fw_status *fw_status; struct wl1271_tx_hw_res_if *tx_res_if; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7d70f4168b2f..dfa08a188632 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1893,13 +1893,6 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->state = WL1271_STATE_OFF; mutex_init(&wl->mutex); - wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL); - if (!wl->rx_descriptor) { - wl1271_error("could not allocate memory for rx descriptor"); - ret = -ENOMEM; - goto out_free; - } - /* This is the only SPI value that we need to set here, the rest * comes from the board-peripherals file */ spi->bits_per_word = 32; @@ -1965,9 +1958,6 @@ static int __devinit wl1271_probe(struct spi_device *spi) free_irq(wl->irq, wl); out_free: - kfree(wl->rx_descriptor); - wl->rx_descriptor = NULL; - ieee80211_free_hw(hw); return ret; @@ -1988,9 +1978,6 @@ static int __devexit wl1271_remove(struct spi_device *spi) kfree(wl->nvs); wl->nvs = NULL; - kfree(wl->rx_descriptor); - wl->rx_descriptor = NULL; - kfree(wl->fw_status); kfree(wl->tx_res_if); -- cgit v1.2.3 From ed317788b925cfd896506ee775acca7392470b9b Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:57 +0300 Subject: wl1271: Correct memory handling for FW boot Several memory allocation related failure cases were not properly handled by the driver - the result was that in low memory conditions booting of a corrupted FW could be attempted - and user space would not get proper failure code. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_boot.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index b8a37a84842f..41a3050afae1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -134,7 +134,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, } chunk = kmalloc(CHUNK_SIZE, GFP_KERNEL); - if (!buf) { + if (!chunk) { wl1271_error("allocation for firmware upload chunk failed"); return -ENOMEM; } @@ -184,6 +184,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, static int wl1271_boot_upload_firmware(struct wl1271 *wl) { u32 chunks, addr, len; + int ret = 0; u8 *fw; fw = wl->fw; @@ -204,11 +205,13 @@ static int wl1271_boot_upload_firmware(struct wl1271 *wl) } wl1271_debug(DEBUG_BOOT, "chunk %d addr 0x%x len %u", chunks, addr, len); - wl1271_boot_upload_firmware_chunk(wl, fw, len, addr); + ret = wl1271_boot_upload_firmware_chunk(wl, fw, len, addr); + if (ret != 0) + break; fw += len; } - return 0; + return ret; } static int wl1271_boot_upload_nvs(struct wl1271 *wl) @@ -284,6 +287,8 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) /* Copy the NVS tables to a new block to ensure alignment */ nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); + if (!nvs_aligned) + return -ENOMEM; /* And finally we upload the NVS tables */ /* FIXME: In wl1271, we upload everything at once. -- cgit v1.2.3 From bd5ea18f7b47b5397233301920180128793295a2 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 13 Oct 2009 12:47:58 +0300 Subject: wl1271: make sure PS is disabled in PLT We cannot be in PS mode when running PLT tests, so we need to make sure we're in active mode. Also, we need to clear up the rx_counter when we stop PLT, otherwise it could cause problems when entering PLT again. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index dfa08a188632..7b8d2799f23e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -774,6 +774,11 @@ int wl1271_plt_start(struct wl1271 *wl) if (ret < 0) goto out_irq_disable; + /* Make sure power saving is disabled */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + if (ret < 0) + goto out_irq_disable; + goto out; out_irq_disable: @@ -807,6 +812,7 @@ int wl1271_plt_stop(struct wl1271 *wl) wl1271_power_off(wl); wl->state = WL1271_STATE_OFF; + wl->rx_counter = 0; out: mutex_unlock(&wl->mutex); -- cgit v1.2.3 From b54853f1b157a173fe5ac9145623670c66a9e7b9 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 13 Oct 2009 12:47:59 +0300 Subject: wl1271: Fix filter configuration Fix the filter configuration to properly work with the two phase filter configuration (prepare_multicast/configure_filter.) Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 3 - drivers/net/wireless/wl12xx/wl1271_main.c | 157 ++++++++++-------------------- 2 files changed, 51 insertions(+), 109 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index fca59687041e..1309b20e4d5b 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -363,9 +363,6 @@ struct wl1271 { struct work_struct tx_work; - struct work_struct filter_work; - struct wl1271_filter_params *filter_params; - /* Pending TX frames */ struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 7b8d2799f23e..ee7ffafaa274 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -675,74 +675,6 @@ out: return ret; } -struct wl1271_filter_params { - unsigned int filters; - unsigned int changed; - int mc_list_length; - u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; -}; - -#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ - FIF_FCSFAIL | \ - FIF_BCN_PRBRESP_PROMISC | \ - FIF_CONTROL | \ - FIF_OTHER_BSS) - -static void wl1271_filter_work(struct work_struct *work) -{ - struct wl1271 *wl = - container_of(work, struct wl1271, filter_work); - struct wl1271_filter_params *fp; - unsigned long flags; - bool enabled = true; - int ret; - - /* first, get the filter parameters */ - spin_lock_irqsave(&wl->wl_lock, flags); - fp = wl->filter_params; - wl->filter_params = NULL; - spin_unlock_irqrestore(&wl->wl_lock, flags); - - if (!fp) - return; - - /* then, lock the mutex without risk of lock-up */ - mutex_lock(&wl->mutex); - - if (wl->state == WL1271_STATE_OFF) - goto out; - - ret = wl1271_ps_elp_wakeup(wl, false); - if (ret < 0) - goto out; - - /* configure the mc filter regardless of the changed flags */ - if (fp->filters & FIF_ALLMULTI) - enabled = false; - - ret = wl1271_acx_group_address_tbl(wl, enabled, - fp->mc_list, fp->mc_list_length); - if (ret < 0) - goto out_sleep; - - /* determine, whether supported filter values have changed */ - if (fp->changed == 0) - goto out; - - /* apply configured filters */ - ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1271_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); - kfree(fp); -} - int wl1271_plt_start(struct wl1271 *wl) { int ret; @@ -993,20 +925,12 @@ out: static void wl1271_op_stop(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; - unsigned long flags; int i; wl1271_info("down"); wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); - /* complete/cancel ongoing work */ - cancel_work_sync(&wl->filter_work); - spin_lock_irqsave(&wl->wl_lock, flags); - kfree(wl->filter_params); - wl->filter_params = NULL; - spin_unlock_irqrestore(&wl->wl_lock, flags); - unregister_inetaddr_notifier(&wl1271_dev_notifier); list_del(&wl->list); @@ -1029,7 +953,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->tx_work); - cancel_work_sync(&wl->filter_work); mutex_lock(&wl->mutex); @@ -1252,19 +1175,18 @@ out: return ret; } +struct wl1271_filter_params { + bool enabled; + int mc_list_length; + u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; +}; + static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mc_list) { - struct wl1271 *wl = hw->priv; struct wl1271_filter_params *fp; - unsigned long flags; int i; - /* - * FIXME: we should return a hash that will be passed to - * configure_filter() instead of saving everything in the context. - */ - fp = kzalloc(sizeof(*fp), GFP_ATOMIC); if (!fp) { wl1271_error("Out of memory setting filters."); @@ -1272,9 +1194,10 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, } /* update multicast filtering parameters */ + fp->enabled = true; if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) { mc_count = 0; - fp->filters |= FIF_ALLMULTI; + fp->enabled = false; } fp->mc_list_length = 0; @@ -1288,42 +1211,65 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, mc_list = mc_list->next; } - /* FIXME: We still need to set our filters properly */ - - spin_lock_irqsave(&wl->wl_lock, flags); - kfree(wl->filter_params); - wl->filter_params = fp; - spin_unlock_irqrestore(&wl->wl_lock, flags); - - return 1; + return (u64)(unsigned long)fp; } +#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_CONTROL | \ + FIF_OTHER_BSS) + static void wl1271_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, unsigned int *total, u64 multicast) { + struct wl1271_filter_params *fp = (void *)(unsigned long)multicast; struct wl1271 *wl = hw->priv; + int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter"); + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) + goto out; + + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + *total &= WL1271_SUPPORTED_FILTERS; changed &= WL1271_SUPPORTED_FILTERS; - if (!multicast) - return; + if (*total & FIF_ALLMULTI) + ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0); + else if (fp) + ret = wl1271_acx_group_address_tbl(wl, fp->enabled, + fp->mc_list, + fp->mc_list_length); + if (ret < 0) + goto out_sleep; - /* - * FIXME: for now we are still using a workqueue for filter - * configuration, but with the new mac80211, this is not needed, - * since configure_filter can now sleep. We now have - * prepare_multicast, which needs to be atomic instead. - */ + kfree(fp); + + /* FIXME: We still need to set our filters properly */ - /* store current filter config */ - wl->filter_params->filters = *total; - wl->filter_params->changed = changed; + /* determine, whether supported filter values have changed */ + if (changed == 0) + goto out_sleep; - ieee80211_queue_work(wl->hw, &wl->filter_work); + /* apply configured filters */ + ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); } static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -1866,7 +1812,6 @@ static int __devinit wl1271_probe(struct spi_device *spi) skb_queue_head_init(&wl->tx_queue); - INIT_WORK(&wl->filter_work, wl1271_filter_work); INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); wl->channel = WL1271_DEFAULT_CHANNEL; wl->scanning = false; -- cgit v1.2.3 From 40f54242ae2d2b958b6ae7644f58de9e8a48992a Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 13 Oct 2009 20:41:20 +0300 Subject: wl1251: rename spi device to wl1251 During rename of the driver from wl12xx to wl1251 the spi device name was accidentally left as wl12xx. Rename it to wl1251 which is the proper name of the driver. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 2 +- drivers/net/wireless/wl12xx/wl1251_spi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 1103256ad989..23ac50303757 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1426,4 +1426,4 @@ EXPORT_SYMBOL_GPL(wl1251_free_hw); MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kalle Valo "); -MODULE_ALIAS("spi:wl12xx"); +MODULE_ALIAS("spi:wl1251"); diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 14eff2b3d4c6..2cf8a2169d43 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -307,7 +307,7 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi) static struct spi_driver wl1251_spi_driver = { .driver = { - .name = "wl12xx", + .name = "wl1251", .bus = &spi_bus_type, .owner = THIS_MODULE, }, -- cgit v1.2.3 From 6d898b1983b62ad52f862014748ddce35aad005a Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 14 Oct 2009 16:49:53 +0200 Subject: libertas: make __lbs_cmd_async() non-static This function will be needed for the cfg80211-enabled libertas driver. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/cmd.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 0fb312576b8d..eb0bce338e55 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -2118,7 +2118,7 @@ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, } -static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, +struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), unsigned long callback_arg) diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 392e578ca095..2730c6aadfd2 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -26,6 +26,11 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), unsigned long callback_arg); +struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, + uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), + unsigned long callback_arg); + int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, int8_t p2); -- cgit v1.2.3 From e307fcf0a10f9c0c21b3d8b2ff7862b29796cc7f Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Wed, 14 Oct 2009 23:04:45 +0800 Subject: ath9k: adjust ahb callbacks to new struct layout to avoid compile errors Signed-off-by: Marek Lindner Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 33c9e8167185..25531f231b67 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -29,15 +29,13 @@ static void ath_ahb_read_cachesize(struct ath_common *common, int *csz) static void ath_ahb_cleanup(struct ath_common *common) { - struct ath_hw *ah = (struct ath_hw *) common->ah; - struct ath_softc *sc = ah->ah_sc; + struct ath_softc *sc = (struct ath_softc *)common->priv; iounmap(sc->mem); } static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_hw *ah = (struct ath_hw *) common->ah; - struct ath_softc *sc = ah->ah_sc; + struct ath_softc *sc = (struct ath_softc *)common->priv; struct platform_device *pdev = to_platform_device(sc->dev); struct ath9k_platform_data *pdata; -- cgit v1.2.3 From e5e2647fd6ceef2cdc479954b84517535eb7febd Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 14 Oct 2009 14:16:30 -0400 Subject: ath5k: use noise calibration from madwifi hal This updates ath5k to calibrate the noise floor similar to the way it is done in the madwifi hal and ath9k. Of note: - we start NF measurement at the same time as AGC calibration, but do not actually read the value until the periodic (long) calibration - we keep a history of the last few values read and write the median back to the hardware for CCA - we do not complain if NF calibration isn't complete, instead we keep the last read value. Signed-off-by: Bob Copeland Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 13 +++ drivers/net/wireless/ath/ath5k/attach.c | 2 + drivers/net/wireless/ath/ath5k/phy.c | 185 ++++++++++++++++++++++---------- drivers/net/wireless/ath/ath5k/reg.h | 11 +- drivers/net/wireless/ath/ath5k/reset.c | 17 +-- 5 files changed, 148 insertions(+), 80 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 647d826bf5fb..6a2a96761111 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -198,6 +198,7 @@ #define AR5K_TUNE_CWMAX_11B 1023 #define AR5K_TUNE_CWMAX_XR 7 #define AR5K_TUNE_NOISE_FLOOR -72 +#define AR5K_TUNE_CCA_MAX_GOOD_VALUE -95 #define AR5K_TUNE_MAX_TXPOWER 63 #define AR5K_TUNE_DEFAULT_TXPOWER 25 #define AR5K_TUNE_TPC_TXPOWER false @@ -1006,6 +1007,14 @@ struct ath5k_capabilities { } cap_queues; }; +/* size of noise floor history (keep it a power of two) */ +#define ATH5K_NF_CAL_HIST_MAX 8 +struct ath5k_nfcal_hist +{ + s16 index; /* current index into nfval */ + s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */ +}; + /***************************************\ HARDWARE ABSTRACTION LAYER STRUCTURE @@ -1112,6 +1121,8 @@ struct ath5k_hw { struct ieee80211_channel r_last_channel; } ah_radar; + struct ath5k_nfcal_hist ah_nfcal_hist; + /* noise floor from last periodic calibration */ s32 ah_noise_floor; @@ -1274,8 +1285,10 @@ extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah); extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); /* PHY calibration */ +void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah); extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); +extern s16 ath5k_hw_get_noise_floor(struct ath5k_hw *ah); extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah); /* Spur mitigation */ bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 92995adeb5cd..42284445b75e 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -331,6 +331,8 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ath5k_hw_rfgain_opt_init(ah); + ath5k_hw_init_nfcal_hist(ah); + /* turn on HW LEDs */ ath5k_hw_set_ledstate(ah, AR5K_LED_INIT); diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 1a039f2bd732..895990751d36 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1124,77 +1124,148 @@ ath5k_hw_calibration_poll(struct ath5k_hw *ah) ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION; AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); } +} +static int sign_extend(int val, const int nbits) +{ + int order = BIT(nbits-1); + return (val ^ order) - order; } -/** - * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration - * - * @ah: struct ath5k_hw pointer we are operating on - * @freq: the channel frequency, just used for error logging - * - * This function performs a noise floor calibration of the PHY and waits for - * it to complete. Then the noise floor value is compared to some maximum - * noise floor we consider valid. - * - * Note that this is different from what the madwifi HAL does: it reads the - * noise floor and afterwards initiates the calibration. Since the noise floor - * calibration can take some time to finish, depending on the current channel - * use, that avoids the occasional timeout warnings we are seeing now. - * - * See the following link for an Atheros patent on noise floor calibration: - * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \ - * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7 +static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah) +{ + s32 val; + + val = ath5k_hw_reg_read(ah, AR5K_PHY_NF); + return sign_extend(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 9); +} + +void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah) +{ + int i; + + ah->ah_nfcal_hist.index = 0; + for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++) + ah->ah_nfcal_hist.nfval[i] = AR5K_TUNE_CCA_MAX_GOOD_VALUE; +} + +static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor) +{ + struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist; + hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX-1); + hist->nfval[hist->index] = noise_floor; +} + +static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) +{ + s16 sort[ATH5K_NF_CAL_HIST_MAX]; + s16 tmp; + int i, j; + + memcpy(sort, ah->ah_nfcal_hist.nfval, sizeof(sort)); + for (i = 0; i < ATH5K_NF_CAL_HIST_MAX - 1; i++) { + for (j = 1; j < ATH5K_NF_CAL_HIST_MAX - i; j++) { + if (sort[j] > sort[j-1]) { + tmp = sort[j]; + sort[j] = sort[j-1]; + sort[j-1] = tmp; + } + } + } + for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++) { + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "cal %d:%d\n", i, sort[i]); + } + return sort[(ATH5K_NF_CAL_HIST_MAX-1) / 2]; +} + +/* + * When we tell the hardware to perform a noise floor calibration + * by setting the AR5K_PHY_AGCCTL_NF bit, it will periodically + * sample-and-hold the minimum noise level seen at the antennas. + * This value is then stored in a ring buffer of recently measured + * noise floor values so we have a moving window of the last few + * samples. * - * XXX: Since during noise floor calibration antennas are detached according to - * the patent, we should stop tx queues here. + * The median of the values in the history is then loaded into the + * hardware for its own use for RSSI and CCA measurements. */ -int -ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) +void ath5k_hw_update_noise_floor(struct ath5k_hw *ah) { - int ret; - unsigned int i; - s32 noise_floor; + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 val; + s16 nf, threshold; + u8 ee_mode; - /* - * Enable noise floor calibration - */ - AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_NF); + /* keep last value if calibration hasn't completed */ + if (ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL) & AR5K_PHY_AGCCTL_NF) { + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "NF did not complete in calibration window\n"); - ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_NF, 0, false); - if (ret) { - ATH5K_ERR(ah->ah_sc, - "noise floor calibration timeout (%uMHz)\n", freq); - return -EAGAIN; + return; } - /* Wait until the noise floor is calibrated and read the value */ - for (i = 20; i > 0; i--) { - mdelay(1); - noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF); - noise_floor = AR5K_PHY_NF_RVAL(noise_floor); - if (noise_floor & AR5K_PHY_NF_ACTIVE) { - noise_floor = AR5K_PHY_NF_AVAL(noise_floor); - - if (noise_floor <= AR5K_TUNE_NOISE_FLOOR) - break; - } + switch (ah->ah_current_channel->hw_value & CHANNEL_MODES) { + case CHANNEL_A: + case CHANNEL_T: + case CHANNEL_XR: + ee_mode = AR5K_EEPROM_MODE_11A; + break; + case CHANNEL_G: + case CHANNEL_TG: + ee_mode = AR5K_EEPROM_MODE_11G; + break; + default: + case CHANNEL_B: + ee_mode = AR5K_EEPROM_MODE_11B; + break; } - ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, - "noise floor %d\n", noise_floor); - if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { - ATH5K_ERR(ah->ah_sc, - "noise floor calibration failed (%uMHz)\n", freq); - return -EAGAIN; + /* completed NF calibration, test threshold */ + nf = ath5k_hw_read_measured_noise_floor(ah); + threshold = ee->ee_noise_floor_thr[ee_mode]; + + if (nf > threshold) { + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "noise floor failure detected; " + "read %d, threshold %d\n", + nf, threshold); + + nf = AR5K_TUNE_CCA_MAX_GOOD_VALUE; } - ah->ah_noise_floor = noise_floor; + ath5k_hw_update_nfcal_hist(ah, nf); + nf = ath5k_hw_get_median_noise_floor(ah); - return 0; + /* load noise floor (in .5 dBm) so the hardware will use it */ + val = ath5k_hw_reg_read(ah, AR5K_PHY_NF) & ~AR5K_PHY_NF_M; + val |= (nf * 2) & AR5K_PHY_NF_M; + ath5k_hw_reg_write(ah, val, AR5K_PHY_NF); + + AR5K_REG_MASKED_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF, + ~(AR5K_PHY_AGCCTL_NF_EN | AR5K_PHY_AGCCTL_NF_NOUPDATE)); + + ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF, + 0, false); + + /* + * Load a high max CCA Power value (-50 dBm in .5 dBm units) + * so that we're not capped by the median we just loaded. + * This will be used as the initial value for the next noise + * floor calibration. + */ + val = (val & ~AR5K_PHY_NF_M) | ((-50 * 2) & AR5K_PHY_NF_M); + ath5k_hw_reg_write(ah, val, AR5K_PHY_NF); + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_NF_EN | + AR5K_PHY_AGCCTL_NF_NOUPDATE | + AR5K_PHY_AGCCTL_NF); + + ah->ah_noise_floor = nf; + + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "noise floor calibrated: %d\n", nf); } /* @@ -1287,7 +1358,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, return ret; } - ath5k_hw_noise_floor_calibration(ah, channel->center_freq); + ath5k_hw_update_noise_floor(ah); /* * Re-enable RX/TX and beacons @@ -1360,7 +1431,7 @@ done: * since noise floor calibration interrupts rx path while I/Q * calibration doesn't. We don't need to run noise floor calibration * as often as I/Q calibration.*/ - ath5k_hw_noise_floor_calibration(ah, channel->center_freq); + ath5k_hw_update_noise_floor(ah); /* Initiate a gain_F calibration */ ath5k_hw_request_rfgain_probe(ah); diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 64227abe3c20..4cb9c5df9f46 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -2033,17 +2033,14 @@ #define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */ /* - * PHY noise floor status register + * PHY noise floor status register (CCA = Clear Channel Assessment) */ #define AR5K_PHY_NF 0x9864 /* Register address */ -#define AR5K_PHY_NF_M 0x000001ff /* Noise floor mask */ -#define AR5K_PHY_NF_ACTIVE 0x00000100 /* Noise floor calibration still active */ -#define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M) -#define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1) -#define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9)) +#define AR5K_PHY_NF_M 0x000001ff /* Noise floor, written to hardware in 1/2 dBm units */ +#define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9)) #define AR5K_PHY_NF_THRESH62 0x0007f000 /* Thresh62 -check ANI patent- (field) */ #define AR5K_PHY_NF_THRESH62_S 12 -#define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* ??? */ +#define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* Minimum measured noise level, read from hardware in 1 dBm units */ #define AR5K_PHY_NF_MINCCA_PWR_S 19 /* diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 3dab3d856d7b..62954fc77869 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1293,7 +1293,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, * out and/or noise floor calibration might timeout. */ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, - AR5K_PHY_AGCCTL_CAL); + AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF); /* At the same time start I/Q calibration for QAM constellation * -no need for CCK- */ @@ -1314,21 +1314,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, channel->center_freq); } - /* - * If we run NF calibration before AGC, it always times out. - * Binary HAL starts NF and AGC calibration at the same time - * and only waits for AGC to finish. Also if AGC or NF cal. - * times out, reset doesn't fail on binary HAL. I believe - * that's wrong because since rx path is routed to a detector, - * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211 - * enables noise floor calibration after offset calibration and if noise - * floor calibration fails, reset fails. I believe that's - * a better approach, we just need to find a polling interval - * that suits best, even if reset continues we need to make - * sure that rx path is ready. - */ - ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - /* Restore antenna mode */ ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); -- cgit v1.2.3 From 7a38079e0da19447ab1c41e42094b311c6e945e4 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Thu, 15 Oct 2009 10:33:26 +0300 Subject: wl1271: Set IEEE80211_FCTL_TODS in the null data template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the IEEE80211_FCTL_TODS bit in the FC of the null data template. This is a mandatory requirement in specification. Signed-off-by: Juuso Oikarinen Cc: Vidhya Govindan Cc: Janne Ylälehto Reviewed-by: Janne Ylalehto Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index fe4f1e64512d..1d64aa47a630 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -769,7 +769,8 @@ int wl1271_cmd_build_null_data(struct wl1271 *wl) memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_NULLFUNC); + IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template, sizeof(template)); -- cgit v1.2.3 From 938e30c9301fbd7c3677d01ad01c7eb4ad78b998 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 15 Oct 2009 10:33:27 +0300 Subject: wl1271: fix sparse warnings about undeclared functions The following sparse warnings were fixed: drivers/net/wireless/wl12xx/wl1271_spi.c:199:6: warning: symbol 'wl1271_spi_read_busy' was not declared. Should it be static? drivers/net/wireless/wl12xx/wl1271_cmd.c:84:5: warning: symbol 'wl1271_cmd_cal_channel_tune' was not declared. Should it be static? drivers/net/wireless/wl12xx/wl1271_cmd.c:107:5: warning: symbol 'wl1271_cmd_cal_update_ref_point' was not declared. Should it be static? drivers/net/wireless/wl12xx/wl1271_cmd.c:132:5: warning: symbol 'wl1271_cmd_cal_p2g' was not declared. Should it be static? drivers/net/wireless/wl12xx/wl1271_cmd.c:153:5: warning: symbol 'wl1271_cmd_cal' was not declared. Should it be static? Reported-by: Johannes Berg Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 8 ++++---- drivers/net/wireless/wl12xx/wl1271_spi.c | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 1d64aa47a630..195eee70e36e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -81,7 +81,7 @@ out: return ret; } -int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) +static int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) { struct wl1271_cmd_cal_channel_tune *cmd; int ret = 0; @@ -104,7 +104,7 @@ int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) return ret; } -int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) +static int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) { struct wl1271_cmd_cal_update_ref_point *cmd; int ret = 0; @@ -129,7 +129,7 @@ int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) return ret; } -int wl1271_cmd_cal_p2g(struct wl1271 *wl) +static int wl1271_cmd_cal_p2g(struct wl1271 *wl) { struct wl1271_cmd_cal_p2g *cmd; int ret = 0; @@ -150,7 +150,7 @@ int wl1271_cmd_cal_p2g(struct wl1271 *wl) return ret; } -int wl1271_cmd_cal(struct wl1271 *wl) +static int wl1271_cmd_cal(struct wl1271 *wl) { /* * FIXME: we must make sure that we're not sleeping when calibration diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 3c5aa584574b..02978a16e732 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c @@ -196,7 +196,9 @@ int wl1271_set_partition(struct wl1271 *wl, #define WL1271_BUSY_WORD_TIMEOUT 1000 -void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len) +/* FIXME: Check busy words, removed due to SPI bug */ +#if 0 +static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len) { struct spi_transfer t[1]; struct spi_message m; @@ -256,6 +258,7 @@ void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len) memset(buf, 0, len); wl1271_error("SPI read busy-word timeout!\n"); } +#endif void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) -- cgit v1.2.3 From 0b5b72da1b21fe61926318dd842f6dd7c8862e9f Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 15 Oct 2009 10:33:28 +0300 Subject: wl1271: added missing packed modifier in some acx structs Some of the struct definitions in the wl1271_acx.h file were missing the __attribute__ ((packed)) modifier. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 15803146d509..5085497d1339 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -75,7 +75,7 @@ struct acx_header { /* payload length (not including headers */ u16 len; -}; +} __attribute__ ((packed)); struct acx_error_counter { struct acx_header header; @@ -390,7 +390,7 @@ struct acx_conn_monit_params { u32 synch_fail_thold; /* number of beacons missed */ u32 bss_lose_timeout; /* number of TU's from synch fail */ -}; +} __attribute__ ((packed)); enum { SG_ENABLE = 0, @@ -420,19 +420,19 @@ struct acx_smart_reflex_state { u8 enable; u8 padding[3]; -}; +} __attribute__ ((packed)); struct smart_reflex_err_table { u8 len; s8 upper_limit; s8 values[14]; -}; +} __attribute__ ((packed)); struct acx_smart_reflex_config_params { struct acx_header header; struct smart_reflex_err_table error_table[3]; -}; +} __attribute__ ((packed)); #define PTA_ANTENNA_TYPE_DEF (0) #define PTA_BT_HP_MAXTIME_DEF (2000) -- cgit v1.2.3 From d0f63b202146f3281800ee44823740c8bbf38f11 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 15 Oct 2009 10:33:29 +0300 Subject: wl1271: fix endianess issues We were not handling endianess correctly. The wl1271 chip runs on little-endian values. This patch makes sure that all the communication with the wl1271 firmware is done in little-endian by using cpu_to_le* and le*_to_cpu where appropriate. Also, all the struct definitions for data exchanged with the firmware has been changed to use __le16/32 types instead of u16/32. This fixes a few sparse warnings, such as these: drivers/net/wireless/wl12xx/wl1271_cmd.c:554:42: warning: incorrect type in assignment (different base types) drivers/net/wireless/wl12xx/wl1271_cmd.c:555:42: warning: incorrect type in assignment (different base types) drivers/net/wireless/wl12xx/wl1271_cmd.c:577:58: warning: incorrect type in assignment (different base types) drivers/net/wireless/wl12xx/wl1271_cmd.c:579:58: warning: incorrect type in assignment (different base types) drivers/net/wireless/wl12xx/wl1271_cmd.c:676:18: warning: incorrect type in assignment (different base types) drivers/net/wireless/wl12xx/wl1271_cmd.c:787:22: warning: incorrect type in assignment (different base types) drivers/net/wireless/wl12xx/wl1271_cmd.c:789:21: warning: incorrect type in assignment (different base types) drivers/net/wireless/wl12xx/wl1271_tx.c:98:47: warning: incorrect type in argument 1 (different base types) drivers/net/wireless/wl12xx/wl1271_acx.c:932:32: warning: incorrect type in assignment (different base types) drivers/net/wireless/wl12xx/wl1271_boot.c:191:32: warning: incorrect type in argument 1 (different base types) drivers/net/wireless/wl12xx/wl1271_boot.c:197:38: warning: incorrect type in argument 1 (different base types) drivers/net/wireless/wl12xx/wl1271_boot.c:199:37: warning: incorrect type in argument 1 (different base types) drivers/net/wireless/wl12xx/wl1271_init.c:255:40: warning: incorrect type in assignment (different base types) drivers/net/wireless/wl12xx/wl1271_init.c:275:53: warning: incorrect type in assignment (different base types) Reported-by: Johannes Berg Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 10 +- drivers/net/wireless/wl12xx/wl1271_acx.c | 72 ++++---- drivers/net/wireless/wl12xx/wl1271_acx.h | 286 ++++++++++++++--------------- drivers/net/wireless/wl12xx/wl1271_boot.c | 6 +- drivers/net/wireless/wl12xx/wl1271_cmd.c | 74 ++++---- drivers/net/wireless/wl12xx/wl1271_cmd.h | 68 +++---- drivers/net/wireless/wl12xx/wl1271_event.c | 3 +- drivers/net/wireless/wl12xx/wl1271_event.h | 28 +-- drivers/net/wireless/wl12xx/wl1271_init.h | 4 +- drivers/net/wireless/wl12xx/wl1271_main.c | 12 +- drivers/net/wireless/wl12xx/wl1271_rx.c | 11 +- drivers/net/wireless/wl12xx/wl1271_rx.h | 4 +- drivers/net/wireless/wl12xx/wl1271_tx.c | 22 ++- drivers/net/wireless/wl12xx/wl1271_tx.h | 18 +- drivers/net/wireless/wl12xx/wl12xx_80211.h | 4 +- 15 files changed, 318 insertions(+), 304 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 1309b20e4d5b..566f1521ec22 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -283,15 +283,15 @@ struct wl1271_debugfs { /* FW status registers */ struct wl1271_fw_status { - u32 intr; + __le32 intr; u8 fw_rx_counter; u8 drv_rx_counter; u8 reserved; u8 tx_results_counter; - u32 rx_pkt_descs[NUM_RX_PKT_DESC]; - u32 tx_released_blks[NUM_TX_QUEUES]; - u32 fw_localtime; - u32 padding[2]; + __le32 rx_pkt_descs[NUM_RX_PKT_DESC]; + __le32 tx_released_blks[NUM_TX_QUEUES]; + __le32 fw_localtime; + __le32 padding[2]; } __attribute__ ((packed)); struct wl1271_rx_mem_pool_addr { diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index e891cd5bd25c..bf5a8680a462 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -210,7 +210,7 @@ int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl) goto out; } - acx->lifetime = wl->conf.rx.rx_msdu_life_time; + acx->lifetime = cpu_to_le32(wl->conf.rx.rx_msdu_life_time); ret = wl1271_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME, acx, sizeof(*acx)); if (ret < 0) { @@ -236,8 +236,8 @@ int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter) goto out; } - rx_config->config_options = config; - rx_config->filter_options = filter; + rx_config->config_options = cpu_to_le32(config); + rx_config->filter_options = cpu_to_le32(filter); ret = wl1271_cmd_configure(wl, ACX_RX_CFG, rx_config, sizeof(*rx_config)); @@ -264,7 +264,7 @@ int wl1271_acx_pd_threshold(struct wl1271 *wl) goto out; } - pd->threshold = wl->conf.rx.packet_detection_threshold; + pd->threshold = cpu_to_le32(wl->conf.rx.packet_detection_threshold); ret = wl1271_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd)); if (ret < 0) { @@ -348,8 +348,8 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl) wl1271_debug(DEBUG_ACX, "acx service period timeout"); - rx_timeout->ps_poll_timeout = wl->conf.rx.ps_poll_timeout; - rx_timeout->upsd_timeout = wl->conf.rx.upsd_timeout; + rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout); + rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout); ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT, rx_timeout, sizeof(*rx_timeout)); @@ -377,7 +377,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold) goto out; } - rts->threshold = rts_threshold; + rts->threshold = cpu_to_le16(rts_threshold); ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); if (ret < 0) { @@ -494,8 +494,8 @@ int wl1271_acx_conn_monit_params(struct wl1271 *wl) goto out; } - acx->synch_fail_thold = wl->conf.conn.synch_fail_thold; - acx->bss_lose_timeout = wl->conf.conn.bss_lose_timeout; + acx->synch_fail_thold = cpu_to_le32(wl->conf.conn.synch_fail_thold); + acx->bss_lose_timeout = cpu_to_le32(wl->conf.conn.bss_lose_timeout); ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, acx, sizeof(*acx)); @@ -552,16 +552,18 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl) } /* BT-WLAN coext parameters */ - param->per_threshold = c->per_threshold; - param->max_scan_compensation_time = c->max_scan_compensation_time; - param->nfs_sample_interval = c->nfs_sample_interval; + param->per_threshold = cpu_to_le32(c->per_threshold); + param->max_scan_compensation_time = + cpu_to_le32(c->max_scan_compensation_time); + param->nfs_sample_interval = cpu_to_le16(c->nfs_sample_interval); param->load_ratio = c->load_ratio; param->auto_ps_mode = c->auto_ps_mode; param->probe_req_compensation = c->probe_req_compensation; param->scan_window_compensation = c->scan_window_compensation; param->antenna_config = c->antenna_config; param->beacon_miss_threshold = c->beacon_miss_threshold; - param->rate_adaptation_threshold = c->rate_adaptation_threshold; + param->rate_adaptation_threshold = + cpu_to_le32(c->rate_adaptation_threshold); param->rate_adaptation_snr = c->rate_adaptation_snr; ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); @@ -588,7 +590,7 @@ int wl1271_acx_cca_threshold(struct wl1271 *wl) goto out; } - detection->rx_cca_threshold = wl->conf.rx.rx_cca_threshold; + detection->rx_cca_threshold = cpu_to_le16(wl->conf.rx.rx_cca_threshold); detection->tx_energy_detection = wl->conf.tx.tx_energy_detection; ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD, @@ -616,8 +618,8 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) goto out; } - bb->beacon_rx_timeout = wl->conf.conn.beacon_rx_timeout; - bb->broadcast_timeout = wl->conf.conn.broadcast_timeout; + bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout); + bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout); bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold; @@ -645,7 +647,7 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid) goto out; } - acx_aid->aid = aid; + acx_aid->aid = cpu_to_le16(aid); ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); if (ret < 0) { @@ -672,9 +674,8 @@ int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask) } /* high event mask is unused */ - mask->high_event_mask = 0xffffffff; - - mask->event_mask = event_mask; + mask->high_event_mask = cpu_to_le32(0xffffffff); + mask->event_mask = cpu_to_le32(event_mask); ret = wl1271_cmd_configure(wl, ACX_EVENT_MBOX_MASK, mask, sizeof(*mask)); @@ -773,8 +774,8 @@ int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) } /* configure one default (one-size-fits-all) rate class */ - acx->rate_class_cnt = 1; - acx->rate_class[0].enabled_rates = enabled_rates; + acx->rate_class_cnt = cpu_to_le32(1); + acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates); acx->rate_class[0].short_retry_limit = c->short_retry_limit; acx->rate_class[0].long_retry_limit = c->long_retry_limit; acx->rate_class[0].aflags = c->aflags; @@ -808,10 +809,10 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl) struct conf_tx_ac_category *c = &(wl->conf.tx.ac_conf[i]); acx->ac = c->ac; acx->cw_min = c->cw_min; - acx->cw_max = c->cw_max; + acx->cw_max = cpu_to_le16(c->cw_max); acx->aifsn = c->aifsn; acx->reserved = 0; - acx->tx_op_limit = c->tx_op_limit; + acx->tx_op_limit = cpu_to_le16(c->tx_op_limit); ret = wl1271_cmd_configure(wl, ACX_AC_CFG, acx, sizeof(*acx)); if (ret < 0) { @@ -847,8 +848,8 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl) acx->tsid = c->tsid; acx->ps_scheme = c->ps_scheme; acx->ack_policy = c->ack_policy; - acx->apsd_conf[0] = c->apsd_conf[0]; - acx->apsd_conf[1] = c->apsd_conf[1]; + acx->apsd_conf[0] = cpu_to_le32(c->apsd_conf[0]); + acx->apsd_conf[1] = cpu_to_le32(c->apsd_conf[1]); ret = wl1271_cmd_configure(wl, ACX_TID_CFG, acx, sizeof(*acx)); if (ret < 0) { @@ -876,7 +877,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl) goto out; } - acx->frag_threshold = wl->conf.tx.frag_threshold; + acx->frag_threshold = cpu_to_le16(wl->conf.tx.frag_threshold); ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("Setting of frag threshold failed: %d", ret); @@ -902,8 +903,8 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl) goto out; } - acx->tx_compl_timeout = wl->conf.tx.tx_compl_timeout; - acx->tx_compl_threshold = wl->conf.tx.tx_compl_threshold; + acx->tx_compl_timeout = cpu_to_le16(wl->conf.tx.tx_compl_timeout); + acx->tx_compl_threshold = cpu_to_le16(wl->conf.tx.tx_compl_threshold); ret = wl1271_cmd_configure(wl, ACX_TX_CONFIG_OPT, acx, sizeof(*acx)); if (ret < 0) { wl1271_warning("Setting of tx options failed: %d", ret); @@ -929,11 +930,11 @@ int wl1271_acx_mem_cfg(struct wl1271 *wl) } /* memory config */ - mem_conf->num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS); + mem_conf->num_stations = DEFAULT_NUM_STATIONS; mem_conf->rx_mem_block_num = ACX_RX_MEM_BLOCKS; mem_conf->tx_min_mem_block_num = ACX_TX_MIN_MEM_BLOCKS; mem_conf->num_ssid_profiles = ACX_NUM_SSID_PROFILES; - mem_conf->total_tx_descriptors = ACX_TX_DESCRIPTORS; + mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, sizeof(*mem_conf)); @@ -973,7 +974,8 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl) } /* initialize TX block book keeping */ - wl->tx_blocks_available = wl->target_mem_map->num_tx_mem_blocks; + wl->tx_blocks_available = + le32_to_cpu(wl->target_mem_map->num_tx_mem_blocks); wl1271_debug(DEBUG_TX, "available tx blocks: %d", wl->tx_blocks_available); @@ -993,9 +995,9 @@ int wl1271_acx_init_rx_interrupt(struct wl1271 *wl) goto out; } - rx_conf->threshold = wl->conf.rx.irq_pkt_threshold; - rx_conf->timeout = wl->conf.rx.irq_timeout; - rx_conf->mblk_threshold = wl->conf.rx.irq_blk_threshold; + rx_conf->threshold = cpu_to_le16(wl->conf.rx.irq_pkt_threshold); + rx_conf->timeout = cpu_to_le16(wl->conf.rx.irq_timeout); + rx_conf->mblk_threshold = cpu_to_le16(wl->conf.rx.irq_blk_threshold); rx_conf->queue_type = wl->conf.rx.queue_type; ret = wl1271_cmd_configure(wl, ACX_RX_CONFIG_OPT, rx_conf, diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 5085497d1339..2ce0a8128542 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -71,10 +71,10 @@ struct acx_header { struct wl1271_cmd_header cmd; /* acx (or information element) header */ - u16 id; + __le16 id; /* payload length (not including headers */ - u16 len; + __le16 len; } __attribute__ ((packed)); struct acx_error_counter { @@ -83,21 +83,21 @@ struct acx_error_counter { /* The number of PLCP errors since the last time this */ /* information element was interrogated. This field is */ /* automatically cleared when it is interrogated.*/ - u32 PLCP_error; + __le32 PLCP_error; /* The number of FCS errors since the last time this */ /* information element was interrogated. This field is */ /* automatically cleared when it is interrogated.*/ - u32 FCS_error; + __le32 FCS_error; /* The number of MPDUs without PLCP header errors received*/ /* since the last time this information element was interrogated. */ /* This field is automatically cleared when it is interrogated.*/ - u32 valid_frame; + __le32 valid_frame; /* the number of missed sequence numbers in the squentially */ /* values of frames seq numbers */ - u32 seq_num_miss; + __le32 seq_num_miss; } __attribute__ ((packed)); struct acx_revision { @@ -126,7 +126,7 @@ struct acx_revision { * (1 = first spin, 2 = second spin, and so on). * bits 24 - 31: Chip ID - The WiLink chip ID. */ - u32 hw_version; + __le32 hw_version; } __attribute__ ((packed)); enum wl1271_psm_mode { @@ -186,7 +186,7 @@ struct acx_rx_msdu_lifetime { * The maximum amount of time, in TU, before the * firmware discards the MSDU. */ - u32 lifetime; + __le32 lifetime; } __attribute__ ((packed)); /* @@ -273,14 +273,14 @@ struct acx_rx_msdu_lifetime { struct acx_rx_config { struct acx_header header; - u32 config_options; - u32 filter_options; + __le32 config_options; + __le32 filter_options; } __attribute__ ((packed)); struct acx_packet_detection { struct acx_header header; - u32 threshold; + __le32 threshold; } __attribute__ ((packed)); @@ -317,14 +317,14 @@ struct acx_dot11_grp_addr_tbl { struct acx_rx_timeout { struct acx_header header; - u16 ps_poll_timeout; - u16 upsd_timeout; + __le16 ps_poll_timeout; + __le16 upsd_timeout; } __attribute__ ((packed)); struct acx_rts_threshold { struct acx_header header; - u16 threshold; + __le16 threshold; u8 pad[2]; } __attribute__ ((packed)); @@ -388,8 +388,8 @@ struct acx_beacon_filter_ie_table { struct acx_conn_monit_params { struct acx_header header; - u32 synch_fail_thold; /* number of beacons missed */ - u32 bss_lose_timeout; /* number of TU's from synch fail */ + __le32 synch_fail_thold; /* number of beacons missed */ + __le32 bss_lose_timeout; /* number of TU's from synch fail */ } __attribute__ ((packed)); enum { @@ -466,16 +466,16 @@ struct acx_smart_reflex_config_params { struct acx_bt_wlan_coex_param { struct acx_header header; - u32 per_threshold; - u32 max_scan_compensation_time; - u16 nfs_sample_interval; + __le32 per_threshold; + __le32 max_scan_compensation_time; + __le16 nfs_sample_interval; u8 load_ratio; u8 auto_ps_mode; u8 probe_req_compensation; u8 scan_window_compensation; u8 antenna_config; u8 beacon_miss_threshold; - u32 rate_adaptation_threshold; + __le32 rate_adaptation_threshold; s8 rate_adaptation_snr; u8 padding[3]; } __attribute__ ((packed)); @@ -484,7 +484,7 @@ struct acx_energy_detection { struct acx_header header; /* The RX Clear Channel Assessment threshold in the PHY */ - u16 rx_cca_threshold; + __le16 rx_cca_threshold; u8 tx_energy_detection; u8 pad; } __attribute__ ((packed)); @@ -492,8 +492,8 @@ struct acx_energy_detection { struct acx_beacon_broadcast { struct acx_header header; - u16 beacon_rx_timeout; - u16 broadcast_timeout; + __le16 beacon_rx_timeout; + __le16 broadcast_timeout; /* Enables receiving of broadcast packets in PS mode */ u8 rx_broadcast_in_ps; @@ -506,8 +506,8 @@ struct acx_beacon_broadcast { struct acx_event_mask { struct acx_header header; - u32 event_mask; - u32 high_event_mask; /* Unused */ + __le32 event_mask; + __le32 high_event_mask; /* Unused */ } __attribute__ ((packed)); #define CFG_RX_FCS BIT(2) @@ -551,8 +551,8 @@ struct acx_event_mask { struct acx_feature_config { struct acx_header header; - u32 options; - u32 data_flow_options; + __le32 options; + __le32 data_flow_options; } __attribute__ ((packed)); struct acx_current_tx_power { @@ -576,7 +576,7 @@ struct acx_aid { /* * To be set when associated with an AP. */ - u16 aid; + __le16 aid; u8 pad[2]; } __attribute__ ((packed)); @@ -608,152 +608,152 @@ struct acx_ctsprotect { } __attribute__ ((packed)); struct acx_tx_statistics { - u32 internal_desc_overflow; + __le32 internal_desc_overflow; } __attribute__ ((packed)); struct acx_rx_statistics { - u32 out_of_mem; - u32 hdr_overflow; - u32 hw_stuck; - u32 dropped; - u32 fcs_err; - u32 xfr_hint_trig; - u32 path_reset; - u32 reset_counter; + __le32 out_of_mem; + __le32 hdr_overflow; + __le32 hw_stuck; + __le32 dropped; + __le32 fcs_err; + __le32 xfr_hint_trig; + __le32 path_reset; + __le32 reset_counter; } __attribute__ ((packed)); struct acx_dma_statistics { - u32 rx_requested; - u32 rx_errors; - u32 tx_requested; - u32 tx_errors; + __le32 rx_requested; + __le32 rx_errors; + __le32 tx_requested; + __le32 tx_errors; } __attribute__ ((packed)); struct acx_isr_statistics { /* host command complete */ - u32 cmd_cmplt; + __le32 cmd_cmplt; /* fiqisr() */ - u32 fiqs; + __le32 fiqs; /* (INT_STS_ND & INT_TRIG_RX_HEADER) */ - u32 rx_headers; + __le32 rx_headers; /* (INT_STS_ND & INT_TRIG_RX_CMPLT) */ - u32 rx_completes; + __le32 rx_completes; /* (INT_STS_ND & INT_TRIG_NO_RX_BUF) */ - u32 rx_mem_overflow; + __le32 rx_mem_overflow; /* (INT_STS_ND & INT_TRIG_S_RX_RDY) */ - u32 rx_rdys; + __le32 rx_rdys; /* irqisr() */ - u32 irqs; + __le32 irqs; /* (INT_STS_ND & INT_TRIG_TX_PROC) */ - u32 tx_procs; + __le32 tx_procs; /* (INT_STS_ND & INT_TRIG_DECRYPT_DONE) */ - u32 decrypt_done; + __le32 decrypt_done; /* (INT_STS_ND & INT_TRIG_DMA0) */ - u32 dma0_done; + __le32 dma0_done; /* (INT_STS_ND & INT_TRIG_DMA1) */ - u32 dma1_done; + __le32 dma1_done; /* (INT_STS_ND & INT_TRIG_TX_EXC_CMPLT) */ - u32 tx_exch_complete; + __le32 tx_exch_complete; /* (INT_STS_ND & INT_TRIG_COMMAND) */ - u32 commands; + __le32 commands; /* (INT_STS_ND & INT_TRIG_RX_PROC) */ - u32 rx_procs; + __le32 rx_procs; /* (INT_STS_ND & INT_TRIG_PM_802) */ - u32 hw_pm_mode_changes; + __le32 hw_pm_mode_changes; /* (INT_STS_ND & INT_TRIG_ACKNOWLEDGE) */ - u32 host_acknowledges; + __le32 host_acknowledges; /* (INT_STS_ND & INT_TRIG_PM_PCI) */ - u32 pci_pm; + __le32 pci_pm; /* (INT_STS_ND & INT_TRIG_ACM_WAKEUP) */ - u32 wakeups; + __le32 wakeups; /* (INT_STS_ND & INT_TRIG_LOW_RSSI) */ - u32 low_rssi; + __le32 low_rssi; } __attribute__ ((packed)); struct acx_wep_statistics { /* WEP address keys configured */ - u32 addr_key_count; + __le32 addr_key_count; /* default keys configured */ - u32 default_key_count; + __le32 default_key_count; - u32 reserved; + __le32 reserved; /* number of times that WEP key not found on lookup */ - u32 key_not_found; + __le32 key_not_found; /* number of times that WEP key decryption failed */ - u32 decrypt_fail; + __le32 decrypt_fail; /* WEP packets decrypted */ - u32 packets; + __le32 packets; /* WEP decrypt interrupts */ - u32 interrupt; + __le32 interrupt; } __attribute__ ((packed)); #define ACX_MISSED_BEACONS_SPREAD 10 struct acx_pwr_statistics { /* the amount of enters into power save mode (both PD & ELP) */ - u32 ps_enter; + __le32 ps_enter; /* the amount of enters into ELP mode */ - u32 elp_enter; + __le32 elp_enter; /* the amount of missing beacon interrupts to the host */ - u32 missing_bcns; + __le32 missing_bcns; /* the amount of wake on host-access times */ - u32 wake_on_host; + __le32 wake_on_host; /* the amount of wake on timer-expire */ - u32 wake_on_timer_exp; + __le32 wake_on_timer_exp; /* the number of packets that were transmitted with PS bit set */ - u32 tx_with_ps; + __le32 tx_with_ps; /* the number of packets that were transmitted with PS bit clear */ - u32 tx_without_ps; + __le32 tx_without_ps; /* the number of received beacons */ - u32 rcvd_beacons; + __le32 rcvd_beacons; /* the number of entering into PowerOn (power save off) */ - u32 power_save_off; + __le32 power_save_off; /* the number of entries into power save mode */ - u16 enable_ps; + __le16 enable_ps; /* * the number of exits from power save, not including failed PS * transitions */ - u16 disable_ps; + __le16 disable_ps; /* * the number of times the TSF counter was adjusted because * of drift */ - u32 fix_tsf_ps; + __le32 fix_tsf_ps; /* Gives statistics about the spread continuous missed beacons. * The 16 LSB are dedicated for the PS mode. @@ -764,53 +764,53 @@ struct acx_pwr_statistics { * ... * cont_miss_bcns_spread[9] - ten and more continuous missed beacons. */ - u32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; + __le32 cont_miss_bcns_spread[ACX_MISSED_BEACONS_SPREAD]; /* the number of beacons in awake mode */ - u32 rcvd_awake_beacons; + __le32 rcvd_awake_beacons; } __attribute__ ((packed)); struct acx_mic_statistics { - u32 rx_pkts; - u32 calc_failure; + __le32 rx_pkts; + __le32 calc_failure; } __attribute__ ((packed)); struct acx_aes_statistics { - u32 encrypt_fail; - u32 decrypt_fail; - u32 encrypt_packets; - u32 decrypt_packets; - u32 encrypt_interrupt; - u32 decrypt_interrupt; + __le32 encrypt_fail; + __le32 decrypt_fail; + __le32 encrypt_packets; + __le32 decrypt_packets; + __le32 encrypt_interrupt; + __le32 decrypt_interrupt; } __attribute__ ((packed)); struct acx_event_statistics { - u32 heart_beat; - u32 calibration; - u32 rx_mismatch; - u32 rx_mem_empty; - u32 rx_pool; - u32 oom_late; - u32 phy_transmit_error; - u32 tx_stuck; + __le32 heart_beat; + __le32 calibration; + __le32 rx_mismatch; + __le32 rx_mem_empty; + __le32 rx_pool; + __le32 oom_late; + __le32 phy_transmit_error; + __le32 tx_stuck; } __attribute__ ((packed)); struct acx_ps_statistics { - u32 pspoll_timeouts; - u32 upsd_timeouts; - u32 upsd_max_sptime; - u32 upsd_max_apturn; - u32 pspoll_max_apturn; - u32 pspoll_utilization; - u32 upsd_utilization; + __le32 pspoll_timeouts; + __le32 upsd_timeouts; + __le32 upsd_max_sptime; + __le32 upsd_max_apturn; + __le32 pspoll_max_apturn; + __le32 pspoll_utilization; + __le32 upsd_utilization; } __attribute__ ((packed)); struct acx_rxpipe_statistics { - u32 rx_prep_beacon_drop; - u32 descr_host_int_trig_rx_data; - u32 beacon_buffer_thres_host_int_trig_rx_data; - u32 missed_beacon_host_int_trig_rx_data; - u32 tx_xfr_host_int_trig_rx_data; + __le32 rx_prep_beacon_drop; + __le32 descr_host_int_trig_rx_data; + __le32 beacon_buffer_thres_host_int_trig_rx_data; + __le32 missed_beacon_host_int_trig_rx_data; + __le32 tx_xfr_host_int_trig_rx_data; } __attribute__ ((packed)); struct acx_statistics { @@ -830,7 +830,7 @@ struct acx_statistics { } __attribute__ ((packed)); struct acx_rate_class { - u32 enabled_rates; + __le32 enabled_rates; u8 short_retry_limit; u8 long_retry_limit; u8 aflags; @@ -840,7 +840,7 @@ struct acx_rate_class { struct acx_rate_policy { struct acx_header header; - u32 rate_class_cnt; + __le32 rate_class_cnt; struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES]; } __attribute__ ((packed)); @@ -848,10 +848,10 @@ struct acx_ac_cfg { struct acx_header header; u8 ac; u8 cw_min; - u16 cw_max; + __le16 cw_max; u8 aifsn; u8 reserved; - u16 tx_op_limit; + __le16 tx_op_limit; } __attribute__ ((packed)); struct acx_tid_config { @@ -862,19 +862,19 @@ struct acx_tid_config { u8 ps_scheme; u8 ack_policy; u8 padding[3]; - u32 apsd_conf[2]; + __le32 apsd_conf[2]; } __attribute__ ((packed)); struct acx_frag_threshold { struct acx_header header; - u16 frag_threshold; + __le16 frag_threshold; u8 padding[2]; } __attribute__ ((packed)); struct acx_tx_config_options { struct acx_header header; - u16 tx_compl_timeout; /* msec */ - u16 tx_compl_threshold; /* number of packets */ + __le16 tx_compl_timeout; /* msec */ + __le16 tx_compl_threshold; /* number of packets */ } __attribute__ ((packed)); #define ACX_RX_MEM_BLOCKS 64 @@ -889,59 +889,59 @@ struct wl1271_acx_config_memory { u8 tx_min_mem_block_num; u8 num_stations; u8 num_ssid_profiles; - u32 total_tx_descriptors; + __le32 total_tx_descriptors; } __attribute__ ((packed)); struct wl1271_acx_mem_map { struct acx_header header; - void *code_start; - void *code_end; + __le32 code_start; + __le32 code_end; - void *wep_defkey_start; - void *wep_defkey_end; + __le32 wep_defkey_start; + __le32 wep_defkey_end; - void *sta_table_start; - void *sta_table_end; + __le32 sta_table_start; + __le32 sta_table_end; - void *packet_template_start; - void *packet_template_end; + __le32 packet_template_start; + __le32 packet_template_end; /* Address of the TX result interface (control block) */ - u32 tx_result; - u32 tx_result_queue_start; + __le32 tx_result; + __le32 tx_result_queue_start; - void *queue_memory_start; - void *queue_memory_end; + __le32 queue_memory_start; + __le32 queue_memory_end; - u32 packet_memory_pool_start; - u32 packet_memory_pool_end; + __le32 packet_memory_pool_start; + __le32 packet_memory_pool_end; - void *debug_buffer1_start; - void *debug_buffer1_end; + __le32 debug_buffer1_start; + __le32 debug_buffer1_end; - void *debug_buffer2_start; - void *debug_buffer2_end; + __le32 debug_buffer2_start; + __le32 debug_buffer2_end; /* Number of blocks FW allocated for TX packets */ - u32 num_tx_mem_blocks; + __le32 num_tx_mem_blocks; /* Number of blocks FW allocated for RX packets */ - u32 num_rx_mem_blocks; + __le32 num_rx_mem_blocks; /* the following 4 fields are valid in SLAVE mode only */ u8 *tx_cbuf; u8 *rx_cbuf; - void *rx_ctrl; - void *tx_ctrl; + __le32 rx_ctrl; + __le32 tx_ctrl; } __attribute__ ((packed)); struct wl1271_acx_rx_config_opt { struct acx_header header; - u16 mblk_threshold; - u16 threshold; - u16 timeout; + __le16 mblk_threshold; + __le16 threshold; + __le16 timeout; u8 queue_type; u8 reserved; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index 41a3050afae1..ba4a2b4f0f56 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -188,15 +188,15 @@ static int wl1271_boot_upload_firmware(struct wl1271 *wl) u8 *fw; fw = wl->fw; - chunks = be32_to_cpup((u32 *) fw); + chunks = be32_to_cpup((__be32 *) fw); fw += sizeof(u32); wl1271_debug(DEBUG_BOOT, "firmware chunks to be uploaded: %u", chunks); while (chunks--) { - addr = be32_to_cpup((u32 *) fw); + addr = be32_to_cpup((__be32 *) fw); fw += sizeof(u32); - len = be32_to_cpup((u32 *) fw); + len = be32_to_cpup((__be32 *) fw); fw += sizeof(u32); if (len > 300000) { diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 195eee70e36e..0666328ce9ab 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -50,7 +50,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) int ret = 0; cmd = buf; - cmd->id = id; + cmd->id = cpu_to_le16(id); cmd->status = 0; WARN_ON(len % 4 != 0); @@ -217,8 +217,8 @@ int wl1271_cmd_join(struct wl1271 *wl) for (i = 0; i < ETH_ALEN; i++) bssid[i] = wl->bssid[ETH_ALEN - i - 1]; - join->rx_config_options = wl->rx_config; - join->rx_filter_options = wl->rx_filter; + join->rx_config_options = cpu_to_le32(wl->rx_config); + join->rx_filter_options = cpu_to_le32(wl->rx_filter); join->bss_type = wl->bss_type; /* @@ -227,21 +227,22 @@ int wl1271_cmd_join(struct wl1271 *wl) * association. The filter logic needs to be implemented properly * and once that is done, this hack can be removed. */ - join->rx_config_options = 0; - join->rx_filter_options = WL1271_DEFAULT_RX_FILTER; + join->rx_config_options = cpu_to_le32(0); + join->rx_filter_options = cpu_to_le32(WL1271_DEFAULT_RX_FILTER); if (wl->band == IEEE80211_BAND_2GHZ) - join->basic_rate_set = - CONF_HW_BIT_RATE_1MBPS | CONF_HW_BIT_RATE_2MBPS | - CONF_HW_BIT_RATE_5_5MBPS | CONF_HW_BIT_RATE_11MBPS; + join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS | + CONF_HW_BIT_RATE_2MBPS | + CONF_HW_BIT_RATE_5_5MBPS | + CONF_HW_BIT_RATE_11MBPS); else { join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; - join->basic_rate_set = - CONF_HW_BIT_RATE_6MBPS | CONF_HW_BIT_RATE_12MBPS | - CONF_HW_BIT_RATE_24MBPS; + join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_6MBPS | + CONF_HW_BIT_RATE_12MBPS | + CONF_HW_BIT_RATE_24MBPS); } - join->beacon_interval = WL1271_DEFAULT_BEACON_INT; + join->beacon_interval = cpu_to_le16(WL1271_DEFAULT_BEACON_INT); join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; join->channel = wl->channel; @@ -305,6 +306,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) if (answer) { struct wl1271_command *cmd_answer; + u16 status; /* * The test command got in, we can read the answer. @@ -314,10 +316,10 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) wl1271_spi_read(wl, wl->cmd_box_addr, buf, buf_len, false); cmd_answer = buf; + status = le16_to_cpu(cmd_answer->header.status); - if (cmd_answer->header.status != CMD_STATUS_SUCCESS) - wl1271_error("TEST command answer error: %d", - cmd_answer->header.status); + if (status != CMD_STATUS_SUCCESS) + wl1271_error("TEST command answer error: %d", status); } return 0; @@ -338,10 +340,10 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) wl1271_debug(DEBUG_CMD, "cmd interrogate"); - acx->id = id; + acx->id = cpu_to_le16(id); /* payload length, does not include any headers */ - acx->len = len - sizeof(*acx); + acx->len = cpu_to_le16(len - sizeof(*acx)); ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); if (ret < 0) { @@ -353,9 +355,9 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) wl1271_spi_read(wl, wl->cmd_box_addr, buf, len, false); acx = buf; - if (acx->cmd.status != CMD_STATUS_SUCCESS) + if (le16_to_cpu(acx->cmd.status) != CMD_STATUS_SUCCESS) wl1271_error("INTERROGATE command error: %d", - acx->cmd.status); + le16_to_cpu(acx->cmd.status)); out: return ret; @@ -376,10 +378,10 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) wl1271_debug(DEBUG_CMD, "cmd configure"); - acx->id = id; + acx->id = cpu_to_le16(id); /* payload length, does not include any headers */ - acx->len = len - sizeof(*acx); + acx->len = cpu_to_le16(len - sizeof(*acx)); ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len); if (ret < 0) { @@ -463,7 +465,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) ps_params->send_null_data = 1; ps_params->retries = 5; ps_params->hang_over_period = 128; - ps_params->null_data_rate = 1; /* 1 Mbps */ + ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */ ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, sizeof(*ps_params)); @@ -494,8 +496,8 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, WARN_ON(len > MAX_READ_SIZE); len = min_t(size_t, len, MAX_READ_SIZE); - cmd->addr = addr; - cmd->size = len; + cmd->addr = cpu_to_le32(addr); + cmd->size = cpu_to_le32(len); ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); if (ret < 0) { @@ -506,9 +508,9 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, /* the read command got in, we can now read the answer */ wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd), false); - if (cmd->header.status != CMD_STATUS_SUCCESS) + if (le16_to_cpu(cmd->header.status) != CMD_STATUS_SUCCESS) wl1271_error("error in read command result: %d", - cmd->header.status); + le16_to_cpu(cmd->header.status)); memcpy(answer, cmd->value, len); @@ -559,7 +561,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, scan_options |= WL1271_SCAN_OPT_PASSIVE; if (high_prio) scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; - params->params.scan_options = scan_options; + params->params.scan_options = cpu_to_le16(scan_options); params->params.num_probe_requests = probe_requests; /* Let the fw autodetect suitable tx_rate for probes */ @@ -643,9 +645,9 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, wl1271_spi_read(wl, wl->cmd_box_addr, params, sizeof(*params), false); - if (params->header.status != CMD_STATUS_SUCCESS) { + if (le16_to_cpu(params->header.status) != CMD_STATUS_SUCCESS) { wl1271_error("Scan command error: %d", - params->header.status); + le16_to_cpu(params->header.status)); wl->scanning = false; ret = -EIO; goto out; @@ -675,7 +677,7 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, cmd->len = cpu_to_le16(buf_len); cmd->template_type = template_id; - cmd->enabled_rates = wl->conf.tx.rc_conf.enabled_rates; + cmd->enabled_rates = cpu_to_le32(wl->conf.tx.rc_conf.enabled_rates); cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; @@ -858,7 +860,7 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) } cmd->id = id; - cmd->key_action = KEY_SET_ID; + cmd->key_action = cpu_to_le16(KEY_SET_ID); cmd->key_type = KEY_WEP; ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); @@ -889,12 +891,12 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, if (key_type != KEY_WEP) memcpy(cmd->addr, addr, ETH_ALEN); - cmd->key_action = action; + cmd->key_action = cpu_to_le16(action); cmd->key_size = key_size; cmd->key_type = key_type; - cmd->ac_seq_num16[0] = tx_seq_16; - cmd->ac_seq_num32[0] = tx_seq_32; + cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); + cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); /* we have only one SSID profile */ cmd->ssid_profile = 0; @@ -943,8 +945,8 @@ int wl1271_cmd_disconnect(struct wl1271 *wl) goto out; } - cmd->rx_config_options = wl->rx_config; - cmd->rx_filter_options = wl->rx_filter; + cmd->rx_config_options = cpu_to_le32(wl->rx_config); + cmd->rx_filter_options = cpu_to_le32(wl->rx_filter); /* disconnect reason is not used in immediate disconnections */ cmd->type = DISCONNECT_IMMEDIATE; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 15254fa82f6a..57d69057b4fa 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -120,8 +120,8 @@ enum cmd_templ { #define WL1271_CMD_TEMPL_MAX_SIZE 252 struct wl1271_cmd_header { - u16 id; - u16 status; + __le16 id; + __le16 status; /* payload */ u8 data[0]; } __attribute__ ((packed)); @@ -174,11 +174,11 @@ struct cmd_read_write_memory { struct wl1271_cmd_header header; /* The address of the memory to read from or write to.*/ - u32 addr; + __le32 addr; /* The amount of data in bytes to read from or write to the WiLink * device.*/ - u32 size; + __le32 size; /* The actual value read from or written to the Wilink. The source of this field is the Host in WRITE command or the Wilink in READ @@ -203,18 +203,18 @@ enum { struct wl1271_cmd_join { struct wl1271_cmd_header header; - u32 bssid_lsb; - u16 bssid_msb; - u16 beacon_interval; /* in TBTTs */ - u32 rx_config_options; - u32 rx_filter_options; + __le32 bssid_lsb; + __le16 bssid_msb; + __le16 beacon_interval; /* in TBTTs */ + __le32 rx_config_options; + __le32 rx_filter_options; /* * The target uses this field to determine the rate at * which to transmit control frame responses (such as * ACK or CTS frames). */ - u32 basic_rate_set; + __le32 basic_rate_set; u8 dtim_interval; /* * bits 0-2: This bitwise field specifies the type @@ -243,10 +243,10 @@ struct cmd_enabledisable_path { struct wl1271_cmd_template_set { struct wl1271_cmd_header header; - u16 len; + __le16 len; u8 template_type; u8 index; /* relevant only for KLV_TEMPLATE type */ - u32 enabled_rates; + __le32 enabled_rates; u8 short_retry_limit; u8 long_retry_limit; u8 aflags; @@ -283,7 +283,7 @@ struct wl1271_cmd_ps_params { * to power save mode. */ u8 hang_over_period; - u32 null_data_rate; + __le32 null_data_rate; } __attribute__ ((packed)); /* HW encryption keys */ @@ -314,9 +314,9 @@ struct wl1271_cmd_set_keys { u8 addr[ETH_ALEN]; /* key_action_e */ - u16 key_action; + __le16 key_action; - u16 reserved_1; + __le16 reserved_1; /* key size in bytes */ u8 key_size; @@ -332,8 +332,8 @@ struct wl1271_cmd_set_keys { u8 id; u8 reserved_2[6]; u8 key[MAX_KEY_SIZE]; - u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; - u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; + __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; + __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; } __attribute__ ((packed)); @@ -350,17 +350,17 @@ struct wl1271_cmd_set_keys { #define WL1271_SCAN_BAND_DUAL 2 struct basic_scan_params { - u32 rx_config_options; - u32 rx_filter_options; + __le32 rx_config_options; + __le32 rx_filter_options; /* Scan option flags (WL1271_SCAN_OPT_*) */ - u16 scan_options; + __le16 scan_options; /* Number of scan channels in the list (maximum 30) */ u8 num_channels; /* This field indicates the number of probe requests to send per channel for an active scan */ u8 num_probe_requests; /* Rate bit field for sending the probes */ - u32 tx_rate; + __le32 tx_rate; u8 tid_trigger; u8 ssid_len; /* in order to align */ @@ -375,10 +375,10 @@ struct basic_scan_params { struct basic_scan_channel_params { /* Duration in TU to wait for frames on a channel for active scan */ - u32 min_duration; - u32 max_duration; - u32 bssid_lsb; - u16 bssid_msb; + __le32 min_duration; + __le32 max_duration; + __le32 bssid_lsb; + __le16 bssid_msb; u8 early_termination; u8 tx_power_att; u8 channel; @@ -398,7 +398,7 @@ struct wl1271_cmd_scan { struct wl1271_cmd_trigger_scan_to { struct wl1271_cmd_header header; - u32 timeout; + __le32 timeout; }; struct wl1271_cmd_test_header { @@ -426,7 +426,7 @@ struct wl1271_cmd_cal_channel_tune { u8 band; u8 channel; - u16 radio_status; + __le16 radio_status; } __attribute__ ((packed)); struct wl1271_cmd_cal_update_ref_point { @@ -434,8 +434,8 @@ struct wl1271_cmd_cal_update_ref_point { struct wl1271_cmd_test_header test; - s32 ref_power; - s32 ref_detector; + __le32 ref_power; + __le32 ref_detector; u8 sub_band; u8 padding[3]; } __attribute__ ((packed)); @@ -450,12 +450,12 @@ struct wl1271_cmd_cal_p2g { struct wl1271_cmd_test_header test; - u16 len; + __le16 len; u8 buf[MAX_TLV_LENGTH]; u8 type; u8 padding; - s16 radio_status; + __le16 radio_status; u8 nvs_version[MAX_NVS_VERSION_LENGTH]; u8 sub_band_mask; @@ -479,10 +479,10 @@ enum wl1271_disconnect_type { }; struct wl1271_cmd_disconnect { - u32 rx_config_options; - u32 rx_filter_options; + __le32 rx_config_options; + __le32 rx_filter_options; - u16 reason; + __le16 reason; u8 type; u8 padding; diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index a4b11e43f0db..31d396ba9188 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -82,7 +82,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_event_mbox_dump(mbox); - vector = mbox->events_vector & ~(mbox->events_mask); + vector = le32_to_cpu(mbox->events_vector); + vector &= ~(le32_to_cpu(mbox->events_mask)); wl1271_debug(DEBUG_EVENT, "vector: 0x%x", vector); if (vector & SCAN_COMPLETE_EVENT_ID) { diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h index adc4653b2616..3ab53d331f15 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.h +++ b/drivers/net/wireless/wl12xx/wl1271_event.h @@ -66,33 +66,33 @@ enum { struct event_debug_report { u8 debug_event_id; u8 num_params; - u16 pad; - u32 report_1; - u32 report_2; - u32 report_3; + __le16 pad; + __le32 report_1; + __le32 report_2; + __le32 report_3; } __attribute__ ((packed)); #define NUM_OF_RSSI_SNR_TRIGGERS 8 struct event_mailbox { - u32 events_vector; - u32 events_mask; - u32 reserved_1; - u32 reserved_2; + __le32 events_vector; + __le32 events_mask; + __le32 reserved_1; + __le32 reserved_2; u8 dbg_event_id; u8 num_relevant_params; - u16 reserved_3; - u32 event_report_p1; - u32 event_report_p2; - u32 event_report_p3; + __le16 reserved_3; + __le32 event_report_p1; + __le32 event_report_p2; + __le32 event_report_p3; u8 number_of_scan_results; u8 scan_tag; u8 reserved_4[2]; - u32 compl_scheduled_scan_status; + __le32 compl_scheduled_scan_status; - u16 scheduled_scan_attended_channels; + __le16 scheduled_scan_attended_channels; u8 soft_gemini_sense_info; u8 soft_gemini_protective_info; s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h index 513d0cb1866b..6e21ceee76a6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.h +++ b/drivers/net/wireless/wl12xx/wl1271_init.h @@ -65,7 +65,7 @@ struct wl1271_radio_parms { /* Dynamic radio parameters */ /* 2.4GHz */ - s16 tx_ref_pd_voltage; + __le16 tx_ref_pd_voltage; s8 tx_ref_power; s8 tx_offset_db; @@ -82,7 +82,7 @@ struct wl1271_radio_parms { u8 padding2; /* 5GHz */ - s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; + __le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index ee7ffafaa274..86132bb00787 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -397,8 +397,11 @@ static void wl1271_fw_status(struct wl1271 *wl, /* update number of available TX blocks */ for (i = 0; i < NUM_TX_QUEUES; i++) { - u32 cnt = status->tx_released_blks[i] - wl->tx_blocks_freed[i]; - wl->tx_blocks_freed[i] = status->tx_released_blks[i]; + u32 cnt = le32_to_cpu(status->tx_released_blks[i]) - + wl->tx_blocks_freed[i]; + + wl->tx_blocks_freed[i] = + le32_to_cpu(status->tx_released_blks[i]); wl->tx_blocks_available += cnt; total += cnt; } @@ -408,7 +411,8 @@ static void wl1271_fw_status(struct wl1271 *wl, ieee80211_queue_work(wl->hw, &wl->tx_work); /* update the host-chipset time offset */ - wl->time_offset = jiffies_to_usecs(jiffies) - status->fw_localtime; + wl->time_offset = jiffies_to_usecs(jiffies) - + le32_to_cpu(status->fw_localtime); } static void wl1271_irq_work(struct work_struct *work) @@ -432,7 +436,7 @@ static void wl1271_irq_work(struct work_struct *work) wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); wl1271_fw_status(wl, wl->fw_status); - intr = wl->fw_status->intr; + intr = le32_to_cpu(wl->fw_status->intr); if (!intr) { wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); goto out_sleep; diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 1ea3f41912a6..dbf07bea87c0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -30,14 +30,15 @@ static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status, u32 drv_rx_counter) { - return status->rx_pkt_descs[drv_rx_counter] & RX_MEM_BLOCK_MASK; + return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & + RX_MEM_BLOCK_MASK; } static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status, u32 drv_rx_counter) { - return (status->rx_pkt_descs[drv_rx_counter] & RX_BUF_SIZE_MASK) >> - RX_BUF_SIZE_SHIFT_DIV; + return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & + RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV; } /* The values of this table must match the wl1271_rates[] array */ @@ -203,8 +204,8 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) break; } - wl->rx_mem_pool_addr.addr = - (mem_block << 8) + wl_mem_map->packet_memory_pool_start; + wl->rx_mem_pool_addr.addr = (mem_block << 8) + + le32_to_cpu(wl_mem_map->packet_memory_pool_start); wl->rx_mem_pool_addr.addr_extra = wl->rx_mem_pool_addr.addr + 4; diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h index d1ca60e43a25..1ae6d1783ed4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.h +++ b/drivers/net/wireless/wl12xx/wl1271_rx.h @@ -102,14 +102,14 @@ #define RX_BUF_SIZE_SHIFT_DIV 6 struct wl1271_rx_descriptor { - u16 length; + __le16 length; u8 status; u8 flags; u8 rate; u8 channel; s8 rssi; u8 snr; - u32 timestamp; + __le32 timestamp; u8 packet_class; u8 process_id; u8 pad_len; diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 4560458a6d60..00af065c77c2 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -88,6 +88,7 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, { struct wl1271_tx_hw_descr *desc; int pad; + u16 tx_attr; desc = (struct wl1271_tx_hw_descr *) skb->data; @@ -95,16 +96,17 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, if (extra) { void *framestart = skb->data + sizeof(*desc); u16 fc = *(u16 *)(framestart + extra); - int hdrlen = ieee80211_hdrlen(fc); + int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc)); memmove(framestart, framestart + extra, hdrlen); } /* configure packet life time */ - desc->start_time = jiffies_to_usecs(jiffies) - wl->time_offset; - desc->life_time = TX_HW_MGMT_PKT_LIFETIME_TU; + desc->start_time = cpu_to_le32(jiffies_to_usecs(jiffies) - + wl->time_offset); + desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); /* configure the tx attributes */ - desc->tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; + tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; /* FIXME: do we know the packet priority? can we identify mgmt packets, and use max prio for them at least? */ desc->tid = 0; @@ -113,11 +115,13 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, /* align the length (and store in terms of words) */ pad = WL1271_TX_ALIGN(skb->len); - desc->length = pad >> 2; + desc->length = cpu_to_le16(pad >> 2); /* calculate number of padding bytes */ pad = pad - skb->len; - desc->tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; + tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; + + desc->tx_attr = cpu_to_le16(tx_attr); wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); return 0; @@ -331,7 +335,7 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count) wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); /* read the tx results from the chipset */ - wl1271_spi_read(wl, memmap->tx_result, + wl1271_spi_read(wl, le32_to_cpu(memmap->tx_result), wl->tx_res_if, sizeof(*wl->tx_res_if), false); /* verify that the result buffer is not getting overrun */ @@ -353,10 +357,10 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count) } /* write host counter to chipset (to ack) */ - wl1271_spi_write32(wl, memmap->tx_result + + wl1271_spi_write32(wl, le32_to_cpu(memmap->tx_result) + offsetof(struct wl1271_tx_hw_res_if, tx_result_host_counter), - wl->tx_res_if->tx_result_fw_counter); + le32_to_cpu(wl->tx_res_if->tx_result_fw_counter)); } /* caller must hold wl->mutex */ diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h index 4a614067ddba..416396caf0a0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.h +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h @@ -58,7 +58,7 @@ struct wl1271_tx_hw_descr { /* Length of packet in words, including descriptor+header+data */ - u16 length; + __le16 length; /* Number of extra memory blocks to allocate for this packet in addition to the number of blocks derived from the packet length */ u8 extra_mem_blocks; @@ -67,12 +67,12 @@ struct wl1271_tx_hw_descr { HW!! */ u8 total_mem_blocks; /* Device time (in us) when the packet arrived to the driver */ - u32 start_time; + __le32 start_time; /* Max delay in TUs until transmission. The last device time the packet can be transmitted is: startTime+(1024*LifeTime) */ - u16 life_time; + __le16 life_time; /* Bitwise fields - see TX_ATTR... definitions above. */ - u16 tx_attr; + __le16 tx_attr; /* Packet identifier used also in the Tx-Result. */ u8 id; /* The packet TID value (as User-Priority) */ @@ -100,12 +100,12 @@ struct wl1271_tx_hw_res_descr { several possible reasons for failure. */ u8 status; /* Total air access duration including all retrys and overheads.*/ - u16 medium_usage; + __le16 medium_usage; /* The time passed from host xfer to Tx-complete.*/ - u32 fw_handling_time; + __le32 fw_handling_time; /* Total media delay (from 1st EDCA AIFS counter until TX Complete). */ - u32 medium_delay; + __le32 medium_delay; /* LS-byte of last TKIP seq-num (saved per AC for recovery). */ u8 lsb_security_sequence_number; /* Retry count - number of transmissions without successful ACK.*/ @@ -118,8 +118,8 @@ struct wl1271_tx_hw_res_descr { } __attribute__ ((packed)); struct wl1271_tx_hw_res_if { - u32 tx_result_fw_counter; - u32 tx_result_host_counter; + __le32 tx_result_fw_counter; + __le32 tx_result_host_counter; struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN]; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h index 657c2dbcb7d3..055d7bc6f592 100644 --- a/drivers/net/wireless/wl12xx/wl12xx_80211.h +++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h @@ -122,8 +122,8 @@ struct wl12xx_null_data_template { } __attribute__ ((packed)); struct wl12xx_ps_poll_template { - u16 fc; - u16 aid; + __le16 fc; + __le16 aid; u8 bssid[ETH_ALEN]; u8 ta[ETH_ALEN]; } __attribute__ ((packed)); -- cgit v1.2.3 From fb46f26f383c3129ce4ae551a359a8e11704cbce Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 15 Oct 2009 10:33:30 +0300 Subject: wl1271: added missing packed modifier in some cmd structs Some of the struct definitions in the wl1271_acx.h file were missing the __attribute__ ((packed)) modifier. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 57d69057b4fa..174b8209dbf3 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -184,7 +184,7 @@ struct cmd_read_write_memory { of this field is the Host in WRITE command or the Wilink in READ command. */ u8 value[MAX_READ_SIZE]; -}; +} __attribute__ ((packed)); #define CMDMBOX_HEADER_LEN 4 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 @@ -399,12 +399,12 @@ struct wl1271_cmd_trigger_scan_to { struct wl1271_cmd_header header; __le32 timeout; -}; +} __attribute__ ((packed)); struct wl1271_cmd_test_header { u8 id; u8 padding[3]; -}; +} __attribute__ ((packed)); enum wl1271_channel_tune_bands { WL1271_CHANNEL_TUNE_BAND_2_4, -- cgit v1.2.3 From 2c759e03b3b7639fff23ec3b7bab64a35ca0914f Mon Sep 17 00:00:00 2001 From: David-John Willis Date: Thu, 15 Oct 2009 14:38:16 +0100 Subject: wl1251: add support for PG11 chips. This simple patch adds support for the PG11 variant of the WL1251 chip as used on the OpenPandora OMAP3 device. Signed-off-by: David-John Willis Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 23ac50303757..ec01e9dadb0d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -185,6 +185,9 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) break; case CHIP_ID_1251_PG10: case CHIP_ID_1251_PG11: + wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG11)", + wl->chip_id); + break; default: wl1251_error("unsupported chip id: 0x%x", wl->chip_id); ret = -ENODEV; -- cgit v1.2.3 From 88499ab3d8dbbf9c080416952603742666c71262 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 9 Oct 2009 20:33:32 +0200 Subject: b43: Optimize PIO scratchbuffer usage This optimizes the PIO scratchbuffer usage. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 16 ++------- drivers/net/wireless/b43/pio.c | 79 ++++++++++++++++++++++++----------------- drivers/net/wireless/b43/xmit.c | 2 +- 3 files changed, 51 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 660716214d49..65b23f725a04 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -749,12 +749,6 @@ struct b43_wldev { #endif }; -/* - * Include goes here to avoid a dependency problem. - * A better fix would be to integrate xmit.h into b43.h. - */ -#include "xmit.h" - /* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */ struct b43_wl { /* Pointer to the active wireless device on this chip */ @@ -830,13 +824,9 @@ struct b43_wl { struct b43_leds leds; #ifdef CONFIG_B43_PIO - /* - * RX/TX header/tail buffers used by the frame transmit functions. - */ - struct b43_rxhdr_fw4 rxhdr; - struct b43_txhdr txhdr; - u8 rx_tail[4]; - u8 tx_tail[4]; + /* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */ + u8 pio_scratchspace[110] __attribute__((__aligned__(8))); + u8 pio_tailspace[4] __attribute__((__aligned__(8))); #endif /* CONFIG_B43_PIO */ }; diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index dbbf0d11e18e..3105f235303a 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -341,12 +341,15 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q, q->mmio_base + B43_PIO_TXDATA, sizeof(u16)); if (data_len & 1) { + u8 *tail = wl->pio_tailspace; + BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2); + /* Write the last byte. */ ctl &= ~B43_PIO_TXCTL_WRITEHI; b43_piotx_write16(q, B43_PIO_TXCTL, ctl); - wl->tx_tail[0] = data[data_len - 1]; - wl->tx_tail[1] = 0; - ssb_block_write(dev->dev, wl->tx_tail, 2, + tail[0] = data[data_len - 1]; + tail[1] = 0; + ssb_block_write(dev->dev, tail, 2, q->mmio_base + B43_PIO_TXDATA, sizeof(u16)); } @@ -392,31 +395,31 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q, q->mmio_base + B43_PIO8_TXDATA, sizeof(u32)); if (data_len & 3) { - wl->tx_tail[3] = 0; + u8 *tail = wl->pio_tailspace; + BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4); + + memset(tail, 0, 4); /* Write the last few bytes. */ ctl &= ~(B43_PIO8_TXCTL_8_15 | B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_24_31); switch (data_len & 3) { case 3: ctl |= B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_8_15; - wl->tx_tail[0] = data[data_len - 3]; - wl->tx_tail[1] = data[data_len - 2]; - wl->tx_tail[2] = data[data_len - 1]; + tail[0] = data[data_len - 3]; + tail[1] = data[data_len - 2]; + tail[2] = data[data_len - 1]; break; case 2: ctl |= B43_PIO8_TXCTL_8_15; - wl->tx_tail[0] = data[data_len - 2]; - wl->tx_tail[1] = data[data_len - 1]; - wl->tx_tail[2] = 0; + tail[0] = data[data_len - 2]; + tail[1] = data[data_len - 1]; break; case 1: - wl->tx_tail[0] = data[data_len - 1]; - wl->tx_tail[1] = 0; - wl->tx_tail[2] = 0; + tail[0] = data[data_len - 1]; break; } b43_piotx_write32(q, B43_PIO8_TXCTL, ctl); - ssb_block_write(dev->dev, wl->tx_tail, 4, + ssb_block_write(dev->dev, tail, 4, q->mmio_base + B43_PIO8_TXDATA, sizeof(u32)); } @@ -455,6 +458,7 @@ static int pio_tx_frame(struct b43_pio_txqueue *q, int err; unsigned int hdrlen; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct b43_txhdr *txhdr = (struct b43_txhdr *)wl->pio_scratchspace; B43_WARN_ON(list_empty(&q->packets_list)); pack = list_entry(q->packets_list.next, @@ -462,7 +466,9 @@ static int pio_tx_frame(struct b43_pio_txqueue *q, cookie = generate_cookie(q, pack); hdrlen = b43_txhdr_size(dev); - err = b43_generate_txhdr(dev, (u8 *)&wl->txhdr, skb, + BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(struct b43_txhdr)); + B43_WARN_ON(sizeof(wl->pio_scratchspace) < hdrlen); + err = b43_generate_txhdr(dev, (u8 *)txhdr, skb, info, cookie); if (err) return err; @@ -476,9 +482,9 @@ static int pio_tx_frame(struct b43_pio_txqueue *q, pack->skb = skb; if (q->rev >= 8) - pio_tx_frame_4byte_queue(pack, (const u8 *)&wl->txhdr, hdrlen); + pio_tx_frame_4byte_queue(pack, (const u8 *)txhdr, hdrlen); else - pio_tx_frame_2byte_queue(pack, (const u8 *)&wl->txhdr, hdrlen); + pio_tx_frame_2byte_queue(pack, (const u8 *)txhdr, hdrlen); /* Remove it from the list of available packet slots. * It will be put back when we receive the status report. */ @@ -624,8 +630,11 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) unsigned int i, padding; struct sk_buff *skb; const char *err_msg = NULL; + struct b43_rxhdr_fw4 *rxhdr = + (struct b43_rxhdr_fw4 *)wl->pio_scratchspace; - memset(&wl->rxhdr, 0, sizeof(wl->rxhdr)); + BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(*rxhdr)); + memset(rxhdr, 0, sizeof(*rxhdr)); /* Check if we have data and wait for it to get ready. */ if (q->rev >= 8) { @@ -663,16 +672,16 @@ data_ready: /* Get the preamble (RX header) */ if (q->rev >= 8) { - ssb_block_read(dev->dev, &wl->rxhdr, sizeof(wl->rxhdr), + ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr), q->mmio_base + B43_PIO8_RXDATA, sizeof(u32)); } else { - ssb_block_read(dev->dev, &wl->rxhdr, sizeof(wl->rxhdr), + ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr), q->mmio_base + B43_PIO_RXDATA, sizeof(u16)); } /* Sanity checks. */ - len = le16_to_cpu(wl->rxhdr.frame_len); + len = le16_to_cpu(rxhdr->frame_len); if (unlikely(len > 0x700)) { err_msg = "len > 0x700"; goto rx_error; @@ -682,7 +691,7 @@ data_ready: goto rx_error; } - macstat = le32_to_cpu(wl->rxhdr.mac_status); + macstat = le32_to_cpu(rxhdr->mac_status); if (macstat & B43_RX_MAC_FCSERR) { if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) { /* Drop frames with failed FCS. */ @@ -707,22 +716,25 @@ data_ready: q->mmio_base + B43_PIO8_RXDATA, sizeof(u32)); if (len & 3) { + u8 *tail = wl->pio_tailspace; + BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4); + /* Read the last few bytes. */ - ssb_block_read(dev->dev, wl->rx_tail, 4, + ssb_block_read(dev->dev, tail, 4, q->mmio_base + B43_PIO8_RXDATA, sizeof(u32)); switch (len & 3) { case 3: - skb->data[len + padding - 3] = wl->rx_tail[0]; - skb->data[len + padding - 2] = wl->rx_tail[1]; - skb->data[len + padding - 1] = wl->rx_tail[2]; + skb->data[len + padding - 3] = tail[0]; + skb->data[len + padding - 2] = tail[1]; + skb->data[len + padding - 1] = tail[2]; break; case 2: - skb->data[len + padding - 2] = wl->rx_tail[0]; - skb->data[len + padding - 1] = wl->rx_tail[1]; + skb->data[len + padding - 2] = tail[0]; + skb->data[len + padding - 1] = tail[1]; break; case 1: - skb->data[len + padding - 1] = wl->rx_tail[0]; + skb->data[len + padding - 1] = tail[0]; break; } } @@ -731,15 +743,18 @@ data_ready: q->mmio_base + B43_PIO_RXDATA, sizeof(u16)); if (len & 1) { + u8 *tail = wl->pio_tailspace; + BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2); + /* Read the last byte. */ - ssb_block_read(dev->dev, wl->rx_tail, 2, + ssb_block_read(dev->dev, tail, 2, q->mmio_base + B43_PIO_RXDATA, sizeof(u16)); - skb->data[len + padding - 1] = wl->rx_tail[0]; + skb->data[len + padding - 1] = tail[0]; } } - b43_rx(q->dev, skb, &wl->rxhdr); + b43_rx(q->dev, skb, rxhdr); return 1; diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index f4e9695ec186..51d68971f6fa 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -27,7 +27,7 @@ */ -#include "b43.h" +#include "xmit.h" #include "phy_common.h" #include "dma.h" #include "pio.h" -- cgit v1.2.3 From 878283f19809bc73872c70ea53381f74a43a15e7 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 13 Oct 2009 20:33:21 +0300 Subject: wl1251: use ieee80211_rx_ni() Because of SPI and SDIO wl1251 does everything in a workqueue, including calling ieee80211_rx() which should be called with bottom halves disabled. An error message is emitted because of this: NOHZ: local_softirq_pending 08 Fix this by using ieee80211_rx_ni(). Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index 17c54b59ef86..601fe0d67827 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -153,7 +153,7 @@ static void wl1251_rx_body(struct wl1251 *wl, beacon ? "beacon" : ""); memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); - ieee80211_rx(wl->hw, skb); + ieee80211_rx_ni(wl->hw, skb); } static void wl1251_rx_ack(struct wl1251 *wl) -- cgit v1.2.3 From 5d78d34ba2d4a044983b599a697dc1d71af38c96 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 15 Oct 2009 21:38:19 +0200 Subject: rt2x00: Add rt2x00soc bus module Add new library module for SoC drivers. This is needed to fully support the platform driver part of rt2800pci. Based on original patch from Felix. Signed-off-by: Felix Fietkau Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 4 + drivers/net/wireless/rt2x00/Makefile | 1 + drivers/net/wireless/rt2x00/rt2x00soc.c | 159 ++++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00soc.h | 52 +++++++++++ 4 files changed, 216 insertions(+) create mode 100644 drivers/net/wireless/rt2x00/rt2x00soc.c create mode 100644 drivers/net/wireless/rt2x00/rt2x00soc.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index ed1f997e3521..e86895ac2d71 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -95,6 +95,10 @@ config RT2X00_LIB_PCI tristate select RT2X00_LIB +config RT2X00_LIB_SOC + tristate + select RT2X00_LIB + config RT2X00_LIB_USB tristate select RT2X00_LIB diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 13043ea97667..5b1ee4f6b8f3 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -11,6 +11,7 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o +obj-$(CONFIG_RT2X00_LIB_SOC) += rt2x00soc.o obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o obj-$(CONFIG_RT2400PCI) += rt2400pci.o obj-$(CONFIG_RT2500PCI) += rt2500pci.o diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c new file mode 100644 index 000000000000..539568c48953 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00soc.c @@ -0,0 +1,159 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00soc + Abstract: rt2x00 generic soc device routines. + */ + +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00soc.h" + +static void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev) +{ + kfree(rt2x00dev->rf); + rt2x00dev->rf = NULL; + + kfree(rt2x00dev->eeprom); + rt2x00dev->eeprom = NULL; +} + +static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev) +{ + struct platform_device *pdev = to_platform_device(rt2x00dev->dev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + rt2x00dev->csr.base = (void __iomem *)KSEG1ADDR(res->start); + if (!rt2x00dev->csr.base) + goto exit; + + rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); + if (!rt2x00dev->eeprom) + goto exit; + + rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); + if (!rt2x00dev->rf) + goto exit; + + return 0; + +exit: + ERROR_PROBE("Failed to allocate registers.\n"); + rt2x00soc_free_reg(rt2x00dev); + + return -ENOMEM; +} + +int rt2x00soc_probe(struct platform_device *pdev, + const unsigned short chipset, + const struct rt2x00_ops *ops) +{ + struct ieee80211_hw *hw; + struct rt2x00_dev *rt2x00dev; + int retval; + + hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); + if (!hw) { + ERROR_PROBE("Failed to allocate hardware.\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, hw); + + rt2x00dev = hw->priv; + rt2x00dev->dev = &pdev->dev; + rt2x00dev->ops = ops; + rt2x00dev->hw = hw; + rt2x00dev->irq = platform_get_irq(pdev, 0); + rt2x00dev->name = pdev->dev.driver->name; + + rt2x00_set_chip_rt(rt2x00dev, chipset); + + retval = rt2x00soc_alloc_reg(rt2x00dev); + if (retval) + goto exit_free_device; + + retval = rt2x00lib_probe_dev(rt2x00dev); + if (retval) + goto exit_free_reg; + + return 0; + +exit_free_reg: + rt2x00soc_free_reg(rt2x00dev); + +exit_free_device: + ieee80211_free_hw(hw); + + return retval; +} + +int rt2x00soc_remove(struct platform_device *pdev) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Free all allocated data. + */ + rt2x00lib_remove_dev(rt2x00dev); + rt2x00soc_free_reg(rt2x00dev); + ieee80211_free_hw(hw); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00soc_remove); + +#ifdef CONFIG_PM +int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + return rt2x00lib_suspend(rt2x00dev, state); +} +EXPORT_SYMBOL_GPL(rt2x00soc_suspend); + +int rt2x00soc_resume(struct platform_device *pdev) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + return rt2x00lib_resume(rt2x00dev); +} +EXPORT_SYMBOL_GPL(rt2x00soc_resume); +#endif /* CONFIG_PM */ + +/* + * rt2x00soc module information. + */ +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("rt2x00 soc library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.h b/drivers/net/wireless/rt2x00/rt2x00soc.h new file mode 100644 index 000000000000..5cf114ac2b9c --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00soc.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2x00soc + Abstract: Data structures for the rt2x00soc module. + */ + +#ifndef RT2X00SOC_H +#define RT2X00SOC_H + +#define KSEG1ADDR(__ptr) __ptr + +#define __rt2x00soc_probe(__chipset, __ops) \ +static int __rt2x00soc_probe(struct platform_device *pdev) \ +{ \ + return rt2x00soc_probe(pdev, (__chipset), (__ops)); \ +} + +/* + * SoC driver handlers. + */ +int rt2x00soc_probe(struct platform_device *pdev, + const unsigned short chipset, + const struct rt2x00_ops *ops); +int rt2x00soc_remove(struct platform_device *pdev); +#ifdef CONFIG_PM +int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state); +int rt2x00soc_resume(struct platform_device *pdev); +#else +#define rt2x00soc_suspend NULL +#define rt2x00soc_resume NULL +#endif /* CONFIG_PM */ + +#endif /* RT2X00SOC_H */ -- cgit v1.2.3 From a9b3a9f7214b3acc56330c2257aeaa5fa85bf520 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 15 Oct 2009 22:04:14 +0200 Subject: rt2x00: Implement support for rt2800pci Add support for the rt2860/rt3090 chipsets from Ralink. Includes various patches from a lot of people who helped getting this driver into the current shape. Signed-off-by: Alban Browaeys Signed-off-by: Benoit PAPILLAULT Signed-off-by: Felix Fietkau Signed-off-by: Luis Correia Signed-off-by: Mattias Nissler Signed-off-by: Mark Asselstine Signed-off-by: Xose Vazquez Perez Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 26 + drivers/net/wireless/rt2x00/Makefile | 1 + drivers/net/wireless/rt2x00/rt2800pci.c | 3323 +++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800pci.h | 1960 ++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00.h | 7 + 5 files changed, 5317 insertions(+) create mode 100644 drivers/net/wireless/rt2x00/rt2800pci.c create mode 100644 drivers/net/wireless/rt2x00/rt2800pci.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index e86895ac2d71..390c0c7b3ac2 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -53,6 +53,32 @@ config RT61PCI When compiled as a module, this driver will be called rt61pci. +config RT2800PCI_PCI + tristate + depends on PCI + default y + +config RT2800PCI_SOC + tristate + depends on RALINK_RT288X || RALINK_RT305X + default y + +config RT2800PCI + tristate "Ralink rt2800 (PCI/PCMCIA) support" + depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL + select RT2X00_LIB_PCI if RT2800PCI_PCI + select RT2X00_LIB_SOC if RT2800PCI_SOC + select RT2X00_LIB_HT + select RT2X00_LIB_FIRMWARE + select RT2X00_LIB_CRYPTO + select CRC_CCITT + select EEPROM_93CX6 + ---help--- + This adds support for rt2800 wireless chipset family. + Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052 + + When compiled as a module, this driver will be called "rt2800pci.ko". + config RT2500USB tristate "Ralink rt2500 (USB) support" depends on USB diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 5b1ee4f6b8f3..912f5f67e159 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o obj-$(CONFIG_RT2400PCI) += rt2400pci.o obj-$(CONFIG_RT2500PCI) += rt2500pci.o obj-$(CONFIG_RT61PCI) += rt61pci.o +obj-$(CONFIG_RT2800PCI) += rt2800pci.o obj-$(CONFIG_RT2500USB) += rt2500usb.o obj-$(CONFIG_RT73USB) += rt73usb.o obj-$(CONFIG_RT2800USB) += rt2800usb.o diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c new file mode 100644 index 000000000000..be81788b80c7 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -0,0 +1,3323 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2800pci + Abstract: rt2800pci device specific routines. + Supported chipsets: RT2800E & RT2800ED. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt2x00.h" +#include "rt2x00pci.h" +#include "rt2x00soc.h" +#include "rt2800pci.h" + +#ifdef CONFIG_RT2800PCI_PCI_MODULE +#define CONFIG_RT2800PCI_PCI +#endif + +#ifdef CONFIG_RT2800PCI_WISOC_MODULE +#define CONFIG_RT2800PCI_WISOC +#endif + +/* + * Allow hardware encryption to be disabled. + */ +static int modparam_nohwcrypt = 1; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + +/* + * Register access. + * BBP and RF register require indirect register access, + * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + */ +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) +#define WAIT_FOR_RFCSR(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) +#define WAIT_FOR_MCU(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \ + H2M_MAILBOX_CSR_OWNER, (__reg)) + +static void rt2800pci_bbp_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBP_CSR_CFG_VALUE, value); + rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); + rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); + rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); + + rt2x00pci_register_write(rt2x00dev, BBP_CSR_CFG, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800pci_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. + */ + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); + rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); + rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); + + rt2x00pci_register_write(rt2x00dev, BBP_CSR_CFG, reg); + + WAIT_FOR_BBP(rt2x00dev, ®); + } + + *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800pci_rfcsr_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RFCSR becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG_DATA, value); + rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); + rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800pci_rfcsr_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RFCSR becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. + */ + if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); + rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG, reg); + + WAIT_FOR_RFCSR(rt2x00dev, ®); + } + + *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800pci_rf_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG0_REG_VALUE_BW, value); + rt2x00_set_field32(®, RF_CSR_CFG0_STANDBYMODE, 0); + rt2x00_set_field32(®, RF_CSR_CFG0_SEL, 0); + rt2x00_set_field32(®, RF_CSR_CFG0_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG0, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800pci_mcu_request(struct rt2x00_dev *rt2x00dev, + const u8 command, const u8 token, + const u8 arg0, const u8 arg1) +{ + u32 reg; + + /* + * RT2880 and RT3052 don't support MCU requests. + */ + if (rt2x00_rt(&rt2x00dev->chip, RT2880) || + rt2x00_rt(&rt2x00dev->chip, RT3052)) + return; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the MCU becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_MCU(rt2x00dev, ®)) { + rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); + + reg = 0; + rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); + rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} + +static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) +{ + unsigned int i; + u32 reg; + + for (i = 0; i < 200; i++) { + rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); + + if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) || + (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) || + (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD2) == token) || + (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD3) == token)) + break; + + udelay(REGISTER_BUSY_DELAY); + } + + if (i == 200) + ERROR(rt2x00dev, "MCU request failed, no response from hardware\n"); + + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); +} + +#ifdef CONFIG_RT2800PCI_WISOC +static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) +{ + u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */ + + memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE); +} +#else +static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) +{ +} +#endif /* CONFIG_RT2800PCI_WISOC */ + +#ifdef CONFIG_RT2800PCI_PCI +static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); + + eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); + eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); + eeprom->reg_data_clock = + !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK); + eeprom->reg_chip_select = + !!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT); +} + +static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom) +{ + struct rt2x00_dev *rt2x00dev = eeprom->data; + u32 reg = 0; + + rt2x00_set_field32(®, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in); + rt2x00_set_field32(®, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out); + rt2x00_set_field32(®, E2PROM_CSR_DATA_CLOCK, + !!eeprom->reg_data_clock); + rt2x00_set_field32(®, E2PROM_CSR_CHIP_SELECT, + !!eeprom->reg_chip_select); + + rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg); +} + +static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) +{ + struct eeprom_93cx6 eeprom; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); + + eeprom.data = rt2x00dev; + eeprom.register_read = rt2800pci_eepromregister_read; + eeprom.register_write = rt2800pci_eepromregister_write; + eeprom.width = !rt2x00_get_field32(reg, E2PROM_CSR_TYPE) ? + PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66; + eeprom.reg_data_in = 0; + eeprom.reg_data_out = 0; + eeprom.reg_data_clock = 0; + eeprom.reg_chip_select = 0; + + eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom, + EEPROM_SIZE / sizeof(u16)); +} + +static void rt2800pci_efuse_read(struct rt2x00_dev *rt2x00dev, + unsigned int i) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, EFUSE_CTRL, ®); + rt2x00_set_field32(®, EFUSE_CTRL_ADDRESS_IN, i); + rt2x00_set_field32(®, EFUSE_CTRL_MODE, 0); + rt2x00_set_field32(®, EFUSE_CTRL_KICK, 1); + rt2x00pci_register_write(rt2x00dev, EFUSE_CTRL, reg); + + /* Wait until the EEPROM has been loaded */ + rt2x00pci_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®); + + /* Apparently the data is read from end to start */ + rt2x00pci_register_read(rt2x00dev, EFUSE_DATA3, + (u32 *)&rt2x00dev->eeprom[i]); + rt2x00pci_register_read(rt2x00dev, EFUSE_DATA2, + (u32 *)&rt2x00dev->eeprom[i + 2]); + rt2x00pci_register_read(rt2x00dev, EFUSE_DATA1, + (u32 *)&rt2x00dev->eeprom[i + 4]); + rt2x00pci_register_read(rt2x00dev, EFUSE_DATA0, + (u32 *)&rt2x00dev->eeprom[i + 6]); +} + +static void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + + for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8) + rt2800pci_efuse_read(rt2x00dev, i); +} +#else +static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) +{ +} + +static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) +{ +} +#endif /* CONFIG_RT2800PCI_PCI */ + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +static const struct rt2x00debug rt2800pci_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt2x00pci_register_read, + .write = rt2x00pci_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt2800pci_bbp_read, + .write = rt2800pci_bbp_write, + .word_base = BBP_BASE, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt2800pci_rf_write, + .word_base = RF_BASE, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +static int rt2800pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); + return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); +} + +#ifdef CONFIG_RT2X00_LIB_LEDS +static void rt2800pci_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + unsigned int enabled = brightness != LED_OFF; + unsigned int bg_mode = + (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); + unsigned int polarity = + rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, + EEPROM_FREQ_LED_POLARITY); + unsigned int ledmode = + rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, + EEPROM_FREQ_LED_MODE); + + if (led->type == LED_TYPE_RADIO) { + rt2800pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? 0x20 : 0); + } else if (led->type == LED_TYPE_ASSOC) { + rt2800pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); + } else if (led->type == LED_TYPE_QUALITY) { + /* + * The brightness is divided into 6 levels (0 - 5), + * The specs tell us the following levels: + * 0, 1 ,3, 7, 15, 31 + * to determine the level in a simple way we can simply + * work with bitshifting: + * (1 << level) - 1 + */ + rt2800pci_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, + (1 << brightness / (LED_FULL / 6)) - 1, + polarity); + } +} + +static int rt2800pci_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + u32 reg; + + rt2x00pci_register_read(led->rt2x00dev, LED_CFG, ®); + rt2x00_set_field32(®, LED_CFG_ON_PERIOD, *delay_on); + rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); + rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); + rt2x00_set_field32(®, LED_CFG_R_LED_MODE, 3); + rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 12); + rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3); + rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1); + rt2x00pci_register_write(led->rt2x00dev, LED_CFG, reg); + + return 0; +} + +static void rt2800pci_init_led(struct rt2x00_dev *rt2x00dev, + struct rt2x00_led *led, + enum led_type type) +{ + led->rt2x00dev = rt2x00dev; + led->type = type; + led->led_dev.brightness_set = rt2800pci_brightness_set; + led->led_dev.blink_set = rt2800pci_blink_set; + led->flags = LED_INITIALIZED; +} +#endif /* CONFIG_RT2X00_LIB_LEDS */ + +/* + * Configuration handlers. + */ +static void rt2800pci_config_wcid_attr(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct mac_wcid_entry wcid_entry; + struct mac_iveiv_entry iveiv_entry; + u32 offset; + u32 reg; + + offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); + + rt2x00pci_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, + !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, + (crypto->cmd == SET_KEY) * crypto->cipher); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, + (crypto->cmd == SET_KEY) * crypto->bssidx); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); + rt2x00pci_register_write(rt2x00dev, offset, reg); + + offset = MAC_IVEIV_ENTRY(key->hw_key_idx); + + memset(&iveiv_entry, 0, sizeof(iveiv_entry)); + if ((crypto->cipher == CIPHER_TKIP) || + (crypto->cipher == CIPHER_TKIP_NO_MIC) || + (crypto->cipher == CIPHER_AES)) + iveiv_entry.iv[3] |= 0x20; + iveiv_entry.iv[3] |= key->keyidx << 6; + rt2x00pci_register_multiwrite(rt2x00dev, offset, + &iveiv_entry, sizeof(iveiv_entry)); + + offset = MAC_WCID_ENTRY(key->hw_key_idx); + + memset(&wcid_entry, 0, sizeof(wcid_entry)); + if (crypto->cmd == SET_KEY) + memcpy(&wcid_entry, crypto->address, ETH_ALEN); + rt2x00pci_register_multiwrite(rt2x00dev, offset, + &wcid_entry, sizeof(wcid_entry)); +} + +static int rt2800pci_config_shared_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + struct rt2x00_field32 field; + u32 offset; + u32 reg; + + if (crypto->cmd == SET_KEY) { + key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx; + + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + offset = SHARED_KEY_ENTRY(key->hw_key_idx); + rt2x00pci_register_multiwrite(rt2x00dev, offset, + &key_entry, sizeof(key_entry)); + } + + /* + * The cipher types are stored over multiple registers + * starting with SHARED_KEY_MODE_BASE each word will have + * 32 bits and contains the cipher types for 2 bssidx each. + * Using the correct defines correctly will cause overhead, + * so just calculate the correct offset. + */ + field.bit_offset = 4 * (key->hw_key_idx % 8); + field.bit_mask = 0x7 << field.bit_offset; + + offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); + + rt2x00pci_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, field, + (crypto->cmd == SET_KEY) * crypto->cipher); + rt2x00pci_register_write(rt2x00dev, offset, reg); + + /* + * Update WCID information + */ + rt2800pci_config_wcid_attr(rt2x00dev, crypto, key); + + return 0; +} + +static int rt2800pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + u32 offset; + + if (crypto->cmd == SET_KEY) { + /* + * 1 pairwise key is possible per AID, this means that the AID + * equals our hw_key_idx. Make sure the WCID starts _after_ the + * last possible shared key entry. + */ + if (crypto->aid > (256 - 32)) + return -ENOSPC; + + key->hw_key_idx = 32 + crypto->aid; + + + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx); + rt2x00pci_register_multiwrite(rt2x00dev, offset, + &key_entry, sizeof(key_entry)); + } + + /* + * Update WCID information + */ + rt2800pci_config_wcid_attr(rt2x00dev, crypto, key); + + return 0; +} + +static void rt2800pci_config_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter_flags) +{ + u32 reg; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2x00pci_register_read(rt2x00dev, RX_FILTER_CFG, ®); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, + !(filter_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, + !(filter_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, + !(filter_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST, + !(filter_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BROADCAST, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_DUPLICATE, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END_ACK, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_ACK, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CTS, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, + !(filter_flags & FIF_PSPOLL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, + !(filter_flags & FIF_CONTROL)); + rt2x00pci_register_write(rt2x00dev, RX_FILTER_CFG, reg); +} + +static void rt2800pci_config_intf(struct rt2x00_dev *rt2x00dev, + struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, + const unsigned int flags) +{ + unsigned int beacon_base; + u32 reg; + + if (flags & CONFIG_UPDATE_TYPE) { + /* + * Clear current synchronisation setup. + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); + rt2x00pci_register_write(rt2x00dev, beacon_base, 0); + + /* + * Enable synchronisation. + */ + rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); + rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); + } + + if (flags & CONFIG_UPDATE_MAC) { + reg = le32_to_cpu(conf->mac[1]); + rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); + conf->mac[1] = cpu_to_le32(reg); + + rt2x00pci_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, + conf->mac, sizeof(conf->mac)); + } + + if (flags & CONFIG_UPDATE_BSSID) { + reg = le32_to_cpu(conf->bssid[1]); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 0); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); + conf->bssid[1] = cpu_to_le32(reg); + + rt2x00pci_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, + conf->bssid, sizeof(conf->bssid)); + } +} + +static void rt2800pci_config_erp(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_erp *erp) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20); + rt2x00pci_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, + !!erp->short_preamble); + rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, + !!erp->short_preamble); + rt2x00pci_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, + erp->cts_protection ? 2 : 0); + rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2x00pci_register_write(rt2x00dev, LEGACY_BASIC_RATE, + erp->basic_rates); + rt2x00pci_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + + rt2x00pci_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); + rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); + rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); + rt2x00pci_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, XIFS_TIME_CFG, ®); + rt2x00_set_field32(®, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4); + rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); + rt2x00pci_register_write(rt2x00dev, XIFS_TIME_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, + erp->beacon_int * 16); + rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); +} + +static void rt2800pci_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) +{ + u8 r1; + u8 r3; + + rt2800pci_bbp_read(rt2x00dev, 1, &r1); + rt2800pci_bbp_read(rt2x00dev, 3, &r3); + + /* + * Configure the TX antenna. + */ + switch ((int)ant->tx) { + case 1: + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); + break; + case 2: + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); + break; + case 3: + /* Do nothing */ + break; + } + + /* + * Configure the RX antenna. + */ + switch ((int)ant->rx) { + case 1: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); + break; + case 2: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1); + break; + case 3: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2); + break; + } + + rt2800pci_bbp_write(rt2x00dev, 3, r3); + rt2800pci_bbp_write(rt2x00dev, 1, r1); +} + +static void rt2800pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain; + + if (libconf->rf.channel <= 14) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG); + } else if (libconf->rf.channel <= 64) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); + } else if (libconf->rf.channel <= 128) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2); + } + + rt2x00dev->lna_gain = lna_gain; +} + +static void rt2800pci_config_channel_rt2x(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + if (rt2x00dev->default_ant.tx == 1) + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1); + + if (rt2x00dev->default_ant.rx == 1) { + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1); + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); + } else if (rt2x00dev->default_ant.rx == 2) + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); + + if (rf->channel > 14) { + /* + * When TX power is below 0, we should increase it by 7 to + * make it a positive value (Minumum value is -7). + * However this means that values between 0 and 7 have + * double meaning, and we should set a 7DBm boost flag. + */ + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, + (info->tx_power1 >= 0)); + + if (info->tx_power1 < 0) + info->tx_power1 += 7; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, + TXPOWER_A_TO_DEV(info->tx_power1)); + + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, + (info->tx_power2 >= 0)); + + if (info->tx_power2 < 0) + info->tx_power2 += 7; + + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, + TXPOWER_A_TO_DEV(info->tx_power2)); + } else { + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, + TXPOWER_G_TO_DEV(info->tx_power1)); + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, + TXPOWER_G_TO_DEV(info->tx_power2)); + } + + rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); + + rt2800pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2800pci_rf_write(rt2x00dev, 2, rf->rf2); + rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt2800pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2800pci_rf_write(rt2x00dev, 2, rf->rf2); + rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt2800pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt2800pci_rf_write(rt2x00dev, 1, rf->rf1); + rt2800pci_rf_write(rt2x00dev, 2, rf->rf2); + rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800pci_rf_write(rt2x00dev, 4, rf->rf4); +} + +static void rt2800pci_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + u8 rfcsr; + + rt2800pci_rfcsr_write(rt2x00dev, 2, rf->rf1); + rt2800pci_rfcsr_write(rt2x00dev, 2, rf->rf3); + + rt2800pci_rfcsr_read(rt2x00dev, 6, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); + rt2800pci_rfcsr_write(rt2x00dev, 6, rfcsr); + + rt2800pci_rfcsr_read(rt2x00dev, 12, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, + TXPOWER_G_TO_DEV(info->tx_power1)); + rt2800pci_rfcsr_write(rt2x00dev, 12, rfcsr); + + rt2800pci_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); + rt2800pci_rfcsr_write(rt2x00dev, 23, rfcsr); + + rt2800pci_rfcsr_write(rt2x00dev, 24, + rt2x00dev->calibration[conf_is_ht40(conf)]); + + rt2800pci_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); + rt2800pci_rfcsr_write(rt2x00dev, 23, rfcsr); +} + +static void rt2800pci_config_channel(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + u32 reg; + unsigned int tx_pin; + u8 bbp; + + if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) + rt2800pci_config_channel_rt2x(rt2x00dev, conf, rf, info); + else + rt2800pci_config_channel_rt3x(rt2x00dev, conf, rf, info); + + /* + * Change BBP settings + */ + rt2800pci_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); + rt2800pci_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); + rt2800pci_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); + rt2800pci_bbp_write(rt2x00dev, 86, 0); + + if (rf->channel <= 14) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + rt2800pci_bbp_write(rt2x00dev, 82, 0x62); + rt2800pci_bbp_write(rt2x00dev, 75, 0x46); + } else { + rt2800pci_bbp_write(rt2x00dev, 82, 0x84); + rt2800pci_bbp_write(rt2x00dev, 75, 0x50); + } + } else { + rt2800pci_bbp_write(rt2x00dev, 82, 0xf2); + + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + rt2800pci_bbp_write(rt2x00dev, 75, 0x46); + else + rt2800pci_bbp_write(rt2x00dev, 75, 0x50); + } + + rt2x00pci_register_read(rt2x00dev, TX_BAND_CFG, ®); + rt2x00_set_field32(®, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf)); + rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); + rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); + rt2x00pci_register_write(rt2x00dev, TX_BAND_CFG, reg); + + tx_pin = 0; + + /* Turn on unused PA or LNA when not using 1T or 1R */ + if (rt2x00dev->default_ant.tx != 1) { + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1); + } + + /* Turn on unused PA or LNA when not using 1T or 1R */ + if (rt2x00dev->default_ant.rx != 1) { + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1); + } + + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14); + + rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); + + rt2800pci_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); + rt2800pci_bbp_write(rt2x00dev, 4, bbp); + + rt2800pci_bbp_read(rt2x00dev, 3, &bbp); + rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); + rt2800pci_bbp_write(rt2x00dev, 3, bbp); + + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { + if (conf_is_ht40(conf)) { + rt2800pci_bbp_write(rt2x00dev, 69, 0x1a); + rt2800pci_bbp_write(rt2x00dev, 70, 0x0a); + rt2800pci_bbp_write(rt2x00dev, 73, 0x16); + } else { + rt2800pci_bbp_write(rt2x00dev, 69, 0x16); + rt2800pci_bbp_write(rt2x00dev, 70, 0x08); + rt2800pci_bbp_write(rt2x00dev, 73, 0x11); + } + } + + msleep(1); +} + +static void rt2800pci_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + u32 reg; + u32 value = TXPOWER_G_TO_DEV(txpower); + u8 r1; + + rt2800pci_bbp_read(rt2x00dev, 1, &r1); + rt2x00_set_field8(®, BBP1_TX_POWER, 0); + rt2800pci_bbp_write(rt2x00dev, 1, r1); + + rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_0, ®); + rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_2MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_55MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_11MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_6MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_9MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_12MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_18MBS, value); + rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_0, reg); + + rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_1, ®); + rt2x00_set_field32(®, TX_PWR_CFG_1_24MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_36MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_48MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_54MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS0, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS1, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS2, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS3, value); + rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_1, reg); + + rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_2, ®); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS4, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS5, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS6, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS7, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS8, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS9, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS10, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS11, value); + rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_2, reg); + + rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_3, ®); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS12, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS13, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS14, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS15, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN1, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN2, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN3, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN4, value); + rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_3, reg); + + rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_4, ®); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN5, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN6, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN7, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN8, value); + rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_4, reg); +} + +static void rt2800pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TX_RTY_CFG, ®); + rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, + libconf->conf->short_frame_max_tx_count); + rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_THRE, 2000); + rt2x00_set_field32(®, TX_RTY_CFG_NON_AGG_RTY_MODE, 0); + rt2x00_set_field32(®, TX_RTY_CFG_AGG_RTY_MODE, 0); + rt2x00_set_field32(®, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1); + rt2x00pci_register_write(rt2x00dev, TX_RTY_CFG, reg); +} + +static void rt2800pci_config_ps(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + enum dev_state state = + (libconf->conf->flags & IEEE80211_CONF_PS) ? + STATE_SLEEP : STATE_AWAKE; + u32 reg; + + if (state == STATE_SLEEP) { + rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); + + rt2x00pci_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, + libconf->conf->listen_interval - 1); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 1); + rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + } else { + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + + rt2x00pci_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); + rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + } +} + +static void rt2800pci_config(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf, + const unsigned int flags) +{ + /* Always recalculate LNA gain before changing configuration */ + rt2800pci_config_lna_gain(rt2x00dev, libconf); + + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) + rt2800pci_config_channel(rt2x00dev, libconf->conf, + &libconf->rf, &libconf->channel); + if (flags & IEEE80211_CONF_CHANGE_POWER) + rt2800pci_config_txpower(rt2x00dev, libconf->conf->power_level); + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt2800pci_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_PS) + rt2800pci_config_ps(rt2x00dev, libconf); +} + +/* + * Link tuning + */ +static void rt2800pci_link_stats(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual) +{ + u32 reg; + + /* + * Update FCS error count from register. + */ + rt2x00pci_register_read(rt2x00dev, RX_STA_CNT0, ®); + qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); +} + +static u8 rt2800pci_get_default_vgc(struct rt2x00_dev *rt2x00dev) +{ + if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) + return 0x2e + rt2x00dev->lna_gain; + + if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) + return 0x32 + (rt2x00dev->lna_gain * 5) / 3; + else + return 0x3a + (rt2x00dev->lna_gain * 5) / 3; +} + +static inline void rt2800pci_set_vgc(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual, u8 vgc_level) +{ + if (qual->vgc_level != vgc_level) { + rt2800pci_bbp_write(rt2x00dev, 66, vgc_level); + qual->vgc_level = vgc_level; + qual->vgc_level_reg = vgc_level; + } +} + +static void rt2800pci_reset_tuner(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual) +{ + rt2800pci_set_vgc(rt2x00dev, qual, + rt2800pci_get_default_vgc(rt2x00dev)); +} + +static void rt2800pci_link_tuner(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual, const u32 count) +{ + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) + return; + + /* + * When RSSI is better then -80 increase VGC level with 0x10 + */ + rt2800pci_set_vgc(rt2x00dev, qual, + rt2800pci_get_default_vgc(rt2x00dev) + + ((qual->rssi > -80) * 0x10)); +} + +/* + * Firmware functions + */ +static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) +{ + return FIRMWARE_RT2860; +} + +static int rt2800pci_check_firmware(struct rt2x00_dev *rt2x00dev, + const u8 *data, const size_t len) +{ + u16 fw_crc; + u16 crc; + + /* + * Only support 8kb firmware files. + */ + if (len != 8192) + return FW_BAD_LENGTH; + + /* + * The last 2 bytes in the firmware array are the crc checksum itself, + * this means that we should never pass those 2 bytes to the crc + * algorithm. + */ + fw_crc = (data[len - 2] << 8 | data[len - 1]); + + /* + * Use the crc ccitt algorithm. + * This will return the same value as the legacy driver which + * used bit ordering reversion on the both the firmware bytes + * before input input as well as on the final output. + * Obviously using crc ccitt directly is much more efficient. + */ + crc = crc_ccitt(~0, data, len - 2); + + /* + * There is a small difference between the crc-itu-t + bitrev and + * the crc-ccitt crc calculation. In the latter method the 2 bytes + * will be swapped, use swab16 to convert the crc to the correct + * value. + */ + crc = swab16(crc); + + return (fw_crc == crc) ? FW_OK : FW_BAD_CRC; +} + +static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev, + const u8 *data, const size_t len) +{ + unsigned int i; + u32 reg; + + /* + * Wait for stable hardware. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg && reg != ~0) + break; + msleep(1); + } + + if (i == REGISTER_BUSY_COUNT) { + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; + } + + rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002); + rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000); + + /* + * Disable DMA, will be reenabled later when enabling + * the radio. + */ + rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); + rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + /* + * enable Host program ram write selection + */ + reg = 0; + rt2x00_set_field32(®, PBF_SYS_CTRL_HOST_RAM_WRITE, 1); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, reg); + + /* + * Write firmware to device. + */ + rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, + data, len); + + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); + + /* + * Wait for device to stabilize. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY)) + break; + msleep(1); + } + + if (i == REGISTER_BUSY_COUNT) { + ERROR(rt2x00dev, "PBF system register not ready.\n"); + return -EBUSY; + } + + /* + * Disable interrupts + */ + rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_IRQ_OFF); + + /* + * Initialize BBP R/W access agent + */ + rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + + return 0; +} + +/* + * Initialization functions. + */ +static bool rt2800pci_get_entry_state(struct queue_entry *entry) +{ + struct queue_entry_priv_pci *entry_priv = entry->priv_data; + u32 word; + + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 1, &word); + + return (!rt2x00_get_field32(word, RXD_W1_DMA_DONE)); + } else { + rt2x00_desc_read(entry_priv->desc, 1, &word); + + return (!rt2x00_get_field32(word, TXD_W1_DMA_DONE)); + } +} + +static void rt2800pci_clear_entry(struct queue_entry *entry) +{ + struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + u32 word; + + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, RXD_W0_SDP0, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 0, word); + + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_DMA_DONE, 0); + rt2x00_desc_write(entry_priv->desc, 1, word); + } else { + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1); + rt2x00_desc_write(entry_priv->desc, 1, word); + } +} + +static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) +{ + struct queue_entry_priv_pci *entry_priv; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1); + rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg); + + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); + + /* + * Initialize registers. + */ + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT0, rt2x00dev->tx[0].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX0, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX0, 0); + + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT1, rt2x00dev->tx[1].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX1, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX1, 0); + + entry_priv = rt2x00dev->tx[2].entries[0].priv_data; + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT2, rt2x00dev->tx[2].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX2, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX2, 0); + + entry_priv = rt2x00dev->tx[3].entries[0].priv_data; + rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT3, rt2x00dev->tx[3].limit); + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX3, 0); + rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX3, 0); + + entry_priv = rt2x00dev->rx->entries[0].priv_data; + rt2x00pci_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma); + rt2x00pci_register_write(rt2x00dev, RX_MAX_CNT, rt2x00dev->rx[0].limit); + rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, rt2x00dev->rx[0].limit - 1); + rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0); + + /* + * Enable global DMA configuration + */ + rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); + rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + rt2x00pci_register_write(rt2x00dev, DELAY_INT_CFG, 0); + + return 0; +} + +static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + + rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + + rt2x00pci_register_read(rt2x00dev, BCN_OFFSET0, ®); + rt2x00_set_field32(®, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */ + rt2x00pci_register_write(rt2x00dev, BCN_OFFSET0, reg); + + rt2x00pci_register_read(rt2x00dev, BCN_OFFSET1, ®); + rt2x00_set_field32(®, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */ + rt2x00pci_register_write(rt2x00dev, BCN_OFFSET1, reg); + + rt2x00pci_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); + rt2x00pci_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + + rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0); + rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + rt2x00pci_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); + rt2x00pci_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); + + rt2x00pci_register_read(rt2x00dev, TX_LINK_CFG, ®); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32); + rt2x00_set_field32(®, TX_LINK_CFG_MFB_ENABLE, 0); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_MRQ_EN, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_RDG_EN, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_CF_ACK_EN, 1); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB, 0); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFS, 0); + rt2x00pci_register_write(rt2x00dev, TX_LINK_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10); + rt2x00pci_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, MAX_LEN_CFG, ®); + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); + if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION && + rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION) + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 2); + else + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); + rt2x00_set_field32(®, MAX_LEN_CFG_MIN_PSDU, 0); + rt2x00_set_field32(®, MAX_LEN_CFG_MIN_MPDU, 0); + rt2x00pci_register_write(rt2x00dev, MAX_LEN_CFG, reg); + + rt2x00pci_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); + + rt2x00pci_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2x00_set_field32(®, AUTO_RSP_CFG_AUTORESPONDER, 1); + rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MMODE, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MREF, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_DUAL_CTS_EN, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0); + rt2x00pci_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00pci_register_write(rt2x00dev, CCK_PROT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, 0x4004); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0); + rt2x00pci_register_write(rt2x00dev, MM20_PROT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00pci_register_write(rt2x00dev, MM40_PROT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, 0x4004); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0); + rt2x00pci_register_write(rt2x00dev, GF20_PROT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, 0x4084); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00pci_register_write(rt2x00dev, GF40_PROT_CFG, reg); + + rt2x00pci_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); + rt2x00pci_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); + + rt2x00pci_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, + IEEE80211_MAX_RTS_THRESHOLD); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_FBK_EN, 0); + rt2x00pci_register_write(rt2x00dev, TX_RTS_CFG, reg); + + rt2x00pci_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca); + rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + + /* + * ASIC will keep garbage value after boot, clear encryption keys. + */ + for (i = 0; i < 4; i++) + rt2x00pci_register_write(rt2x00dev, + SHARED_KEY_MODE_ENTRY(i), 0); + + for (i = 0; i < 256; i++) { + u32 wcid[2] = { 0xffffffff, 0x00ffffff }; + rt2x00pci_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), + wcid, sizeof(wcid)); + + rt2x00pci_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); + rt2x00pci_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); + } + + /* + * Clear all beacons + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE4, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE5, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE6, 0); + rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE7, 0); + + rt2x00pci_register_read(rt2x00dev, HT_FBK_CFG0, ®); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS0FBK, 0); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS1FBK, 0); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS2FBK, 1); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS3FBK, 2); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS4FBK, 3); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS5FBK, 4); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS6FBK, 5); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS7FBK, 6); + rt2x00pci_register_write(rt2x00dev, HT_FBK_CFG0, reg); + + rt2x00pci_register_read(rt2x00dev, HT_FBK_CFG1, ®); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS8FBK, 8); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS9FBK, 8); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS10FBK, 9); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS11FBK, 10); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS12FBK, 11); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS13FBK, 12); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS14FBK, 13); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS15FBK, 14); + rt2x00pci_register_write(rt2x00dev, HT_FBK_CFG1, reg); + + rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG0, ®); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 9); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 10); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 11); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 13); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); + rt2x00pci_register_write(rt2x00dev, LG_FBK_CFG0, reg); + + rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG1, ®); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS0FBK, 0); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS1FBK, 0); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS2FBK, 1); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS3FBK, 2); + rt2x00pci_register_write(rt2x00dev, LG_FBK_CFG1, reg); + + /* + * We must clear the error counters. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt2x00pci_register_read(rt2x00dev, RX_STA_CNT0, ®); + rt2x00pci_register_read(rt2x00dev, RX_STA_CNT1, ®); + rt2x00pci_register_read(rt2x00dev, RX_STA_CNT2, ®); + rt2x00pci_register_read(rt2x00dev, TX_STA_CNT0, ®); + rt2x00pci_register_read(rt2x00dev, TX_STA_CNT1, ®); + rt2x00pci_register_read(rt2x00dev, TX_STA_CNT2, ®); + + return 0; +} + +static int rt2800pci_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, MAC_STATUS_CFG, ®); + if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY)) + return 0; + + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP/RF register access failed, aborting.\n"); + return -EACCES; +} + +static int rt2800pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u8 value; + + /* + * BBP was enabled after firmware was loaded, + * but we need to reactivate it now. + */ + rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + msleep(1); + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800pci_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + return 0; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; +} + +static int rt2800pci_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + if (unlikely(rt2800pci_wait_bbp_rf_ready(rt2x00dev) || + rt2800pci_wait_bbp_ready(rt2x00dev))) + return -EACCES; + + rt2800pci_bbp_write(rt2x00dev, 65, 0x2c); + rt2800pci_bbp_write(rt2x00dev, 66, 0x38); + rt2800pci_bbp_write(rt2x00dev, 69, 0x12); + rt2800pci_bbp_write(rt2x00dev, 70, 0x0a); + rt2800pci_bbp_write(rt2x00dev, 73, 0x10); + rt2800pci_bbp_write(rt2x00dev, 81, 0x37); + rt2800pci_bbp_write(rt2x00dev, 82, 0x62); + rt2800pci_bbp_write(rt2x00dev, 83, 0x6a); + rt2800pci_bbp_write(rt2x00dev, 84, 0x99); + rt2800pci_bbp_write(rt2x00dev, 86, 0x00); + rt2800pci_bbp_write(rt2x00dev, 91, 0x04); + rt2800pci_bbp_write(rt2x00dev, 92, 0x00); + rt2800pci_bbp_write(rt2x00dev, 103, 0x00); + rt2800pci_bbp_write(rt2x00dev, 105, 0x05); + + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { + rt2800pci_bbp_write(rt2x00dev, 69, 0x16); + rt2800pci_bbp_write(rt2x00dev, 73, 0x12); + } + + if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) + rt2800pci_bbp_write(rt2x00dev, 84, 0x19); + + if (rt2x00_rt(&rt2x00dev->chip, RT3052)) { + rt2800pci_bbp_write(rt2x00dev, 31, 0x08); + rt2800pci_bbp_write(rt2x00dev, 78, 0x0e); + rt2800pci_bbp_write(rt2x00dev, 80, 0x08); + } + + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + rt2800pci_bbp_write(rt2x00dev, reg_id, value); + } + } + + return 0; +} + +static u8 rt2800pci_init_rx_filter(struct rt2x00_dev *rt2x00dev, + bool bw40, u8 rfcsr24, u8 filter_target) +{ + unsigned int i; + u8 bbp; + u8 rfcsr; + u8 passband; + u8 stopband; + u8 overtuned = 0; + + rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24); + + rt2800pci_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); + rt2800pci_bbp_write(rt2x00dev, 4, bbp); + + rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); + rt2800pci_rfcsr_write(rt2x00dev, 22, rfcsr); + + /* + * Set power & frequency of passband test tone + */ + rt2800pci_bbp_write(rt2x00dev, 24, 0); + + for (i = 0; i < 100; i++) { + rt2800pci_bbp_write(rt2x00dev, 25, 0x90); + msleep(1); + + rt2800pci_bbp_read(rt2x00dev, 55, &passband); + if (passband) + break; + } + + /* + * Set power & frequency of stopband test tone + */ + rt2800pci_bbp_write(rt2x00dev, 24, 0x06); + + for (i = 0; i < 100; i++) { + rt2800pci_bbp_write(rt2x00dev, 25, 0x90); + msleep(1); + + rt2800pci_bbp_read(rt2x00dev, 55, &stopband); + + if ((passband - stopband) <= filter_target) { + rfcsr24++; + overtuned += ((passband - stopband) == filter_target); + } else + break; + + rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24); + } + + rfcsr24 -= !!overtuned; + + rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24); + return rfcsr24; +} + +static int rt2800pci_init_rfcsr(struct rt2x00_dev *rt2x00dev) +{ + u8 rfcsr; + u8 bbp; + + if (!rt2x00_rf(&rt2x00dev->chip, RF3020) && + !rt2x00_rf(&rt2x00dev->chip, RF3021) && + !rt2x00_rf(&rt2x00dev->chip, RF3022)) + return 0; + + /* + * Init RF calibration. + */ + rt2800pci_rfcsr_read(rt2x00dev, 30, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); + rt2800pci_rfcsr_write(rt2x00dev, 30, rfcsr); + msleep(1); + rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); + rt2800pci_rfcsr_write(rt2x00dev, 30, rfcsr); + + rt2800pci_rfcsr_write(rt2x00dev, 0, 0x50); + rt2800pci_rfcsr_write(rt2x00dev, 1, 0x01); + rt2800pci_rfcsr_write(rt2x00dev, 2, 0xf7); + rt2800pci_rfcsr_write(rt2x00dev, 3, 0x75); + rt2800pci_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800pci_rfcsr_write(rt2x00dev, 5, 0x03); + rt2800pci_rfcsr_write(rt2x00dev, 6, 0x02); + rt2800pci_rfcsr_write(rt2x00dev, 7, 0x50); + rt2800pci_rfcsr_write(rt2x00dev, 8, 0x39); + rt2800pci_rfcsr_write(rt2x00dev, 9, 0x0f); + rt2800pci_rfcsr_write(rt2x00dev, 10, 0x60); + rt2800pci_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800pci_rfcsr_write(rt2x00dev, 12, 0x75); + rt2800pci_rfcsr_write(rt2x00dev, 13, 0x75); + rt2800pci_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800pci_rfcsr_write(rt2x00dev, 15, 0x58); + rt2800pci_rfcsr_write(rt2x00dev, 16, 0xb3); + rt2800pci_rfcsr_write(rt2x00dev, 17, 0x92); + rt2800pci_rfcsr_write(rt2x00dev, 18, 0x2c); + rt2800pci_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800pci_rfcsr_write(rt2x00dev, 20, 0xba); + rt2800pci_rfcsr_write(rt2x00dev, 21, 0xdb); + rt2800pci_rfcsr_write(rt2x00dev, 22, 0x00); + rt2800pci_rfcsr_write(rt2x00dev, 23, 0x31); + rt2800pci_rfcsr_write(rt2x00dev, 24, 0x08); + rt2800pci_rfcsr_write(rt2x00dev, 25, 0x01); + rt2800pci_rfcsr_write(rt2x00dev, 26, 0x25); + rt2800pci_rfcsr_write(rt2x00dev, 27, 0x23); + rt2800pci_rfcsr_write(rt2x00dev, 28, 0x13); + rt2800pci_rfcsr_write(rt2x00dev, 29, 0x83); + + /* + * Set RX Filter calibration for 20MHz and 40MHz + */ + rt2x00dev->calibration[0] = + rt2800pci_init_rx_filter(rt2x00dev, false, 0x07, 0x16); + rt2x00dev->calibration[1] = + rt2800pci_init_rx_filter(rt2x00dev, true, 0x27, 0x19); + + /* + * Set back to initial state + */ + rt2800pci_bbp_write(rt2x00dev, 24, 0); + + rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); + rt2800pci_rfcsr_write(rt2x00dev, 22, rfcsr); + + /* + * set BBP back to BW20 + */ + rt2800pci_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0); + rt2800pci_bbp_write(rt2x00dev, 4, bbp); + + return 0; +} + +/* + * Device state switch handlers. + */ +static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, + (state == STATE_RADIO_RX_ON) || + (state == STATE_RADIO_RX_ON_LINK)); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); +} + +static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int mask = (state == STATE_RADIO_IRQ_ON); + u32 reg; + + /* + * When interrupts are being enabled, the interrupt registers + * should clear the register to assure a clean state. + */ + if (state == STATE_RADIO_IRQ_ON) { + rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + } + + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00_set_field32(®, INT_MASK_CSR_RXDELAYINT, mask); + rt2x00_set_field32(®, INT_MASK_CSR_TXDELAYINT, mask); + rt2x00_set_field32(®, INT_MASK_CSR_RX_DONE, mask); + rt2x00_set_field32(®, INT_MASK_CSR_AC0_DMA_DONE, mask); + rt2x00_set_field32(®, INT_MASK_CSR_AC1_DMA_DONE, mask); + rt2x00_set_field32(®, INT_MASK_CSR_AC2_DMA_DONE, mask); + rt2x00_set_field32(®, INT_MASK_CSR_AC3_DMA_DONE, mask); + rt2x00_set_field32(®, INT_MASK_CSR_HCCA_DMA_DONE, mask); + rt2x00_set_field32(®, INT_MASK_CSR_MGMT_DMA_DONE, mask); + rt2x00_set_field32(®, INT_MASK_CSR_MCU_COMMAND, mask); + rt2x00_set_field32(®, INT_MASK_CSR_RXTX_COHERENT, mask); + rt2x00_set_field32(®, INT_MASK_CSR_TBTT, mask); + rt2x00_set_field32(®, INT_MASK_CSR_PRE_TBTT, mask); + rt2x00_set_field32(®, INT_MASK_CSR_TX_FIFO_STATUS, mask); + rt2x00_set_field32(®, INT_MASK_CSR_AUTO_WAKEUP, mask); + rt2x00_set_field32(®, INT_MASK_CSR_GPTIMER, mask); + rt2x00_set_field32(®, INT_MASK_CSR_RX_COHERENT, mask); + rt2x00_set_field32(®, INT_MASK_CSR_TX_COHERENT, mask); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); +} + +static int rt2800pci_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && + !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) + return 0; + + msleep(1); + } + + ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); + return -EACCES; +} + +static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 word; + + /* + * Initialize all registers. + */ + if (unlikely(rt2800pci_wait_wpdma_ready(rt2x00dev) || + rt2800pci_init_queues(rt2x00dev) || + rt2800pci_init_registers(rt2x00dev) || + rt2800pci_wait_wpdma_ready(rt2x00dev) || + rt2800pci_init_bbp(rt2x00dev) || + rt2800pci_init_rfcsr(rt2x00dev))) + return -EIO; + + /* + * Send signal to firmware during boot time. + */ + rt2800pci_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0); + + /* + * Enable RX. + */ + rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); + rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); + rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + /* + * Initialize LED control + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); + rt2800pci_mcu_request(rt2x00dev, MCU_LED_1, 0xff, + word & 0xff, (word >> 8) & 0xff); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); + rt2800pci_mcu_request(rt2x00dev, MCU_LED_2, 0xff, + word & 0xff, (word >> 8) & 0xff); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); + rt2800pci_mcu_request(rt2x00dev, MCU_LED_3, 0xff, + word & 0xff, (word >> 8) & 0xff); + + return 0; +} + +static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); + rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0); + rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0); + rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, 0); + + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280); + + rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1); + rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1); + rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg); + + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); + rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); + + /* Wait for DMA, ignore error */ + rt2800pci_wait_wpdma_ready(rt2x00dev); +} + +static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + /* + * Always put the device to sleep (even when we intend to wakeup!) + * if the device is booting and wasn't asleep it will return + * failure when attempting to wakeup. + */ + rt2800pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2); + + if (state == STATE_AWAKE) { + rt2800pci_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0); + rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP); + } + + return 0; +} + +static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, + enum dev_state state) +{ + int retval = 0; + + switch (state) { + case STATE_RADIO_ON: + /* + * Before the radio can be enabled, the device first has + * to be woken up. After that it needs a bit of time + * to be fully awake and then the radio can be enabled. + */ + rt2800pci_set_state(rt2x00dev, STATE_AWAKE); + msleep(1); + retval = rt2800pci_enable_radio(rt2x00dev); + break; + case STATE_RADIO_OFF: + /* + * After the radio has been disabled, the device should + * be put to sleep for powersaving. + */ + rt2800pci_disable_radio(rt2x00dev); + rt2800pci_set_state(rt2x00dev, STATE_SLEEP); + break; + case STATE_RADIO_RX_ON: + case STATE_RADIO_RX_ON_LINK: + case STATE_RADIO_RX_OFF: + case STATE_RADIO_RX_OFF_LINK: + rt2800pci_toggle_rx(rt2x00dev, state); + break; + case STATE_RADIO_IRQ_ON: + case STATE_RADIO_IRQ_OFF: + rt2800pci_toggle_irq(rt2x00dev, state); + break; + case STATE_DEEP_SLEEP: + case STATE_SLEEP: + case STATE_STANDBY: + case STATE_AWAKE: + retval = rt2800pci_set_state(rt2x00dev, state); + break; + default: + retval = -ENOTSUPP; + break; + } + + if (unlikely(retval)) + ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n", + state, retval); + + return retval; +} + +/* + * TX descriptor initialization + */ +static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, + struct txentry_desc *txdesc) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + __le32 *txd = skbdesc->desc; + __le32 *txwi = (__le32 *)(skb->data - rt2x00dev->hw->extra_tx_headroom); + u32 word; + + /* + * Initialize TX Info descriptor + */ + rt2x00_desc_read(txwi, 0, &word); + rt2x00_set_field32(&word, TXWI_W0_FRAG, + test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0); + rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0); + rt2x00_set_field32(&word, TXWI_W0_TS, + test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_AMPDU, + test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density); + rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->ifs); + rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs); + rt2x00_set_field32(&word, TXWI_W0_BW, + test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_SHORT_GI, + test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc); + rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode); + rt2x00_desc_write(txwi, 0, word); + + rt2x00_desc_read(txwi, 1, &word); + rt2x00_set_field32(&word, TXWI_W1_ACK, + test_bit(ENTRY_TXD_ACK, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W1_NSEQ, + test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size); + rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, + test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? + (skbdesc->entry->entry_idx + 1) : 0xff); + rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, + skb->len - txdesc->l2pad); + rt2x00_set_field32(&word, TXWI_W1_PACKETID, + skbdesc->entry->queue->qid + 1); + rt2x00_desc_write(txwi, 1, word); + + /* + * Always write 0 to IV/EIV fields, hardware will insert the IV + * from the IVEIV register when ENTRY_TXD_ENCRYPT_IV is set to 0. + * When ENTRY_TXD_ENCRYPT_IV is set to 1 it will use the IV data + * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which + * crypto entry in the registers should be used to encrypt the frame. + */ + _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */); + _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */); + + /* + * The buffers pointed by SD_PTR0/SD_LEN0 and SD_PTR1/SD_LEN1 + * must contains a TXWI structure + 802.11 header + padding + 802.11 + * data. We choose to have SD_PTR0/SD_LEN0 only contains TXWI and + * SD_PTR1/SD_LEN1 contains 802.11 header + padding + 802.11 + * data. It means that LAST_SEC0 is always 0. + */ + + /* + * Initialize TX descriptor + */ + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_SD_PTR0, skbdesc->skb_dma); + rt2x00_desc_write(txd, 0, word); + + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_SD_LEN1, skb->len); + rt2x00_set_field32(&word, TXD_W1_LAST_SEC1, + !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W1_BURST, + test_bit(ENTRY_TXD_BURST, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W1_SD_LEN0, + rt2x00dev->hw->extra_tx_headroom); + rt2x00_set_field32(&word, TXD_W1_LAST_SEC0, 0); + rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0); + rt2x00_desc_write(txd, 1, word); + + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_SD_PTR1, + skbdesc->skb_dma + rt2x00dev->hw->extra_tx_headroom); + rt2x00_desc_write(txd, 2, word); + + rt2x00_desc_read(txd, 3, &word); + rt2x00_set_field32(&word, TXD_W3_WIV, + !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags)); + rt2x00_set_field32(&word, TXD_W3_QSEL, 2); + rt2x00_desc_write(txd, 3, word); +} + +/* + * TX data initialization + */ +static void rt2800pci_write_beacon(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + unsigned int beacon_base; + u32 reg; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); + rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + /* + * Write entire beacon with descriptor to register. + */ + beacon_base = HW_BEACON_OFFSET(entry->entry_idx); + rt2x00pci_register_multiwrite(rt2x00dev, + beacon_base, + skbdesc->desc, skbdesc->desc_len); + rt2x00pci_register_multiwrite(rt2x00dev, + beacon_base + skbdesc->desc_len, + entry->skb->data, entry->skb->len); + + /* + * Clean up beacon skb. + */ + dev_kfree_skb_any(entry->skb); + entry->skb = NULL; +} + +static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, + const enum data_queue_qid queue_idx) +{ + struct data_queue *queue; + unsigned int idx, qidx = 0; + u32 reg; + + if (queue_idx == QID_BEACON) { + rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) { + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); + rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); + } + return; + } + + if (queue_idx > QID_HCCA && queue_idx != QID_MGMT) + return; + + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + idx = queue->index[Q_INDEX]; + + if (queue_idx == QID_MGMT) + qidx = 5; + else + qidx = queue_idx; + + rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx); +} + +static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, + const enum data_queue_qid qid) +{ + u32 reg; + + if (qid == QID_BEACON) { + rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, 0); + return; + } + + rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, (qid == QID_AC_BE)); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, (qid == QID_AC_BK)); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, (qid == QID_AC_VI)); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, (qid == QID_AC_VO)); + rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg); +} + +/* + * RX control handlers + */ +static void rt2800pci_fill_rxdone(struct queue_entry *entry, + struct rxdone_entry_desc *rxdesc) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + struct queue_entry_priv_pci *entry_priv = entry->priv_data; + __le32 *rxd = entry_priv->desc; + __le32 *rxwi = (__le32 *)entry->skb->data; + u32 rxd3; + u32 rxwi0; + u32 rxwi1; + u32 rxwi2; + u32 rxwi3; + + rt2x00_desc_read(rxd, 3, &rxd3); + rt2x00_desc_read(rxwi, 0, &rxwi0); + rt2x00_desc_read(rxwi, 1, &rxwi1); + rt2x00_desc_read(rxwi, 2, &rxwi2); + rt2x00_desc_read(rxwi, 3, &rxwi3); + + if (rt2x00_get_field32(rxd3, RXD_W3_CRC_ERROR)) + rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; + + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + /* + * Unfortunately we don't know the cipher type used during + * decryption. This prevents us from correct providing + * correct statistics through debugfs. + */ + rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF); + rxdesc->cipher_status = + rt2x00_get_field32(rxd3, RXD_W3_CIPHER_ERROR); + } + + if (rt2x00_get_field32(rxd3, RXD_W3_DECRYPTED)) { + /* + * Hardware has stripped IV/EIV data from 802.11 frame during + * decryption. Unfortunately the descriptor doesn't contain + * any fields with the EIV/IV data either, so they can't + * be restored by rt2x00lib. + */ + rxdesc->flags |= RX_FLAG_IV_STRIPPED; + + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) + rxdesc->flags |= RX_FLAG_DECRYPTED; + else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) + rxdesc->flags |= RX_FLAG_MMIC_ERROR; + } + + if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS)) + rxdesc->dev_flags |= RXDONE_MY_BSS; + + if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD)) { + rxdesc->dev_flags |= RXDONE_L2PAD; + skbdesc->flags |= SKBDESC_L2_PADDED; + } + + if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI)) + rxdesc->flags |= RX_FLAG_SHORT_GI; + + if (rt2x00_get_field32(rxwi1, RXWI_W1_BW)) + rxdesc->flags |= RX_FLAG_40MHZ; + + /* + * Detect RX rate, always use MCS as signal type. + */ + rxdesc->dev_flags |= RXDONE_SIGNAL_MCS; + rxdesc->rate_mode = rt2x00_get_field32(rxwi1, RXWI_W1_PHYMODE); + rxdesc->signal = rt2x00_get_field32(rxwi1, RXWI_W1_MCS); + + /* + * Mask of 0x8 bit to remove the short preamble flag. + */ + if (rxdesc->rate_mode == RATE_MODE_CCK) + rxdesc->signal &= ~0x8; + + rxdesc->rssi = + (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) + + rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2; + + rxdesc->noise = + (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) + + rt2x00_get_field32(rxwi3, RXWI_W3_SNR1)) / 2; + + rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT); + + /* + * Set RX IDX in register to inform hardware that we have handled + * this entry and it is available for reuse again. + */ + rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx); + + /* + * Remove TXWI descriptor from start of buffer. + */ + skb_pull(entry->skb, RXWI_DESC_SIZE); + skb_trim(entry->skb, rxdesc->size); +} + +/* + * Interrupt functions. + */ +static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) +{ + struct data_queue *queue; + struct queue_entry *entry; + struct queue_entry *entry_done; + struct queue_entry_priv_pci *entry_priv; + struct txdone_entry_desc txdesc; + u32 word; + u32 reg; + u32 old_reg; + unsigned int type; + unsigned int index; + u16 mcs, real_mcs; + + /* + * During each loop we will compare the freshly read + * TX_STA_FIFO register value with the value read from + * the previous loop. If the 2 values are equal then + * we should stop processing because the chance it + * quite big that the device has been unplugged and + * we risk going into an endless loop. + */ + old_reg = 0; + + while (1) { + rt2x00pci_register_read(rt2x00dev, TX_STA_FIFO, ®); + if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID)) + break; + + if (old_reg == reg) + break; + old_reg = reg; + + /* + * Skip this entry when it contains an invalid + * queue identication number. + */ + type = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1; + if (type >= QID_RX) + continue; + + queue = rt2x00queue_get_queue(rt2x00dev, type); + if (unlikely(!queue)) + continue; + + /* + * Skip this entry when it contains an invalid + * index number. + */ + index = rt2x00_get_field32(reg, TX_STA_FIFO_WCID) - 1; + if (unlikely(index >= queue->limit)) + continue; + + entry = &queue->entries[index]; + entry_priv = entry->priv_data; + rt2x00_desc_read((__le32 *)entry->skb->data, 0, &word); + + entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + while (entry != entry_done) { + /* + * Catch up. + * Just report any entries we missed as failed. + */ + WARNING(rt2x00dev, + "TX status report missed for entry %d\n", + entry_done->entry_idx); + + txdesc.flags = 0; + __set_bit(TXDONE_UNKNOWN, &txdesc.flags); + txdesc.retry = 0; + + rt2x00lib_txdone(entry_done, &txdesc); + entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE); + } + + /* + * Obtain the status about this packet. + */ + txdesc.flags = 0; + if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) + __set_bit(TXDONE_SUCCESS, &txdesc.flags); + else + __set_bit(TXDONE_FAILURE, &txdesc.flags); + + /* + * Ralink has a retry mechanism using a global fallback + * table. We setup this fallback table to try immediate + * lower rate for all rates. In the TX_STA_FIFO, + * the MCS field contains the MCS used for the successfull + * transmission. If the first transmission succeed, + * we have mcs == tx_mcs. On the second transmission, + * we have mcs = tx_mcs - 1. So the number of + * retry is (tx_mcs - mcs). + */ + mcs = rt2x00_get_field32(word, TXWI_W0_MCS); + real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS); + __set_bit(TXDONE_FALLBACK, &txdesc.flags); + txdesc.retry = mcs - min(mcs, real_mcs); + + rt2x00lib_txdone(entry, &txdesc); + } +} + +static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) +{ + struct rt2x00_dev *rt2x00dev = dev_instance; + u32 reg; + + /* Read status and ACK all interrupts */ + rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + + if (!reg) + return IRQ_NONE; + + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return IRQ_HANDLED; + + /* + * 1 - Rx ring done interrupt. + */ + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE)) + rt2x00pci_rxdone(rt2x00dev); + + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) + rt2800pci_txdone(rt2x00dev); + + return IRQ_HANDLED; +} + +/* + * Device probe functions. + */ +static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u16 word; + u8 *mac; + u8 default_lna_gain; + + /* + * Read EEPROM into buffer + */ + switch(rt2x00dev->chip.rt) { + case RT2880: + case RT3052: + rt2800pci_read_eeprom_soc(rt2x00dev); + break; + case RT3090: + rt2800pci_read_eeprom_efuse(rt2x00dev); + break; + default: + rt2800pci_read_eeprom_pci(rt2x00dev); + break; + } + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { + /* + * There is a max of 2 RX streams for RT2860 series + */ + if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) + rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); + rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0); + rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + if ((word & 0x00ff) == 0x00ff) { + rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); + rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, + LED_MODE_TXRX_ACTIVITY); + rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8); + EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); + } + + /* + * During the LNA validation we are going to use + * lna0 as correct value. Note that EEPROM_LNA + * is never validated. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word); + default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); + if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, + default_lna_gain); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); + if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, + default_lna_gain); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); + + return 0; +} + +static int rt2800pci_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00_set_chip_rf(rt2x00dev, value, reg); + + if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && + !rt2x00_rf(&rt2x00dev->chip, RF2850) && + !rt2x00_rf(&rt2x00dev->chip, RF2720) && + !rt2x00_rf(&rt2x00dev->chip, RF2750) && + !rt2x00_rf(&rt2x00dev->chip, RF3020) && + !rt2x00_rf(&rt2x00dev->chip, RF2020) && + !rt2x00_rf(&rt2x00dev->chip, RF3021) && + !rt2x00_rf(&rt2x00dev->chip, RF3022)) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->default_ant.tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH); + rt2x00dev->default_ant.rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH); + + /* + * Read frequency offset and RF programming sequence. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + + /* + * Read external LNA informations. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) + __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) + __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + + /* + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO)) + __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + + /* + * Store led settings, for correct led behaviour. + */ +#ifdef CONFIG_RT2X00_LIB_LEDS + rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); + rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); + rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); +#endif /* CONFIG_RT2X00_LIB_LEDS */ + + return 0; +} + +/* + * RF value list for rt2860 + * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750) + */ +static const struct rf_channel rf_vals[] = { + { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b }, + { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f }, + { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b }, + { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f }, + { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b }, + { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f }, + { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b }, + { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f }, + { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b }, + { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f }, + { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b }, + { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f }, + { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b }, + { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 }, + { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 }, + { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 }, + { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 }, + { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b }, + { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b }, + { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 }, + { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 }, + { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b }, + { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 }, + { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 }, + { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 }, + + /* 802.11 HyperLan 2 */ + { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 }, + { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 }, + { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 }, + { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 }, + { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 }, + { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b }, + { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 }, + { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 }, + { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 }, + { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 }, + { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b }, + { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 }, + { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b }, + { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 }, + { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b }, + { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 }, + + /* 802.11 UNII */ + { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 }, + { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 }, + { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f }, + { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f }, + { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 }, + { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 }, + { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 }, + + /* 802.11 Japan */ + { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b }, + { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 }, + { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b }, + { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 }, + { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 }, + { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b }, + { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 }, +}; + +static int rt2800pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct hw_mode_spec *spec = &rt2x00dev->spec; + struct channel_info *info; + char *tx_power1; + char *tx_power2; + unsigned int i; + u16 eeprom; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK; + rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE; + + SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Initialize hw_mode information. + */ + spec->supported_bands = SUPPORT_BAND_2GHZ; + spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; + + if (rt2x00_rf(&rt2x00dev->chip, RF2820) || + rt2x00_rf(&rt2x00dev->chip, RF2720) || + rt2x00_rf(&rt2x00dev->chip, RF3020) || + rt2x00_rf(&rt2x00dev->chip, RF3021) || + rt2x00_rf(&rt2x00dev->chip, RF3022) || + rt2x00_rf(&rt2x00dev->chip, RF2020) || + rt2x00_rf(&rt2x00dev->chip, RF3052)) { + spec->num_channels = 14; + spec->channels = rf_vals; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2850) || + rt2x00_rf(&rt2x00dev->chip, RF2750)) { + spec->supported_bands |= SUPPORT_BAND_5GHZ; + spec->num_channels = ARRAY_SIZE(rf_vals); + spec->channels = rf_vals; + } + + /* + * Initialize HT information. + */ + spec->ht.ht_supported = true; + spec->ht.cap = + IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_TX_STBC | + IEEE80211_HT_CAP_RX_STBC | + IEEE80211_HT_CAP_PSMP_SUPPORT; + spec->ht.ampdu_factor = 3; + spec->ht.ampdu_density = 4; + spec->ht.mcs.tx_params = + IEEE80211_HT_MCS_TX_DEFINED | + IEEE80211_HT_MCS_TX_RX_DIFF | + ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + + switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) { + case 3: + spec->ht.mcs.rx_mask[2] = 0xff; + case 2: + spec->ht.mcs.rx_mask[1] = 0xff; + case 1: + spec->ht.mcs.rx_mask[0] = 0xff; + spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */ + break; + } + + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + spec->channels_info = info; + + tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); + tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); + + for (i = 0; i < 14; i++) { + info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); + info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); + } + + if (spec->num_channels > 14) { + tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); + tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); + + for (i = 14; i < spec->num_channels; i++) { + info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); + info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); + } + } + + return 0; +} + +static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + /* + * Allocate eeprom data. + */ + retval = rt2800pci_validate_eeprom(rt2x00dev); + if (retval) + return retval; + + retval = rt2800pci_init_eeprom(rt2x00dev); + if (retval) + return retval; + + /* + * Initialize hw specifications. + */ + retval = rt2800pci_probe_hw_mode(rt2x00dev); + if (retval) + return retval; + + /* + * This device has multiple filters for control frames + * and has a separate filter for PS Poll frames. + */ + __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags); + __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags); + + /* + * This device requires firmware. + */ + if (!rt2x00_rt(&rt2x00dev->chip, RT2880) && + !rt2x00_rt(&rt2x00dev->chip, RT3052)) + __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); + if (!modparam_nohwcrypt) + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); + + /* + * Set the rssi offset. + */ + rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET; + + return 0; +} + +/* + * IEEE80211 stack callback functions. + */ +static void rt2800pci_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, + u32 *iv32, u16 *iv16) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct mac_iveiv_entry iveiv_entry; + u32 offset; + + offset = MAC_IVEIV_ENTRY(hw_key_idx); + rt2x00pci_register_multiread(rt2x00dev, offset, + &iveiv_entry, sizeof(iveiv_entry)); + + memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16)); + memcpy(&iveiv_entry.iv[4], iv32, sizeof(iv32)); +} + +static int rt2800pci_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD); + + rt2x00pci_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, value); + rt2x00pci_register_write(rt2x00dev, TX_RTS_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, enabled); + rt2x00pci_register_write(rt2x00dev, CCK_PROT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, enabled); + rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, enabled); + rt2x00pci_register_write(rt2x00dev, MM20_PROT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, enabled); + rt2x00pci_register_write(rt2x00dev, MM40_PROT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, enabled); + rt2x00pci_register_write(rt2x00dev, GF20_PROT_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2x00_set_field32(®, GF40_PROT_CFG_RTS_TH_EN, enabled); + rt2x00pci_register_write(rt2x00dev, GF40_PROT_CFG, reg); + + return 0; +} + +static int rt2800pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + struct rt2x00_field32 field; + int retval; + u32 reg; + u32 offset; + + /* + * First pass the configuration through rt2x00lib, that will + * update the queue settings and validate the input. After that + * we are free to update the registers based on the value + * in the queue parameter. + */ + retval = rt2x00mac_conf_tx(hw, queue_idx, params); + if (retval) + return retval; + + /* + * We only need to perform additional register initialization + * for WMM queues/ + */ + if (queue_idx >= 4) + return 0; + + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + + /* Update WMM TXOP register */ + offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2))); + field.bit_offset = (queue_idx & 1) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, field, queue->txop); + rt2x00pci_register_write(rt2x00dev, offset, reg); + + /* Update WMM registers */ + field.bit_offset = queue_idx * 4; + field.bit_mask = 0xf << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); + rt2x00_set_field32(®, field, queue->aifs); + rt2x00pci_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); + rt2x00_set_field32(®, field, queue->cw_min); + rt2x00pci_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); + + rt2x00pci_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); + rt2x00_set_field32(®, field, queue->cw_max); + rt2x00pci_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); + + /* Update EDCA registers */ + offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx); + + rt2x00pci_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop); + rt2x00_set_field32(®, EDCA_AC0_CFG_AIFSN, queue->aifs); + rt2x00_set_field32(®, EDCA_AC0_CFG_CWMIN, queue->cw_min); + rt2x00_set_field32(®, EDCA_AC0_CFG_CWMAX, queue->cw_max); + rt2x00pci_register_write(rt2x00dev, offset, reg); + + return 0; +} + +static u64 rt2800pci_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt2x00pci_register_read(rt2x00dev, TSF_TIMER_DW1, ®); + tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32; + rt2x00pci_register_read(rt2x00dev, TSF_TIMER_DW0, ®); + tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD); + + return tsf; +} + +static const struct ieee80211_ops rt2800pci_mac80211_ops = { + .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .configure_filter = rt2x00mac_configure_filter, + .set_key = rt2x00mac_set_key, + .get_stats = rt2x00mac_get_stats, + .get_tkip_seq = rt2800pci_get_tkip_seq, + .set_rts_threshold = rt2800pci_set_rts_threshold, + .bss_info_changed = rt2x00mac_bss_info_changed, + .conf_tx = rt2800pci_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .get_tsf = rt2800pci_get_tsf, + .rfkill_poll = rt2x00mac_rfkill_poll, +}; + +static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { + .irq_handler = rt2800pci_interrupt, + .probe_hw = rt2800pci_probe_hw, + .get_firmware_name = rt2800pci_get_firmware_name, + .check_firmware = rt2800pci_check_firmware, + .load_firmware = rt2800pci_load_firmware, + .initialize = rt2x00pci_initialize, + .uninitialize = rt2x00pci_uninitialize, + .get_entry_state = rt2800pci_get_entry_state, + .clear_entry = rt2800pci_clear_entry, + .set_device_state = rt2800pci_set_device_state, + .rfkill_poll = rt2800pci_rfkill_poll, + .link_stats = rt2800pci_link_stats, + .reset_tuner = rt2800pci_reset_tuner, + .link_tuner = rt2800pci_link_tuner, + .write_tx_desc = rt2800pci_write_tx_desc, + .write_tx_data = rt2x00pci_write_tx_data, + .write_beacon = rt2800pci_write_beacon, + .kick_tx_queue = rt2800pci_kick_tx_queue, + .kill_tx_queue = rt2800pci_kill_tx_queue, + .fill_rxdone = rt2800pci_fill_rxdone, + .config_shared_key = rt2800pci_config_shared_key, + .config_pairwise_key = rt2800pci_config_pairwise_key, + .config_filter = rt2800pci_config_filter, + .config_intf = rt2800pci_config_intf, + .config_erp = rt2800pci_config_erp, + .config_ant = rt2800pci_config_ant, + .config = rt2800pci_config, +}; + +static const struct data_queue_desc rt2800pci_queue_rx = { + .entry_num = RX_ENTRIES, + .data_size = AGGREGATION_SIZE, + .desc_size = RXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci), +}; + +static const struct data_queue_desc rt2800pci_queue_tx = { + .entry_num = TX_ENTRIES, + .data_size = AGGREGATION_SIZE, + .desc_size = TXD_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci), +}; + +static const struct data_queue_desc rt2800pci_queue_bcn = { + .entry_num = 8 * BEACON_ENTRIES, + .data_size = 0, /* No DMA required for beacons */ + .desc_size = TXWI_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_pci), +}; + +static const struct rt2x00_ops rt2800pci_ops = { + .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 8, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, + .rx = &rt2800pci_queue_rx, + .tx = &rt2800pci_queue_tx, + .bcn = &rt2800pci_queue_bcn, + .lib = &rt2800pci_rt2x00_ops, + .hw = &rt2800pci_mac80211_ops, +#ifdef CONFIG_RT2X00_LIB_DEBUGFS + .debugfs = &rt2800pci_rt2x00debug, +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ +}; + +/* + * RT2800pci module information. + */ +static struct pci_device_id rt2800pci_device_table[] = { + { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1432, 0x7738), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) }, + { 0, } +}; + +MODULE_AUTHOR(DRV_PROJECT); +MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Ralink RT2800 PCI & PCMCIA Wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Ralink RT2860 PCI & PCMCIA chipset based cards"); +#ifdef CONFIG_RT2800PCI_PCI +MODULE_FIRMWARE(FIRMWARE_RT2860); +MODULE_DEVICE_TABLE(pci, rt2800pci_device_table); +#endif /* CONFIG_RT2800PCI_PCI */ +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_RT2800PCI_WISOC +#if defined(CONFIG_RALINK_RT288X) +__rt2x00soc_probe(RT2880, &rt2800pci_ops); +#elif defined(CONFIG_RALINK_RT305X) +__rt2x00soc_probe(RT3052, &rt2800pci_ops); +#endif + +static struct platform_driver rt2800soc_driver = { + .driver = { + .name = "rt2800_wmac", + .owner = THIS_MODULE, + .mod_name = KBUILD_MODNAME, + }, + .probe = __rt2x00soc_probe, + .remove = __devexit_p(rt2x00soc_remove), + .suspend = rt2x00soc_suspend, + .resume = rt2x00soc_resume, +}; +#endif /* CONFIG_RT2800PCI_WISOC */ + +#ifdef CONFIG_RT2800PCI_PCI +static struct pci_driver rt2800pci_driver = { + .name = KBUILD_MODNAME, + .id_table = rt2800pci_device_table, + .probe = rt2x00pci_probe, + .remove = __devexit_p(rt2x00pci_remove), + .suspend = rt2x00pci_suspend, + .resume = rt2x00pci_resume, +}; +#endif /* CONFIG_RT2800PCI_PCI */ + +static int __init rt2800pci_init(void) +{ + int ret = 0; + +#ifdef CONFIG_RT2800PCI_WISOC + ret = platform_driver_register(&rt2800soc_driver); + if (ret) + return ret; +#endif +#ifdef CONFIG_RT2800PCI_PCI + ret = pci_register_driver(&rt2800pci_driver); + if (ret) { +#ifdef CONFIG_RT2800PCI_WISOC + platform_driver_unregister(&rt2800soc_driver); +#endif + return ret; + } +#endif + + return ret; +} + +static void __exit rt2800pci_exit(void) +{ +#ifdef CONFIG_RT2800PCI_PCI + pci_unregister_driver(&rt2800pci_driver); +#endif +#ifdef CONFIG_RT2800PCI_WISOC + platform_driver_unregister(&rt2800soc_driver); +#endif +} + +module_init(rt2800pci_init); +module_exit(rt2800pci_exit); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h new file mode 100644 index 000000000000..856908815221 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -0,0 +1,1960 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2800pci + Abstract: Data structures and registers for the rt2800pci module. + Supported chipsets: RT2800E & RT2800ED. + */ + +#ifndef RT2800PCI_H +#define RT2800PCI_H + +/* + * RF chip defines. + * + * RF2820 2.4G 2T3R + * RF2850 2.4G/5G 2T3R + * RF2720 2.4G 1T2R + * RF2750 2.4G/5G 1T2R + * RF3020 2.4G 1T1R + * RF2020 2.4G B/G + * RF3021 2.4G 1T2R + * RF3022 2.4G 2T2R + * RF3052 2.4G 2T2R + */ +#define RF2820 0x0001 +#define RF2850 0x0002 +#define RF2720 0x0003 +#define RF2750 0x0004 +#define RF3020 0x0005 +#define RF2020 0x0006 +#define RF3021 0x0007 +#define RF3022 0x0008 +#define RF3052 0x0009 + +/* + * RT2860 version + */ +#define RT2860C_VERSION 0x28600100 +#define RT2860D_VERSION 0x28600101 +#define RT2880E_VERSION 0x28720200 +#define RT2883_VERSION 0x28830300 +#define RT3070_VERSION 0x30700200 + +/* + * Signal information. + * Default offset is required for RSSI <-> dBm conversion. + */ +#define DEFAULT_RSSI_OFFSET 120 /* FIXME */ + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x1000 +#define CSR_REG_SIZE 0x0800 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0110 +#define BBP_BASE 0x0000 +#define BBP_SIZE 0x0080 +#define RF_BASE 0x0004 +#define RF_SIZE 0x0010 + +/* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 4 + +/* + * PCI registers. + */ + +/* + * E2PROM_CSR: EEPROM control register. + * RELOAD: Write 1 to reload eeprom content. + * TYPE: 0: 93c46, 1:93c66. + * LOAD_STATUS: 1:loading, 0:done. + */ +#define E2PROM_CSR 0x0004 +#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000001) +#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000002) +#define E2PROM_CSR_DATA_IN FIELD32(0x00000004) +#define E2PROM_CSR_DATA_OUT FIELD32(0x00000008) +#define E2PROM_CSR_TYPE FIELD32(0x00000030) +#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040) +#define E2PROM_CSR_RELOAD FIELD32(0x00000080) + +/* + * INT_SOURCE_CSR: Interrupt source register. + * Write one to clear corresponding bit. + * TX_FIFO_STATUS: FIFO Statistics is full, sw should read 0x171c + */ +#define INT_SOURCE_CSR 0x0200 +#define INT_SOURCE_CSR_RXDELAYINT FIELD32(0x00000001) +#define INT_SOURCE_CSR_TXDELAYINT FIELD32(0x00000002) +#define INT_SOURCE_CSR_RX_DONE FIELD32(0x00000004) +#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00000008) +#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00000010) +#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00000020) +#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00000040) +#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00000080) +#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00000100) +#define INT_SOURCE_CSR_MCU_COMMAND FIELD32(0x00000200) +#define INT_SOURCE_CSR_RXTX_COHERENT FIELD32(0x00000400) +#define INT_SOURCE_CSR_TBTT FIELD32(0x00000800) +#define INT_SOURCE_CSR_PRE_TBTT FIELD32(0x00001000) +#define INT_SOURCE_CSR_TX_FIFO_STATUS FIELD32(0x00002000) +#define INT_SOURCE_CSR_AUTO_WAKEUP FIELD32(0x00004000) +#define INT_SOURCE_CSR_GPTIMER FIELD32(0x00008000) +#define INT_SOURCE_CSR_RX_COHERENT FIELD32(0x00010000) +#define INT_SOURCE_CSR_TX_COHERENT FIELD32(0x00020000) + +/* + * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF. + */ +#define INT_MASK_CSR 0x0204 +#define INT_MASK_CSR_RXDELAYINT FIELD32(0x00000001) +#define INT_MASK_CSR_TXDELAYINT FIELD32(0x00000002) +#define INT_MASK_CSR_RX_DONE FIELD32(0x00000004) +#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00000008) +#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00000010) +#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00000020) +#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00000040) +#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00000080) +#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00000100) +#define INT_MASK_CSR_MCU_COMMAND FIELD32(0x00000200) +#define INT_MASK_CSR_RXTX_COHERENT FIELD32(0x00000400) +#define INT_MASK_CSR_TBTT FIELD32(0x00000800) +#define INT_MASK_CSR_PRE_TBTT FIELD32(0x00001000) +#define INT_MASK_CSR_TX_FIFO_STATUS FIELD32(0x00002000) +#define INT_MASK_CSR_AUTO_WAKEUP FIELD32(0x00004000) +#define INT_MASK_CSR_GPTIMER FIELD32(0x00008000) +#define INT_MASK_CSR_RX_COHERENT FIELD32(0x00010000) +#define INT_MASK_CSR_TX_COHERENT FIELD32(0x00020000) + +/* + * WPDMA_GLO_CFG + */ +#define WPDMA_GLO_CFG 0x0208 +#define WPDMA_GLO_CFG_ENABLE_TX_DMA FIELD32(0x00000001) +#define WPDMA_GLO_CFG_TX_DMA_BUSY FIELD32(0x00000002) +#define WPDMA_GLO_CFG_ENABLE_RX_DMA FIELD32(0x00000004) +#define WPDMA_GLO_CFG_RX_DMA_BUSY FIELD32(0x00000008) +#define WPDMA_GLO_CFG_WP_DMA_BURST_SIZE FIELD32(0x00000030) +#define WPDMA_GLO_CFG_TX_WRITEBACK_DONE FIELD32(0x00000040) +#define WPDMA_GLO_CFG_BIG_ENDIAN FIELD32(0x00000080) +#define WPDMA_GLO_CFG_RX_HDR_SCATTER FIELD32(0x0000ff00) +#define WPDMA_GLO_CFG_HDR_SEG_LEN FIELD32(0xffff0000) + +/* + * WPDMA_RST_IDX + */ +#define WPDMA_RST_IDX 0x020c +#define WPDMA_RST_IDX_DTX_IDX0 FIELD32(0x00000001) +#define WPDMA_RST_IDX_DTX_IDX1 FIELD32(0x00000002) +#define WPDMA_RST_IDX_DTX_IDX2 FIELD32(0x00000004) +#define WPDMA_RST_IDX_DTX_IDX3 FIELD32(0x00000008) +#define WPDMA_RST_IDX_DTX_IDX4 FIELD32(0x00000010) +#define WPDMA_RST_IDX_DTX_IDX5 FIELD32(0x00000020) +#define WPDMA_RST_IDX_DRX_IDX0 FIELD32(0x00010000) + +/* + * DELAY_INT_CFG + */ +#define DELAY_INT_CFG 0x0210 +#define DELAY_INT_CFG_RXMAX_PTIME FIELD32(0x000000ff) +#define DELAY_INT_CFG_RXMAX_PINT FIELD32(0x00007f00) +#define DELAY_INT_CFG_RXDLY_INT_EN FIELD32(0x00008000) +#define DELAY_INT_CFG_TXMAX_PTIME FIELD32(0x00ff0000) +#define DELAY_INT_CFG_TXMAX_PINT FIELD32(0x7f000000) +#define DELAY_INT_CFG_TXDLY_INT_EN FIELD32(0x80000000) + +/* + * WMM_AIFSN_CFG: Aifsn for each EDCA AC + * AIFSN0: AC_BE + * AIFSN1: AC_BK + * AIFSN1: AC_VI + * AIFSN1: AC_VO + */ +#define WMM_AIFSN_CFG 0x0214 +#define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f) +#define WMM_AIFSN_CFG_AIFSN1 FIELD32(0x000000f0) +#define WMM_AIFSN_CFG_AIFSN2 FIELD32(0x00000f00) +#define WMM_AIFSN_CFG_AIFSN3 FIELD32(0x0000f000) + +/* + * WMM_CWMIN_CSR: CWmin for each EDCA AC + * CWMIN0: AC_BE + * CWMIN1: AC_BK + * CWMIN1: AC_VI + * CWMIN1: AC_VO + */ +#define WMM_CWMIN_CFG 0x0218 +#define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f) +#define WMM_CWMIN_CFG_CWMIN1 FIELD32(0x000000f0) +#define WMM_CWMIN_CFG_CWMIN2 FIELD32(0x00000f00) +#define WMM_CWMIN_CFG_CWMIN3 FIELD32(0x0000f000) + +/* + * WMM_CWMAX_CSR: CWmax for each EDCA AC + * CWMAX0: AC_BE + * CWMAX1: AC_BK + * CWMAX1: AC_VI + * CWMAX1: AC_VO + */ +#define WMM_CWMAX_CFG 0x021c +#define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f) +#define WMM_CWMAX_CFG_CWMAX1 FIELD32(0x000000f0) +#define WMM_CWMAX_CFG_CWMAX2 FIELD32(0x00000f00) +#define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000) + +/* + * AC_TXOP0: AC_BK/AC_BE TXOP register + * AC0TXOP: AC_BK in unit of 32us + * AC1TXOP: AC_BE in unit of 32us + */ +#define WMM_TXOP0_CFG 0x0220 +#define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff) +#define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000) + +/* + * AC_TXOP1: AC_VO/AC_VI TXOP register + * AC2TXOP: AC_VI in unit of 32us + * AC3TXOP: AC_VO in unit of 32us + */ +#define WMM_TXOP1_CFG 0x0224 +#define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff) +#define WMM_TXOP1_CFG_AC3TXOP FIELD32(0xffff0000) + +/* + * GPIO_CTRL_CFG: + */ +#define GPIO_CTRL_CFG 0x0228 +#define GPIO_CTRL_CFG_BIT0 FIELD32(0x00000001) +#define GPIO_CTRL_CFG_BIT1 FIELD32(0x00000002) +#define GPIO_CTRL_CFG_BIT2 FIELD32(0x00000004) +#define GPIO_CTRL_CFG_BIT3 FIELD32(0x00000008) +#define GPIO_CTRL_CFG_BIT4 FIELD32(0x00000010) +#define GPIO_CTRL_CFG_BIT5 FIELD32(0x00000020) +#define GPIO_CTRL_CFG_BIT6 FIELD32(0x00000040) +#define GPIO_CTRL_CFG_BIT7 FIELD32(0x00000080) +#define GPIO_CTRL_CFG_BIT8 FIELD32(0x00000100) + +/* + * MCU_CMD_CFG + */ +#define MCU_CMD_CFG 0x022c + +/* + * AC_BK register offsets + */ +#define TX_BASE_PTR0 0x0230 +#define TX_MAX_CNT0 0x0234 +#define TX_CTX_IDX0 0x0238 +#define TX_DTX_IDX0 0x023c + +/* + * AC_BE register offsets + */ +#define TX_BASE_PTR1 0x0240 +#define TX_MAX_CNT1 0x0244 +#define TX_CTX_IDX1 0x0248 +#define TX_DTX_IDX1 0x024c + +/* + * AC_VI register offsets + */ +#define TX_BASE_PTR2 0x0250 +#define TX_MAX_CNT2 0x0254 +#define TX_CTX_IDX2 0x0258 +#define TX_DTX_IDX2 0x025c + +/* + * AC_VO register offsets + */ +#define TX_BASE_PTR3 0x0260 +#define TX_MAX_CNT3 0x0264 +#define TX_CTX_IDX3 0x0268 +#define TX_DTX_IDX3 0x026c + +/* + * HCCA register offsets + */ +#define TX_BASE_PTR4 0x0270 +#define TX_MAX_CNT4 0x0274 +#define TX_CTX_IDX4 0x0278 +#define TX_DTX_IDX4 0x027c + +/* + * MGMT register offsets + */ +#define TX_BASE_PTR5 0x0280 +#define TX_MAX_CNT5 0x0284 +#define TX_CTX_IDX5 0x0288 +#define TX_DTX_IDX5 0x028c + +/* + * Queue register offset macros + */ +#define TX_QUEUE_REG_OFFSET 0x10 +#define TX_BASE_PTR(__x) TX_BASE_PTR0 + ((__x) * TX_QUEUE_REG_OFFSET) +#define TX_MAX_CNT(__x) TX_MAX_CNT0 + ((__x) * TX_QUEUE_REG_OFFSET) +#define TX_CTX_IDX(__x) TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) +#define TX_DTX_IDX(__x) TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) + +/* + * RX register offsets + */ +#define RX_BASE_PTR 0x0290 +#define RX_MAX_CNT 0x0294 +#define RX_CRX_IDX 0x0298 +#define RX_DRX_IDX 0x029c + +/* + * PBF_SYS_CTRL + * HOST_RAM_WRITE: enable Host program ram write selection + */ +#define PBF_SYS_CTRL 0x0400 +#define PBF_SYS_CTRL_READY FIELD32(0x00000080) +#define PBF_SYS_CTRL_HOST_RAM_WRITE FIELD32(0x00010000) + +/* + * HOST-MCU shared memory + */ +#define HOST_CMD_CSR 0x0404 +#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x000000ff) + +/* + * PBF registers + * Most are for debug. Driver doesn't touch PBF register. + */ +#define PBF_CFG 0x0408 +#define PBF_MAX_PCNT 0x040c +#define PBF_CTRL 0x0410 +#define PBF_INT_STA 0x0414 +#define PBF_INT_ENA 0x0418 + +/* + * BCN_OFFSET0: + */ +#define BCN_OFFSET0 0x042c +#define BCN_OFFSET0_BCN0 FIELD32(0x000000ff) +#define BCN_OFFSET0_BCN1 FIELD32(0x0000ff00) +#define BCN_OFFSET0_BCN2 FIELD32(0x00ff0000) +#define BCN_OFFSET0_BCN3 FIELD32(0xff000000) + +/* + * BCN_OFFSET1: + */ +#define BCN_OFFSET1 0x0430 +#define BCN_OFFSET1_BCN4 FIELD32(0x000000ff) +#define BCN_OFFSET1_BCN5 FIELD32(0x0000ff00) +#define BCN_OFFSET1_BCN6 FIELD32(0x00ff0000) +#define BCN_OFFSET1_BCN7 FIELD32(0xff000000) + +/* + * PBF registers + * Most are for debug. Driver doesn't touch PBF register. + */ +#define TXRXQ_PCNT 0x0438 +#define PBF_DBG 0x043c + +/* + * RF registers + */ +#define RF_CSR_CFG 0x0500 +#define RF_CSR_CFG_DATA FIELD32(0x000000ff) +#define RF_CSR_CFG_REGNUM FIELD32(0x00001f00) +#define RF_CSR_CFG_WRITE FIELD32(0x00010000) +#define RF_CSR_CFG_BUSY FIELD32(0x00020000) + +/* + * EFUSE_CSR: RT3090 EEPROM + */ +#define EFUSE_CTRL 0x0580 +#define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000) +#define EFUSE_CTRL_MODE FIELD32(0x000000c0) +#define EFUSE_CTRL_KICK FIELD32(0x40000000) + +/* + * EFUSE_DATA0 + */ +#define EFUSE_DATA0 0x0590 + +/* + * EFUSE_DATA1 + */ +#define EFUSE_DATA1 0x0594 + +/* + * EFUSE_DATA2 + */ +#define EFUSE_DATA2 0x0598 + +/* + * EFUSE_DATA3 + */ +#define EFUSE_DATA3 0x059c + +/* + * MAC Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * MAC_CSR0: ASIC revision number. + * ASIC_REV: 0 + * ASIC_VER: 2860 + */ +#define MAC_CSR0 0x1000 +#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff) +#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000) + +/* + * MAC_SYS_CTRL: + */ +#define MAC_SYS_CTRL 0x1004 +#define MAC_SYS_CTRL_RESET_CSR FIELD32(0x00000001) +#define MAC_SYS_CTRL_RESET_BBP FIELD32(0x00000002) +#define MAC_SYS_CTRL_ENABLE_TX FIELD32(0x00000004) +#define MAC_SYS_CTRL_ENABLE_RX FIELD32(0x00000008) +#define MAC_SYS_CTRL_CONTINUOUS_TX FIELD32(0x00000010) +#define MAC_SYS_CTRL_LOOPBACK FIELD32(0x00000020) +#define MAC_SYS_CTRL_WLAN_HALT FIELD32(0x00000040) +#define MAC_SYS_CTRL_RX_TIMESTAMP FIELD32(0x00000080) + +/* + * MAC_ADDR_DW0: STA MAC register 0 + */ +#define MAC_ADDR_DW0 0x1008 +#define MAC_ADDR_DW0_BYTE0 FIELD32(0x000000ff) +#define MAC_ADDR_DW0_BYTE1 FIELD32(0x0000ff00) +#define MAC_ADDR_DW0_BYTE2 FIELD32(0x00ff0000) +#define MAC_ADDR_DW0_BYTE3 FIELD32(0xff000000) + +/* + * MAC_ADDR_DW1: STA MAC register 1 + * UNICAST_TO_ME_MASK: + * Used to mask off bits from byte 5 of the MAC address + * to determine the UNICAST_TO_ME bit for RX frames. + * The full mask is complemented by BSS_ID_MASK: + * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK + */ +#define MAC_ADDR_DW1 0x100c +#define MAC_ADDR_DW1_BYTE4 FIELD32(0x000000ff) +#define MAC_ADDR_DW1_BYTE5 FIELD32(0x0000ff00) +#define MAC_ADDR_DW1_UNICAST_TO_ME_MASK FIELD32(0x00ff0000) + +/* + * MAC_BSSID_DW0: BSSID register 0 + */ +#define MAC_BSSID_DW0 0x1010 +#define MAC_BSSID_DW0_BYTE0 FIELD32(0x000000ff) +#define MAC_BSSID_DW0_BYTE1 FIELD32(0x0000ff00) +#define MAC_BSSID_DW0_BYTE2 FIELD32(0x00ff0000) +#define MAC_BSSID_DW0_BYTE3 FIELD32(0xff000000) + +/* + * MAC_BSSID_DW1: BSSID register 1 + * BSS_ID_MASK: + * 0: 1-BSSID mode (BSS index = 0) + * 1: 2-BSSID mode (BSS index: Byte5, bit 0) + * 2: 4-BSSID mode (BSS index: byte5, bit 0 - 1) + * 3: 8-BSSID mode (BSS index: byte5, bit 0 - 2) + * This mask is used to mask off bits 0, 1 and 2 of byte 5 of the + * BSSID. This will make sure that those bits will be ignored + * when determining the MY_BSS of RX frames. + */ +#define MAC_BSSID_DW1 0x1014 +#define MAC_BSSID_DW1_BYTE4 FIELD32(0x000000ff) +#define MAC_BSSID_DW1_BYTE5 FIELD32(0x0000ff00) +#define MAC_BSSID_DW1_BSS_ID_MASK FIELD32(0x00030000) +#define MAC_BSSID_DW1_BSS_BCN_NUM FIELD32(0x001c0000) + +/* + * MAX_LEN_CFG: Maximum frame length register. + * MAX_MPDU: rt2860b max 16k bytes + * MAX_PSDU: Maximum PSDU length + * (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 + */ +#define MAX_LEN_CFG 0x1018 +#define MAX_LEN_CFG_MAX_MPDU FIELD32(0x00000fff) +#define MAX_LEN_CFG_MAX_PSDU FIELD32(0x00003000) +#define MAX_LEN_CFG_MIN_PSDU FIELD32(0x0000c000) +#define MAX_LEN_CFG_MIN_MPDU FIELD32(0x000f0000) + +/* + * BBP_CSR_CFG: BBP serial control register + * VALUE: Register value to program into BBP + * REG_NUM: Selected BBP register + * READ_CONTROL: 0 write BBP, 1 read BBP + * BUSY: ASIC is busy executing BBP commands + * BBP_PAR_DUR: 0 4 MAC clocks, 1 8 MAC clocks + * BBP_RW_MODE: 0 serial, 1 paralell + */ +#define BBP_CSR_CFG 0x101c +#define BBP_CSR_CFG_VALUE FIELD32(0x000000ff) +#define BBP_CSR_CFG_REGNUM FIELD32(0x0000ff00) +#define BBP_CSR_CFG_READ_CONTROL FIELD32(0x00010000) +#define BBP_CSR_CFG_BUSY FIELD32(0x00020000) +#define BBP_CSR_CFG_BBP_PAR_DUR FIELD32(0x00040000) +#define BBP_CSR_CFG_BBP_RW_MODE FIELD32(0x00080000) + +/* + * RF_CSR_CFG0: RF control register + * REGID_AND_VALUE: Register value to program into RF + * BITWIDTH: Selected RF register + * STANDBYMODE: 0 high when standby, 1 low when standby + * SEL: 0 RF_LE0 activate, 1 RF_LE1 activate + * BUSY: ASIC is busy executing RF commands + */ +#define RF_CSR_CFG0 0x1020 +#define RF_CSR_CFG0_REGID_AND_VALUE FIELD32(0x00ffffff) +#define RF_CSR_CFG0_BITWIDTH FIELD32(0x1f000000) +#define RF_CSR_CFG0_REG_VALUE_BW FIELD32(0x1fffffff) +#define RF_CSR_CFG0_STANDBYMODE FIELD32(0x20000000) +#define RF_CSR_CFG0_SEL FIELD32(0x40000000) +#define RF_CSR_CFG0_BUSY FIELD32(0x80000000) + +/* + * RF_CSR_CFG1: RF control register + * REGID_AND_VALUE: Register value to program into RF + * RFGAP: Gap between BB_CONTROL_RF and RF_LE + * 0: 3 system clock cycle (37.5usec) + * 1: 5 system clock cycle (62.5usec) + */ +#define RF_CSR_CFG1 0x1024 +#define RF_CSR_CFG1_REGID_AND_VALUE FIELD32(0x00ffffff) +#define RF_CSR_CFG1_RFGAP FIELD32(0x1f000000) + +/* + * RF_CSR_CFG2: RF control register + * VALUE: Register value to program into RF + * RFGAP: Gap between BB_CONTROL_RF and RF_LE + * 0: 3 system clock cycle (37.5usec) + * 1: 5 system clock cycle (62.5usec) + */ +#define RF_CSR_CFG2 0x1028 +#define RF_CSR_CFG2_VALUE FIELD32(0x00ffffff) + +/* + * LED_CFG: LED control + * color LED's: + * 0: off + * 1: blinking upon TX2 + * 2: periodic slow blinking + * 3: always on + * LED polarity: + * 0: active low + * 1: active high + */ +#define LED_CFG 0x102c +#define LED_CFG_ON_PERIOD FIELD32(0x000000ff) +#define LED_CFG_OFF_PERIOD FIELD32(0x0000ff00) +#define LED_CFG_SLOW_BLINK_PERIOD FIELD32(0x003f0000) +#define LED_CFG_R_LED_MODE FIELD32(0x03000000) +#define LED_CFG_G_LED_MODE FIELD32(0x0c000000) +#define LED_CFG_Y_LED_MODE FIELD32(0x30000000) +#define LED_CFG_LED_POLAR FIELD32(0x40000000) + +/* + * XIFS_TIME_CFG: MAC timing + * CCKM_SIFS_TIME: unit 1us. Applied after CCK RX/TX + * OFDM_SIFS_TIME: unit 1us. Applied after OFDM RX/TX + * OFDM_XIFS_TIME: unit 1us. Applied after OFDM RX + * when MAC doesn't reference BBP signal BBRXEND + * EIFS: unit 1us + * BB_RXEND_ENABLE: reference RXEND signal to begin XIFS defer + * + */ +#define XIFS_TIME_CFG 0x1100 +#define XIFS_TIME_CFG_CCKM_SIFS_TIME FIELD32(0x000000ff) +#define XIFS_TIME_CFG_OFDM_SIFS_TIME FIELD32(0x0000ff00) +#define XIFS_TIME_CFG_OFDM_XIFS_TIME FIELD32(0x000f0000) +#define XIFS_TIME_CFG_EIFS FIELD32(0x1ff00000) +#define XIFS_TIME_CFG_BB_RXEND_ENABLE FIELD32(0x20000000) + +/* + * BKOFF_SLOT_CFG: + */ +#define BKOFF_SLOT_CFG 0x1104 +#define BKOFF_SLOT_CFG_SLOT_TIME FIELD32(0x000000ff) +#define BKOFF_SLOT_CFG_CC_DELAY_TIME FIELD32(0x0000ff00) + +/* + * NAV_TIME_CFG: + */ +#define NAV_TIME_CFG 0x1108 +#define NAV_TIME_CFG_SIFS FIELD32(0x000000ff) +#define NAV_TIME_CFG_SLOT_TIME FIELD32(0x0000ff00) +#define NAV_TIME_CFG_EIFS FIELD32(0x01ff0000) +#define NAV_TIME_ZERO_SIFS FIELD32(0x02000000) + +/* + * CH_TIME_CFG: count as channel busy + */ +#define CH_TIME_CFG 0x110c + +/* + * PBF_LIFE_TIMER: TX/RX MPDU timestamp timer (free run) Unit: 1us + */ +#define PBF_LIFE_TIMER 0x1110 + +/* + * BCN_TIME_CFG: + * BEACON_INTERVAL: in unit of 1/16 TU + * TSF_TICKING: Enable TSF auto counting + * TSF_SYNC: Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode + * BEACON_GEN: Enable beacon generator + */ +#define BCN_TIME_CFG 0x1114 +#define BCN_TIME_CFG_BEACON_INTERVAL FIELD32(0x0000ffff) +#define BCN_TIME_CFG_TSF_TICKING FIELD32(0x00010000) +#define BCN_TIME_CFG_TSF_SYNC FIELD32(0x00060000) +#define BCN_TIME_CFG_TBTT_ENABLE FIELD32(0x00080000) +#define BCN_TIME_CFG_BEACON_GEN FIELD32(0x00100000) +#define BCN_TIME_CFG_TX_TIME_COMPENSATE FIELD32(0xf0000000) + +/* + * TBTT_SYNC_CFG: + */ +#define TBTT_SYNC_CFG 0x1118 + +/* + * TSF_TIMER_DW0: Local lsb TSF timer, read-only + */ +#define TSF_TIMER_DW0 0x111c +#define TSF_TIMER_DW0_LOW_WORD FIELD32(0xffffffff) + +/* + * TSF_TIMER_DW1: Local msb TSF timer, read-only + */ +#define TSF_TIMER_DW1 0x1120 +#define TSF_TIMER_DW1_HIGH_WORD FIELD32(0xffffffff) + +/* + * TBTT_TIMER: TImer remains till next TBTT, read-only + */ +#define TBTT_TIMER 0x1124 + +/* + * INT_TIMER_CFG: + */ +#define INT_TIMER_CFG 0x1128 + +/* + * INT_TIMER_EN: GP-timer and pre-tbtt Int enable + */ +#define INT_TIMER_EN 0x112c + +/* + * CH_IDLE_STA: channel idle time + */ +#define CH_IDLE_STA 0x1130 + +/* + * CH_BUSY_STA: channel busy time + */ +#define CH_BUSY_STA 0x1134 + +/* + * MAC_STATUS_CFG: + * BBP_RF_BUSY: When set to 0, BBP and RF are stable. + * if 1 or higher one of the 2 registers is busy. + */ +#define MAC_STATUS_CFG 0x1200 +#define MAC_STATUS_CFG_BBP_RF_BUSY FIELD32(0x00000003) + +/* + * PWR_PIN_CFG: + */ +#define PWR_PIN_CFG 0x1204 + +/* + * AUTOWAKEUP_CFG: Manual power control / status register + * TBCN_BEFORE_WAKE: ForceWake has high privilege than PutToSleep when both set + * AUTOWAKE: 0:sleep, 1:awake + */ +#define AUTOWAKEUP_CFG 0x1208 +#define AUTOWAKEUP_CFG_AUTO_LEAD_TIME FIELD32(0x000000ff) +#define AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE FIELD32(0x00007f00) +#define AUTOWAKEUP_CFG_AUTOWAKE FIELD32(0x00008000) + +/* + * EDCA_AC0_CFG: + */ +#define EDCA_AC0_CFG 0x1300 +#define EDCA_AC0_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC0_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC0_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC0_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC1_CFG: + */ +#define EDCA_AC1_CFG 0x1304 +#define EDCA_AC1_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC1_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC1_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC1_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC2_CFG: + */ +#define EDCA_AC2_CFG 0x1308 +#define EDCA_AC2_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC2_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC2_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC2_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC3_CFG: + */ +#define EDCA_AC3_CFG 0x130c +#define EDCA_AC3_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC3_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC3_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC3_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_TID_AC_MAP: + */ +#define EDCA_TID_AC_MAP 0x1310 + +/* + * TX_PWR_CFG_0: + */ +#define TX_PWR_CFG_0 0x1314 +#define TX_PWR_CFG_0_1MBS FIELD32(0x0000000f) +#define TX_PWR_CFG_0_2MBS FIELD32(0x000000f0) +#define TX_PWR_CFG_0_55MBS FIELD32(0x00000f00) +#define TX_PWR_CFG_0_11MBS FIELD32(0x0000f000) +#define TX_PWR_CFG_0_6MBS FIELD32(0x000f0000) +#define TX_PWR_CFG_0_9MBS FIELD32(0x00f00000) +#define TX_PWR_CFG_0_12MBS FIELD32(0x0f000000) +#define TX_PWR_CFG_0_18MBS FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_1: + */ +#define TX_PWR_CFG_1 0x1318 +#define TX_PWR_CFG_1_24MBS FIELD32(0x0000000f) +#define TX_PWR_CFG_1_36MBS FIELD32(0x000000f0) +#define TX_PWR_CFG_1_48MBS FIELD32(0x00000f00) +#define TX_PWR_CFG_1_54MBS FIELD32(0x0000f000) +#define TX_PWR_CFG_1_MCS0 FIELD32(0x000f0000) +#define TX_PWR_CFG_1_MCS1 FIELD32(0x00f00000) +#define TX_PWR_CFG_1_MCS2 FIELD32(0x0f000000) +#define TX_PWR_CFG_1_MCS3 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_2: + */ +#define TX_PWR_CFG_2 0x131c +#define TX_PWR_CFG_2_MCS4 FIELD32(0x0000000f) +#define TX_PWR_CFG_2_MCS5 FIELD32(0x000000f0) +#define TX_PWR_CFG_2_MCS6 FIELD32(0x00000f00) +#define TX_PWR_CFG_2_MCS7 FIELD32(0x0000f000) +#define TX_PWR_CFG_2_MCS8 FIELD32(0x000f0000) +#define TX_PWR_CFG_2_MCS9 FIELD32(0x00f00000) +#define TX_PWR_CFG_2_MCS10 FIELD32(0x0f000000) +#define TX_PWR_CFG_2_MCS11 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_3: + */ +#define TX_PWR_CFG_3 0x1320 +#define TX_PWR_CFG_3_MCS12 FIELD32(0x0000000f) +#define TX_PWR_CFG_3_MCS13 FIELD32(0x000000f0) +#define TX_PWR_CFG_3_MCS14 FIELD32(0x00000f00) +#define TX_PWR_CFG_3_MCS15 FIELD32(0x0000f000) +#define TX_PWR_CFG_3_UKNOWN1 FIELD32(0x000f0000) +#define TX_PWR_CFG_3_UKNOWN2 FIELD32(0x00f00000) +#define TX_PWR_CFG_3_UKNOWN3 FIELD32(0x0f000000) +#define TX_PWR_CFG_3_UKNOWN4 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_4: + */ +#define TX_PWR_CFG_4 0x1324 +#define TX_PWR_CFG_4_UKNOWN5 FIELD32(0x0000000f) +#define TX_PWR_CFG_4_UKNOWN6 FIELD32(0x000000f0) +#define TX_PWR_CFG_4_UKNOWN7 FIELD32(0x00000f00) +#define TX_PWR_CFG_4_UKNOWN8 FIELD32(0x0000f000) + +/* + * TX_PIN_CFG: + */ +#define TX_PIN_CFG 0x1328 +#define TX_PIN_CFG_PA_PE_A0_EN FIELD32(0x00000001) +#define TX_PIN_CFG_PA_PE_G0_EN FIELD32(0x00000002) +#define TX_PIN_CFG_PA_PE_A1_EN FIELD32(0x00000004) +#define TX_PIN_CFG_PA_PE_G1_EN FIELD32(0x00000008) +#define TX_PIN_CFG_PA_PE_A0_POL FIELD32(0x00000010) +#define TX_PIN_CFG_PA_PE_G0_POL FIELD32(0x00000020) +#define TX_PIN_CFG_PA_PE_A1_POL FIELD32(0x00000040) +#define TX_PIN_CFG_PA_PE_G1_POL FIELD32(0x00000080) +#define TX_PIN_CFG_LNA_PE_A0_EN FIELD32(0x00000100) +#define TX_PIN_CFG_LNA_PE_G0_EN FIELD32(0x00000200) +#define TX_PIN_CFG_LNA_PE_A1_EN FIELD32(0x00000400) +#define TX_PIN_CFG_LNA_PE_G1_EN FIELD32(0x00000800) +#define TX_PIN_CFG_LNA_PE_A0_POL FIELD32(0x00001000) +#define TX_PIN_CFG_LNA_PE_G0_POL FIELD32(0x00002000) +#define TX_PIN_CFG_LNA_PE_A1_POL FIELD32(0x00004000) +#define TX_PIN_CFG_LNA_PE_G1_POL FIELD32(0x00008000) +#define TX_PIN_CFG_RFTR_EN FIELD32(0x00010000) +#define TX_PIN_CFG_RFTR_POL FIELD32(0x00020000) +#define TX_PIN_CFG_TRSW_EN FIELD32(0x00040000) +#define TX_PIN_CFG_TRSW_POL FIELD32(0x00080000) + +/* + * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz + */ +#define TX_BAND_CFG 0x132c +#define TX_BAND_CFG_HT40_PLUS FIELD32(0x00000001) +#define TX_BAND_CFG_A FIELD32(0x00000002) +#define TX_BAND_CFG_BG FIELD32(0x00000004) + +/* + * TX_SW_CFG0: + */ +#define TX_SW_CFG0 0x1330 + +/* + * TX_SW_CFG1: + */ +#define TX_SW_CFG1 0x1334 + +/* + * TX_SW_CFG2: + */ +#define TX_SW_CFG2 0x1338 + +/* + * TXOP_THRES_CFG: + */ +#define TXOP_THRES_CFG 0x133c + +/* + * TXOP_CTRL_CFG: + */ +#define TXOP_CTRL_CFG 0x1340 + +/* + * TX_RTS_CFG: + * RTS_THRES: unit:byte + * RTS_FBK_EN: enable rts rate fallback + */ +#define TX_RTS_CFG 0x1344 +#define TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT FIELD32(0x000000ff) +#define TX_RTS_CFG_RTS_THRES FIELD32(0x00ffff00) +#define TX_RTS_CFG_RTS_FBK_EN FIELD32(0x01000000) + +/* + * TX_TIMEOUT_CFG: + * MPDU_LIFETIME: expiration time = 2^(9+MPDU LIFE TIME) us + * RX_ACK_TIMEOUT: unit:slot. Used for TX procedure + * TX_OP_TIMEOUT: TXOP timeout value for TXOP truncation. + * it is recommended that: + * (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) + */ +#define TX_TIMEOUT_CFG 0x1348 +#define TX_TIMEOUT_CFG_MPDU_LIFETIME FIELD32(0x000000f0) +#define TX_TIMEOUT_CFG_RX_ACK_TIMEOUT FIELD32(0x0000ff00) +#define TX_TIMEOUT_CFG_TX_OP_TIMEOUT FIELD32(0x00ff0000) + +/* + * TX_RTY_CFG: + * SHORT_RTY_LIMIT: short retry limit + * LONG_RTY_LIMIT: long retry limit + * LONG_RTY_THRE: Long retry threshoold + * NON_AGG_RTY_MODE: Non-Aggregate MPDU retry mode + * 0:expired by retry limit, 1: expired by mpdu life timer + * AGG_RTY_MODE: Aggregate MPDU retry mode + * 0:expired by retry limit, 1: expired by mpdu life timer + * TX_AUTO_FB_ENABLE: Tx retry PHY rate auto fallback enable + */ +#define TX_RTY_CFG 0x134c +#define TX_RTY_CFG_SHORT_RTY_LIMIT FIELD32(0x000000ff) +#define TX_RTY_CFG_LONG_RTY_LIMIT FIELD32(0x0000ff00) +#define TX_RTY_CFG_LONG_RTY_THRE FIELD32(0x0fff0000) +#define TX_RTY_CFG_NON_AGG_RTY_MODE FIELD32(0x10000000) +#define TX_RTY_CFG_AGG_RTY_MODE FIELD32(0x20000000) +#define TX_RTY_CFG_TX_AUTO_FB_ENABLE FIELD32(0x40000000) + +/* + * TX_LINK_CFG: + * REMOTE_MFB_LIFETIME: remote MFB life time. unit: 32us + * MFB_ENABLE: TX apply remote MFB 1:enable + * REMOTE_UMFS_ENABLE: remote unsolicit MFB enable + * 0: not apply remote remote unsolicit (MFS=7) + * TX_MRQ_EN: MCS request TX enable + * TX_RDG_EN: RDG TX enable + * TX_CF_ACK_EN: Piggyback CF-ACK enable + * REMOTE_MFB: remote MCS feedback + * REMOTE_MFS: remote MCS feedback sequence number + */ +#define TX_LINK_CFG 0x1350 +#define TX_LINK_CFG_REMOTE_MFB_LIFETIME FIELD32(0x000000ff) +#define TX_LINK_CFG_MFB_ENABLE FIELD32(0x00000100) +#define TX_LINK_CFG_REMOTE_UMFS_ENABLE FIELD32(0x00000200) +#define TX_LINK_CFG_TX_MRQ_EN FIELD32(0x00000400) +#define TX_LINK_CFG_TX_RDG_EN FIELD32(0x00000800) +#define TX_LINK_CFG_TX_CF_ACK_EN FIELD32(0x00001000) +#define TX_LINK_CFG_REMOTE_MFB FIELD32(0x00ff0000) +#define TX_LINK_CFG_REMOTE_MFS FIELD32(0xff000000) + +/* + * HT_FBK_CFG0: + */ +#define HT_FBK_CFG0 0x1354 +#define HT_FBK_CFG0_HTMCS0FBK FIELD32(0x0000000f) +#define HT_FBK_CFG0_HTMCS1FBK FIELD32(0x000000f0) +#define HT_FBK_CFG0_HTMCS2FBK FIELD32(0x00000f00) +#define HT_FBK_CFG0_HTMCS3FBK FIELD32(0x0000f000) +#define HT_FBK_CFG0_HTMCS4FBK FIELD32(0x000f0000) +#define HT_FBK_CFG0_HTMCS5FBK FIELD32(0x00f00000) +#define HT_FBK_CFG0_HTMCS6FBK FIELD32(0x0f000000) +#define HT_FBK_CFG0_HTMCS7FBK FIELD32(0xf0000000) + +/* + * HT_FBK_CFG1: + */ +#define HT_FBK_CFG1 0x1358 +#define HT_FBK_CFG1_HTMCS8FBK FIELD32(0x0000000f) +#define HT_FBK_CFG1_HTMCS9FBK FIELD32(0x000000f0) +#define HT_FBK_CFG1_HTMCS10FBK FIELD32(0x00000f00) +#define HT_FBK_CFG1_HTMCS11FBK FIELD32(0x0000f000) +#define HT_FBK_CFG1_HTMCS12FBK FIELD32(0x000f0000) +#define HT_FBK_CFG1_HTMCS13FBK FIELD32(0x00f00000) +#define HT_FBK_CFG1_HTMCS14FBK FIELD32(0x0f000000) +#define HT_FBK_CFG1_HTMCS15FBK FIELD32(0xf0000000) + +/* + * LG_FBK_CFG0: + */ +#define LG_FBK_CFG0 0x135c +#define LG_FBK_CFG0_OFDMMCS0FBK FIELD32(0x0000000f) +#define LG_FBK_CFG0_OFDMMCS1FBK FIELD32(0x000000f0) +#define LG_FBK_CFG0_OFDMMCS2FBK FIELD32(0x00000f00) +#define LG_FBK_CFG0_OFDMMCS3FBK FIELD32(0x0000f000) +#define LG_FBK_CFG0_OFDMMCS4FBK FIELD32(0x000f0000) +#define LG_FBK_CFG0_OFDMMCS5FBK FIELD32(0x00f00000) +#define LG_FBK_CFG0_OFDMMCS6FBK FIELD32(0x0f000000) +#define LG_FBK_CFG0_OFDMMCS7FBK FIELD32(0xf0000000) + +/* + * LG_FBK_CFG1: + */ +#define LG_FBK_CFG1 0x1360 +#define LG_FBK_CFG0_CCKMCS0FBK FIELD32(0x0000000f) +#define LG_FBK_CFG0_CCKMCS1FBK FIELD32(0x000000f0) +#define LG_FBK_CFG0_CCKMCS2FBK FIELD32(0x00000f00) +#define LG_FBK_CFG0_CCKMCS3FBK FIELD32(0x0000f000) + +/* + * CCK_PROT_CFG: CCK Protection + * PROTECT_RATE: Protection control frame rate for CCK TX(RTS/CTS/CFEnd) + * PROTECT_CTRL: Protection control frame type for CCK TX + * 0:none, 1:RTS/CTS, 2:CTS-to-self + * PROTECT_NAV: TXOP protection type for CCK TX + * 0:none, 1:ShortNAVprotect, 2:LongNAVProtect + * TX_OP_ALLOW_CCK: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_OFDM: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_MM20: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_MM40: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_GF20: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_GF40: CCK TXOP allowance, 0:disallow + * RTS_TH_EN: RTS threshold enable on CCK TX + */ +#define CCK_PROT_CFG 0x1364 +#define CCK_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define CCK_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define CCK_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define CCK_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define CCK_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define CCK_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define CCK_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define CCK_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define CCK_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define CCK_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * OFDM_PROT_CFG: OFDM Protection + */ +#define OFDM_PROT_CFG 0x1368 +#define OFDM_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define OFDM_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define OFDM_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define OFDM_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * MM20_PROT_CFG: MM20 Protection + */ +#define MM20_PROT_CFG 0x136c +#define MM20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define MM20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define MM20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define MM20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define MM20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define MM20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define MM20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define MM20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define MM20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define MM20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * MM40_PROT_CFG: MM40 Protection + */ +#define MM40_PROT_CFG 0x1370 +#define MM40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define MM40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define MM40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define MM40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define MM40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define MM40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define MM40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define MM40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define MM40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define MM40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * GF20_PROT_CFG: GF20 Protection + */ +#define GF20_PROT_CFG 0x1374 +#define GF20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define GF20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define GF20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define GF20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define GF20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define GF20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define GF20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define GF20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define GF20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define GF20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * GF40_PROT_CFG: GF40 Protection + */ +#define GF40_PROT_CFG 0x1378 +#define GF40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define GF40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define GF40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define GF40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define GF40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define GF40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define GF40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define GF40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define GF40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define GF40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * EXP_CTS_TIME: + */ +#define EXP_CTS_TIME 0x137c + +/* + * EXP_ACK_TIME: + */ +#define EXP_ACK_TIME 0x1380 + +/* + * RX_FILTER_CFG: RX configuration register. + */ +#define RX_FILTER_CFG 0x1400 +#define RX_FILTER_CFG_DROP_CRC_ERROR FIELD32(0x00000001) +#define RX_FILTER_CFG_DROP_PHY_ERROR FIELD32(0x00000002) +#define RX_FILTER_CFG_DROP_NOT_TO_ME FIELD32(0x00000004) +#define RX_FILTER_CFG_DROP_NOT_MY_BSSD FIELD32(0x00000008) +#define RX_FILTER_CFG_DROP_VER_ERROR FIELD32(0x00000010) +#define RX_FILTER_CFG_DROP_MULTICAST FIELD32(0x00000020) +#define RX_FILTER_CFG_DROP_BROADCAST FIELD32(0x00000040) +#define RX_FILTER_CFG_DROP_DUPLICATE FIELD32(0x00000080) +#define RX_FILTER_CFG_DROP_CF_END_ACK FIELD32(0x00000100) +#define RX_FILTER_CFG_DROP_CF_END FIELD32(0x00000200) +#define RX_FILTER_CFG_DROP_ACK FIELD32(0x00000400) +#define RX_FILTER_CFG_DROP_CTS FIELD32(0x00000800) +#define RX_FILTER_CFG_DROP_RTS FIELD32(0x00001000) +#define RX_FILTER_CFG_DROP_PSPOLL FIELD32(0x00002000) +#define RX_FILTER_CFG_DROP_BA FIELD32(0x00004000) +#define RX_FILTER_CFG_DROP_BAR FIELD32(0x00008000) +#define RX_FILTER_CFG_DROP_CNTL FIELD32(0x00010000) + +/* + * AUTO_RSP_CFG: + * AUTORESPONDER: 0: disable, 1: enable + * BAC_ACK_POLICY: 0:long, 1:short preamble + * CTS_40_MMODE: Response CTS 40MHz duplicate mode + * CTS_40_MREF: Response CTS 40MHz duplicate mode + * AR_PREAMBLE: Auto responder preamble 0:long, 1:short preamble + * DUAL_CTS_EN: Power bit value in control frame + * ACK_CTS_PSM_BIT:Power bit value in control frame + */ +#define AUTO_RSP_CFG 0x1404 +#define AUTO_RSP_CFG_AUTORESPONDER FIELD32(0x00000001) +#define AUTO_RSP_CFG_BAC_ACK_POLICY FIELD32(0x00000002) +#define AUTO_RSP_CFG_CTS_40_MMODE FIELD32(0x00000004) +#define AUTO_RSP_CFG_CTS_40_MREF FIELD32(0x00000008) +#define AUTO_RSP_CFG_AR_PREAMBLE FIELD32(0x00000010) +#define AUTO_RSP_CFG_DUAL_CTS_EN FIELD32(0x00000040) +#define AUTO_RSP_CFG_ACK_CTS_PSM_BIT FIELD32(0x00000080) + +/* + * LEGACY_BASIC_RATE: + */ +#define LEGACY_BASIC_RATE 0x1408 + +/* + * HT_BASIC_RATE: + */ +#define HT_BASIC_RATE 0x140c + +/* + * HT_CTRL_CFG: + */ +#define HT_CTRL_CFG 0x1410 + +/* + * SIFS_COST_CFG: + */ +#define SIFS_COST_CFG 0x1414 + +/* + * RX_PARSER_CFG: + * Set NAV for all received frames + */ +#define RX_PARSER_CFG 0x1418 + +/* + * TX_SEC_CNT0: + */ +#define TX_SEC_CNT0 0x1500 + +/* + * RX_SEC_CNT0: + */ +#define RX_SEC_CNT0 0x1504 + +/* + * CCMP_FC_MUTE: + */ +#define CCMP_FC_MUTE 0x1508 + +/* + * TXOP_HLDR_ADDR0: + */ +#define TXOP_HLDR_ADDR0 0x1600 + +/* + * TXOP_HLDR_ADDR1: + */ +#define TXOP_HLDR_ADDR1 0x1604 + +/* + * TXOP_HLDR_ET: + */ +#define TXOP_HLDR_ET 0x1608 + +/* + * QOS_CFPOLL_RA_DW0: + */ +#define QOS_CFPOLL_RA_DW0 0x160c + +/* + * QOS_CFPOLL_RA_DW1: + */ +#define QOS_CFPOLL_RA_DW1 0x1610 + +/* + * QOS_CFPOLL_QC: + */ +#define QOS_CFPOLL_QC 0x1614 + +/* + * RX_STA_CNT0: RX PLCP error count & RX CRC error count + */ +#define RX_STA_CNT0 0x1700 +#define RX_STA_CNT0_CRC_ERR FIELD32(0x0000ffff) +#define RX_STA_CNT0_PHY_ERR FIELD32(0xffff0000) + +/* + * RX_STA_CNT1: RX False CCA count & RX LONG frame count + */ +#define RX_STA_CNT1 0x1704 +#define RX_STA_CNT1_FALSE_CCA FIELD32(0x0000ffff) +#define RX_STA_CNT1_PLCP_ERR FIELD32(0xffff0000) + +/* + * RX_STA_CNT2: + */ +#define RX_STA_CNT2 0x1708 +#define RX_STA_CNT2_RX_DUPLI_COUNT FIELD32(0x0000ffff) +#define RX_STA_CNT2_RX_FIFO_OVERFLOW FIELD32(0xffff0000) + +/* + * TX_STA_CNT0: TX Beacon count + */ +#define TX_STA_CNT0 0x170c +#define TX_STA_CNT0_TX_FAIL_COUNT FIELD32(0x0000ffff) +#define TX_STA_CNT0_TX_BEACON_COUNT FIELD32(0xffff0000) + +/* + * TX_STA_CNT1: TX tx count + */ +#define TX_STA_CNT1 0x1710 +#define TX_STA_CNT1_TX_SUCCESS FIELD32(0x0000ffff) +#define TX_STA_CNT1_TX_RETRANSMIT FIELD32(0xffff0000) + +/* + * TX_STA_CNT2: TX tx count + */ +#define TX_STA_CNT2 0x1714 +#define TX_STA_CNT2_TX_ZERO_LEN_COUNT FIELD32(0x0000ffff) +#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000) + +/* + * TX_STA_FIFO: TX Result for specific PID status fifo register + */ +#define TX_STA_FIFO 0x1718 +#define TX_STA_FIFO_VALID FIELD32(0x00000001) +#define TX_STA_FIFO_PID_TYPE FIELD32(0x0000001e) +#define TX_STA_FIFO_TX_SUCCESS FIELD32(0x00000020) +#define TX_STA_FIFO_TX_AGGRE FIELD32(0x00000040) +#define TX_STA_FIFO_TX_ACK_REQUIRED FIELD32(0x00000080) +#define TX_STA_FIFO_WCID FIELD32(0x0000ff00) +#define TX_STA_FIFO_MCS FIELD32(0x007f0000) +#define TX_STA_FIFO_PHYMODE FIELD32(0xc0000000) + +/* + * TX_AGG_CNT: Debug counter + */ +#define TX_AGG_CNT 0x171c +#define TX_AGG_CNT_NON_AGG_TX_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT_AGG_TX_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT0: + */ +#define TX_AGG_CNT0 0x1720 +#define TX_AGG_CNT0_AGG_SIZE_1_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT0_AGG_SIZE_2_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT1: + */ +#define TX_AGG_CNT1 0x1724 +#define TX_AGG_CNT1_AGG_SIZE_3_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT1_AGG_SIZE_4_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT2: + */ +#define TX_AGG_CNT2 0x1728 +#define TX_AGG_CNT2_AGG_SIZE_5_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT2_AGG_SIZE_6_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT3: + */ +#define TX_AGG_CNT3 0x172c +#define TX_AGG_CNT3_AGG_SIZE_7_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT3_AGG_SIZE_8_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT4: + */ +#define TX_AGG_CNT4 0x1730 +#define TX_AGG_CNT4_AGG_SIZE_9_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT4_AGG_SIZE_10_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT5: + */ +#define TX_AGG_CNT5 0x1734 +#define TX_AGG_CNT5_AGG_SIZE_11_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT5_AGG_SIZE_12_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT6: + */ +#define TX_AGG_CNT6 0x1738 +#define TX_AGG_CNT6_AGG_SIZE_13_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT6_AGG_SIZE_14_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT7: + */ +#define TX_AGG_CNT7 0x173c +#define TX_AGG_CNT7_AGG_SIZE_15_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT7_AGG_SIZE_16_COUNT FIELD32(0xffff0000) + +/* + * MPDU_DENSITY_CNT: + * TX_ZERO_DEL: TX zero length delimiter count + * RX_ZERO_DEL: RX zero length delimiter count + */ +#define MPDU_DENSITY_CNT 0x1740 +#define MPDU_DENSITY_CNT_TX_ZERO_DEL FIELD32(0x0000ffff) +#define MPDU_DENSITY_CNT_RX_ZERO_DEL FIELD32(0xffff0000) + +/* + * Security key table memory. + * MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry + * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry + * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry + * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry + * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry + * SHARED_KEY_MODE_BASE: 4 bits * 32-entry + */ +#define MAC_WCID_BASE 0x1800 +#define PAIRWISE_KEY_TABLE_BASE 0x4000 +#define MAC_IVEIV_TABLE_BASE 0x6000 +#define MAC_WCID_ATTRIBUTE_BASE 0x6800 +#define SHARED_KEY_TABLE_BASE 0x6c00 +#define SHARED_KEY_MODE_BASE 0x7000 + +#define MAC_WCID_ENTRY(__idx) \ + ( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) ) +#define PAIRWISE_KEY_ENTRY(__idx) \ + ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) +#define MAC_IVEIV_ENTRY(__idx) \ + ( MAC_IVEIV_TABLE_BASE + ((__idx) & sizeof(struct mac_iveiv_entry)) ) +#define MAC_WCID_ATTR_ENTRY(__idx) \ + ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) ) +#define SHARED_KEY_ENTRY(__idx) \ + ( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) +#define SHARED_KEY_MODE_ENTRY(__idx) \ + ( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) ) + +struct mac_wcid_entry { + u8 mac[6]; + u8 reserved[2]; +} __attribute__ ((packed)); + +struct hw_key_entry { + u8 key[16]; + u8 tx_mic[8]; + u8 rx_mic[8]; +} __attribute__ ((packed)); + +struct mac_iveiv_entry { + u8 iv[8]; +} __attribute__ ((packed)); + +/* + * MAC_WCID_ATTRIBUTE: + */ +#define MAC_WCID_ATTRIBUTE_KEYTAB FIELD32(0x00000001) +#define MAC_WCID_ATTRIBUTE_CIPHER FIELD32(0x0000000e) +#define MAC_WCID_ATTRIBUTE_BSS_IDX FIELD32(0x00000070) +#define MAC_WCID_ATTRIBUTE_RX_WIUDF FIELD32(0x00000380) + +/* + * SHARED_KEY_MODE: + */ +#define SHARED_KEY_MODE_BSS0_KEY0 FIELD32(0x00000007) +#define SHARED_KEY_MODE_BSS0_KEY1 FIELD32(0x00000070) +#define SHARED_KEY_MODE_BSS0_KEY2 FIELD32(0x00000700) +#define SHARED_KEY_MODE_BSS0_KEY3 FIELD32(0x00007000) +#define SHARED_KEY_MODE_BSS1_KEY0 FIELD32(0x00070000) +#define SHARED_KEY_MODE_BSS1_KEY1 FIELD32(0x00700000) +#define SHARED_KEY_MODE_BSS1_KEY2 FIELD32(0x07000000) +#define SHARED_KEY_MODE_BSS1_KEY3 FIELD32(0x70000000) + +/* + * HOST-MCU communication + */ + +/* + * H2M_MAILBOX_CSR: Host-to-MCU Mailbox. + */ +#define H2M_MAILBOX_CSR 0x7010 +#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff) +#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00) +#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000) +#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000) + +/* + * H2M_MAILBOX_CID: + */ +#define H2M_MAILBOX_CID 0x7014 +#define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff) +#define H2M_MAILBOX_CID_CMD1 FIELD32(0x0000ff00) +#define H2M_MAILBOX_CID_CMD2 FIELD32(0x00ff0000) +#define H2M_MAILBOX_CID_CMD3 FIELD32(0xff000000) + +/* + * H2M_MAILBOX_STATUS: + */ +#define H2M_MAILBOX_STATUS 0x701c + +/* + * H2M_INT_SRC: + */ +#define H2M_INT_SRC 0x7024 + +/* + * H2M_BBP_AGENT: + */ +#define H2M_BBP_AGENT 0x7028 + +/* + * MCU_LEDCS: LED control for MCU Mailbox. + */ +#define MCU_LEDCS_LED_MODE FIELD8(0x1f) +#define MCU_LEDCS_POLARITY FIELD8(0x01) + +/* + * HW_CS_CTS_BASE: + * Carrier-sense CTS frame base address. + * It's where mac stores carrier-sense frame for carrier-sense function. + */ +#define HW_CS_CTS_BASE 0x7700 + +/* + * HW_DFS_CTS_BASE: + * FS CTS frame base address. It's where mac stores CTS frame for DFS. + */ +#define HW_DFS_CTS_BASE 0x7780 + +/* + * TXRX control registers - base address 0x3000 + */ + +/* + * TXRX_CSR1: + * rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first.. + */ +#define TXRX_CSR1 0x77d0 + +/* + * HW_DEBUG_SETTING_BASE: + * since NULL frame won't be that long (256 byte) + * We steal 16 tail bytes to save debugging settings + */ +#define HW_DEBUG_SETTING_BASE 0x77f0 +#define HW_DEBUG_SETTING_BASE2 0x7770 + +/* + * HW_BEACON_BASE + * In order to support maximum 8 MBSS and its maximum length + * is 512 bytes for each beacon + * Three section discontinue memory segments will be used. + * 1. The original region for BCN 0~3 + * 2. Extract memory from FCE table for BCN 4~5 + * 3. Extract memory from Pair-wise key table for BCN 6~7 + * It occupied those memory of wcid 238~253 for BCN 6 + * and wcid 222~237 for BCN 7 + * + * IMPORTANT NOTE: Not sure why legacy driver does this, + * but HW_BEACON_BASE7 is 0x0200 bytes below HW_BEACON_BASE6. + */ +#define HW_BEACON_BASE0 0x7800 +#define HW_BEACON_BASE1 0x7a00 +#define HW_BEACON_BASE2 0x7c00 +#define HW_BEACON_BASE3 0x7e00 +#define HW_BEACON_BASE4 0x7200 +#define HW_BEACON_BASE5 0x7400 +#define HW_BEACON_BASE6 0x5dc0 +#define HW_BEACON_BASE7 0x5bc0 + +#define HW_BEACON_OFFSET(__index) \ + ( ((__index) < 4) ? ( HW_BEACON_BASE0 + (__index * 0x0200) ) : \ + (((__index) < 6) ? ( HW_BEACON_BASE4 + ((__index - 4) * 0x0200) ) : \ + (HW_BEACON_BASE6 - ((__index - 6) * 0x0200))) ) + +/* + * 8051 firmware image. + */ +#define FIRMWARE_RT2860 "rt2860.bin" +#define FIRMWARE_IMAGE_BASE 0x2000 + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * BBP 1: TX Antenna + */ +#define BBP1_TX_POWER FIELD8(0x07) +#define BBP1_TX_ANTENNA FIELD8(0x18) + +/* + * BBP 3: RX Antenna + */ +#define BBP3_RX_ANTENNA FIELD8(0x18) +#define BBP3_HT40_PLUS FIELD8(0x20) + +/* + * BBP 4: Bandwidth + */ +#define BBP4_TX_BF FIELD8(0x01) +#define BBP4_BANDWIDTH FIELD8(0x18) + +/* + * RFCSR registers + * The wordsize of the RFCSR is 8 bits. + */ + +/* + * RFCSR 6: + */ +#define RFCSR6_R FIELD8(0x03) + +/* + * RFCSR 7: + */ +#define RFCSR7_RF_TUNING FIELD8(0x01) + +/* + * RFCSR 12: + */ +#define RFCSR12_TX_POWER FIELD8(0x1f) + +/* + * RFCSR 22: + */ +#define RFCSR22_BASEBAND_LOOPBACK FIELD8(0x01) + +/* + * RFCSR 23: + */ +#define RFCSR23_FREQ_OFFSET FIELD8(0x7f) + +/* + * RFCSR 30: + */ +#define RFCSR30_RF_CALIBRATION FIELD8(0x80) + +/* + * RF registers + */ + +/* + * RF 2 + */ +#define RF2_ANTENNA_RX2 FIELD32(0x00000040) +#define RF2_ANTENNA_TX1 FIELD32(0x00004000) +#define RF2_ANTENNA_RX1 FIELD32(0x00020000) + +/* + * RF 3 + */ +#define RF3_TXPOWER_G FIELD32(0x00003e00) +#define RF3_TXPOWER_A_7DBM_BOOST FIELD32(0x00000200) +#define RF3_TXPOWER_A FIELD32(0x00003c00) + +/* + * RF 4 + */ +#define RF4_TXPOWER_G FIELD32(0x000007c0) +#define RF4_TXPOWER_A_7DBM_BOOST FIELD32(0x00000040) +#define RF4_TXPOWER_A FIELD32(0x00000780) +#define RF4_FREQ_OFFSET FIELD32(0x001f8000) +#define RF4_HT40 FIELD32(0x00200000) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * EEPROM Version + */ +#define EEPROM_VERSION 0x0001 +#define EEPROM_VERSION_FAE FIELD16(0x00ff) +#define EEPROM_VERSION_VERSION FIELD16(0xff00) + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM ANTENNA config + * RXPATH: 1: 1R, 2: 2R, 3: 3R + * TXPATH: 1: 1T, 2: 2T + */ +#define EEPROM_ANTENNA 0x001a +#define EEPROM_ANTENNA_RXPATH FIELD16(0x000f) +#define EEPROM_ANTENNA_TXPATH FIELD16(0x00f0) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0f00) + +/* + * EEPROM NIC config + * CARDBUS_ACCEL: 0 - enable, 1 - disable + */ +#define EEPROM_NIC 0x001b +#define EEPROM_NIC_HW_RADIO FIELD16(0x0001) +#define EEPROM_NIC_DYNAMIC_TX_AGC FIELD16(0x0002) +#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0004) +#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0008) +#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0010) +#define EEPROM_NIC_BW40M_SB_BG FIELD16(0x0020) +#define EEPROM_NIC_BW40M_SB_A FIELD16(0x0040) +#define EEPROM_NIC_WPS_PBC FIELD16(0x0080) +#define EEPROM_NIC_BW40M_BG FIELD16(0x0100) +#define EEPROM_NIC_BW40M_A FIELD16(0x0200) + +/* + * EEPROM frequency + */ +#define EEPROM_FREQ 0x001d +#define EEPROM_FREQ_OFFSET FIELD16(0x00ff) +#define EEPROM_FREQ_LED_MODE FIELD16(0x7f00) +#define EEPROM_FREQ_LED_POLARITY FIELD16(0x1000) + +/* + * EEPROM LED + * POLARITY_RDY_G: Polarity RDY_G setting. + * POLARITY_RDY_A: Polarity RDY_A setting. + * POLARITY_ACT: Polarity ACT setting. + * POLARITY_GPIO_0: Polarity GPIO0 setting. + * POLARITY_GPIO_1: Polarity GPIO1 setting. + * POLARITY_GPIO_2: Polarity GPIO2 setting. + * POLARITY_GPIO_3: Polarity GPIO3 setting. + * POLARITY_GPIO_4: Polarity GPIO4 setting. + * LED_MODE: Led mode. + */ +#define EEPROM_LED1 0x001e +#define EEPROM_LED2 0x001f +#define EEPROM_LED3 0x0020 +#define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001) +#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002) +#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004) +#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008) +#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010) +#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020) +#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040) +#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080) +#define EEPROM_LED_LED_MODE FIELD16(0x1f00) + +/* + * EEPROM LNA + */ +#define EEPROM_LNA 0x0022 +#define EEPROM_LNA_BG FIELD16(0x00ff) +#define EEPROM_LNA_A0 FIELD16(0xff00) + +/* + * EEPROM RSSI BG offset + */ +#define EEPROM_RSSI_BG 0x0023 +#define EEPROM_RSSI_BG_OFFSET0 FIELD16(0x00ff) +#define EEPROM_RSSI_BG_OFFSET1 FIELD16(0xff00) + +/* + * EEPROM RSSI BG2 offset + */ +#define EEPROM_RSSI_BG2 0x0024 +#define EEPROM_RSSI_BG2_OFFSET2 FIELD16(0x00ff) +#define EEPROM_RSSI_BG2_LNA_A1 FIELD16(0xff00) + +/* + * EEPROM RSSI A offset + */ +#define EEPROM_RSSI_A 0x0025 +#define EEPROM_RSSI_A_OFFSET0 FIELD16(0x00ff) +#define EEPROM_RSSI_A_OFFSET1 FIELD16(0xff00) + +/* + * EEPROM RSSI A2 offset + */ +#define EEPROM_RSSI_A2 0x0026 +#define EEPROM_RSSI_A2_OFFSET2 FIELD16(0x00ff) +#define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00) + +/* + * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power. + * This is delta in 40MHZ. + * VALUE: Tx Power dalta value (MAX=4) + * TYPE: 1: Plus the delta value, 0: minus the delta value + * TXPOWER: Enable: + */ +#define EEPROM_TXPOWER_DELTA 0x0028 +#define EEPROM_TXPOWER_DELTA_VALUE FIELD16(0x003f) +#define EEPROM_TXPOWER_DELTA_TYPE FIELD16(0x0040) +#define EEPROM_TXPOWER_DELTA_TXPOWER FIELD16(0x0080) + +/* + * EEPROM TXPOWER 802.11BG + */ +#define EEPROM_TXPOWER_BG1 0x0029 +#define EEPROM_TXPOWER_BG2 0x0030 +#define EEPROM_TXPOWER_BG_SIZE 7 +#define EEPROM_TXPOWER_BG_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) + +/* + * EEPROM TXPOWER 802.11A + */ +#define EEPROM_TXPOWER_A1 0x003c +#define EEPROM_TXPOWER_A2 0x0053 +#define EEPROM_TXPOWER_A_SIZE 6 +#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_A_2 FIELD16(0xff00) + +/* + * EEPROM TXpower byrate: 20MHZ power + */ +#define EEPROM_TXPOWER_BYRATE 0x006f + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x0078 +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * MCU mailbox commands. + */ +#define MCU_SLEEP 0x30 +#define MCU_WAKEUP 0x31 +#define MCU_RADIO_OFF 0x35 +#define MCU_CURRENT 0x36 +#define MCU_LED 0x50 +#define MCU_LED_STRENGTH 0x51 +#define MCU_LED_1 0x52 +#define MCU_LED_2 0x53 +#define MCU_LED_3 0x54 +#define MCU_RADAR 0x60 +#define MCU_BOOT_SIGNAL 0x72 +#define MCU_BBP_SIGNAL 0x80 +#define MCU_POWER_SAVE 0x83 + +/* + * MCU mailbox tokens + */ +#define TOKEN_WAKUP 3 + +/* + * DMA descriptor defines. + */ +#define TXD_DESC_SIZE ( 4 * sizeof(__le32) ) +#define TXWI_DESC_SIZE ( 4 * sizeof(__le32) ) +#define RXD_DESC_SIZE ( 4 * sizeof(__le32) ) +#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) ) + +/* + * TX descriptor format for TX, PRIO and Beacon Ring. + */ + +/* + * Word0 + */ +#define TXD_W0_SD_PTR0 FIELD32(0xffffffff) + +/* + * Word1 + */ +#define TXD_W1_SD_LEN1 FIELD32(0x00003fff) +#define TXD_W1_LAST_SEC1 FIELD32(0x00004000) +#define TXD_W1_BURST FIELD32(0x00008000) +#define TXD_W1_SD_LEN0 FIELD32(0x3fff0000) +#define TXD_W1_LAST_SEC0 FIELD32(0x40000000) +#define TXD_W1_DMA_DONE FIELD32(0x80000000) + +/* + * Word2 + */ +#define TXD_W2_SD_PTR1 FIELD32(0xffffffff) + +/* + * Word3 + * WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI + * QSEL: Select on-chip FIFO ID for 2nd-stage output scheduler. + * 0:MGMT, 1:HCCA 2:EDCA + */ +#define TXD_W3_WIV FIELD32(0x01000000) +#define TXD_W3_QSEL FIELD32(0x06000000) +#define TXD_W3_TCO FIELD32(0x20000000) +#define TXD_W3_UCO FIELD32(0x40000000) +#define TXD_W3_ICO FIELD32(0x80000000) + +/* + * TX WI structure + */ + +/* + * Word0 + * FRAG: 1 To inform TKIP engine this is a fragment. + * MIMO_PS: The remote peer is in dynamic MIMO-PS mode + * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs + * BW: Channel bandwidth 20MHz or 40 MHz + * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED + */ +#define TXWI_W0_FRAG FIELD32(0x00000001) +#define TXWI_W0_MIMO_PS FIELD32(0x00000002) +#define TXWI_W0_CF_ACK FIELD32(0x00000004) +#define TXWI_W0_TS FIELD32(0x00000008) +#define TXWI_W0_AMPDU FIELD32(0x00000010) +#define TXWI_W0_MPDU_DENSITY FIELD32(0x000000e0) +#define TXWI_W0_TX_OP FIELD32(0x00000300) +#define TXWI_W0_MCS FIELD32(0x007f0000) +#define TXWI_W0_BW FIELD32(0x00800000) +#define TXWI_W0_SHORT_GI FIELD32(0x01000000) +#define TXWI_W0_STBC FIELD32(0x06000000) +#define TXWI_W0_IFS FIELD32(0x08000000) +#define TXWI_W0_PHYMODE FIELD32(0xc0000000) + +/* + * Word1 + */ +#define TXWI_W1_ACK FIELD32(0x00000001) +#define TXWI_W1_NSEQ FIELD32(0x00000002) +#define TXWI_W1_BW_WIN_SIZE FIELD32(0x000000fc) +#define TXWI_W1_WIRELESS_CLI_ID FIELD32(0x0000ff00) +#define TXWI_W1_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) +#define TXWI_W1_PACKETID FIELD32(0xf0000000) + +/* + * Word2 + */ +#define TXWI_W2_IV FIELD32(0xffffffff) + +/* + * Word3 + */ +#define TXWI_W3_EIV FIELD32(0xffffffff) + +/* + * RX descriptor format for RX Ring. + */ + +/* + * Word0 + */ +#define RXD_W0_SDP0 FIELD32(0xffffffff) + +/* + * Word1 + */ +#define RXD_W1_SDL1 FIELD32(0x00003fff) +#define RXD_W1_SDL0 FIELD32(0x3fff0000) +#define RXD_W1_LS0 FIELD32(0x40000000) +#define RXD_W1_DMA_DONE FIELD32(0x80000000) + +/* + * Word2 + */ +#define RXD_W2_SDP1 FIELD32(0xffffffff) + +/* + * Word3 + * AMSDU: RX with 802.3 header, not 802.11 header. + * DECRYPTED: This frame is being decrypted. + */ +#define RXD_W3_BA FIELD32(0x00000001) +#define RXD_W3_DATA FIELD32(0x00000002) +#define RXD_W3_NULLDATA FIELD32(0x00000004) +#define RXD_W3_FRAG FIELD32(0x00000008) +#define RXD_W3_UNICAST_TO_ME FIELD32(0x00000010) +#define RXD_W3_MULTICAST FIELD32(0x00000020) +#define RXD_W3_BROADCAST FIELD32(0x00000040) +#define RXD_W3_MY_BSS FIELD32(0x00000080) +#define RXD_W3_CRC_ERROR FIELD32(0x00000100) +#define RXD_W3_CIPHER_ERROR FIELD32(0x00000600) +#define RXD_W3_AMSDU FIELD32(0x00000800) +#define RXD_W3_HTC FIELD32(0x00001000) +#define RXD_W3_RSSI FIELD32(0x00002000) +#define RXD_W3_L2PAD FIELD32(0x00004000) +#define RXD_W3_AMPDU FIELD32(0x00008000) +#define RXD_W3_DECRYPTED FIELD32(0x00010000) +#define RXD_W3_PLCP_SIGNAL FIELD32(0x00020000) +#define RXD_W3_PLCP_RSSI FIELD32(0x00040000) + +/* + * RX WI structure + */ + +/* + * Word0 + */ +#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff) +#define RXWI_W0_KEY_INDEX FIELD32(0x00000300) +#define RXWI_W0_BSSID FIELD32(0x00001c00) +#define RXWI_W0_UDF FIELD32(0x0000e000) +#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) +#define RXWI_W0_TID FIELD32(0xf0000000) + +/* + * Word1 + */ +#define RXWI_W1_FRAG FIELD32(0x0000000f) +#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0) +#define RXWI_W1_MCS FIELD32(0x007f0000) +#define RXWI_W1_BW FIELD32(0x00800000) +#define RXWI_W1_SHORT_GI FIELD32(0x01000000) +#define RXWI_W1_STBC FIELD32(0x06000000) +#define RXWI_W1_PHYMODE FIELD32(0xc0000000) + +/* + * Word2 + */ +#define RXWI_W2_RSSI0 FIELD32(0x000000ff) +#define RXWI_W2_RSSI1 FIELD32(0x0000ff00) +#define RXWI_W2_RSSI2 FIELD32(0x00ff0000) + +/* + * Word3 + */ +#define RXWI_W3_SNR0 FIELD32(0x000000ff) +#define RXWI_W3_SNR1 FIELD32(0x0000ff00) + +/* + * Macros for converting txpower from EEPROM to mac80211 value + * and from mac80211 value to register value. + */ +#define MIN_G_TXPOWER 0 +#define MIN_A_TXPOWER -7 +#define MAX_G_TXPOWER 31 +#define MAX_A_TXPOWER 15 +#define DEFAULT_TXPOWER 5 + +#define TXPOWER_G_FROM_DEV(__txpower) \ + ((__txpower) > MAX_G_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_G_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_G_TXPOWER, MAX_G_TXPOWER) + +#define TXPOWER_A_FROM_DEV(__txpower) \ + ((__txpower) > MAX_A_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_A_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_A_TXPOWER, MAX_A_TXPOWER) + +#endif /* RT2800PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 27bc6b7fbfde..196de8ab8153 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -158,6 +158,13 @@ struct rt2x00_chip { #define RT2561 0x0302 #define RT2661 0x0401 #define RT2571 0x1300 +#define RT2860 0x0601 /* 2.4GHz PCI/CB */ +#define RT2860D 0x0681 /* 2.4GHz, 5GHz PCI/CB */ +#define RT2890 0x0701 /* 2.4GHz PCIe */ +#define RT2890D 0x0781 /* 2.4GHz, 5GHz PCIe */ +#define RT2880 0x2880 /* WSOC */ +#define RT3052 0x3052 /* WSOC */ +#define RT3090 0x3090 /* 2.4GHz PCIe */ #define RT2870 0x1600 u16 rf; -- cgit v1.2.3 From 30315ff05fce99ef0c172a966b3ed71baa62219b Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 16 Oct 2009 13:18:45 +0800 Subject: iwmc3200wifi: add BGN sdio device id Add BGN SKU sdio device id. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/sdio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index 8b1de84003ca..38026b70a2f9 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -493,8 +493,10 @@ static void iwm_sdio_remove(struct sdio_func *func) } static const struct sdio_device_id iwm_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, - SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) }, + /* Global/AGN SKU */ + { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1403) }, + /* BGN SKU */ + { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1408) }, { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); -- cgit v1.2.3 From 03d1a62c1fb10fe00cfc5cb7f4496d8d6d0e7660 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 16 Oct 2009 13:18:46 +0800 Subject: iwmc3200wifi: allow joining an existed IBSS network We used to only support creating a new IBSS network. Now joining to an existed IBSS network is supported as well. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index a56a2b0ac99a..703edb30c269 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -404,39 +404,21 @@ static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, { struct iwm_priv *iwm = wiphy_to_iwm(wiphy); struct ieee80211_channel *chan = params->channel; - struct cfg80211_bss *bss; if (!test_bit(IWM_STATUS_READY, &iwm->status)) return -EIO; - /* UMAC doesn't support creating IBSS network with specified bssid. - * This should be removed after we have join only mode supported. */ + /* UMAC doesn't support creating or joining an IBSS network + * with specified bssid. */ if (params->bssid) return -EOPNOTSUPP; - bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL, - params->ssid, params->ssid_len); - if (!bss) { - iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len); - schedule_timeout_interruptible(2 * HZ); - bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL, - params->ssid, params->ssid_len); - } - /* IBSS join only mode is not supported by UMAC ATM */ - if (bss) { - cfg80211_put_bss(bss); - return -EOPNOTSUPP; - } - iwm->channel = ieee80211_frequency_to_channel(chan->center_freq); iwm->umac_profile->ibss.band = chan->band; iwm->umac_profile->ibss.channel = iwm->channel; iwm->umac_profile->ssid.ssid_len = params->ssid_len; memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len); - if (params->bssid) - memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN); - return iwm_send_mlme_profile(iwm); } -- cgit v1.2.3 From a82aedbf1b043f7a7474aa9b6d223104ac51827a Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:47 +0800 Subject: iwmc3200wifi: WPS support By setting the WSC profile flag, we now support WPS as an enrollee. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 7 +++++++ drivers/net/wireless/iwmc3200wifi/commands.h | 3 +++ 2 files changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 703edb30c269..ca75d07831a9 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -627,6 +627,13 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, iwm->default_key = sme->key_idx; } + /* WPA and open AUTH type from wpa_s means WPS (a.k.a. WSC) */ + if ((iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) && + iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN) { + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WSC_ON_MSK; + } + ret = iwm_send_mlme_profile(iwm); if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK || diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index e24d5b633997..4e183be1f262 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -288,6 +288,9 @@ struct iwm_umac_cmd_scan_request { /* iwm_umac_security.flag is WSC mode on -- bits [2:2] */ #define UMAC_SEC_FLG_WSC_ON_POS 2 #define UMAC_SEC_FLG_WSC_ON_SEED 1 +#define UMAC_SEC_FLG_WSC_ON_MSK (UMAC_SEC_FLG_WSC_ON_SEED << \ + UMAC_SEC_FLG_WSC_ON_POS) + /* Legacy profile can use only WEP40 and WEP104 for encryption and * OPEN or PSK for authentication */ -- cgit v1.2.3 From e85498b21d0372a00f31ab9f7c0d215c32c9fad5 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:48 +0800 Subject: iwmc3200wifi: CT kill support We set the initial CT (Temperature control) value to 110 degrees. If the chip goes over that threshold, we hard block the device which will turn it down. At the same time we schedule a 30 seconds delayed work that unblock the device (and userspace is supposed to bring it back up), hoping that the chip will have cooled down by then... Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 11 +++++++++++ drivers/net/wireless/iwmc3200wifi/commands.h | 1 + drivers/net/wireless/iwmc3200wifi/fw.c | 2 ++ drivers/net/wireless/iwmc3200wifi/iwm.h | 3 +++ drivers/net/wireless/iwmc3200wifi/lmac.h | 8 ++++++++ drivers/net/wireless/iwmc3200wifi/main.c | 14 ++++++++++++++ drivers/net/wireless/iwmc3200wifi/netdev.c | 1 + drivers/net/wireless/iwmc3200wifi/rx.c | 16 +++++++++++++++- 8 files changed, 55 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 23b52fa2605f..aeea909992fe 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -274,6 +274,17 @@ int iwm_send_calib_results(struct iwm_priv *iwm) return ret; } +int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit) +{ + struct iwm_ct_kill_cfg_cmd cmd; + + cmd.entry_threshold = entry; + cmd.exit_threshold = exit; + + return iwm_send_lmac_ptrough_cmd(iwm, REPLY_CT_KILL_CONFIG_CMD, &cmd, + sizeof(struct iwm_ct_kill_cfg_cmd), 0); +} + int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp) { struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index 4e183be1f262..e486f8e89378 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -396,6 +396,7 @@ int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); int iwm_send_calib_results(struct iwm_priv *iwm); int iwm_store_rxiq_calib_result(struct iwm_priv *iwm); +int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit); /* UMAC commands */ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index 6b0bcad758ca..f02d571b0a13 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -398,6 +398,8 @@ int iwm_load_fw(struct iwm_priv *iwm) iwm_send_prio_table(iwm); iwm_send_calib_results(iwm); iwm_send_periodic_calib_cfg(iwm, periodic_calib_map); + iwm_send_ct_kill_cfg(iwm, iwm->conf.ct_kill_entry, + iwm->conf.ct_kill_exit); return 0; diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 1b02a4e2a1ac..fe0ab80994dd 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -65,6 +65,8 @@ struct iwm_conf { u32 sdio_ior_timeout; unsigned long calib_map; unsigned long expected_calib_map; + u8 ct_kill_entry; + u8 ct_kill_exit; bool reset_on_fatal_err; bool auto_connect; bool wimax_not_present; @@ -276,6 +278,7 @@ struct iwm_priv { struct iw_statistics wstats; struct delayed_work stats_request; struct delayed_work disconnect; + struct delayed_work ct_kill_delay; struct iwm_debugfs dbg; diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h index 6c1a14c4480f..a3a79b5e2898 100644 --- a/drivers/net/wireless/iwmc3200wifi/lmac.h +++ b/drivers/net/wireless/iwmc3200wifi/lmac.h @@ -187,6 +187,14 @@ struct iwm_coex_prio_table_cmd { COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) +/* CT kill config command */ +struct iwm_ct_kill_cfg_cmd { + u32 exit_threshold; + u32 reserved; + u32 entry_threshold; +} __attribute__ ((packed)); + + /* LMAC OP CODES */ #define REPLY_PAD 0x0 #define REPLY_ALIVE 0x1 diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 170f33706490..3147fe7b5130 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -63,6 +63,8 @@ static struct iwm_conf def_iwm_conf = { BIT(PHY_CALIBRATE_TX_IQ_CMD) | BIT(PHY_CALIBRATE_RX_IQ_CMD) | BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), + .ct_kill_entry = 110, + .ct_kill_exit = 110, .reset_on_fatal_err = 1, .auto_connect = 1, .wimax_not_present = 0, @@ -133,6 +135,17 @@ static void iwm_disconnect_work(struct work_struct *work) cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); } +static void iwm_ct_kill_work(struct work_struct *work) +{ + struct iwm_priv *iwm = + container_of(work, struct iwm_priv, ct_kill_delay.work); + struct wiphy *wiphy = iwm_to_wiphy(iwm); + + IWM_INFO(iwm, "CT kill delay timeout\n"); + + wiphy_rfkill_set_hw_state(wiphy, false); +} + static int __iwm_up(struct iwm_priv *iwm); static int __iwm_down(struct iwm_priv *iwm); @@ -225,6 +238,7 @@ int iwm_priv_init(struct iwm_priv *iwm) iwm->scan_id = 1; INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work); + INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work); INIT_WORK(&iwm->reset_worker, iwm_reset_worker); INIT_LIST_HEAD(&iwm->bss_list); diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index 35ec006c2d2c..4f8dbdd7b917 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -152,6 +152,7 @@ void iwm_if_free(struct iwm_priv *iwm) if (!iwm_to_ndev(iwm)) return; + cancel_delayed_work_sync(&iwm->ct_kill_delay); free_netdev(iwm_to_ndev(iwm)); iwm_priv_deinit(iwm); kfree(iwm->umac_profile); diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 40dbcbc16593..14a2a0b3d614 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1078,6 +1078,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, return 0; } +#define CT_KILL_DELAY (30 * HZ) static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) { @@ -1090,7 +1091,20 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); - wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED); + if (flags & IWM_CARD_STATE_CTKILL_DISABLED) { + /* + * We got a CTKILL event: We bring the interface down in + * oder to cool the device down, and try to bring it up + * 30 seconds later. If it's still too hot, we'll go through + * this code path again. + */ + cancel_delayed_work_sync(&iwm->ct_kill_delay); + schedule_delayed_work(&iwm->ct_kill_delay, CT_KILL_DELAY); + } + + wiphy_rfkill_set_hw_state(wiphy, flags & + (IWM_CARD_STATE_HW_DISABLED | + IWM_CARD_STATE_CTKILL_DISABLED)); return 0; } -- cgit v1.2.3 From 6a79c9f62a87e39a265f9b855911fbc1f094ded0 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:49 +0800 Subject: iwmc3200wifi: Profile flags can be WPA1 or WPA2 not both UMAC will ASSERT if the profile security flag is WPA1 | WPA2, so we can only accept one of those. Moreover wpa_s wext and nl80211 drivers dont try to send WPA1 | WPA2, but only one at a time. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index ca75d07831a9..89edb6629426 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -471,12 +471,12 @@ static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version) return 0; } + if (wpa_version & NL80211_WPA_VERSION_1) + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK; + if (wpa_version & NL80211_WPA_VERSION_2) iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; - if (wpa_version & NL80211_WPA_VERSION_1) - iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK; - return 0; } -- cgit v1.2.3 From 69cf6e2d5bd90436a0fa6cef2f4d65583faef388 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:50 +0800 Subject: iwmc3200wifi: Improve rx debug We display the correct DROP/RELEASE string for each rx packets, and when it's dropped we also display the reason. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/rx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 14a2a0b3d614..225b1d3b2735 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -422,7 +422,9 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf, if (IS_ERR(ticket_node)) return PTR_ERR(ticket_node); - IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n", + IWM_DBG_RX(iwm, DBG, "TICKET %s(%d)\n", + ticket->action == IWM_RX_TICKET_RELEASE ? + "RELEASE" : "DROP", ticket->id); list_add_tail(&ticket_node->node, &iwm->rx_tickets); @@ -1457,7 +1459,8 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm, } break; case IWM_RX_TICKET_DROP: - IWM_DBG_RX(iwm, DBG, "DROP packet\n"); + IWM_DBG_RX(iwm, DBG, "DROP packet: 0x%x\n", + le16_to_cpu(ticket_node->ticket->flags)); kfree_skb(packet->skb); break; default: -- cgit v1.2.3 From 05f9589cd37be9ead62a92755cd86f14b247229d Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:51 +0800 Subject: iwmc3200wifi: Update statistics notification structure The latest firmware adds a ht_rates and a chain_energy field. The latter is needed as we want to eventually support RSSI/antenna handling. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/umac.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h index c5a14ae3160a..be903543bb47 100644 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -687,6 +687,9 @@ struct iwm_umac_notif_rx_ticket { /* Tx/Rx rates window (number of max of last update window per second) */ #define UMAC_NTF_RATE_SAMPLE_NR 4 +/* Max numbers of bits required to go through all antennae in bitmasks */ +#define UMAC_PHY_NUM_CHAINS 3 + #define IWM_UMAC_MGMT_TID 8 #define IWM_UMAC_TID_NR 8 @@ -697,9 +700,11 @@ struct iwm_umac_notif_stats { __le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */ __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; + __le32 chain_energy[UMAC_PHY_NUM_CHAINS]; s32 rssi_dbm; s32 noise_dbm; __le32 supp_rates; + __le32 supp_ht_rates; __le32 missed_beacons; __le32 rx_beacons; __le32 rx_dir_pkts; -- cgit v1.2.3 From 7eae165e2d7dd32e88a641c0f38b2be840bcae07 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:52 +0800 Subject: iwmc3200wifi: Update fixed size config definitions We need to be in sync with the latest firmware API. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.h | 60 +++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index e486f8e89378..511b6e395ac5 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -102,7 +102,6 @@ enum { CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN, CFG_TLC_SUPPORTED_TX_HT_RATES, CFG_TLC_SUPPORTED_TX_RATES, - CFG_TLC_VALID_ANTENNA, CFG_TLC_SPATIAL_STREAM_SUPPORTED, CFG_TLC_RETRY_PER_RATE, CFG_TLC_RETRY_PER_HT_RATE, @@ -136,6 +135,10 @@ enum { CFG_TLC_RENEW_ADDBA_DELAY, CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD, CFG_TLC_IS_STABLE_IN_HT, + CFG_TLC_SR_SIC_1ST_FAIL, + CFG_TLC_SR_SIC_1ST_PASS, + CFG_TLC_SR_SIC_TOTAL_FAIL, + CFG_TLC_SR_SIC_TOTAL_PASS, CFG_RLC_CHAIN_CTRL, CFG_TRK_TABLE_OP_MODE, CFG_TRK_TABLE_RSSI_THRESHOLD, @@ -147,6 +150,58 @@ enum { CFG_MLME_DBG_NOTIF_BLOCK, CFG_BT_OFF_BECONS_INTERVALS, CFG_BT_FRAG_DURATION, + CFG_ACTIVE_CHAINS, + CFG_CALIB_CTRL, + CFG_CAPABILITY_SUPPORTED_HT_RATES, + CFG_HT_MAC_PARAM_INFO, + CFG_MIMO_PS_MODE, + CFG_HT_DEFAULT_CAPABILIES_INFO, + CFG_LED_SC_RESOLUTION_FACTOR, + CFG_PTAM_ENERGY_CCK_DET_DEFAULT, + CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_DEFAULT, + CFG_PTAM_CORR40_4_TH_ADD_MIN_DEFAULT, + CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_DEFAULT, + CFG_PTAM_CORR32_4_TH_ADD_MIN_DEFAULT, + CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_DEFAULT, + CFG_PTAM_CORR32_1_TH_ADD_MIN_DEFAULT, + CFG_PTAM_ENERGY_CCK_DET_MIN_VAL, + CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MIN_VAL, + CFG_PTAM_CORR40_4_TH_ADD_MIN_MIN_VAL, + CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MIN_VAL, + CFG_PTAM_CORR32_4_TH_ADD_MIN_MIN_VAL, + CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MIN_VAL, + CFG_PTAM_CORR32_1_TH_ADD_MIN_MIN_VAL, + CFG_PTAM_ENERGY_CCK_DET_MAX_VAL, + CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MAX_VAL, + CFG_PTAM_CORR40_4_TH_ADD_MIN_MAX_VAL, + CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MAX_VAL, + CFG_PTAM_CORR32_4_TH_ADD_MIN_MAX_VAL, + CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MAX_VAL, + CFG_PTAM_CORR32_1_TH_ADD_MIN_MAX_VAL, + CFG_PTAM_ENERGY_CCK_DET_STEP_VAL, + CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_STEP_VAL, + CFG_PTAM_CORR40_4_TH_ADD_MIN_STEP_VAL, + CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_STEP_VAL, + CFG_PTAM_CORR32_4_TH_ADD_MIN_STEP_VAL, + CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_STEP_VAL, + CFG_PTAM_CORR32_1_TH_ADD_MIN_STEP_VAL, + CFG_PTAM_LINK_SENS_FA_OFDM_MAX, + CFG_PTAM_LINK_SENS_FA_OFDM_MIN, + CFG_PTAM_LINK_SENS_FA_CCK_MAX, + CFG_PTAM_LINK_SENS_FA_CCK_MIN, + CFG_PTAM_LINK_SENS_NRG_DIFF, + CFG_PTAM_LINK_SENS_NRG_MARGIN, + CFG_PTAM_LINK_SENS_MAX_NUMBER_OF_TIMES_IN_CCK_NO_FA, + CFG_PTAM_LINK_SENS_AUTO_CORR_MAX_TH_CCK, + CFG_AGG_MGG_TID_LOAD_ADDBA_THRESHOLD, + CFG_AGG_MGG_TID_LOAD_DELBA_THRESHOLD, + CFG_AGG_MGG_ADDBA_BUF_SIZE, + CFG_AGG_MGG_ADDBA_INACTIVE_TIMEOUT, + CFG_AGG_MGG_ADDBA_DEBUG_FLAGS, + CFG_SCAN_PERIODIC_RSSI_HIGH_THRESHOLD, + CFG_SCAN_PERIODIC_COEF_RSSI_HIGH, + CFG_11D_ENABLED, + CFG_11H_FEATURE_FLAGS, /* <-- LAST --> */ CFG_TBL_FIX_LAST @@ -155,7 +210,8 @@ enum { /* variable size table */ enum { CFG_NET_ADDR = 0, - CFG_PROFILE, + CFG_LED_PATTERN_TABLE, + /* <-- LAST --> */ CFG_TBL_VAR_LAST }; -- cgit v1.2.3 From 88e6195a911bce85adcc14e8377aa619e8054ab2 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:53 +0800 Subject: iwmc3200wifi: Tx power setting We can now set the Tx power from e.g. iwconfig. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 12 +++++++++++- drivers/net/wireless/iwmc3200wifi/commands.c | 13 +++++++++++++ drivers/net/wireless/iwmc3200wifi/commands.h | 6 ++++++ 3 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 89edb6629426..af72cc746f15 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -670,9 +670,19 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, enum tx_power_setting type, int dbm) { + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + int ret; + switch (type) { case TX_POWER_AUTOMATIC: return 0; + case TX_POWER_FIXED: + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_TX_PWR_LIMIT_USR, dbm * 2); + if (ret < 0) + return ret; + + return iwm_tx_power_trigger(iwm); default: return -EOPNOTSUPP; } @@ -684,7 +694,7 @@ static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) { struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - *dbm = iwm->txpower; + *dbm = iwm->txpower >> 1; return 0; } diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index aeea909992fe..d5125b7659a8 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -793,6 +793,19 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) return ret ? 0 : -EBUSY; } +int iwm_tx_power_trigger(struct iwm_priv *iwm) +{ + struct iwm_umac_pwr_trigger pwr_trigger; + + pwr_trigger.hdr.oid = UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER; + pwr_trigger.hdr.buf_size = + cpu_to_le16(sizeof(struct iwm_umac_pwr_trigger) - + sizeof(struct iwm_umac_wifi_if)); + + + return iwm_send_wifi_if_cmd(iwm, &pwr_trigger, sizeof(pwr_trigger), 1); +} + int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) { struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index 511b6e395ac5..b36be2b23a3c 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -441,6 +441,11 @@ struct iwm_umac_tx_key_id { u8 reserved[3]; } __attribute__ ((packed)); +struct iwm_umac_pwr_trigger { + struct iwm_umac_wifi_if hdr; + __le32 reseved; +} __attribute__ ((packed)); + struct iwm_umac_cmd_stats_req { __le32 flags; } __attribute__ ((packed)); @@ -467,6 +472,7 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm); int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key); +int iwm_tx_power_trigger(struct iwm_priv *iwm); int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); int iwm_send_umac_channel_list(struct iwm_priv *iwm); int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, -- cgit v1.2.3 From f96cca8483c1b0bcc8002dc466159bf8fd53ca47 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:54 +0800 Subject: iwmc3200wifi: SDIO disable race fix When calling sdio->bus_disable(), we are flushing the command lists before disabling the sdio function. We can thus potentially get a command response after having flushed the command list. To avoid that race, we have to call iwm_reset() after disabling the sdio function. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index 38026b70a2f9..cf86294f719b 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -224,8 +224,6 @@ static int if_sdio_disable(struct iwm_priv *iwm) struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); int ret; - iwm_reset(iwm); - sdio_claim_host(hw->func); sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret); if (ret < 0) @@ -237,6 +235,8 @@ static int if_sdio_disable(struct iwm_priv *iwm) iwm_sdio_rx_free(hw); + iwm_reset(iwm); + IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n"); return 0; -- cgit v1.2.3 From 708567e0723f3a217286c2b60805af6de360ec50 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:55 +0800 Subject: iwmc3200wifi: Check for cmd pointer before dereferencing it The wifi_if_wrapper notification handling code uses a cmd pointer without checking if it's valid or not. We're dereferencing it because we assume that we only get to that point if there was a pending command for us. That's not always true, so we'd better check. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/rx.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 225b1d3b2735..648f84a83705 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1057,8 +1057,14 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) { - struct iwm_umac_wifi_if *hdr = - (struct iwm_umac_wifi_if *)cmd->buf.payload; + struct iwm_umac_wifi_if *hdr; + + if (cmd == NULL) { + IWM_ERR(iwm, "Couldn't find expected wifi command\n"); + return -EINVAL; + } + + hdr = (struct iwm_umac_wifi_if *)cmd->buf.payload; IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " "oid is 0x%x\n", hdr->oid); -- cgit v1.2.3 From 56e3f085f5b5e49cca37a3d1b0aa4266b984eb12 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:56 +0800 Subject: iwmc3200wifi: Do not handle wifi command if the interface is not ready When resetting or bringing the interface down, we should just reject any wifi related command. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index d5125b7659a8..25fb8dfd83b5 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -76,6 +76,11 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, int ret; u8 oid = hdr->oid; + if (!test_bit(IWM_STATUS_READY, &iwm->status)) { + IWM_ERR(iwm, "Interface is not ready yet"); + return -EAGAIN; + } + umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; umac_cmd.resp = resp; -- cgit v1.2.3 From 9829e1b510214956bc9d5e278be49d781e1a6fbf Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:57 +0800 Subject: iwmc3200wifi: Try shared auth when open WEP fails When we fail to associate with an open WEP AP, we fall back to shared auth. This allows us to support joining a shared auth WEP AP with iwconfig. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 2 +- drivers/net/wireless/iwmc3200wifi/iwm.h | 1 + drivers/net/wireless/iwmc3200wifi/main.c | 28 ++++++++++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/rx.c | 28 +++++++++++++++++++++++----- 4 files changed, 53 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 25fb8dfd83b5..cad511afd907 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -793,7 +793,7 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) return ret; ret = wait_event_interruptible_timeout(iwm->mlme_queue, - (iwm->umac_profile_active == 0), 2 * HZ); + (iwm->umac_profile_active == 0), 5 * HZ); return ret ? 0 : -EBUSY; } diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index fe0ab80994dd..c4a01f2a6028 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -285,6 +285,7 @@ struct iwm_priv { u8 *eeprom; struct timer_list watchdog; struct work_struct reset_worker; + struct work_struct auth_retry_worker; struct mutex mutex; u8 *req_ie; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 3147fe7b5130..952701e6127e 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -207,6 +207,33 @@ static void iwm_reset_worker(struct work_struct *work) mutex_unlock(&iwm->mutex); } +static void iwm_auth_retry_worker(struct work_struct *work) +{ + struct iwm_priv *iwm; + int i, ret; + + iwm = container_of(work, struct iwm_priv, auth_retry_worker); + if (iwm->umac_profile_active) { + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) + return; + } + + iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + + ret = iwm_send_mlme_profile(iwm); + if (ret < 0) + return; + + for (i = 0; i < IWM_NUM_KEYS; i++) + if (iwm->keys[i].key_len) + iwm_set_key(iwm, 0, &iwm->keys[i]); + + iwm_set_tx_key(iwm, iwm->default_key); +} + + + static void iwm_watchdog(unsigned long data) { struct iwm_priv *iwm = (struct iwm_priv *)data; @@ -240,6 +267,7 @@ int iwm_priv_init(struct iwm_priv *iwm) INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work); INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work); INIT_WORK(&iwm->reset_worker, iwm_reset_worker); + INIT_WORK(&iwm->auth_retry_worker, iwm_auth_retry_worker); INIT_LIST_HEAD(&iwm->bss_list); skb_queue_head_init(&iwm->rx_list); diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 648f84a83705..5fa0a63ef0bf 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -501,6 +501,18 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf, return 0; } +static u8 iwm_is_open_wep_profile(struct iwm_priv *iwm) +{ + if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 || + iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) && + (iwm->umac_profile->sec.ucast_cipher == + iwm->umac_profile->sec.mcast_cipher) && + (iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN)) + return 1; + + return 0; +} + static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) @@ -566,11 +578,17 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, goto ibss; if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) - cfg80211_connect_result(iwm_to_ndev(iwm), - complete->bssid, - NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); + if (!iwm_is_open_wep_profile(iwm)) { + cfg80211_connect_result(iwm_to_ndev(iwm), + complete->bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + } else { + /* Let's try shared WEP auth */ + IWM_ERR(iwm, "Trying WEP shared auth\n"); + schedule_work(&iwm->auth_retry_worker); + } else cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); -- cgit v1.2.3 From 7fd6b12f329b7ec1c1e3ad49d701d2ac7ab42d9e Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:58 +0800 Subject: iwmc3200wifi: Support unexpected reboot barker We can receive unexpected reboot barker at any time, and we're supposed to reset the whole device then. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/rx.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 5fa0a63ef0bf..bca3bb2d2dec 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1321,6 +1321,14 @@ int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size) switch (le32_to_cpu(hdr->cmd)) { case UMAC_REBOOT_BARKER: + if (test_bit(IWM_STATUS_READY, &iwm->status)) { + IWM_ERR(iwm, "Unexpected BARKER\n"); + + schedule_work(&iwm->reset_worker); + + return 0; + } + return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION, IWM_SRC_UDMA, buf, buf_size); case UMAC_ACK_BARKER: -- cgit v1.2.3 From 5dc53163c24ad288cfa2369b14a073992e069908 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 16 Oct 2009 13:18:59 +0800 Subject: iwmc3200wifi: Set wiphy firmware version Our wiphy firmware version is a combination of the UMAC and LMAC ones. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/fw.c | 7 +++++++ drivers/net/wireless/iwmc3200wifi/iwm.h | 2 ++ drivers/net/wireless/iwmc3200wifi/main.c | 4 ++++ 3 files changed, 13 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index f02d571b0a13..49067092d336 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -217,6 +217,13 @@ static int iwm_load_img(struct iwm_priv *iwm, const char *img_name) IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date), IWM_BUILD_DAY(build_date)); + if (!strcmp(img_name, iwm->bus_ops->umac_name)) + sprintf(iwm->umac_version, "%02X.%02X", + ver->major, ver->minor); + + if (!strcmp(img_name, iwm->bus_ops->lmac_name)) + sprintf(iwm->lmac_version, "%02X.%02X", + ver->major, ver->minor); err_release_fw: release_firmware(fw); diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index c4a01f2a6028..a9bf6bc97bea 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -294,6 +294,8 @@ struct iwm_priv { int resp_ie_len; struct iwm_fw_error_hdr *last_fw_err; + char umac_version[8]; + char lmac_version[8]; char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 952701e6127e..f93e9139b0f2 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -628,6 +628,7 @@ static int __iwm_up(struct iwm_priv *iwm) { int ret; struct iwm_notif *notif_reboot, *notif_ack = NULL; + struct wiphy *wiphy = iwm_to_wiphy(iwm); ret = iwm_bus_enable(iwm); if (ret) { @@ -689,6 +690,9 @@ static int __iwm_up(struct iwm_priv *iwm) goto err_disable; } + snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s", + iwm->lmac_version, iwm->umac_version); + /* We configure the UMAC and enable the wifi module */ ret = iwm_send_umac_config(iwm, cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) | -- cgit v1.2.3 From b8fcf590939f0aa24d43bdbdae7c963f31ba90bd Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 16 Oct 2009 13:19:00 +0800 Subject: iwmc3200wifi: handle coexistence radio notification Handle WiFi/WiMax coexistence radio preemption notification event. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/rx.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index bca3bb2d2dec..3ad95dc0dd8d 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -732,6 +732,19 @@ static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf, return 0; } +static int iwm_mlme_medium_lost(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct wiphy *wiphy = iwm_to_wiphy(iwm); + + IWM_DBG_NTF(iwm, DBG, "WiFi/WiMax coexistence radio is OFF\n"); + + wiphy_rfkill_set_hw_state(wiphy, true); + + return 0; +} + static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) @@ -918,6 +931,8 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf, case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED: IWM_DBG_MLME(iwm, DBG, "Extended IE required\n"); break; + case WIFI_IF_NTFY_RADIO_PREEMPTION: + return iwm_mlme_medium_lost(iwm, buf, buf_size, cmd); case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED: return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd); case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED: -- cgit v1.2.3 From 9e66e701d0e42efd548f0f7249af8a56f8e07b67 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Fri, 16 Oct 2009 17:32:16 +0200 Subject: libertas: cleanup host.h and hostcmd.h Also remove some unused definitions and make tab usage consistent. Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 1 - drivers/net/wireless/libertas/cmd.h | 2 +- drivers/net/wireless/libertas/dev.h | 2 +- drivers/net/wireless/libertas/host.h | 1001 ++++++++++++++++++++++++++----- drivers/net/wireless/libertas/hostcmd.h | 800 ------------------------ drivers/net/wireless/libertas/rx.c | 2 +- drivers/net/wireless/libertas/tx.c | 2 +- 7 files changed, 853 insertions(+), 957 deletions(-) delete mode 100644 drivers/net/wireless/libertas/hostcmd.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index eb0bce338e55..cced646a8847 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -7,7 +7,6 @@ #include #include #include "host.h" -#include "hostcmd.h" #include "decl.h" #include "defs.h" #include "dev.h" diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 2730c6aadfd2..bf7c421c7a53 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -3,7 +3,7 @@ #ifndef _LBS_CMD_H_ #define _LBS_CMD_H_ -#include "hostcmd.h" +#include "host.h" #include "dev.h" /* lbs_cmd() infers the size of the buffer to copy data back into, from diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 8abb28af5afa..191ea33de509 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -12,7 +12,7 @@ #include #include "defs.h" -#include "hostcmd.h" +#include "host.h" extern const struct ethtool_ops lbs_ethtool_ops; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index c055daabea13..45cd7f1e5937 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -1,202 +1,189 @@ /** - * This file contains definitions of WLAN commands. + * This file function prototypes, data structure + * and definitions for all the host/station commands */ #ifndef _LBS_HOST_H_ #define _LBS_HOST_H_ -/** PUBLIC DEFINITIONS */ -#define DEFAULT_AD_HOC_CHANNEL 6 -#define DEFAULT_AD_HOC_CHANNEL_A 36 +#include "11d.h" -#define CMD_OPTION_WAITFORRSP 0x0002 +#define DEFAULT_AD_HOC_CHANNEL 6 + +#define CMD_OPTION_WAITFORRSP 0x0002 /** Host command IDs */ /* Return command are almost always the same as the host command, but with * bit 15 set high. There are a few exceptions, though... */ -#define CMD_RET(cmd) (0x8000 | cmd) +#define CMD_RET(cmd) (0x8000 | cmd) /* Return command convention exceptions: */ -#define CMD_RET_802_11_ASSOCIATE 0x8012 +#define CMD_RET_802_11_ASSOCIATE 0x8012 /* Command codes */ -#define CMD_GET_HW_SPEC 0x0003 -#define CMD_EEPROM_UPDATE 0x0004 -#define CMD_802_11_RESET 0x0005 -#define CMD_802_11_SCAN 0x0006 -#define CMD_802_11_GET_LOG 0x000b -#define CMD_MAC_MULTICAST_ADR 0x0010 -#define CMD_802_11_AUTHENTICATE 0x0011 -#define CMD_802_11_EEPROM_ACCESS 0x0059 -#define CMD_802_11_ASSOCIATE 0x0050 -#define CMD_802_11_SET_WEP 0x0013 -#define CMD_802_11_GET_STAT 0x0014 -#define CMD_802_3_GET_STAT 0x0015 -#define CMD_802_11_SNMP_MIB 0x0016 -#define CMD_MAC_REG_MAP 0x0017 -#define CMD_BBP_REG_MAP 0x0018 -#define CMD_MAC_REG_ACCESS 0x0019 -#define CMD_BBP_REG_ACCESS 0x001a -#define CMD_RF_REG_ACCESS 0x001b -#define CMD_802_11_RADIO_CONTROL 0x001c -#define CMD_802_11_RF_CHANNEL 0x001d -#define CMD_802_11_RF_TX_POWER 0x001e -#define CMD_802_11_RSSI 0x001f -#define CMD_802_11_RF_ANTENNA 0x0020 -#define CMD_802_11_PS_MODE 0x0021 -#define CMD_802_11_DATA_RATE 0x0022 -#define CMD_RF_REG_MAP 0x0023 -#define CMD_802_11_DEAUTHENTICATE 0x0024 -#define CMD_802_11_REASSOCIATE 0x0025 -#define CMD_MAC_CONTROL 0x0028 -#define CMD_802_11_AD_HOC_START 0x002b -#define CMD_802_11_AD_HOC_JOIN 0x002c -#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e -#define CMD_802_11_ENABLE_RSN 0x002f -#define CMD_802_11_SET_AFC 0x003c -#define CMD_802_11_GET_AFC 0x003d -#define CMD_802_11_DEEP_SLEEP 0x003e -#define CMD_802_11_AD_HOC_STOP 0x0040 -#define CMD_802_11_HOST_SLEEP_CFG 0x0043 -#define CMD_802_11_WAKEUP_CONFIRM 0x0044 -#define CMD_802_11_HOST_SLEEP_ACTIVATE 0x0045 -#define CMD_802_11_BEACON_STOP 0x0049 -#define CMD_802_11_MAC_ADDRESS 0x004d -#define CMD_802_11_LED_GPIO_CTRL 0x004e -#define CMD_802_11_EEPROM_ACCESS 0x0059 -#define CMD_802_11_BAND_CONFIG 0x0058 -#define CMD_GSPI_BUS_CONFIG 0x005a -#define CMD_802_11D_DOMAIN_INFO 0x005b -#define CMD_802_11_KEY_MATERIAL 0x005e -#define CMD_802_11_SLEEP_PARAMS 0x0066 -#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 -#define CMD_802_11_SLEEP_PERIOD 0x0068 -#define CMD_802_11_TPC_CFG 0x0072 -#define CMD_802_11_PA_CFG 0x0073 -#define CMD_802_11_FW_WAKE_METHOD 0x0074 -#define CMD_802_11_SUBSCRIBE_EVENT 0x0075 -#define CMD_802_11_RATE_ADAPT_RATESET 0x0076 -#define CMD_802_11_TX_RATE_QUERY 0x007f -#define CMD_GET_TSF 0x0080 -#define CMD_BT_ACCESS 0x0087 -#define CMD_FWT_ACCESS 0x0095 -#define CMD_802_11_MONITOR_MODE 0x0098 -#define CMD_MESH_ACCESS 0x009b -#define CMD_MESH_CONFIG_OLD 0x00a3 -#define CMD_MESH_CONFIG 0x00ac -#define CMD_SET_BOOT2_VER 0x00a5 -#define CMD_FUNC_INIT 0x00a9 -#define CMD_FUNC_SHUTDOWN 0x00aa -#define CMD_802_11_BEACON_CTRL 0x00b0 +#define CMD_GET_HW_SPEC 0x0003 +#define CMD_EEPROM_UPDATE 0x0004 +#define CMD_802_11_RESET 0x0005 +#define CMD_802_11_SCAN 0x0006 +#define CMD_802_11_GET_LOG 0x000b +#define CMD_MAC_MULTICAST_ADR 0x0010 +#define CMD_802_11_AUTHENTICATE 0x0011 +#define CMD_802_11_EEPROM_ACCESS 0x0059 +#define CMD_802_11_ASSOCIATE 0x0050 +#define CMD_802_11_SET_WEP 0x0013 +#define CMD_802_11_GET_STAT 0x0014 +#define CMD_802_3_GET_STAT 0x0015 +#define CMD_802_11_SNMP_MIB 0x0016 +#define CMD_MAC_REG_MAP 0x0017 +#define CMD_BBP_REG_MAP 0x0018 +#define CMD_MAC_REG_ACCESS 0x0019 +#define CMD_BBP_REG_ACCESS 0x001a +#define CMD_RF_REG_ACCESS 0x001b +#define CMD_802_11_RADIO_CONTROL 0x001c +#define CMD_802_11_RF_CHANNEL 0x001d +#define CMD_802_11_RF_TX_POWER 0x001e +#define CMD_802_11_RSSI 0x001f +#define CMD_802_11_RF_ANTENNA 0x0020 +#define CMD_802_11_PS_MODE 0x0021 +#define CMD_802_11_DATA_RATE 0x0022 +#define CMD_RF_REG_MAP 0x0023 +#define CMD_802_11_DEAUTHENTICATE 0x0024 +#define CMD_802_11_REASSOCIATE 0x0025 +#define CMD_MAC_CONTROL 0x0028 +#define CMD_802_11_AD_HOC_START 0x002b +#define CMD_802_11_AD_HOC_JOIN 0x002c +#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e +#define CMD_802_11_ENABLE_RSN 0x002f +#define CMD_802_11_SET_AFC 0x003c +#define CMD_802_11_GET_AFC 0x003d +#define CMD_802_11_DEEP_SLEEP 0x003e +#define CMD_802_11_AD_HOC_STOP 0x0040 +#define CMD_802_11_HOST_SLEEP_CFG 0x0043 +#define CMD_802_11_WAKEUP_CONFIRM 0x0044 +#define CMD_802_11_HOST_SLEEP_ACTIVATE 0x0045 +#define CMD_802_11_BEACON_STOP 0x0049 +#define CMD_802_11_MAC_ADDRESS 0x004d +#define CMD_802_11_LED_GPIO_CTRL 0x004e +#define CMD_802_11_EEPROM_ACCESS 0x0059 +#define CMD_802_11_BAND_CONFIG 0x0058 +#define CMD_GSPI_BUS_CONFIG 0x005a +#define CMD_802_11D_DOMAIN_INFO 0x005b +#define CMD_802_11_KEY_MATERIAL 0x005e +#define CMD_802_11_SLEEP_PARAMS 0x0066 +#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 +#define CMD_802_11_SLEEP_PERIOD 0x0068 +#define CMD_802_11_TPC_CFG 0x0072 +#define CMD_802_11_PA_CFG 0x0073 +#define CMD_802_11_FW_WAKE_METHOD 0x0074 +#define CMD_802_11_SUBSCRIBE_EVENT 0x0075 +#define CMD_802_11_RATE_ADAPT_RATESET 0x0076 +#define CMD_802_11_TX_RATE_QUERY 0x007f +#define CMD_GET_TSF 0x0080 +#define CMD_BT_ACCESS 0x0087 +#define CMD_FWT_ACCESS 0x0095 +#define CMD_802_11_MONITOR_MODE 0x0098 +#define CMD_MESH_ACCESS 0x009b +#define CMD_MESH_CONFIG_OLD 0x00a3 +#define CMD_MESH_CONFIG 0x00ac +#define CMD_SET_BOOT2_VER 0x00a5 +#define CMD_FUNC_INIT 0x00a9 +#define CMD_FUNC_SHUTDOWN 0x00aa +#define CMD_802_11_BEACON_CTRL 0x00b0 /* For the IEEE Power Save */ -#define CMD_SUBCMD_ENTER_PS 0x0030 -#define CMD_SUBCMD_EXIT_PS 0x0031 -#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034 -#define CMD_SUBCMD_FULL_POWERDOWN 0x0035 -#define CMD_SUBCMD_FULL_POWERUP 0x0036 +#define CMD_SUBCMD_ENTER_PS 0x0030 +#define CMD_SUBCMD_EXIT_PS 0x0031 +#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034 +#define CMD_SUBCMD_FULL_POWERDOWN 0x0035 +#define CMD_SUBCMD_FULL_POWERUP 0x0036 -#define CMD_ENABLE_RSN 0x0001 -#define CMD_DISABLE_RSN 0x0000 +#define CMD_ENABLE_RSN 0x0001 +#define CMD_DISABLE_RSN 0x0000 -#define CMD_ACT_GET 0x0000 -#define CMD_ACT_SET 0x0001 -#define CMD_ACT_GET_AES 0x0002 -#define CMD_ACT_SET_AES 0x0003 -#define CMD_ACT_REMOVE_AES 0x0004 +#define CMD_ACT_GET 0x0000 +#define CMD_ACT_SET 0x0001 /* Define action or option for CMD_802_11_SET_WEP */ -#define CMD_ACT_ADD 0x0002 -#define CMD_ACT_REMOVE 0x0004 -#define CMD_ACT_USE_DEFAULT 0x0008 - -#define CMD_TYPE_WEP_40_BIT 0x01 -#define CMD_TYPE_WEP_104_BIT 0x02 +#define CMD_ACT_ADD 0x0002 +#define CMD_ACT_REMOVE 0x0004 -#define CMD_NUM_OF_WEP_KEYS 4 +#define CMD_TYPE_WEP_40_BIT 0x01 +#define CMD_TYPE_WEP_104_BIT 0x02 -#define CMD_WEP_KEY_INDEX_MASK 0x3fff +#define CMD_NUM_OF_WEP_KEYS 4 -/* Define action or option for CMD_802_11_RESET */ -#define CMD_ACT_HALT 0x0003 +#define CMD_WEP_KEY_INDEX_MASK 0x3fff /* Define action or option for CMD_802_11_SCAN */ -#define CMD_BSS_TYPE_BSS 0x0001 -#define CMD_BSS_TYPE_IBSS 0x0002 -#define CMD_BSS_TYPE_ANY 0x0003 +#define CMD_BSS_TYPE_BSS 0x0001 +#define CMD_BSS_TYPE_IBSS 0x0002 +#define CMD_BSS_TYPE_ANY 0x0003 /* Define action or option for CMD_802_11_SCAN */ -#define CMD_SCAN_TYPE_ACTIVE 0x0000 -#define CMD_SCAN_TYPE_PASSIVE 0x0001 +#define CMD_SCAN_TYPE_ACTIVE 0x0000 +#define CMD_SCAN_TYPE_PASSIVE 0x0001 -#define CMD_SCAN_RADIO_TYPE_BG 0 +#define CMD_SCAN_RADIO_TYPE_BG 0 -#define CMD_SCAN_PROBE_DELAY_TIME 0 +#define CMD_SCAN_PROBE_DELAY_TIME 0 /* Define action or option for CMD_MAC_CONTROL */ -#define CMD_ACT_MAC_RX_ON 0x0001 -#define CMD_ACT_MAC_TX_ON 0x0002 -#define CMD_ACT_MAC_LOOPBACK_ON 0x0004 -#define CMD_ACT_MAC_WEP_ENABLE 0x0008 -#define CMD_ACT_MAC_INT_ENABLE 0x0010 -#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020 -#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040 -#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 -#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 -#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 +#define CMD_ACT_MAC_RX_ON 0x0001 +#define CMD_ACT_MAC_TX_ON 0x0002 +#define CMD_ACT_MAC_LOOPBACK_ON 0x0004 +#define CMD_ACT_MAC_WEP_ENABLE 0x0008 +#define CMD_ACT_MAC_INT_ENABLE 0x0010 +#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020 +#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040 +#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 +#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 +#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 /* Event flags for CMD_802_11_SUBSCRIBE_EVENT */ -#define CMD_SUBSCRIBE_RSSI_LOW 0x0001 -#define CMD_SUBSCRIBE_SNR_LOW 0x0002 -#define CMD_SUBSCRIBE_FAILCOUNT 0x0004 -#define CMD_SUBSCRIBE_BCNMISS 0x0008 -#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010 -#define CMD_SUBSCRIBE_SNR_HIGH 0x0020 +#define CMD_SUBSCRIBE_RSSI_LOW 0x0001 +#define CMD_SUBSCRIBE_SNR_LOW 0x0002 +#define CMD_SUBSCRIBE_FAILCOUNT 0x0004 +#define CMD_SUBSCRIBE_BCNMISS 0x0008 +#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010 +#define CMD_SUBSCRIBE_SNR_HIGH 0x0020 -#define RADIO_PREAMBLE_LONG 0x00 -#define RADIO_PREAMBLE_SHORT 0x02 -#define RADIO_PREAMBLE_AUTO 0x04 +#define RADIO_PREAMBLE_LONG 0x00 +#define RADIO_PREAMBLE_SHORT 0x02 +#define RADIO_PREAMBLE_AUTO 0x04 /* Define action or option for CMD_802_11_RF_CHANNEL */ -#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 -#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 +#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 +#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 /* Define action or option for CMD_802_11_DATA_RATE */ -#define CMD_ACT_SET_TX_AUTO 0x0000 -#define CMD_ACT_SET_TX_FIX_RATE 0x0001 -#define CMD_ACT_GET_TX_RATE 0x0002 - -#define CMD_ACT_SET_RX 0x0001 -#define CMD_ACT_SET_TX 0x0002 -#define CMD_ACT_SET_BOTH 0x0003 -#define CMD_ACT_GET_RX 0x0004 -#define CMD_ACT_GET_TX 0x0008 -#define CMD_ACT_GET_BOTH 0x000c +#define CMD_ACT_SET_TX_AUTO 0x0000 +#define CMD_ACT_SET_TX_FIX_RATE 0x0001 +#define CMD_ACT_GET_TX_RATE 0x0002 /* Define action or option for CMD_802_11_PS_MODE */ -#define CMD_TYPE_CAM 0x0000 -#define CMD_TYPE_MAX_PSP 0x0001 -#define CMD_TYPE_FAST_PSP 0x0002 +#define CMD_TYPE_CAM 0x0000 +#define CMD_TYPE_MAX_PSP 0x0001 +#define CMD_TYPE_FAST_PSP 0x0002 /* Options for CMD_802_11_FW_WAKE_METHOD */ -#define CMD_WAKE_METHOD_UNCHANGED 0x0000 -#define CMD_WAKE_METHOD_COMMAND_INT 0x0001 -#define CMD_WAKE_METHOD_GPIO 0x0002 +#define CMD_WAKE_METHOD_UNCHANGED 0x0000 +#define CMD_WAKE_METHOD_COMMAND_INT 0x0001 +#define CMD_WAKE_METHOD_GPIO 0x0002 /* Object IDs for CMD_802_11_SNMP_MIB */ -#define SNMP_MIB_OID_BSS_TYPE 0x0000 -#define SNMP_MIB_OID_OP_RATE_SET 0x0001 -#define SNMP_MIB_OID_BEACON_PERIOD 0x0002 /* Reserved on v9+ */ -#define SNMP_MIB_OID_DTIM_PERIOD 0x0003 /* Reserved on v9+ */ -#define SNMP_MIB_OID_ASSOC_TIMEOUT 0x0004 /* Reserved on v9+ */ -#define SNMP_MIB_OID_RTS_THRESHOLD 0x0005 -#define SNMP_MIB_OID_SHORT_RETRY_LIMIT 0x0006 -#define SNMP_MIB_OID_LONG_RETRY_LIMIT 0x0007 -#define SNMP_MIB_OID_FRAG_THRESHOLD 0x0008 -#define SNMP_MIB_OID_11D_ENABLE 0x0009 -#define SNMP_MIB_OID_11H_ENABLE 0x000A +#define SNMP_MIB_OID_BSS_TYPE 0x0000 +#define SNMP_MIB_OID_OP_RATE_SET 0x0001 +#define SNMP_MIB_OID_BEACON_PERIOD 0x0002 /* Reserved on v9+ */ +#define SNMP_MIB_OID_DTIM_PERIOD 0x0003 /* Reserved on v9+ */ +#define SNMP_MIB_OID_ASSOC_TIMEOUT 0x0004 /* Reserved on v9+ */ +#define SNMP_MIB_OID_RTS_THRESHOLD 0x0005 +#define SNMP_MIB_OID_SHORT_RETRY_LIMIT 0x0006 +#define SNMP_MIB_OID_LONG_RETRY_LIMIT 0x0007 +#define SNMP_MIB_OID_FRAG_THRESHOLD 0x0008 +#define SNMP_MIB_OID_11D_ENABLE 0x0009 +#define SNMP_MIB_OID_11H_ENABLE 0x000A /* Define action or option for CMD_BT_ACCESS */ enum cmd_bt_access_opts { @@ -303,4 +290,714 @@ enum cmd_mesh_config_types { #define MACREG_INT_CODE_MESH_AUTO_STARTED 35 #define MACREG_INT_CODE_FIRMWARE_READY 48 + +/* 802.11-related definitions */ + +/* TxPD descriptor */ +struct txpd { + /* union to cope up with later FW revisions */ + union { + /* Current Tx packet status */ + __le32 tx_status; + struct { + /* BSS type: client, AP, etc. */ + u8 bss_type; + /* BSS number */ + u8 bss_num; + /* Reserved */ + __le16 reserved; + } bss; + } u; + /* Tx control */ + __le32 tx_control; + __le32 tx_packet_location; + /* Tx packet length */ + __le16 tx_packet_length; + /* First 2 byte of destination MAC address */ + u8 tx_dest_addr_high[2]; + /* Last 4 byte of destination MAC address */ + u8 tx_dest_addr_low[4]; + /* Pkt Priority */ + u8 priority; + /* Pkt Trasnit Power control */ + u8 powermgmt; + /* Amount of time the packet has been queued (units = 2ms) */ + u8 pktdelay_2ms; + /* reserved */ + u8 reserved1; +} __attribute__ ((packed)); + +/* RxPD Descriptor */ +struct rxpd { + /* union to cope up with later FW revisions */ + union { + /* Current Rx packet status */ + __le16 status; + struct { + /* BSS type: client, AP, etc. */ + u8 bss_type; + /* BSS number */ + u8 bss_num; + } __attribute__ ((packed)) bss; + } __attribute__ ((packed)) u; + + /* SNR */ + u8 snr; + + /* Tx control */ + u8 rx_control; + + /* Pkt length */ + __le16 pkt_len; + + /* Noise Floor */ + u8 nf; + + /* Rx Packet Rate */ + u8 rx_rate; + + /* Pkt addr */ + __le32 pkt_ptr; + + /* Next Rx RxPD addr */ + __le32 next_rxpd_ptr; + + /* Pkt Priority */ + u8 priority; + u8 reserved[3]; +} __attribute__ ((packed)); + +struct cmd_header { + __le16 command; + __le16 size; + __le16 seqnum; + __le16 result; +} __attribute__ ((packed)); + +struct cmd_ctrl_node { + struct list_head list; + int result; + /* command response */ + int (*callback)(struct lbs_private *, + unsigned long, + struct cmd_header *); + unsigned long callback_arg; + /* command data */ + struct cmd_header *cmdbuf; + /* wait queue */ + u16 cmdwaitqwoken; + wait_queue_head_t cmdwait_q; +}; + +/* Generic structure to hold all key types. */ +struct enc_key { + u16 len; + u16 flags; /* KEY_INFO_* from defs.h */ + u16 type; /* KEY_TYPE_* from defs.h */ + u8 key[32]; +}; + +/* lbs_offset_value */ +struct lbs_offset_value { + u32 offset; + u32 value; +} __attribute__ ((packed)); + +/* Define general data structure */ +/* cmd_DS_GEN */ +struct cmd_ds_gen { + __le16 command; + __le16 size; + __le16 seqnum; + __le16 result; + void *cmdresp[0]; +} __attribute__ ((packed)); + +#define S_DS_GEN sizeof(struct cmd_ds_gen) + + +/* + * Define data structure for CMD_GET_HW_SPEC + * This structure defines the response for the GET_HW_SPEC command + */ +struct cmd_ds_get_hw_spec { + struct cmd_header hdr; + + /* HW Interface version number */ + __le16 hwifversion; + /* HW version number */ + __le16 version; + /* Max number of TxPD FW can handle */ + __le16 nr_txpd; + /* Max no of Multicast address */ + __le16 nr_mcast_adr; + /* MAC address */ + u8 permanentaddr[6]; + + /* region Code */ + __le16 regioncode; + + /* Number of antenna used */ + __le16 nr_antenna; + + /* FW release number, example 0x01030304 = 2.3.4p1 */ + __le32 fwrelease; + + /* Base Address of TxPD queue */ + __le32 wcb_base; + /* Read Pointer of RxPd queue */ + __le32 rxpd_rdptr; + + /* Write Pointer of RxPd queue */ + __le32 rxpd_wrptr; + + /*FW/HW capability */ + __le32 fwcapinfo; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_subscribe_event { + struct cmd_header hdr; + + __le16 action; + __le16 events; + + /* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a + * number of TLVs. From the v5.1 manual, those TLVs would add up to + * 40 bytes. However, future firmware might add additional TLVs, so I + * bump this up a bit. + */ + uint8_t tlv[128]; +} __attribute__ ((packed)); + +/* + * This scan handle Country Information IE(802.11d compliant) + * Define data structure for CMD_802_11_SCAN + */ +struct cmd_ds_802_11_scan { + struct cmd_header hdr; + + uint8_t bsstype; + uint8_t bssid[ETH_ALEN]; + uint8_t tlvbuffer[0]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_scan_rsp { + struct cmd_header hdr; + + __le16 bssdescriptsize; + uint8_t nr_sets; + uint8_t bssdesc_and_tlvbuffer[0]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_get_log { + struct cmd_header hdr; + + __le32 mcasttxframe; + __le32 failed; + __le32 retry; + __le32 multiretry; + __le32 framedup; + __le32 rtssuccess; + __le32 rtsfailure; + __le32 ackfailure; + __le32 rxfrag; + __le32 mcastrxframe; + __le32 fcserror; + __le32 txframe; + __le32 wepundecryptable; +} __attribute__ ((packed)); + +struct cmd_ds_mac_control { + struct cmd_header hdr; + __le16 action; + u16 reserved; +} __attribute__ ((packed)); + +struct cmd_ds_mac_multicast_adr { + struct cmd_header hdr; + __le16 action; + __le16 nr_of_adrs; + u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_authenticate { + struct cmd_header hdr; + + u8 bssid[ETH_ALEN]; + u8 authtype; + u8 reserved[10]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_deauthenticate { + struct cmd_header hdr; + + u8 macaddr[ETH_ALEN]; + __le16 reasoncode; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_associate { + struct cmd_header hdr; + + u8 bssid[6]; + __le16 capability; + __le16 listeninterval; + __le16 bcnperiod; + u8 dtimperiod; + u8 iebuf[512]; /* Enough for required and most optional IEs */ +} __attribute__ ((packed)); + +struct cmd_ds_802_11_associate_response { + struct cmd_header hdr; + + __le16 capability; + __le16 statuscode; + __le16 aid; + u8 iebuf[512]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_set_wep { + struct cmd_header hdr; + + /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */ + __le16 action; + + /* key Index selected for Tx */ + __le16 keyindex; + + /* 40, 128bit or TXWEP */ + uint8_t keytype[4]; + uint8_t keymaterial[4][16]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_snmp_mib { + struct cmd_header hdr; + + __le16 action; + __le16 oid; + __le16 bufsize; + u8 value[128]; +} __attribute__ ((packed)); + +struct cmd_ds_mac_reg_access { + __le16 action; + __le16 offset; + __le32 value; +} __attribute__ ((packed)); + +struct cmd_ds_bbp_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __attribute__ ((packed)); + +struct cmd_ds_rf_reg_access { + __le16 action; + __le16 offset; + u8 value; + u8 reserved[3]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_radio_control { + struct cmd_header hdr; + + __le16 action; + __le16 control; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_beacon_control { + __le16 action; + __le16 beacon_enable; + __le16 beacon_period; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_sleep_params { + struct cmd_header hdr; + + /* ACT_GET/ACT_SET */ + __le16 action; + + /* Sleep clock error in ppm */ + __le16 error; + + /* Wakeup offset in usec */ + __le16 offset; + + /* Clock stabilization time in usec */ + __le16 stabletime; + + /* control periodic calibration */ + uint8_t calcontrol; + + /* control the use of external sleep clock */ + uint8_t externalsleepclk; + + /* reserved field, should be set to zero */ + __le16 reserved; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_inactivity_timeout { + struct cmd_header hdr; + + /* ACT_GET/ACT_SET */ + __le16 action; + + /* Inactivity timeout in msec */ + __le16 timeout; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_rf_channel { + struct cmd_header hdr; + + __le16 action; + __le16 channel; + __le16 rftype; /* unused */ + __le16 reserved; /* unused */ + u8 channellist[32]; /* unused */ +} __attribute__ ((packed)); + +struct cmd_ds_802_11_rssi { + /* weighting factor */ + __le16 N; + + __le16 reserved_0; + __le16 reserved_1; + __le16 reserved_2; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_rssi_rsp { + __le16 SNR; + __le16 noisefloor; + __le16 avgSNR; + __le16 avgnoisefloor; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_mac_address { + struct cmd_header hdr; + + __le16 action; + u8 macadd[ETH_ALEN]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_rf_tx_power { + struct cmd_header hdr; + + __le16 action; + __le16 curlevel; + s8 maxlevel; + s8 minlevel; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_monitor_mode { + __le16 action; + __le16 mode; +} __attribute__ ((packed)); + +struct cmd_ds_set_boot2_ver { + struct cmd_header hdr; + + __le16 action; + __le16 version; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_fw_wake_method { + struct cmd_header hdr; + + __le16 action; + __le16 method; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_ps_mode { + __le16 action; + __le16 nullpktinterval; + __le16 multipledtim; + __le16 reserved; + __le16 locallisteninterval; +} __attribute__ ((packed)); + +struct cmd_confirm_sleep { + struct cmd_header hdr; + + __le16 action; + __le16 nullpktinterval; + __le16 multipledtim; + __le16 reserved; + __le16 locallisteninterval; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_data_rate { + struct cmd_header hdr; + + __le16 action; + __le16 reserved; + u8 rates[MAX_RATES]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_rate_adapt_rateset { + struct cmd_header hdr; + __le16 action; + __le16 enablehwauto; + __le16 bitmap; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_ad_hoc_start { + struct cmd_header hdr; + + u8 ssid[IW_ESSID_MAX_SIZE]; + u8 bsstype; + __le16 beaconperiod; + u8 dtimperiod; /* Reserved on v9 and later */ + struct ieee_ie_ibss_param_set ibss; + u8 reserved1[4]; + struct ieee_ie_ds_param_set ds; + u8 reserved2[4]; + __le16 probedelay; /* Reserved on v9 and later */ + __le16 capability; + u8 rates[MAX_RATES]; + u8 tlv_memory_size_pad[100]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_ad_hoc_result { + struct cmd_header hdr; + + u8 pad[3]; + u8 bssid[ETH_ALEN]; +} __attribute__ ((packed)); + +struct adhoc_bssdesc { + u8 bssid[ETH_ALEN]; + u8 ssid[IW_ESSID_MAX_SIZE]; + u8 type; + __le16 beaconperiod; + u8 dtimperiod; + __le64 timestamp; + __le64 localtime; + struct ieee_ie_ds_param_set ds; + u8 reserved1[4]; + struct ieee_ie_ibss_param_set ibss; + u8 reserved2[4]; + __le16 capability; + u8 rates[MAX_RATES]; + + /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the + * Adhoc join command and will cause a binary layout mismatch with + * the firmware + */ +} __attribute__ ((packed)); + +struct cmd_ds_802_11_ad_hoc_join { + struct cmd_header hdr; + + struct adhoc_bssdesc bss; + __le16 failtimeout; /* Reserved on v9 and later */ + __le16 probedelay; /* Reserved on v9 and later */ +} __attribute__ ((packed)); + +struct cmd_ds_802_11_ad_hoc_stop { + struct cmd_header hdr; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_enable_rsn { + struct cmd_header hdr; + + __le16 action; + __le16 enable; +} __attribute__ ((packed)); + +struct MrvlIEtype_keyParamSet { + /* type ID */ + __le16 type; + + /* length of Payload */ + __le16 length; + + /* type of key: WEP=0, TKIP=1, AES=2 */ + __le16 keytypeid; + + /* key control Info specific to a keytypeid */ + __le16 keyinfo; + + /* length of key */ + __le16 keylen; + + /* key material of size keylen */ + u8 key[32]; +} __attribute__ ((packed)); + +#define MAX_WOL_RULES 16 + +struct host_wol_rule { + uint8_t rule_no; + uint8_t rule_ops; + __le16 sig_offset; + __le16 sig_length; + __le16 reserve; + __be32 sig_mask; + __be32 signature; +} __attribute__ ((packed)); + +struct wol_config { + uint8_t action; + uint8_t pattern; + uint8_t no_rules_in_cmd; + uint8_t result; + struct host_wol_rule rule[MAX_WOL_RULES]; +} __attribute__ ((packed)); + +struct cmd_ds_host_sleep { + struct cmd_header hdr; + __le32 criteria; + uint8_t gpio; + uint16_t gap; + struct wol_config wol_conf; +} __attribute__ ((packed)); + + + +struct cmd_ds_802_11_key_material { + struct cmd_header hdr; + + __le16 action; + struct MrvlIEtype_keyParamSet keyParamSet[2]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_eeprom_access { + struct cmd_header hdr; + __le16 action; + __le16 offset; + __le16 len; + /* firmware says it returns a maximum of 20 bytes */ +#define LBS_EEPROM_READ_LEN 20 + u8 value[LBS_EEPROM_READ_LEN]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_tpc_cfg { + struct cmd_header hdr; + + __le16 action; + uint8_t enable; + int8_t P0; + int8_t P1; + int8_t P2; + uint8_t usesnr; +} __attribute__ ((packed)); + + +struct cmd_ds_802_11_pa_cfg { + struct cmd_header hdr; + + __le16 action; + uint8_t enable; + int8_t P0; + int8_t P1; + int8_t P2; +} __attribute__ ((packed)); + + +struct cmd_ds_802_11_led_ctrl { + __le16 action; + __le16 numled; + u8 data[256]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_afc { + __le16 afc_auto; + union { + struct { + __le16 threshold; + __le16 period; + }; + struct { + __le16 timing_offset; /* signed */ + __le16 carrier_offset; /* signed */ + }; + }; +} __attribute__ ((packed)); + +struct cmd_tx_rate_query { + __le16 txrate; +} __attribute__ ((packed)); + +struct cmd_ds_get_tsf { + __le64 tsfvalue; +} __attribute__ ((packed)); + +struct cmd_ds_bt_access { + __le16 action; + __le32 id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; +} __attribute__ ((packed)); + +struct cmd_ds_fwt_access { + __le16 action; + __le32 id; + u8 valid; + u8 da[ETH_ALEN]; + u8 dir; + u8 ra[ETH_ALEN]; + __le32 ssn; + __le32 dsn; + __le32 metric; + u8 rate; + u8 hopcount; + u8 ttl; + __le32 expiration; + u8 sleepmode; + __le32 snr; + __le32 references; + u8 prec[ETH_ALEN]; +} __attribute__ ((packed)); + +struct cmd_ds_mesh_config { + struct cmd_header hdr; + + __le16 action; + __le16 channel; + __le16 type; + __le16 length; + u8 data[128]; /* last position reserved */ +} __attribute__ ((packed)); + +struct cmd_ds_mesh_access { + struct cmd_header hdr; + + __le16 action; + __le32 data[32]; /* last position reserved */ +} __attribute__ ((packed)); + +/* Number of stats counters returned by the firmware */ +#define MESH_STATS_NUM 8 + +struct cmd_ds_command { + /* command header */ + __le16 command; + __le16 size; + __le16 seqnum; + __le16 result; + + /* command Body */ + union { + struct cmd_ds_802_11_ps_mode psmode; + struct cmd_ds_802_11_monitor_mode monitor; + struct cmd_ds_802_11_rssi rssi; + struct cmd_ds_802_11_rssi_rsp rssirsp; + struct cmd_ds_mac_reg_access macreg; + struct cmd_ds_bbp_reg_access bbpreg; + struct cmd_ds_rf_reg_access rfreg; + + struct cmd_ds_802_11d_domain_info domaininfo; + struct cmd_ds_802_11d_domain_info domaininforesp; + + struct cmd_ds_802_11_tpc_cfg tpccfg; + struct cmd_ds_802_11_afc afc; + struct cmd_ds_802_11_led_ctrl ledgpio; + + struct cmd_ds_bt_access bt; + struct cmd_ds_fwt_access fwt; + struct cmd_ds_get_tsf gettsf; + struct cmd_ds_802_11_beacon_control bcn_ctrl; + } params; +} __attribute__ ((packed)); + #endif diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h deleted file mode 100644 index c8a1998d4744..000000000000 --- a/drivers/net/wireless/libertas/hostcmd.h +++ /dev/null @@ -1,800 +0,0 @@ -/* - * This file contains the function prototypes, data structure - * and defines for all the host/station commands - */ -#ifndef _LBS_HOSTCMD_H -#define _LBS_HOSTCMD_H - -#include -#include "11d.h" -#include "types.h" - -/* 802.11-related definitions */ - -/* TxPD descriptor */ -struct txpd { - /* union to cope up with later FW revisions */ - union { - /* Current Tx packet status */ - __le32 tx_status; - struct { - /* BSS type: client, AP, etc. */ - u8 bss_type; - /* BSS number */ - u8 bss_num; - /* Reserved */ - __le16 reserved; - } bss; - } u; - /* Tx control */ - __le32 tx_control; - __le32 tx_packet_location; - /* Tx packet length */ - __le16 tx_packet_length; - /* First 2 byte of destination MAC address */ - u8 tx_dest_addr_high[2]; - /* Last 4 byte of destination MAC address */ - u8 tx_dest_addr_low[4]; - /* Pkt Priority */ - u8 priority; - /* Pkt Trasnit Power control */ - u8 powermgmt; - /* Amount of time the packet has been queued in the driver (units = 2ms) */ - u8 pktdelay_2ms; - /* reserved */ - u8 reserved1; -} __attribute__ ((packed)); - -/* RxPD Descriptor */ -struct rxpd { - /* union to cope up with later FW revisions */ - union { - /* Current Rx packet status */ - __le16 status; - struct { - /* BSS type: client, AP, etc. */ - u8 bss_type; - /* BSS number */ - u8 bss_num; - } __attribute__ ((packed)) bss; - } __attribute__ ((packed)) u; - - /* SNR */ - u8 snr; - - /* Tx control */ - u8 rx_control; - - /* Pkt length */ - __le16 pkt_len; - - /* Noise Floor */ - u8 nf; - - /* Rx Packet Rate */ - u8 rx_rate; - - /* Pkt addr */ - __le32 pkt_ptr; - - /* Next Rx RxPD addr */ - __le32 next_rxpd_ptr; - - /* Pkt Priority */ - u8 priority; - u8 reserved[3]; -} __attribute__ ((packed)); - -struct cmd_header { - __le16 command; - __le16 size; - __le16 seqnum; - __le16 result; -} __attribute__ ((packed)); - -struct cmd_ctrl_node { - struct list_head list; - int result; - /* command response */ - int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *); - unsigned long callback_arg; - /* command data */ - struct cmd_header *cmdbuf; - /* wait queue */ - u16 cmdwaitqwoken; - wait_queue_head_t cmdwait_q; -}; - -/* Generic structure to hold all key types. */ -struct enc_key { - u16 len; - u16 flags; /* KEY_INFO_* from defs.h */ - u16 type; /* KEY_TYPE_* from defs.h */ - u8 key[32]; -}; - -/* lbs_offset_value */ -struct lbs_offset_value { - u32 offset; - u32 value; -} __attribute__ ((packed)); - -/* Define general data structure */ -/* cmd_DS_GEN */ -struct cmd_ds_gen { - __le16 command; - __le16 size; - __le16 seqnum; - __le16 result; - void *cmdresp[0]; -} __attribute__ ((packed)); - -#define S_DS_GEN sizeof(struct cmd_ds_gen) - - -/* - * Define data structure for CMD_GET_HW_SPEC - * This structure defines the response for the GET_HW_SPEC command - */ -struct cmd_ds_get_hw_spec { - struct cmd_header hdr; - - /* HW Interface version number */ - __le16 hwifversion; - /* HW version number */ - __le16 version; - /* Max number of TxPD FW can handle */ - __le16 nr_txpd; - /* Max no of Multicast address */ - __le16 nr_mcast_adr; - /* MAC address */ - u8 permanentaddr[6]; - - /* region Code */ - __le16 regioncode; - - /* Number of antenna used */ - __le16 nr_antenna; - - /* FW release number, example 0x01030304 = 2.3.4p1 */ - __le32 fwrelease; - - /* Base Address of TxPD queue */ - __le32 wcb_base; - /* Read Pointer of RxPd queue */ - __le32 rxpd_rdptr; - - /* Write Pointer of RxPd queue */ - __le32 rxpd_wrptr; - - /*FW/HW capability */ - __le32 fwcapinfo; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_subscribe_event { - struct cmd_header hdr; - - __le16 action; - __le16 events; - - /* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a - * number of TLVs. From the v5.1 manual, those TLVs would add up to - * 40 bytes. However, future firmware might add additional TLVs, so I - * bump this up a bit. - */ - uint8_t tlv[128]; -} __attribute__ ((packed)); - -/* - * This scan handle Country Information IE(802.11d compliant) - * Define data structure for CMD_802_11_SCAN - */ -struct cmd_ds_802_11_scan { - struct cmd_header hdr; - - uint8_t bsstype; - uint8_t bssid[ETH_ALEN]; - uint8_t tlvbuffer[0]; -#if 0 - mrvlietypes_ssidparamset_t ssidParamSet; - mrvlietypes_chanlistparamset_t ChanListParamSet; - mrvlietypes_ratesparamset_t OpRateSet; -#endif -} __attribute__ ((packed)); - -struct cmd_ds_802_11_scan_rsp { - struct cmd_header hdr; - - __le16 bssdescriptsize; - uint8_t nr_sets; - uint8_t bssdesc_and_tlvbuffer[0]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_get_log { - struct cmd_header hdr; - - __le32 mcasttxframe; - __le32 failed; - __le32 retry; - __le32 multiretry; - __le32 framedup; - __le32 rtssuccess; - __le32 rtsfailure; - __le32 ackfailure; - __le32 rxfrag; - __le32 mcastrxframe; - __le32 fcserror; - __le32 txframe; - __le32 wepundecryptable; -} __attribute__ ((packed)); - -struct cmd_ds_mac_control { - struct cmd_header hdr; - __le16 action; - u16 reserved; -} __attribute__ ((packed)); - -struct cmd_ds_mac_multicast_adr { - struct cmd_header hdr; - __le16 action; - __le16 nr_of_adrs; - u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; -} __attribute__ ((packed)); - -struct cmd_ds_gspi_bus_config { - struct cmd_header hdr; - __le16 action; - __le16 bus_delay_mode; - __le16 host_time_delay_to_read_port; - __le16 host_time_delay_to_read_register; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_authenticate { - struct cmd_header hdr; - - u8 bssid[ETH_ALEN]; - u8 authtype; - u8 reserved[10]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_deauthenticate { - struct cmd_header hdr; - - u8 macaddr[ETH_ALEN]; - __le16 reasoncode; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_associate { - struct cmd_header hdr; - - u8 bssid[6]; - __le16 capability; - __le16 listeninterval; - __le16 bcnperiod; - u8 dtimperiod; - u8 iebuf[512]; /* Enough for required and most optional IEs */ -} __attribute__ ((packed)); - -struct cmd_ds_802_11_associate_response { - struct cmd_header hdr; - - __le16 capability; - __le16 statuscode; - __le16 aid; - u8 iebuf[512]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_set_wep { - struct cmd_header hdr; - - /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */ - __le16 action; - - /* key Index selected for Tx */ - __le16 keyindex; - - /* 40, 128bit or TXWEP */ - uint8_t keytype[4]; - uint8_t keymaterial[4][16]; -} __attribute__ ((packed)); - -struct cmd_ds_802_3_get_stat { - __le32 xmitok; - __le32 rcvok; - __le32 xmiterror; - __le32 rcverror; - __le32 rcvnobuffer; - __le32 rcvcrcerror; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_get_stat { - __le32 txfragmentcnt; - __le32 mcasttxframecnt; - __le32 failedcnt; - __le32 retrycnt; - __le32 Multipleretrycnt; - __le32 rtssuccesscnt; - __le32 rtsfailurecnt; - __le32 ackfailurecnt; - __le32 frameduplicatecnt; - __le32 rxfragmentcnt; - __le32 mcastrxframecnt; - __le32 fcserrorcnt; - __le32 bcasttxframecnt; - __le32 bcastrxframecnt; - __le32 txbeacon; - __le32 rxbeacon; - __le32 wepundecryptable; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_snmp_mib { - struct cmd_header hdr; - - __le16 action; - __le16 oid; - __le16 bufsize; - u8 value[128]; -} __attribute__ ((packed)); - -struct cmd_ds_mac_reg_map { - __le16 buffersize; - u8 regmap[128]; - __le16 reserved; -} __attribute__ ((packed)); - -struct cmd_ds_bbp_reg_map { - __le16 buffersize; - u8 regmap[128]; - __le16 reserved; -} __attribute__ ((packed)); - -struct cmd_ds_rf_reg_map { - __le16 buffersize; - u8 regmap[64]; - __le16 reserved; -} __attribute__ ((packed)); - -struct cmd_ds_mac_reg_access { - __le16 action; - __le16 offset; - __le32 value; -} __attribute__ ((packed)); - -struct cmd_ds_bbp_reg_access { - __le16 action; - __le16 offset; - u8 value; - u8 reserved[3]; -} __attribute__ ((packed)); - -struct cmd_ds_rf_reg_access { - __le16 action; - __le16 offset; - u8 value; - u8 reserved[3]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_radio_control { - struct cmd_header hdr; - - __le16 action; - __le16 control; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_beacon_control { - __le16 action; - __le16 beacon_enable; - __le16 beacon_period; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_sleep_params { - struct cmd_header hdr; - - /* ACT_GET/ACT_SET */ - __le16 action; - - /* Sleep clock error in ppm */ - __le16 error; - - /* Wakeup offset in usec */ - __le16 offset; - - /* Clock stabilization time in usec */ - __le16 stabletime; - - /* control periodic calibration */ - uint8_t calcontrol; - - /* control the use of external sleep clock */ - uint8_t externalsleepclk; - - /* reserved field, should be set to zero */ - __le16 reserved; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_inactivity_timeout { - struct cmd_header hdr; - - /* ACT_GET/ACT_SET */ - __le16 action; - - /* Inactivity timeout in msec */ - __le16 timeout; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_rf_channel { - struct cmd_header hdr; - - __le16 action; - __le16 channel; - __le16 rftype; /* unused */ - __le16 reserved; /* unused */ - u8 channellist[32]; /* unused */ -} __attribute__ ((packed)); - -struct cmd_ds_802_11_rssi { - /* weighting factor */ - __le16 N; - - __le16 reserved_0; - __le16 reserved_1; - __le16 reserved_2; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_rssi_rsp { - __le16 SNR; - __le16 noisefloor; - __le16 avgSNR; - __le16 avgnoisefloor; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_mac_address { - struct cmd_header hdr; - - __le16 action; - u8 macadd[ETH_ALEN]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_rf_tx_power { - struct cmd_header hdr; - - __le16 action; - __le16 curlevel; - s8 maxlevel; - s8 minlevel; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_rf_antenna { - __le16 action; - - /* Number of antennas or 0xffff(diversity) */ - __le16 antennamode; - -} __attribute__ ((packed)); - -struct cmd_ds_802_11_monitor_mode { - __le16 action; - __le16 mode; -} __attribute__ ((packed)); - -struct cmd_ds_set_boot2_ver { - struct cmd_header hdr; - - __le16 action; - __le16 version; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_fw_wake_method { - struct cmd_header hdr; - - __le16 action; - __le16 method; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_sleep_period { - struct cmd_header hdr; - - __le16 action; - __le16 period; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_ps_mode { - __le16 action; - __le16 nullpktinterval; - __le16 multipledtim; - __le16 reserved; - __le16 locallisteninterval; -} __attribute__ ((packed)); - -struct cmd_confirm_sleep { - struct cmd_header hdr; - - __le16 action; - __le16 nullpktinterval; - __le16 multipledtim; - __le16 reserved; - __le16 locallisteninterval; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_data_rate { - struct cmd_header hdr; - - __le16 action; - __le16 reserved; - u8 rates[MAX_RATES]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_rate_adapt_rateset { - struct cmd_header hdr; - __le16 action; - __le16 enablehwauto; - __le16 bitmap; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_ad_hoc_start { - struct cmd_header hdr; - - u8 ssid[IW_ESSID_MAX_SIZE]; - u8 bsstype; - __le16 beaconperiod; - u8 dtimperiod; /* Reserved on v9 and later */ - struct ieee_ie_ibss_param_set ibss; - u8 reserved1[4]; - struct ieee_ie_ds_param_set ds; - u8 reserved2[4]; - __le16 probedelay; /* Reserved on v9 and later */ - __le16 capability; - u8 rates[MAX_RATES]; - u8 tlv_memory_size_pad[100]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_ad_hoc_result { - struct cmd_header hdr; - - u8 pad[3]; - u8 bssid[ETH_ALEN]; -} __attribute__ ((packed)); - -struct adhoc_bssdesc { - u8 bssid[ETH_ALEN]; - u8 ssid[IW_ESSID_MAX_SIZE]; - u8 type; - __le16 beaconperiod; - u8 dtimperiod; - __le64 timestamp; - __le64 localtime; - struct ieee_ie_ds_param_set ds; - u8 reserved1[4]; - struct ieee_ie_ibss_param_set ibss; - u8 reserved2[4]; - __le16 capability; - u8 rates[MAX_RATES]; - - /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the - * Adhoc join command and will cause a binary layout mismatch with - * the firmware - */ -} __attribute__ ((packed)); - -struct cmd_ds_802_11_ad_hoc_join { - struct cmd_header hdr; - - struct adhoc_bssdesc bss; - __le16 failtimeout; /* Reserved on v9 and later */ - __le16 probedelay; /* Reserved on v9 and later */ -} __attribute__ ((packed)); - -struct cmd_ds_802_11_ad_hoc_stop { - struct cmd_header hdr; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_enable_rsn { - struct cmd_header hdr; - - __le16 action; - __le16 enable; -} __attribute__ ((packed)); - -struct MrvlIEtype_keyParamSet { - /* type ID */ - __le16 type; - - /* length of Payload */ - __le16 length; - - /* type of key: WEP=0, TKIP=1, AES=2 */ - __le16 keytypeid; - - /* key control Info specific to a keytypeid */ - __le16 keyinfo; - - /* length of key */ - __le16 keylen; - - /* key material of size keylen */ - u8 key[32]; -} __attribute__ ((packed)); - -#define MAX_WOL_RULES 16 - -struct host_wol_rule { - uint8_t rule_no; - uint8_t rule_ops; - __le16 sig_offset; - __le16 sig_length; - __le16 reserve; - __be32 sig_mask; - __be32 signature; -} __attribute__ ((packed)); - -struct wol_config { - uint8_t action; - uint8_t pattern; - uint8_t no_rules_in_cmd; - uint8_t result; - struct host_wol_rule rule[MAX_WOL_RULES]; -} __attribute__ ((packed)); - -struct cmd_ds_host_sleep { - struct cmd_header hdr; - __le32 criteria; - uint8_t gpio; - uint16_t gap; - struct wol_config wol_conf; -} __attribute__ ((packed)); - - - -struct cmd_ds_802_11_key_material { - struct cmd_header hdr; - - __le16 action; - struct MrvlIEtype_keyParamSet keyParamSet[2]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_eeprom_access { - struct cmd_header hdr; - __le16 action; - __le16 offset; - __le16 len; - /* firmware says it returns a maximum of 20 bytes */ -#define LBS_EEPROM_READ_LEN 20 - u8 value[LBS_EEPROM_READ_LEN]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_tpc_cfg { - struct cmd_header hdr; - - __le16 action; - uint8_t enable; - int8_t P0; - int8_t P1; - int8_t P2; - uint8_t usesnr; -} __attribute__ ((packed)); - - -struct cmd_ds_802_11_pa_cfg { - struct cmd_header hdr; - - __le16 action; - uint8_t enable; - int8_t P0; - int8_t P1; - int8_t P2; -} __attribute__ ((packed)); - - -struct cmd_ds_802_11_led_ctrl { - __le16 action; - __le16 numled; - u8 data[256]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11_afc { - __le16 afc_auto; - union { - struct { - __le16 threshold; - __le16 period; - }; - struct { - __le16 timing_offset; /* signed */ - __le16 carrier_offset; /* signed */ - }; - }; -} __attribute__ ((packed)); - -struct cmd_tx_rate_query { - __le16 txrate; -} __attribute__ ((packed)); - -struct cmd_ds_get_tsf { - __le64 tsfvalue; -} __attribute__ ((packed)); - -struct cmd_ds_bt_access { - __le16 action; - __le32 id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; -} __attribute__ ((packed)); - -struct cmd_ds_fwt_access { - __le16 action; - __le32 id; - u8 valid; - u8 da[ETH_ALEN]; - u8 dir; - u8 ra[ETH_ALEN]; - __le32 ssn; - __le32 dsn; - __le32 metric; - u8 rate; - u8 hopcount; - u8 ttl; - __le32 expiration; - u8 sleepmode; - __le32 snr; - __le32 references; - u8 prec[ETH_ALEN]; -} __attribute__ ((packed)); - - -struct cmd_ds_mesh_config { - struct cmd_header hdr; - - __le16 action; - __le16 channel; - __le16 type; - __le16 length; - u8 data[128]; /* last position reserved */ -} __attribute__ ((packed)); - - -struct cmd_ds_mesh_access { - struct cmd_header hdr; - - __le16 action; - __le32 data[32]; /* last position reserved */ -} __attribute__ ((packed)); - -/* Number of stats counters returned by the firmware */ -#define MESH_STATS_NUM 8 - -struct cmd_ds_command { - /* command header */ - __le16 command; - __le16 size; - __le16 seqnum; - __le16 result; - - /* command Body */ - union { - struct cmd_ds_802_11_ps_mode psmode; - struct cmd_ds_802_11_get_stat gstat; - struct cmd_ds_802_3_get_stat gstat_8023; - struct cmd_ds_802_11_rf_antenna rant; - struct cmd_ds_802_11_monitor_mode monitor; - struct cmd_ds_802_11_rssi rssi; - struct cmd_ds_802_11_rssi_rsp rssirsp; - struct cmd_ds_mac_reg_access macreg; - struct cmd_ds_bbp_reg_access bbpreg; - struct cmd_ds_rf_reg_access rfreg; - - struct cmd_ds_802_11d_domain_info domaininfo; - struct cmd_ds_802_11d_domain_info domaininforesp; - - struct cmd_ds_802_11_tpc_cfg tpccfg; - struct cmd_ds_802_11_afc afc; - struct cmd_ds_802_11_led_ctrl ledgpio; - - struct cmd_tx_rate_query txrate; - struct cmd_ds_bt_access bt; - struct cmd_ds_fwt_access fwt; - struct cmd_ds_get_tsf gettsf; - struct cmd_ds_802_11_beacon_control bcn_ctrl; - } params; -} __attribute__ ((packed)); - -#endif diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 65f02cc6752f..9f18a19cc49d 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -4,7 +4,7 @@ #include #include -#include "hostcmd.h" +#include "host.h" #include "radiotap.h" #include "decl.h" #include "dev.h" diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 4c018f7a0a8d..5d7c011fe296 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -4,7 +4,7 @@ #include #include -#include "hostcmd.h" +#include "host.h" #include "radiotap.h" #include "decl.h" #include "defs.h" -- cgit v1.2.3 From bca61f8a4df69949cc7426b39daa867f5274a9b8 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Fri, 16 Oct 2009 17:33:23 +0200 Subject: libertas: harmonize cmd.h * move declarations for functions of cmd.c/cmdresp.c into cmd.h * move declarations from cmd.h that are in main.c to decl.h * group command functions Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/11d.c | 1 + drivers/net/wireless/libertas/cmd.h | 120 ++++++++++++++++++++++++-------- drivers/net/wireless/libertas/cmdresp.c | 1 + drivers/net/wireless/libertas/decl.h | 24 +------ drivers/net/wireless/libertas/host.h | 15 ---- 5 files changed, 96 insertions(+), 65 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 5c6968101f0d..93f2d5fb3920 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -6,6 +6,7 @@ #include #include "host.h" +#include "cmd.h" #include "decl.h" #include "11d.h" #include "dev.h" diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index bf7c421c7a53..7c44cc94a25b 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -6,8 +6,27 @@ #include "host.h" #include "dev.h" + +/* Command & response transfer between host and card */ + +struct cmd_ctrl_node { + struct list_head list; + int result; + /* command response */ + int (*callback)(struct lbs_private *, + unsigned long, + struct cmd_header *); + unsigned long callback_arg; + /* command data */ + struct cmd_header *cmdbuf; + /* wait queue */ + u16 cmdwaitqwoken; + wait_queue_head_t cmdwait_q; +}; + + /* lbs_cmd() infers the size of the buffer to copy data back into, from - the size of the target of the pointer. Since the command to be sent + the size of the target of the pointer. Since the command to be sent may often be smaller, that size is set in cmd->size by the caller.*/ #define lbs_cmd(priv, cmdnr, cmd, cb, cb_arg) ({ \ uint16_t __sz = le16_to_cpu((cmd)->hdr.size); \ @@ -18,6 +37,11 @@ #define lbs_cmd_with_response(priv, cmdnr, cmd) \ lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd)) +int lbs_prepare_and_send_command(struct lbs_private *priv, + u16 cmd_no, + u16 cmd_action, + u16 wait_option, u32 cmd_oid, void *pdata_buf); + void lbs_cmd_async(struct lbs_private *priv, uint16_t command, struct cmd_header *in_cmd, int in_cmd_size); @@ -31,62 +55,102 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), unsigned long callback_arg); -int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, - int8_t p1, int8_t p2); +int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, + struct cmd_header *resp); -int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, - int8_t p2, int usesnr); +int lbs_allocate_cmd_buffer(struct lbs_private *priv); +int lbs_free_cmd_buffer(struct lbs_private *priv); -int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, - int8_t p1, int8_t p2); +int lbs_execute_next_command(struct lbs_private *priv); +void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, + int result); +int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len); -int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, - int8_t p2, int usesnr); -int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, - struct cmd_header *resp); +/* From cmdresp.c */ -int lbs_update_hw_spec(struct lbs_private *priv); +void lbs_mac_event_disconnected(struct lbs_private *priv); -int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, - struct cmd_ds_mesh_access *cmd); -int lbs_set_data_rate(struct lbs_private *priv, u8 rate); + +/* Events */ + +int lbs_process_event(struct lbs_private *priv, u32 event); + + +/* Actual commands */ + +int lbs_update_hw_spec(struct lbs_private *priv); int lbs_get_channel(struct lbs_private *priv); + int lbs_set_channel(struct lbs_private *priv, u8 channel); +int lbs_update_channel(struct lbs_private *priv); + +int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, + struct wol_config *p_wol_config); + +int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, + struct sleep_params *sp); + +void lbs_ps_sleep(struct lbs_private *priv, int wait_option); + +void lbs_ps_wakeup(struct lbs_private *priv, int wait_option); + +void lbs_ps_confirm_sleep(struct lbs_private *priv); + +int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on); + +void lbs_set_mac_control(struct lbs_private *priv); + +int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, + s16 *maxlevel); + +int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val); + +int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val); + + +/* Mesh related */ + +int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, + struct cmd_ds_mesh_access *cmd); + int lbs_mesh_config_send(struct lbs_private *priv, struct cmd_ds_mesh_config *cmd, uint16_t action, uint16_t type); + int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); -int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, - struct wol_config *p_wol_config); -int lbs_suspend(struct lbs_private *priv); -void lbs_resume(struct lbs_private *priv); + +/* Commands only used in wext.c, assoc. and scan.c */ + +int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, + int8_t p1, int8_t p2); + +int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, + int8_t p2, int usesnr); + +int lbs_set_data_rate(struct lbs_private *priv, u8 rate); int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, uint16_t cmd_action); + int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv, uint16_t cmd_action, uint16_t *timeout); -int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, - struct sleep_params *sp); + int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, struct assoc_request *assoc); + int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, uint16_t *enable); + int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, struct assoc_request *assoc); -int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, - s16 *maxlevel); int lbs_set_tx_power(struct lbs_private *priv, s16 dbm); -int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on); - -int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val); - -int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val); +int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep); #endif /* _LBS_CMD_H */ diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 9ee8bd11bda9..a45061b1f33c 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -11,6 +11,7 @@ #include "host.h" #include "decl.h" +#include "cmd.h" #include "defs.h" #include "dev.h" #include "assoc.h" diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index fb91c3639fc1..20fa8176cd88 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -17,23 +17,13 @@ struct net_device; struct cmd_ctrl_node; struct cmd_ds_command; -void lbs_set_mac_control(struct lbs_private *priv); +int lbs_suspend(struct lbs_private *priv); +void lbs_resume(struct lbs_private *priv); void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count); -int lbs_free_cmd_buffer(struct lbs_private *priv); - -int lbs_prepare_and_send_command(struct lbs_private *priv, - u16 cmd_no, - u16 cmd_action, - u16 wait_option, u32 cmd_oid, void *pdata_buf); - -int lbs_allocate_cmd_buffer(struct lbs_private *priv); -int lbs_execute_next_command(struct lbs_private *priv); -int lbs_process_event(struct lbs_private *priv, u32 event); void lbs_queue_event(struct lbs_private *priv, u32 event); void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); -int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep); int lbs_enter_auto_deep_sleep(struct lbs_private *priv); int lbs_exit_auto_deep_sleep(struct lbs_private *priv); @@ -41,26 +31,17 @@ u32 lbs_fw_index_to_data_rate(u8 index); u8 lbs_data_rate_to_fw_index(u32 rate); /** The proc fs interface */ -int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len); -void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, - int result); netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band); int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *); -void lbs_ps_sleep(struct lbs_private *priv, int wait_option); -void lbs_ps_confirm_sleep(struct lbs_private *priv); -void lbs_ps_wakeup(struct lbs_private *priv, int wait_option); - struct chan_freq_power *lbs_find_cfp_by_band_and_channel( struct lbs_private *priv, u8 band, u16 channel); -void lbs_mac_event_disconnected(struct lbs_private *priv); - void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); /* persistcfg.c */ @@ -76,6 +57,5 @@ int lbs_start_card(struct lbs_private *priv); void lbs_stop_card(struct lbs_private *priv); void lbs_host_to_card_done(struct lbs_private *priv); -int lbs_update_channel(struct lbs_private *priv); #endif diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 45cd7f1e5937..5188e6539c6c 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -374,21 +374,6 @@ struct cmd_header { __le16 result; } __attribute__ ((packed)); -struct cmd_ctrl_node { - struct list_head list; - int result; - /* command response */ - int (*callback)(struct lbs_private *, - unsigned long, - struct cmd_header *); - unsigned long callback_arg; - /* command data */ - struct cmd_header *cmdbuf; - /* wait queue */ - u16 cmdwaitqwoken; - wait_queue_head_t cmdwait_q; -}; - /* Generic structure to hold all key types. */ struct enc_key { u16 len; -- cgit v1.2.3 From a3cbfb08ca634019516c91f3d5266b18e3dbbf77 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Fri, 16 Oct 2009 17:33:56 +0200 Subject: libertas: make lbs_get_channel() static Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/cmd.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index cced646a8847..e0de9a3dd12b 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -879,7 +879,7 @@ out: * * @return The channel on success, error on failure */ -int lbs_get_channel(struct lbs_private *priv) +static int lbs_get_channel(struct lbs_private *priv) { struct cmd_ds_802_11_rf_channel cmd; int ret = 0; diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 7c44cc94a25b..999d146c2f89 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -82,8 +82,6 @@ int lbs_process_event(struct lbs_private *priv, u32 event); int lbs_update_hw_spec(struct lbs_private *priv); -int lbs_get_channel(struct lbs_private *priv); - int lbs_set_channel(struct lbs_private *priv, u8 channel); int lbs_update_channel(struct lbs_private *priv); -- cgit v1.2.3 From 8ef37f1cb24bfc89297eab6cd6f1e1096d954139 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Fri, 16 Oct 2009 17:34:22 +0200 Subject: libertas: remove unused lbs_cmd_802_11_inactivity_timeout() Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 27 --------------------------- drivers/net/wireless/libertas/cmd.h | 3 --- drivers/net/wireless/libertas/host.h | 10 ---------- 3 files changed, 40 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index e0de9a3dd12b..8841a0ecf3b8 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -272,33 +272,6 @@ static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd, return 0; } -int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv, - uint16_t cmd_action, uint16_t *timeout) -{ - struct cmd_ds_802_11_inactivity_timeout cmd; - int ret; - - lbs_deb_enter(LBS_DEB_CMD); - - cmd.hdr.command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - - cmd.action = cpu_to_le16(cmd_action); - - if (cmd_action == CMD_ACT_SET) - cmd.timeout = cpu_to_le16(*timeout); - else - cmd.timeout = 0; - - ret = lbs_cmd_with_response(priv, CMD_802_11_INACTIVITY_TIMEOUT, &cmd); - - if (!ret) - *timeout = le16_to_cpu(cmd.timeout); - - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); - return 0; -} - int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, struct sleep_params *sp) { diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 999d146c2f89..9d29b578799a 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -135,9 +135,6 @@ int lbs_set_data_rate(struct lbs_private *priv, u8 rate); int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, uint16_t cmd_action); -int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv, - uint16_t cmd_action, uint16_t *timeout); - int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, struct assoc_request *assoc); diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 5188e6539c6c..25342743b1f7 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -621,16 +621,6 @@ struct cmd_ds_802_11_sleep_params { __le16 reserved; } __attribute__ ((packed)); -struct cmd_ds_802_11_inactivity_timeout { - struct cmd_header hdr; - - /* ACT_GET/ACT_SET */ - __le16 action; - - /* Inactivity timeout in msec */ - __le16 timeout; -} __attribute__ ((packed)); - struct cmd_ds_802_11_rf_channel { struct cmd_header hdr; -- cgit v1.2.3 From 72f5f457564e8ebc6c38ee4f98ee59cd03c2f614 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 16 Oct 2009 14:35:51 -0400 Subject: b43: use ieee80211_rx_ni() Convert to new use ieee80211_rx_ni() routine rather than open-coded version. Signed-off-by: John W. Linville --- drivers/net/wireless/b43/xmit.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 51d68971f6fa..7a5e294be2bc 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -690,10 +690,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) } memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); - - local_bh_disable(); - ieee80211_rx(dev->wl->hw, skb); - local_bh_enable(); + ieee80211_rx_ni(dev->wl->hw, skb); #if B43_DEBUG dev->rx_count++; -- cgit v1.2.3 From 9a493e8f4d78fc3f2494fa952500b720c86737d8 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 27 Oct 2009 15:15:05 -0400 Subject: wl1251: re-disable PG10 chips "wl1251: add support for PG11 chips." accidentally enabled PG10 chips as well... Reported-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index ec01e9dadb0d..48b0bfd6c55a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -183,11 +183,11 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)", wl->chip_id); break; - case CHIP_ID_1251_PG10: case CHIP_ID_1251_PG11: wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG11)", wl->chip_id); break; + case CHIP_ID_1251_PG10: default: wl1251_error("unsupported chip id: 0x%x", wl->chip_id); ret = -ENODEV; -- cgit v1.2.3 From 1f80989e8b7f79d8e916b14600488489bdd5569f Mon Sep 17 00:00:00 2001 From: Abhijeet Kolekar Date: Fri, 16 Oct 2009 14:25:49 -0700 Subject: iwl3945: disable all tx fifos Disable the all the tx fifos while stopping the tx queues. Signed-off-by: Abhijeet Kolekar Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index b188a026637a..9f18b4cba952 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1219,6 +1219,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) /* stop SCD */ iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); + iwl_write_prph(priv, ALM_SCD_TXFACT_REG, 0); /* reset TFD queues */ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { -- cgit v1.2.3 From c09430abed4159e5c56aaea257d040f7452daba6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:50 -0700 Subject: iwlwifi: show current power save status reported by uCode Power save request is sent from driver to uCode, but there is no indication from uCode about the current device power save state. Reading GP_CNTRL register bit 25:24 to show the current power save status 00: no power save 01: MAC power down 10: PHY power down 11: Error The uCode could switch in and out of power save mode in the order of once per 100-300 ms in many cases. The reading here should just be used for reference on the current uCode power save status. Do not confuse this reading with the PowerSave set by driver and mac80211. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-csr.h | 5 +++++ drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 26 ++++++++++++++++++++++++++ 3 files changed, 32 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 8f183e0fa512..401e1e01be67 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -235,6 +235,11 @@ #define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ #define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ #define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ +#define CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */ +#define CSR_GP_REG_NO_POWER_SAVE (0x00000000) +#define CSR_GP_REG_MAC_POWER_SAVE (0x01000000) +#define CSR_GP_REG_PHY_POWER_SAVE (0x02000000) +#define CSR_GP_REG_POWER_SAVE_ERROR (0x03000000) /* EEPROM signature */ #define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000) diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index b9ca475cc61c..96c92eab692a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -106,6 +106,7 @@ struct iwl_debugfs { struct dentry *file_sensitivity; struct dentry *file_chain_noise; struct dentry *file_tx_power; + struct dentry *file_power_save_status; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 2cd11ba96370..e78cd26b809f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1802,6 +1802,29 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[60]; + int pos = 0; + const size_t bufsz = sizeof(buf); + u32 pwrsave_status; + + pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) & + CSR_GP_REG_POWER_SAVE_STATUS_MSK; + + pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: "); + pos += scnprintf(buf + pos, bufsz - pos, "%s\n", + (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" : + (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" : + (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" : + "error"); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1813,6 +1836,7 @@ DEBUGFS_READ_FILE_OPS(ucode_general_stats); DEBUGFS_READ_FILE_OPS(sensitivity); DEBUGFS_READ_FILE_OPS(chain_noise); DEBUGFS_READ_FILE_OPS(tx_power); +DEBUGFS_READ_FILE_OPS(power_save_status); /* * Create the debugfs files and directories @@ -1860,6 +1884,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(rx_queue, debug); DEBUGFS_ADD_FILE(tx_queue, debug); DEBUGFS_ADD_FILE(tx_power, debug); + DEBUGFS_ADD_FILE(power_save_status, debug); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_ADD_FILE(ucode_rx_stats, debug); DEBUGFS_ADD_FILE(ucode_tx_stats, debug); @@ -1912,6 +1937,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_rx_queue); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_rx_stats); -- cgit v1.2.3 From 32b7e244f2b1082ac0a1cda1b088574f2d590496 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:51 -0700 Subject: iwlwifi: identify eeprom version for 6x50 series NIC Adding support for 6x50 series EEPROM version check, 6x50 is wifi/wimax combo device which has different EEPROM map Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index bdc1c74b6820..e74dad3280cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -399,7 +399,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .num_of_queues = IWL50_NUM_QUEUES, .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, @@ -425,7 +425,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .sku = IWL_SKU_A|IWL_SKU_G, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .num_of_queues = IWL50_NUM_QUEUES, .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, @@ -476,7 +476,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl6000_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, + .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .num_of_queues = IWL50_NUM_QUEUES, .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index b363c96fd6c6..5ba5a4e9e49a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -261,9 +261,12 @@ struct iwl_eeprom_enhanced_txpwr { /* 1000 Specific */ #define EEPROM_1000_EEPROM_VERSION (0x15C) -/* 60x0 Specific */ +/* 6x00 Specific */ #define EEPROM_6000_EEPROM_VERSION (0x434) +/* 6x50 Specific */ +#define EEPROM_6050_EEPROM_VERSION (0x532) + /* OTP */ /* lower blocks contain EEPROM image and calibration data */ #define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ -- cgit v1.2.3 From 3ab312a893bbfc0fad7b1b644b3d477905773b1a Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:52 -0700 Subject: iwlwifi: fix incorrect otp blocks number for 6x50 series For 6x50 series, number of OTP blocks is different from 6x00 series Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index e74dad3280cc..887e4e3674cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -408,7 +408,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, @@ -434,7 +434,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .valid_rx_ant = ANT_AB, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, @@ -485,7 +485,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .valid_rx_ant = ANT_ABC, .need_pll_cfg = false, .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, + .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .ht_greenfield_support = true, .led_compensation = 51, -- cgit v1.2.3 From f0b6e2e8cbc6026d3d6d3087032f5eceafaee0b8 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 16 Oct 2009 14:25:53 -0700 Subject: iwlwifi: move iwl_setup_mac to iwlagn This function is only used in iwlagn so there is no need to have it in iwlcore. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 62 +++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 58 ------------------------------ drivers/net/wireless/iwlwifi/iwl-core.h | 1 - 3 files changed, 62 insertions(+), 59 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index fc7a51144f0c..6c4fa011a924 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2284,6 +2284,68 @@ void iwl_post_associate(struct iwl_priv *priv) #define UCODE_READY_TIMEOUT (4 * HZ) +/* + * Not a mac80211 entry point function, but it fits in with all the + * other mac80211 functions grouped here. + */ +static int iwl_setup_mac(struct iwl_priv *priv) +{ + int ret; + struct ieee80211_hw *hw = priv->hw; + hw->rate_control_algorithm = "iwl-agn-rs"; + + /* Tell mac80211 our characteristics */ + hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_SPECTRUM_MGMT; + + if (!priv->cfg->broken_powersave) + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + + hw->wiphy->custom_regulatory = true; + + /* Firmware does not support this */ + hw->wiphy->disable_beacon_hints = true; + + /* + * For now, disable PS by default because it affects + * RX performance significantly. + */ + hw->wiphy->ps_default = false; + + hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; + /* we create the 802.11 header and a zero-length SSID element */ + hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; + + /* Default value; 4 EDCA QOS priorities */ + hw->queues = 4; + + hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; + + if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &priv->bands[IEEE80211_BAND_2GHZ]; + if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &priv->bands[IEEE80211_BAND_5GHZ]; + + ret = ieee80211_register_hw(priv->hw); + if (ret) { + IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); + return ret; + } + priv->mac80211_registered = 1; + + return 0; +} + + static int iwl_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 3e6ce5ce36aa..7ce8663fdb7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1429,64 +1429,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw, } EXPORT_SYMBOL(iwl_configure_filter); -int iwl_setup_mac(struct iwl_priv *priv) -{ - int ret; - struct ieee80211_hw *hw = priv->hw; - hw->rate_control_algorithm = "iwl-agn-rs"; - - /* Tell mac80211 our characteristics */ - hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM | - IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_SPECTRUM_MGMT; - - if (!priv->cfg->broken_powersave) - hw->flags |= IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_SUPPORTS_DYNAMIC_PS; - - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); - - hw->wiphy->custom_regulatory = true; - - /* Firmware does not support this */ - hw->wiphy->disable_beacon_hints = true; - - /* - * For now, disable PS by default because it affects - * RX performance significantly. - */ - hw->wiphy->ps_default = false; - - hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; - /* we create the 802.11 header and a zero-length SSID element */ - hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2; - - /* Default value; 4 EDCA QOS priorities */ - hw->queues = 4; - - hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; - - if (priv->bands[IEEE80211_BAND_2GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->bands[IEEE80211_BAND_2GHZ]; - if (priv->bands[IEEE80211_BAND_5GHZ].n_channels) - priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->bands[IEEE80211_BAND_5GHZ]; - - ret = ieee80211_register_hw(priv->hw); - if (ret) { - IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); - return ret; - } - priv->mac80211_registered = 1; - - return 0; -} -EXPORT_SYMBOL(iwl_setup_mac); - int iwl_set_hw_params(struct iwl_priv *priv) { priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b877f8893fdf..a2a580df3d99 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -305,7 +305,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast); int iwl_hw_nic_init(struct iwl_priv *priv); -int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); int iwl_init_drv(struct iwl_priv *priv); void iwl_uninit_drv(struct iwl_priv *priv); -- cgit v1.2.3 From cc1282f63b53d0967bd96ed56aa3d2463dc4b4b6 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 16 Oct 2009 14:25:54 -0700 Subject: iwlwifi: move rate scaling structures to header file Move to header file so they can be included and used in other parts of the driver. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 100 ----------------------------- drivers/net/wireless/iwlwifi/iwl-agn-rs.h | 101 ++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 100 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index a07be29cc5e5..2d4ec1a65957 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -75,106 +75,6 @@ static const u8 ant_toggle_lookup[] = { /*ANT_ABC -> */ ANT_ABC, }; -/** - * struct iwl_rate_scale_data -- tx success history for one rate - */ -struct iwl_rate_scale_data { - u64 data; /* bitmap of successful frames */ - s32 success_counter; /* number of frames successful */ - s32 success_ratio; /* per-cent * 128 */ - s32 counter; /* number of frames attempted */ - s32 average_tpt; /* success ratio * expected throughput */ - unsigned long stamp; -}; - -/** - * struct iwl_scale_tbl_info -- tx params and success history for all rates - * - * There are two of these in struct iwl_lq_sta, - * one for "active", and one for "search". - */ -struct iwl_scale_tbl_info { - enum iwl_table_type lq_type; - u8 ant_type; - u8 is_SGI; /* 1 = short guard interval */ - u8 is_ht40; /* 1 = 40 MHz channel width */ - u8 is_dup; /* 1 = duplicated data streams */ - u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ - u8 max_search; /* maximun number of tables we can search */ - s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ - u32 current_rate; /* rate_n_flags, uCode API format */ - struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ -}; - -struct iwl_traffic_load { - unsigned long time_stamp; /* age of the oldest statistics */ - u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time - * slice */ - u32 total; /* total num of packets during the - * last TID_MAX_TIME_DIFF */ - u8 queue_count; /* number of queues that has - * been used since the last cleanup */ - u8 head; /* start of the circular buffer */ -}; - -/** - * struct iwl_lq_sta -- driver's rate scaling private structure - * - * Pointer to this gets passed back and forth between driver and mac80211. - */ -struct iwl_lq_sta { - u8 active_tbl; /* index of active table, range 0-1 */ - u8 enable_counter; /* indicates HT mode */ - u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */ - u8 search_better_tbl; /* 1: currently trying alternate mode */ - s32 last_tpt; - - /* The following determine when to search for a new mode */ - u32 table_count_limit; - u32 max_failure_limit; /* # failed frames before new search */ - u32 max_success_limit; /* # successful frames before new search */ - u32 table_count; - u32 total_failed; /* total failed frames, any/all rates */ - u32 total_success; /* total successful frames, any/all rates */ - u64 flush_timer; /* time staying in mode before new search */ - - u8 action_counter; /* # mode-switch actions tried */ - u8 is_green; - u8 is_dup; - enum ieee80211_band band; - u8 ibss_sta_added; - - /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ - u32 supp_rates; - u16 active_legacy_rate; - u16 active_siso_rate; - u16 active_mimo2_rate; - u16 active_mimo3_rate; - u16 active_rate_basic; - s8 max_rate_idx; /* Max rate set by user */ - u8 missed_rate_counter; - - struct iwl_link_quality_cmd lq; - struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ - struct iwl_traffic_load load[TID_MAX_LOAD_COUNT]; - u8 tx_agg_tid_en; -#ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *rs_sta_dbgfs_scale_table_file; - struct dentry *rs_sta_dbgfs_stats_table_file; - struct dentry *rs_sta_dbgfs_rate_scale_data_file; - struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; - u32 dbg_fixed_rate; -#endif - struct iwl_priv *drv; - - /* used to be in sta_info */ - int last_txrate_idx; - /* last tx rate_n_flags */ - u32 last_rate_n_flags; - /* packets destined for this STA are aggregated */ - u8 is_agg; -}; - static void rs_rate_scale_perform(struct iwl_priv *priv, struct sk_buff *skb, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index 9fac530cfb7e..affc0c5a2f2c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -54,6 +54,7 @@ struct iwl3945_rate_info { u8 prev_table_rs; /* prev in rate table cmd */ }; + /* * These serve as indexes into * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; @@ -335,6 +336,106 @@ struct iwl_rate_mcs_info { char mcs[IWL_MAX_MCS_DISPLAY_SIZE]; }; +/** + * struct iwl_rate_scale_data -- tx success history for one rate + */ +struct iwl_rate_scale_data { + u64 data; /* bitmap of successful frames */ + s32 success_counter; /* number of frames successful */ + s32 success_ratio; /* per-cent * 128 */ + s32 counter; /* number of frames attempted */ + s32 average_tpt; /* success ratio * expected throughput */ + unsigned long stamp; +}; + +/** + * struct iwl_scale_tbl_info -- tx params and success history for all rates + * + * There are two of these in struct iwl_lq_sta, + * one for "active", and one for "search". + */ +struct iwl_scale_tbl_info { + enum iwl_table_type lq_type; + u8 ant_type; + u8 is_SGI; /* 1 = short guard interval */ + u8 is_ht40; /* 1 = 40 MHz channel width */ + u8 is_dup; /* 1 = duplicated data streams */ + u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */ + u8 max_search; /* maximun number of tables we can search */ + s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ + u32 current_rate; /* rate_n_flags, uCode API format */ + struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ +}; + +struct iwl_traffic_load { + unsigned long time_stamp; /* age of the oldest statistics */ + u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time + * slice */ + u32 total; /* total num of packets during the + * last TID_MAX_TIME_DIFF */ + u8 queue_count; /* number of queues that has + * been used since the last cleanup */ + u8 head; /* start of the circular buffer */ +}; + +/** + * struct iwl_lq_sta -- driver's rate scaling private structure + * + * Pointer to this gets passed back and forth between driver and mac80211. + */ +struct iwl_lq_sta { + u8 active_tbl; /* index of active table, range 0-1 */ + u8 enable_counter; /* indicates HT mode */ + u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */ + u8 search_better_tbl; /* 1: currently trying alternate mode */ + s32 last_tpt; + + /* The following determine when to search for a new mode */ + u32 table_count_limit; + u32 max_failure_limit; /* # failed frames before new search */ + u32 max_success_limit; /* # successful frames before new search */ + u32 table_count; + u32 total_failed; /* total failed frames, any/all rates */ + u32 total_success; /* total successful frames, any/all rates */ + u64 flush_timer; /* time staying in mode before new search */ + + u8 action_counter; /* # mode-switch actions tried */ + u8 is_green; + u8 is_dup; + enum ieee80211_band band; + u8 ibss_sta_added; + + /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ + u32 supp_rates; + u16 active_legacy_rate; + u16 active_siso_rate; + u16 active_mimo2_rate; + u16 active_mimo3_rate; + u16 active_rate_basic; + s8 max_rate_idx; /* Max rate set by user */ + u8 missed_rate_counter; + + struct iwl_link_quality_cmd lq; + struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ + struct iwl_traffic_load load[TID_MAX_LOAD_COUNT]; + u8 tx_agg_tid_en; +#ifdef CONFIG_MAC80211_DEBUGFS + struct dentry *rs_sta_dbgfs_scale_table_file; + struct dentry *rs_sta_dbgfs_stats_table_file; + struct dentry *rs_sta_dbgfs_rate_scale_data_file; + struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file; + u32 dbg_fixed_rate; +#endif + struct iwl_priv *drv; + + /* used to be in sta_info */ + int last_txrate_idx; + /* last tx rate_n_flags */ + u32 last_rate_n_flags; + /* packets destined for this STA are aggregated */ + u8 is_agg; +}; + static inline u8 num_of_ant(u8 mask) { return !!((mask) & ANT_A) + -- cgit v1.2.3 From 8d9698b3e6ce3c50f9ec5a0aaea4da82d5af7779 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 16 Oct 2009 14:25:55 -0700 Subject: iwlagn: store station rate scale information in mac80211 station structure Currently mac80211 initializes the rate scaling before notifying the driver of the station's existence. The driver dealt with this by not relying on mac80211's station notifications and instead mixing this functionality with the rate scaling code and other places. To clean this up the driver needs to do rate scaling initialization after being notified of the station, this can be done if the rate scaling information forms part of the station information passed from mac80211 to driver. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 8 ++------ drivers/net/wireless/iwlwifi/iwl-agn.c | 1 + drivers/net/wireless/iwlwifi/iwl-dev.h | 13 +++++++++++++ 3 files changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 2d4ec1a65957..27d4ece4d467 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2475,19 +2475,17 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl_lq_sta *lq_sta; + struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; struct iwl_priv *priv; int i, j; priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE(priv, "create station rate scale window\n"); - lq_sta = kzalloc(sizeof(struct iwl_lq_sta), gfp); + lq_sta = &sta_priv->lq_sta; - if (lq_sta == NULL) - return NULL; lq_sta->lq.sta_id = 0xff; - for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); @@ -2719,11 +2717,9 @@ static void rs_free(void *priv_rate) static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, void *priv_sta) { - struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_priv *priv __maybe_unused = priv_r; IWL_DEBUG_RATE(priv, "enter\n"); - kfree(lq_sta); IWL_DEBUG_RATE(priv, "leave\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6c4fa011a924..64d918787e88 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2304,6 +2304,7 @@ static int iwl_setup_mac(struct iwl_priv *priv) hw->flags |= IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; + hw->sta_data_size = sizeof(struct iwl_station_priv); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 35d579455c3c..6ba082d6ab16 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -576,6 +576,19 @@ struct iwl_station_entry { struct iwl_hw_key keyinfo; }; +/* + * iwl_station_priv: Driver's private station information + * + * When mac80211 creates a station it reserves some space (hw->sta_data_size) + * in the structure for use by driver. This structure is places in that + * space. + * + * At the moment use it for the station's rate scaling information. + */ +struct iwl_station_priv { + struct iwl_lq_sta lq_sta; +}; + /* one for each uCode image (inst/data, boot/init/runtime) */ struct fw_desc { void *v_addr; /* access by driver */ -- cgit v1.2.3 From 32004ee42fced8b2372dd2f93e65cc9d71e8c4bf Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:56 -0700 Subject: iwlwifi: set auto clock gate disable bit for 6x00/6x50 series For 6x00 and 6x50 series NIC with OTP shadow RAM, set auto clock gate disable bit when initializing OTP access. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-csr.h | 6 ++++-- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 401e1e01be67..b6ed5a3147a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -109,8 +109,9 @@ * Bit fields: * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step */ -#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) -#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240) +#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) +#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240) +#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250) /* Bits for CSR_HW_IF_CONFIG_REG */ #define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010) @@ -195,6 +196,7 @@ #define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) #define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) #define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) +#define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000) /* GP (general purpose) CONTROL */ #define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 2e8c40576d22..9429cb1c69bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -358,6 +358,14 @@ static int iwl_init_otp_access(struct iwl_priv *priv) udelay(5); iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); + + /* + * CSR auto clock gate disable bit - + * this is only applicable for HW with OTP shadow RAM + */ + if (priv->cfg->shadow_ram_support) + iwl_set_bit(priv, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); } return ret; } -- cgit v1.2.3 From 9444b188022418c624ce32584c3b9544b500d15e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:57 -0700 Subject: iwlwifi: no chain noise support for 6x50 series For initial bring up of 6x50 series NICs, no chain noise support in uCode, this feature will be added in the later stage of development. Two chain noise related functions are removed from 6x50 series: 1. gain computation 2. chain noise reset Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 887e4e3674cf..b53181324487 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -232,6 +232,21 @@ static struct iwl_ops iwl6000_ops = { .led = &iwlagn_led_ops, }; +static struct iwl_hcmd_utils_ops iwl6050_hcmd_utils = { + .get_hcmd_size = iwl5000_get_hcmd_size, + .build_addsta_hcmd = iwl5000_build_addsta_hcmd, + .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag, + .calc_rssi = iwl5000_calc_rssi, +}; + +static struct iwl_ops iwl6050_ops = { + .ucode = &iwl5000_ucode, + .lib = &iwl6000_lib, + .hcmd = &iwl5000_hcmd, + .utils = &iwl6050_hcmd_utils, + .led = &iwlagn_led_ops, +}; + /* * "h": Hybrid configuration, use both internal and external Power Amplifier @@ -397,7 +412,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000_ops, + .ops = &iwl6050_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, @@ -423,7 +438,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl6000_ops, + .ops = &iwl6050_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, @@ -474,7 +489,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .ucode_api_max = IWL6050_UCODE_API_MAX, .ucode_api_min = IWL6050_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000_ops, + .ops = &iwl6050_ops, .eeprom_size = OTP_LOW_IMAGE_SIZE, .eeprom_ver = EEPROM_6050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, -- cgit v1.2.3 From 4ad177b5c860dc0b1083eccc55957daf4a116b90 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 16 Oct 2009 14:25:58 -0700 Subject: iwlwifi: rework for static power save For static power save, the actual intervals are calculated by driver based on the default table and DTIM flag, then sent to uCode when the scheme is changed. Three tables are defined based on DTIM period. 1. DTIM 0 - 2 2. DTIM 3 - 10 3. DTIM > 11 The actual number of DTIM a station may miss may not exceed the following: . Only 1 DTIM may be skipped at PI=4 when allowed . Only 2 DTIMs may be skipped at PI=5 when allowed . DTIM may be skipped only 5 sec after last activity . DTIM may be skipped only 30 sec after connection establishment Only allow user to override the power_level when rf is ready to make sure power level gets changed upon request. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 5 +- drivers/net/wireless/iwlwifi/iwl-power.c | 75 +++++++++++++++++++++--------- drivers/net/wireless/iwlwifi/iwl-power.h | 2 + 3 files changed, 59 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index e78cd26b809f..8784911fd56e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -809,9 +809,12 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, if (value != -1 && (value < 0 || value >= IWL_POWER_NUM)) return -EINVAL; + if (!iwl_is_ready_rf(priv)) + return -EAGAIN; + priv->power_data.debug_sleep_level_override = value; - iwl_power_update_mode(priv, false); + iwl_power_update_mode(priv, true); return count; } diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 9c6b14952061..150ff87af33b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(no_sleep_autoadjust, struct iwl_power_vec_entry { struct iwl_powertable_cmd cmd; - u8 no_dtim; + u8 no_dtim; /* number of skip dtim */ }; #define IWL_DTIM_RANGE_0_MAX 2 @@ -83,8 +83,9 @@ struct iwl_power_vec_entry { cpu_to_le32(X4)} /* default power management (not Tx power) table values */ /* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */ +/* DTIM 0 - 2 */ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { - {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, + {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 1, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1}, @@ -93,15 +94,17 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { /* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */ +/* DTIM 3 - 10 */ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1}, - {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} + {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 6, 10, 10)}, 2} }; /* for DTIM period > IWL_DTIM_RANGE_1_MAX */ +/* DTIM 11 - */ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, @@ -115,13 +118,15 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, enum iwl_power_level lvl, int period) { const struct iwl_power_vec_entry *table; - int max_sleep, i; - bool skip; + int max_sleep[IWL_POWER_VEC_SIZE] = { 0 }; + int i; + u8 skip; + u32 slp_itrvl; table = range_2; - if (period < IWL_DTIM_RANGE_1_MAX) + if (period <= IWL_DTIM_RANGE_1_MAX) table = range_1; - if (period < IWL_DTIM_RANGE_0_MAX) + if (period <= IWL_DTIM_RANGE_0_MAX) table = range_0; BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); @@ -129,34 +134,60 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, *cmd = table[lvl].cmd; if (period == 0) { - skip = false; + skip = 0; period = 1; + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) + max_sleep[i] = 1; + } else { - skip = !!table[lvl].no_dtim; + skip = table[lvl].no_dtim; + for (i = 0; i < IWL_POWER_VEC_SIZE; i++) + max_sleep[i] = le32_to_cpu(cmd->sleep_interval[i]); + max_sleep[IWL_POWER_VEC_SIZE - 1] = skip + 1; } - if (skip) { - __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; - max_sleep = le32_to_cpu(slp_itrvl); - if (max_sleep == 0xFF) - max_sleep = period * (skip + 1); - else if (max_sleep > period) - max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; + slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); + /* figure out the listen interval based on dtim period and skip */ + if (slp_itrvl == 0xFF) + cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = + cpu_to_le32(period * (skip + 1)); + + slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); + if (slp_itrvl > period) + cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = + cpu_to_le32((slp_itrvl / period) * period); + + if (skip) cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; - } else { - max_sleep = period; + else cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; - } - for (i = 0; i < IWL_POWER_VEC_SIZE; i++) - if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) - cmd->sleep_interval[i] = cpu_to_le32(max_sleep); + slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); + if (slp_itrvl > IWL_CONN_LISTEN_INTERVAL) + cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = + cpu_to_le32(IWL_CONN_LISTEN_INTERVAL); + + /* enforce max sleep interval */ + for (i = IWL_POWER_VEC_SIZE - 1; i >= 0 ; i--) { + if (le32_to_cpu(cmd->sleep_interval[i]) > + (max_sleep[i] * period)) + cmd->sleep_interval[i] = + cpu_to_le32(max_sleep[i] * period); + if (i != (IWL_POWER_VEC_SIZE - 1)) { + if (le32_to_cpu(cmd->sleep_interval[i]) > + le32_to_cpu(cmd->sleep_interval[i+1])) + cmd->sleep_interval[i] = + cmd->sleep_interval[i+1]; + } + } if (priv->power_data.pci_pm) cmd->flags |= IWL_POWER_PCI_PM_MSK; else cmd->flags &= ~IWL_POWER_PCI_PM_MSK; + IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n", + skip, period); IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1); } diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 310c32e8f698..0755518f86e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -30,6 +30,8 @@ #include "iwl-commands.h" +#define IWL_CONN_LISTEN_INTERVAL 10 + #define IWL_ABSOLUTE_ZERO 0 #define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 -- cgit v1.2.3 From 02bdf5b48a2cd90a5d036eab68e6f65adb200140 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 17 Oct 2009 21:56:43 +0200 Subject: ar9170: atomic pending A-MPDU counter A ref-counting bug emerged after testing ar9170usb's HT implementation on a bigger SMP/SMT system without the usual _debugging_ overhead. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/ar9170.h | 2 +- drivers/net/wireless/ath/ar9170/main.c | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index ec034af26980..9f9459860d82 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -231,7 +231,7 @@ struct ar9170 { struct sk_buff_head tx_status_ampdu; spinlock_t tx_ampdu_list_lock; struct list_head tx_ampdu_list; - unsigned int tx_ampdu_pending; + atomic_t tx_ampdu_pending; /* rxstream mpdu merge */ struct ar9170_rxstream_mpdu_merge rx_mpdu; diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index de0ba2bf7691..7e59b82e64d3 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -414,9 +414,9 @@ static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb) skb_queue_tail(&ar->tx_status_ampdu, skb); ar9170_tx_fake_ampdu_status(ar); - ar->tx_ampdu_pending--; - if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending) + if (atomic_dec_and_test(&ar->tx_ampdu_pending) && + !list_empty(&ar->tx_ampdu_list)) ar9170_tx_ampdu(ar); } @@ -1248,6 +1248,7 @@ static int ar9170_op_start(struct ieee80211_hw *hw) ar->global_ampdu_density = 6; ar->global_ampdu_factor = 3; + atomic_set(&ar->tx_ampdu_pending, 0); ar->bad_hw_nagger = jiffies; err = ar->open(ar); @@ -1773,7 +1774,7 @@ static void ar9170_tx(struct ar9170 *ar) msecs_to_jiffies(AR9170_TX_TIMEOUT); if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) - ar->tx_ampdu_pending++; + atomic_inc(&ar->tx_ampdu_pending); #ifdef AR9170_QUEUE_DEBUG printk(KERN_DEBUG "%s: send frame q:%d =>\n", @@ -1784,7 +1785,7 @@ static void ar9170_tx(struct ar9170 *ar) err = ar->tx(ar, skb); if (unlikely(err)) { if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK) - ar->tx_ampdu_pending--; + atomic_dec(&ar->tx_ampdu_pending); frames_failed++; dev_kfree_skb_any(skb); @@ -1931,7 +1932,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (info->flags & IEEE80211_TX_CTL_AMPDU) { bool run = ar9170_tx_ampdu_queue(ar, skb); - if (run || !ar->tx_ampdu_pending) + if (run || !atomic_read(&ar->tx_ampdu_pending)) ar9170_tx_ampdu(ar); } else { unsigned int queue = skb_get_queue_mapping(skb); -- cgit v1.2.3 From 731d6bfc2d201958cfa3d08c7acff218497bbd50 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 17 Oct 2009 21:56:51 +0200 Subject: ar9170usb: atomic pending urbs counter This patch follows "ar9170: atomic pending A-MPDU counter" idea and converts another critical counter to atomic_*. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/usb.c | 12 ++++++------ drivers/net/wireless/ath/ar9170/usb.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index e974e5829e1a..6bdcdf6d1cc0 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -108,15 +108,15 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru) return ; spin_lock_irqsave(&aru->tx_urb_lock, flags); - if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) { + if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) { spin_unlock_irqrestore(&aru->tx_urb_lock, flags); return ; } - aru->tx_submitted_urbs++; + atomic_inc(&aru->tx_submitted_urbs); urb = usb_get_from_anchor(&aru->tx_pending); if (!urb) { - aru->tx_submitted_urbs--; + atomic_dec(&aru->tx_submitted_urbs); spin_unlock_irqrestore(&aru->tx_urb_lock, flags); return ; @@ -133,7 +133,7 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru) err); usb_unanchor_urb(urb); - aru->tx_submitted_urbs--; + atomic_dec(&aru->tx_submitted_urbs); ar9170_tx_callback(&aru->common, urb->context); } @@ -151,7 +151,7 @@ static void ar9170_usb_tx_urb_complete_frame(struct urb *urb) return ; } - aru->tx_submitted_urbs--; + atomic_dec(&aru->tx_submitted_urbs); ar9170_tx_callback(&aru->common, skb); @@ -794,7 +794,7 @@ static int ar9170_usb_probe(struct usb_interface *intf, spin_lock_init(&aru->tx_urb_lock); aru->tx_pending_urbs = 0; - aru->tx_submitted_urbs = 0; + atomic_set(&aru->tx_submitted_urbs, 0); aru->common.stop = ar9170_usb_stop; aru->common.flush = ar9170_usb_flush; diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h index d098f4d5d2f2..a2ce3b169ceb 100644 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ b/drivers/net/wireless/ath/ar9170/usb.h @@ -67,7 +67,7 @@ struct ar9170_usb { bool req_one_stage_fw; spinlock_t tx_urb_lock; - unsigned int tx_submitted_urbs; + atomic_t tx_submitted_urbs; unsigned int tx_pending_urbs; struct completion cmd_wait; -- cgit v1.2.3 From 68676df00d956e191c442cb697154a7a18a1e054 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 17 Oct 2009 21:56:55 +0200 Subject: ar9170: don't filter BlockACK frames The current A-MPDU tx_status report mechanism is too inaccurate. With this patch BlockACK frames show now up to the driver and can be processed. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/hw.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 88113148331c..701ddb7d8400 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -152,14 +152,14 @@ enum ar9170_cmd { #define AR9170_MAC_REG_FTF_BIT14 BIT(14) #define AR9170_MAC_REG_FTF_BIT15 BIT(15) #define AR9170_MAC_REG_FTF_BAR BIT(24) -#define AR9170_MAC_REG_FTF_BIT25 BIT(25) +#define AR9170_MAC_REG_FTF_BA BIT(25) #define AR9170_MAC_REG_FTF_PSPOLL BIT(26) #define AR9170_MAC_REG_FTF_RTS BIT(27) #define AR9170_MAC_REG_FTF_CTS BIT(28) #define AR9170_MAC_REG_FTF_ACK BIT(29) #define AR9170_MAC_REG_FTF_CFE BIT(30) #define AR9170_MAC_REG_FTF_CFE_ACK BIT(31) -#define AR9170_MAC_REG_FTF_DEFAULTS 0x0500ffff +#define AR9170_MAC_REG_FTF_DEFAULTS 0x0700ffff #define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff #define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0) -- cgit v1.2.3 From 287d37412035d003430f69a828c98b1cc6ee6d60 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 21 Oct 2009 14:03:46 +0300 Subject: wl1271: use ieee80211_rx_ni() Use the new ieee80211_rx_ni() function instead of ieee80211_rx(). Since we use a workqueue to handle the RX path, we need to call the new function, which disables bottom half handling. This patch fixes the NOHZ: local_softirq_pending messages. CC: Kalle Valo Signed-off-by: Luciano Coelho Reviewed-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index dbf07bea87c0..37d81ab6acc0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -184,7 +184,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) beacon ? "beacon" : ""); memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); - ieee80211_rx(wl->hw, skb); + ieee80211_rx_ni(wl->hw, skb); } void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) -- cgit v1.2.3 From 7f4013f09654216653121f216bd0257f460f5dcc Mon Sep 17 00:00:00 2001 From: Benoit PAPILLAULT Date: Thu, 22 Oct 2009 12:04:52 +0200 Subject: zd1211rw: Fix TX status reporting in order to have proper rate control First, we reduce the number of hardware retries to 0 (ie 2 real retries for each rate). Next, when we report the retries to mac80211, we always report a retry count of 1 (it seems to be 2 in fact, but using 2 seems to lead to wrong performance for some reason). We use a state machine to determine the real fate of a packet based on the 802.11 ACK and what the Zydas hardware is saying when a real retry occurs. The real retry rates are encoded in a static array. It has been tested with both zd1211 and zd1211b hardware. Of course, since the Zydas hardware is not reporting retries accurately, we are just doing our best in order to get the best performance (ie higher throughput). Signed-off-by: Benoit PAPILLAULT Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_chip.c | 4 +- drivers/net/wireless/zd1211rw/zd_chip.h | 18 ++- drivers/net/wireless/zd1211rw/zd_mac.c | 202 ++++++++++++++++++++++++++++---- drivers/net/wireless/zd1211rw/zd_mac.h | 25 +++- drivers/net/wireless/zd1211rw/zd_usb.c | 4 +- 5 files changed, 227 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 4e79a9800134..dfa1b9bc22c8 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -755,7 +755,7 @@ static int hw_reset_phy(struct zd_chip *chip) static int zd1211_hw_init_hmac(struct zd_chip *chip) { static const struct zd_ioreq32 ioreqs[] = { - { CR_ZD1211_RETRY_MAX, 0x2 }, + { CR_ZD1211_RETRY_MAX, ZD1211_RETRY_COUNT }, { CR_RX_THRESHOLD, 0x000c0640 }, }; @@ -767,7 +767,7 @@ static int zd1211_hw_init_hmac(struct zd_chip *chip) static int zd1211b_hw_init_hmac(struct zd_chip *chip) { static const struct zd_ioreq32 ioreqs[] = { - { CR_ZD1211B_RETRY_MAX, 0x02020202 }, + { CR_ZD1211B_RETRY_MAX, ZD1211B_RETRY_COUNT }, { CR_ZD1211B_CWIN_MAX_MIN_AC0, 0x007f003f }, { CR_ZD1211B_CWIN_MAX_MIN_AC1, 0x007f003f }, { CR_ZD1211B_CWIN_MAX_MIN_AC2, 0x003f001f }, diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 678c139a840c..9fd8f3508d66 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -642,13 +642,29 @@ enum { #define CR_ZD1211B_TXOP CTL_REG(0x0b20) #define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28) +/* Value for CR_ZD1211_RETRY_MAX & CR_ZD1211B_RETRY_MAX. Vendor driver uses 2, + * we use 0. The first rate is tried (count+2), then all next rates are tried + * twice, until 1 Mbits is tried. */ +#define ZD1211_RETRY_COUNT 0 +#define ZD1211B_RETRY_COUNT \ + (ZD1211_RETRY_COUNT << 0)| \ + (ZD1211_RETRY_COUNT << 8)| \ + (ZD1211_RETRY_COUNT << 16)| \ + (ZD1211_RETRY_COUNT << 24) + /* Used to detect PLL lock */ #define UW2453_INTR_REG ((zd_addr_t)0x85c1) #define CWIN_SIZE 0x007f043f -#define HWINT_ENABLED 0x004f0000 +#define HWINT_ENABLED \ + (INT_TX_COMPLETE_EN| \ + INT_RX_COMPLETE_EN| \ + INT_RETRY_FAIL_EN| \ + INT_WAKEUP_EN| \ + INT_CFG_NEXT_BCN_EN) + #define HWINT_DISABLED 0 #define E2P_PWR_INT_GUARD 8 diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 6d666359a42f..8a243732c519 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -88,6 +88,34 @@ static const struct ieee80211_rate zd_rates[] = { .flags = 0 }, }; +/* + * Zydas retry rates table. Each line is listed in the same order as + * in zd_rates[] and contains all the rate used when a packet is sent + * starting with a given rates. Let's consider an example : + * + * "11 Mbits : 4, 3, 2, 1, 0" means : + * - packet is sent using 4 different rates + * - 1st rate is index 3 (ie 11 Mbits) + * - 2nd rate is index 2 (ie 5.5 Mbits) + * - 3rd rate is index 1 (ie 2 Mbits) + * - 4th rate is index 0 (ie 1 Mbits) + */ + +static const struct tx_retry_rate zd_retry_rates[] = { + { /* 1 Mbits */ 1, { 0 }}, + { /* 2 Mbits */ 2, { 1, 0 }}, + { /* 5.5 Mbits */ 3, { 2, 1, 0 }}, + { /* 11 Mbits */ 4, { 3, 2, 1, 0 }}, + { /* 6 Mbits */ 5, { 4, 3, 2, 1, 0 }}, + { /* 9 Mbits */ 6, { 5, 4, 3, 2, 1, 0}}, + { /* 12 Mbits */ 5, { 6, 3, 2, 1, 0 }}, + { /* 18 Mbits */ 6, { 7, 6, 3, 2, 1, 0 }}, + { /* 24 Mbits */ 6, { 8, 6, 3, 2, 1, 0 }}, + { /* 36 Mbits */ 7, { 9, 8, 6, 3, 2, 1, 0 }}, + { /* 48 Mbits */ 8, {10, 9, 8, 6, 3, 2, 1, 0 }}, + { /* 54 Mbits */ 9, {11, 10, 9, 8, 6, 3, 2, 1, 0 }} +}; + static const struct ieee80211_channel zd_channels[] = { { .center_freq = 2412, .hw_value = 1 }, { .center_freq = 2417, .hw_value = 2 }, @@ -282,7 +310,7 @@ static void zd_op_stop(struct ieee80211_hw *hw) } /** - * tx_status - reports tx status of a packet if required + * zd_mac_tx_status - reports tx status of a packet if required * @hw - a &struct ieee80211_hw pointer * @skb - a sk-buffer * @flags: extra flags to set in the TX status info @@ -295,15 +323,49 @@ static void zd_op_stop(struct ieee80211_hw *hw) * * If no status information has been requested, the skb is freed. */ -static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - int ackssi, bool success) +static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, + int ackssi, struct tx_status *tx_status) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int i; + int success = 1, retry = 1; + int first_idx; + const struct tx_retry_rate *retries; ieee80211_tx_info_clear_status(info); - if (success) + if (tx_status) { + success = !tx_status->failure; + retry = tx_status->retry + success; + } + + if (success) { + /* success */ info->flags |= IEEE80211_TX_STAT_ACK; + } else { + /* failure */ + info->flags &= ~IEEE80211_TX_STAT_ACK; + } + + first_idx = info->status.rates[0].idx; + ZD_ASSERT(0<=first_idx && first_idxcount); + + info->status.rates[0].idx = retries->rate[0]; + info->status.rates[0].count = 1; // (retry > 1 ? 2 : 1); + + for (i=1; istatus.rates[i].idx = retries->rate[i]; + info->status.rates[i].count = 1; // ((i==retry-1) && success ? 1:2); + } + for (; istatus.rates[i].idx = retries->rate[retry-1]; + info->status.rates[i].count = 1; // (success ? 1:2); + } + if (istatus.rates[i].idx = -1; /* terminate */ + info->status.ack_signal = ackssi; ieee80211_tx_status_irqsafe(hw, skb); } @@ -316,16 +378,79 @@ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, * transferred. The first frame from the tx queue, will be selected and * reported as error to the upper layers. */ -void zd_mac_tx_failed(struct ieee80211_hw *hw) +void zd_mac_tx_failed(struct urb *urb) { - struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; + struct ieee80211_hw * hw = zd_usb_to_hw(urb->context); + struct zd_mac *mac = zd_hw_mac(hw); + struct sk_buff_head *q = &mac->ack_wait_queue; struct sk_buff *skb; + struct tx_status *tx_status = (struct tx_status *)urb->transfer_buffer; + unsigned long flags; + int success = !tx_status->failure; + int retry = tx_status->retry + success; + int found = 0; + int i, position = 0; - skb = skb_dequeue(q); - if (skb == NULL) - return; + q = &mac->ack_wait_queue; + spin_lock_irqsave(&q->lock, flags); + + skb_queue_walk(q, skb) { + struct ieee80211_hdr *tx_hdr; + struct ieee80211_tx_info *info; + int first_idx, final_idx; + const struct tx_retry_rate *retries; + u8 final_rate; + + position ++; + + /* if the hardware reports a failure and we had a 802.11 ACK + * pending, then we skip the first skb when searching for a + * matching frame */ + if (tx_status->failure && mac->ack_pending && + skb_queue_is_first(q, skb)) { + continue; + } + + tx_hdr = (struct ieee80211_hdr *)skb->data; + + /* we skip all frames not matching the reported destination */ + if (unlikely(memcmp(tx_hdr->addr1, tx_status->mac, ETH_ALEN))) { + continue; + } + + /* we skip all frames not matching the reported final rate */ - tx_status(hw, skb, 0, 0); + info = IEEE80211_SKB_CB(skb); + first_idx = info->status.rates[0].idx; + ZD_ASSERT(0<=first_idx && first_idx retries->count) { + continue; + } + + ZD_ASSERT(0<=retry && retry<=retries->count); + final_idx = retries->rate[retry-1]; + final_rate = zd_rates[final_idx].hw_value; + + if (final_rate != tx_status->rate) { + continue; + } + + found = 1; + break; + } + + if (found) { + for (i=1; i<=position; i++) { + skb = __skb_dequeue(q); + zd_mac_tx_status(hw, skb, + mac->ack_pending ? mac->ack_signal : 0, + i == position ? tx_status : NULL); + mac->ack_pending = 0; + } + } + + spin_unlock_irqrestore(&q->lock, flags); } /** @@ -342,18 +467,27 @@ void zd_mac_tx_to_dev(struct sk_buff *skb, int error) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hw *hw = info->rate_driver_data[0]; + struct zd_mac *mac = zd_hw_mac(hw); + + ieee80211_tx_info_clear_status(info); skb_pull(skb, sizeof(struct zd_ctrlset)); if (unlikely(error || (info->flags & IEEE80211_TX_CTL_NO_ACK))) { - tx_status(hw, skb, 0, !error); + /* + * FIXME : do we need to fill in anything ? + */ + ieee80211_tx_status_irqsafe(hw, skb); } else { - struct sk_buff_head *q = - &zd_hw_mac(hw)->ack_wait_queue; + struct sk_buff_head *q = &mac->ack_wait_queue; skb_queue_tail(q, skb); - while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) - zd_mac_tx_failed(hw); + while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) { + zd_mac_tx_status(hw, skb_dequeue(q), + mac->ack_pending ? mac->ack_signal : 0, + NULL); + mac->ack_pending = 0; + } } } @@ -606,27 +740,47 @@ fail: static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, struct ieee80211_rx_status *stats) { + struct zd_mac *mac = zd_hw_mac(hw); struct sk_buff *skb; struct sk_buff_head *q; unsigned long flags; + int found = 0; + int i, position = 0; if (!ieee80211_is_ack(rx_hdr->frame_control)) return 0; - q = &zd_hw_mac(hw)->ack_wait_queue; + q = &mac->ack_wait_queue; spin_lock_irqsave(&q->lock, flags); skb_queue_walk(q, skb) { struct ieee80211_hdr *tx_hdr; + position ++; + + if (mac->ack_pending && skb_queue_is_first(q, skb)) + continue; + tx_hdr = (struct ieee80211_hdr *)skb->data; if (likely(!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN))) { - __skb_unlink(skb, q); - tx_status(hw, skb, stats->signal, 1); - goto out; + found = 1; + break; } } -out: + + if (found) { + for (i=1; iack_pending ? mac->ack_signal : 0, + NULL); + mac->ack_pending = 0; + } + + mac->ack_pending = 1; + mac->ack_signal = stats->signal; + } + spin_unlock_irqrestore(&q->lock, flags); return 1; } @@ -709,6 +863,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) skb_reserve(skb, 2); } + /* FIXME : could we avoid this big memcpy ? */ memcpy(skb_put(skb, length), buffer, length); memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats)); @@ -999,7 +1154,14 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) hw->queues = 1; hw->extra_tx_headroom = sizeof(struct zd_ctrlset); + /* + * Tell mac80211 that we support multi rate retries + */ + hw->max_rates = IEEE80211_TX_MAX_RATES; + hw->max_rate_tries = 18; /* 9 rates * 2 retries/rate */ + skb_queue_head_init(&mac->ack_wait_queue); + mac->ack_pending = 0; zd_chip_init(&mac->chip, hw, intf); housekeeping_init(mac); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 7c2759118d13..630c298a730e 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -140,6 +140,21 @@ struct rx_status { #define ZD_RX_CRC16_ERROR 0x40 #define ZD_RX_ERROR 0x80 +struct tx_retry_rate { + int count; /* number of valid element in rate[] array */ + int rate[10]; /* retry rates, described by an index in zd_rates[] */ +}; + +struct tx_status { + u8 type; /* must always be 0x01 : USB_INT_TYPE */ + u8 id; /* must always be 0xa0 : USB_INT_ID_RETRY_FAILED */ + u8 rate; + u8 pad; + u8 mac[ETH_ALEN]; + u8 retry; + u8 failure; +} __attribute__((packed)); + enum mac_flags { MAC_FIXED_CHANNEL = 0x01, }; @@ -150,7 +165,7 @@ struct housekeeping { #define ZD_MAC_STATS_BUFFER_SIZE 16 -#define ZD_MAC_MAX_ACK_WAITERS 10 +#define ZD_MAC_MAX_ACK_WAITERS 50 struct zd_mac { struct zd_chip chip; @@ -184,6 +199,12 @@ struct zd_mac { /* whether to pass control frames to stack */ unsigned int pass_ctrl:1; + + /* whether we have received a 802.11 ACK that is pending */ + unsigned int ack_pending:1; + + /* signal strength of the last 802.11 ACK received */ + int ack_signal; }; #define ZD_REGDOMAIN_FCC 0x10 @@ -279,7 +300,7 @@ int zd_mac_preinit_hw(struct ieee80211_hw *hw); int zd_mac_init_hw(struct ieee80211_hw *hw); int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length); -void zd_mac_tx_failed(struct ieee80211_hw *hw); +void zd_mac_tx_failed(struct urb *urb); void zd_mac_tx_to_dev(struct sk_buff *skb, int error); #ifdef DEBUG diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 23a6a6d4863b..d46f20a57b7d 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -419,7 +419,7 @@ static void int_urb_complete(struct urb *urb) handle_regs_int(urb); break; case USB_INT_ID_RETRY_FAILED: - zd_mac_tx_failed(zd_usb_to_hw(urb->context)); + zd_mac_tx_failed(urb); break; default: dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb, @@ -553,6 +553,8 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, if (length < sizeof(struct rx_length_info)) { /* It's not a complete packet anyhow. */ + printk("%s: invalid, small RX packet : %d\n", + __func__, length); return; } length_info = (struct rx_length_info *) -- cgit v1.2.3 From d37b4fdd43f7e5686c40181f33a50a7ee03ddbd8 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:45 +0200 Subject: libertas: remove unused 11d code Most of the 11d code was protected with an "if (priv->enable11d)" clause. But there was no code that anywhere that was able to set this variable to true. So all 11d code was dead for almost a year and no one complained. That's enought incentive to remove this code. Besides removing old cruft, we gain back the 11d capability in a common way when we merge the cfg80211 functionality. Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/11d.c | 697 -------------------------------- drivers/net/wireless/libertas/11d.h | 23 -- drivers/net/wireless/libertas/Makefile | 1 - drivers/net/wireless/libertas/assoc.c | 16 - drivers/net/wireless/libertas/cmd.c | 10 - drivers/net/wireless/libertas/cmdresp.c | 4 - drivers/net/wireless/libertas/dev.h | 9 - drivers/net/wireless/libertas/main.c | 3 - drivers/net/wireless/libertas/scan.c | 22 +- drivers/net/wireless/libertas/wext.c | 58 +-- 10 files changed, 13 insertions(+), 830 deletions(-) delete mode 100644 drivers/net/wireless/libertas/11d.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c deleted file mode 100644 index 93f2d5fb3920..000000000000 --- a/drivers/net/wireless/libertas/11d.c +++ /dev/null @@ -1,697 +0,0 @@ -/** - * This file contains functions for 802.11D. - */ -#include -#include -#include - -#include "host.h" -#include "cmd.h" -#include "decl.h" -#include "11d.h" -#include "dev.h" -#include "wext.h" - -#define TX_PWR_DEFAULT 10 - -static struct region_code_mapping region_code_mapping[] = { - {"US ", 0x10}, /* US FCC */ - {"CA ", 0x10}, /* IC Canada */ - {"SG ", 0x10}, /* Singapore */ - {"EU ", 0x30}, /* ETSI */ - {"AU ", 0x30}, /* Australia */ - {"KR ", 0x30}, /* Republic Of Korea */ - {"ES ", 0x31}, /* Spain */ - {"FR ", 0x32}, /* France */ - {"JP ", 0x40}, /* Japan */ -}; - -/* Following 2 structure defines the supported channels */ -static struct chan_freq_power channel_freq_power_UN_BG[] = { - {1, 2412, TX_PWR_DEFAULT}, - {2, 2417, TX_PWR_DEFAULT}, - {3, 2422, TX_PWR_DEFAULT}, - {4, 2427, TX_PWR_DEFAULT}, - {5, 2432, TX_PWR_DEFAULT}, - {6, 2437, TX_PWR_DEFAULT}, - {7, 2442, TX_PWR_DEFAULT}, - {8, 2447, TX_PWR_DEFAULT}, - {9, 2452, TX_PWR_DEFAULT}, - {10, 2457, TX_PWR_DEFAULT}, - {11, 2462, TX_PWR_DEFAULT}, - {12, 2467, TX_PWR_DEFAULT}, - {13, 2472, TX_PWR_DEFAULT}, - {14, 2484, TX_PWR_DEFAULT} -}; - -static u8 lbs_region_2_code(u8 *region) -{ - u8 i; - - for (i = 0; i < COUNTRY_CODE_LEN && region[i]; i++) - region[i] = toupper(region[i]); - - for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) { - if (!memcmp(region, region_code_mapping[i].region, - COUNTRY_CODE_LEN)) - return (region_code_mapping[i].code); - } - - /* default is US */ - return (region_code_mapping[0].code); -} - -static u8 *lbs_code_2_region(u8 code) -{ - u8 i; - - for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) { - if (region_code_mapping[i].code == code) - return (region_code_mapping[i].region); - } - /* default is US */ - return (region_code_mapping[0].region); -} - -/** - * @brief This function finds the nrchan-th chan after the firstchan - * @param band band - * @param firstchan first channel number - * @param nrchan number of channels - * @return the nrchan-th chan number -*/ -static u8 lbs_get_chan_11d(u8 firstchan, u8 nrchan, u8 *chan) -/*find the nrchan-th chan after the firstchan*/ -{ - u8 i; - struct chan_freq_power *cfp; - u8 cfp_no; - - cfp = channel_freq_power_UN_BG; - cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG); - - for (i = 0; i < cfp_no; i++) { - if ((cfp + i)->channel == firstchan) { - lbs_deb_11d("firstchan found\n"); - break; - } - } - - if (i < cfp_no) { - /*if beyond the boundary */ - if (i + nrchan < cfp_no) { - *chan = (cfp + i + nrchan)->channel; - return 1; - } - } - - return 0; -} - -/** - * @brief This function Checks if chan txpwr is learned from AP/IBSS - * @param chan chan number - * @param parsed_region_chan pointer to parsed_region_chan_11d - * @return TRUE; FALSE -*/ -static u8 lbs_channel_known_11d(u8 chan, - struct parsed_region_chan_11d * parsed_region_chan) -{ - struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr; - u8 nr_chan = parsed_region_chan->nr_chan; - u8 i = 0; - - lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr, - sizeof(struct chan_power_11d) * nr_chan); - - for (i = 0; i < nr_chan; i++) { - if (chan == chanpwr[i].chan) { - lbs_deb_11d("found chan %d\n", chan); - return 1; - } - } - - lbs_deb_11d("chan %d not found\n", chan); - return 0; -} - -u32 lbs_chan_2_freq(u8 chan) -{ - struct chan_freq_power *cf; - u16 i; - u32 freq = 0; - - cf = channel_freq_power_UN_BG; - - for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) { - if (chan == cf[i].channel) - freq = cf[i].freq; - } - - return freq; -} - -static int generate_domain_info_11d(struct parsed_region_chan_11d - *parsed_region_chan, - struct lbs_802_11d_domain_reg *domaininfo) -{ - u8 nr_subband = 0; - - u8 nr_chan = parsed_region_chan->nr_chan; - u8 nr_parsedchan = 0; - - u8 firstchan = 0, nextchan = 0, maxpwr = 0; - - u8 i, flag = 0; - - memcpy(domaininfo->countrycode, parsed_region_chan->countrycode, - COUNTRY_CODE_LEN); - - lbs_deb_11d("nrchan %d\n", nr_chan); - lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan, - sizeof(struct parsed_region_chan_11d)); - - for (i = 0; i < nr_chan; i++) { - if (!flag) { - flag = 1; - nextchan = firstchan = - parsed_region_chan->chanpwr[i].chan; - maxpwr = parsed_region_chan->chanpwr[i].pwr; - nr_parsedchan = 1; - continue; - } - - if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 && - parsed_region_chan->chanpwr[i].pwr == maxpwr) { - nextchan++; - nr_parsedchan++; - } else { - domaininfo->subband[nr_subband].firstchan = firstchan; - domaininfo->subband[nr_subband].nrchan = - nr_parsedchan; - domaininfo->subband[nr_subband].maxtxpwr = maxpwr; - nr_subband++; - nextchan = firstchan = - parsed_region_chan->chanpwr[i].chan; - maxpwr = parsed_region_chan->chanpwr[i].pwr; - } - } - - if (flag) { - domaininfo->subband[nr_subband].firstchan = firstchan; - domaininfo->subband[nr_subband].nrchan = nr_parsedchan; - domaininfo->subband[nr_subband].maxtxpwr = maxpwr; - nr_subband++; - } - domaininfo->nr_subband = nr_subband; - - lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband); - lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo, - COUNTRY_CODE_LEN + 1 + - sizeof(struct ieee_subbandset) * nr_subband); - return 0; -} - -/** - * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS - * @param region_chan pointer to struct region_channel - * @param *parsed_region_chan pointer to parsed_region_chan_11d - * @return N/A -*/ -static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan, - struct parsed_region_chan_11d * - parsed_region_chan) -{ - u8 i; - struct chan_freq_power *cfp; - - if (region_chan == NULL) { - lbs_deb_11d("region_chan is NULL\n"); - return; - } - - cfp = region_chan->CFP; - if (cfp == NULL) { - lbs_deb_11d("cfp is NULL \n"); - return; - } - - parsed_region_chan->band = region_chan->band; - parsed_region_chan->region = region_chan->region; - memcpy(parsed_region_chan->countrycode, - lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN); - - lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region, - parsed_region_chan->band); - - for (i = 0; i < region_chan->nrcfp; i++, cfp++) { - parsed_region_chan->chanpwr[i].chan = cfp->channel; - parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower; - lbs_deb_11d("chan %d, pwr %d\n", - parsed_region_chan->chanpwr[i].chan, - parsed_region_chan->chanpwr[i].pwr); - } - parsed_region_chan->nr_chan = region_chan->nrcfp; - - lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan); - - return; -} - -/** - * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS - * @param region region ID - * @param band band - * @param chan chan - * @return TRUE;FALSE -*/ -static u8 lbs_region_chan_supported_11d(u8 region, u8 chan) -{ - struct chan_freq_power *cfp; - int cfp_no; - u8 idx; - int ret = 0; - - lbs_deb_enter(LBS_DEB_11D); - - cfp = lbs_get_region_cfp_table(region, &cfp_no); - if (cfp == NULL) - return 0; - - for (idx = 0; idx < cfp_no; idx++) { - if (chan == (cfp + idx)->channel) { - /* If Mrvl Chip Supported? */ - if ((cfp + idx)->unsupported) { - ret = 0; - } else { - ret = 1; - } - goto done; - } - } - - /*chan is not in the region table */ - -done: - lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret); - return ret; -} - -/** - * @brief This function checks if chan txpwr is learned from AP/IBSS - * @param chan chan number - * @param parsed_region_chan pointer to parsed_region_chan_11d - * @return 0 -*/ -static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo, - u8 band, - struct parsed_region_chan_11d *parsed_region_chan) -{ - u8 nr_subband, nrchan; - u8 lastchan, firstchan; - u8 region; - u8 curchan = 0; - - u8 idx = 0; /*chan index in parsed_region_chan */ - - u8 j, i; - - lbs_deb_enter(LBS_DEB_11D); - - /*validation Rules: - 1. valid region Code - 2. First Chan increment - 3. channel range no overlap - 4. channel is valid? - 5. channel is supported by region? - 6. Others - */ - - lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30); - - if ((*(countryinfo->countrycode)) == 0 - || (countryinfo->header.len <= COUNTRY_CODE_LEN)) { - /* No region Info or Wrong region info: treat as No 11D info */ - goto done; - } - - /*Step1: check region_code */ - parsed_region_chan->region = region = - lbs_region_2_code(countryinfo->countrycode); - - lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region); - lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode, - COUNTRY_CODE_LEN); - - parsed_region_chan->band = band; - - memcpy(parsed_region_chan->countrycode, countryinfo->countrycode, - COUNTRY_CODE_LEN); - - nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) / - sizeof(struct ieee_subbandset); - - for (j = 0, lastchan = 0; j < nr_subband; j++) { - - if (countryinfo->subband[j].firstchan <= lastchan) { - /*Step2&3. Check First Chan Num increment and no overlap */ - lbs_deb_11d("chan %d>%d, overlap\n", - countryinfo->subband[j].firstchan, lastchan); - continue; - } - - firstchan = countryinfo->subband[j].firstchan; - nrchan = countryinfo->subband[j].nrchan; - - for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) { - /*step4: channel is supported? */ - - if (!lbs_get_chan_11d(firstchan, i, &curchan)) { - /* Chan is not found in UN table */ - lbs_deb_11d("chan is not supported: %d \n", i); - break; - } - - lastchan = curchan; - - if (lbs_region_chan_supported_11d(region, curchan)) { - /*step5: Check if curchan is supported by mrvl in region */ - parsed_region_chan->chanpwr[idx].chan = curchan; - parsed_region_chan->chanpwr[idx].pwr = - countryinfo->subband[j].maxtxpwr; - idx++; - } else { - /*not supported and ignore the chan */ - lbs_deb_11d( - "i %d, chan %d unsupported in region %x, band %d\n", - i, curchan, region, band); - } - } - - /*Step6: Add other checking if any */ - - } - - parsed_region_chan->nr_chan = idx; - - lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan); - lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan, - 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx); - -done: - lbs_deb_enter(LBS_DEB_11D); - return 0; -} - -/** - * @brief This function calculates the scan type for channels - * @param chan chan number - * @param parsed_region_chan pointer to parsed_region_chan_11d - * @return PASSIVE if chan is unknown; ACTIVE if chan is known -*/ -u8 lbs_get_scan_type_11d(u8 chan, - struct parsed_region_chan_11d * parsed_region_chan) -{ - u8 scan_type = CMD_SCAN_TYPE_PASSIVE; - - lbs_deb_enter(LBS_DEB_11D); - - if (lbs_channel_known_11d(chan, parsed_region_chan)) { - lbs_deb_11d("found, do active scan\n"); - scan_type = CMD_SCAN_TYPE_ACTIVE; - } else { - lbs_deb_11d("not found, do passive scan\n"); - } - - lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type); - return scan_type; - -} - -void lbs_init_11d(struct lbs_private *priv) -{ - priv->enable11d = 0; - memset(&(priv->parsed_region_chan), 0, - sizeof(struct parsed_region_chan_11d)); - return; -} - -/** - * @brief This function sets DOMAIN INFO to FW - * @param priv pointer to struct lbs_private - * @return 0; -1 -*/ -static int set_domain_info_11d(struct lbs_private *priv) -{ - int ret; - - if (!priv->enable11d) { - lbs_deb_11d("dnld domain Info with 11d disabled\n"); - return 0; - } - - ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, 0, NULL); - if (ret) - lbs_deb_11d("fail to dnld domain info\n"); - - return ret; -} - -/** - * @brief This function setups scan channels - * @param priv pointer to struct lbs_private - * @param band band - * @return 0 -*/ -int lbs_set_universaltable(struct lbs_private *priv, u8 band) -{ - u16 size = sizeof(struct chan_freq_power); - u16 i = 0; - - memset(priv->universal_channel, 0, - sizeof(priv->universal_channel)); - - priv->universal_channel[i].nrcfp = - sizeof(channel_freq_power_UN_BG) / size; - lbs_deb_11d("BG-band nrcfp %d\n", - priv->universal_channel[i].nrcfp); - - priv->universal_channel[i].CFP = channel_freq_power_UN_BG; - priv->universal_channel[i].valid = 1; - priv->universal_channel[i].region = UNIVERSAL_REGION_CODE; - priv->universal_channel[i].band = band; - i++; - - return 0; -} - -/** - * @brief This function implements command CMD_802_11D_DOMAIN_INFO - * @param priv pointer to struct lbs_private - * @param cmd pointer to cmd buffer - * @param cmdno cmd ID - * @param cmdOption cmd action - * @return 0 -*/ -int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, - struct cmd_ds_command *cmd, u16 cmdno, - u16 cmdoption) -{ - struct cmd_ds_802_11d_domain_info *pdomaininfo = - &cmd->params.domaininfo; - struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain; - u8 nr_subband = priv->domainreg.nr_subband; - - lbs_deb_enter(LBS_DEB_11D); - - lbs_deb_11d("nr_subband=%x\n", nr_subband); - - cmd->command = cpu_to_le16(cmdno); - pdomaininfo->action = cpu_to_le16(cmdoption); - if (cmdoption == CMD_ACT_GET) { - cmd->size = - cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); - lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, - le16_to_cpu(cmd->size)); - goto done; - } - - domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN); - memcpy(domain->countrycode, priv->domainreg.countrycode, - sizeof(domain->countrycode)); - - domain->header.len = - cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) + - sizeof(domain->countrycode)); - - if (nr_subband) { - memcpy(domain->subband, priv->domainreg.subband, - nr_subband * sizeof(struct ieee_subbandset)); - - cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + - le16_to_cpu(domain->header.len) + - sizeof(struct mrvl_ie_header) + - S_DS_GEN); - } else { - cmd->size = - cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); - } - - lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size)); - -done: - lbs_deb_enter(LBS_DEB_11D); - return 0; -} - -/** - * @brief This function parses countryinfo from AP and download country info to FW - * @param priv pointer to struct lbs_private - * @param resp pointer to command response buffer - * @return 0; -1 - */ -int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp; - struct mrvl_ie_domain_param_set *domain = &domaininfo->domain; - u16 action = le16_to_cpu(domaininfo->action); - s16 ret = 0; - u8 nr_subband = 0; - - lbs_deb_enter(LBS_DEB_11D); - - lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp, - (int)le16_to_cpu(resp->size)); - - nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) / - sizeof(struct ieee_subbandset); - - lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband); - - if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) { - lbs_deb_11d("Invalid Numrer of Subband returned!!\n"); - return -1; - } - - switch (action) { - case CMD_ACT_SET: /*Proc Set action */ - break; - - case CMD_ACT_GET: - break; - default: - lbs_deb_11d("Invalid action:%d\n", domaininfo->action); - ret = -1; - break; - } - - lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret); - return ret; -} - -/** - * @brief This function parses countryinfo from AP and download country info to FW - * @param priv pointer to struct lbs_private - * @return 0; -1 - */ -int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv, - struct bss_descriptor * bss) -{ - int ret; - - lbs_deb_enter(LBS_DEB_11D); - if (priv->enable11d) { - memset(&priv->parsed_region_chan, 0, - sizeof(struct parsed_region_chan_11d)); - ret = parse_domain_info_11d(&bss->countryinfo, 0, - &priv->parsed_region_chan); - - if (ret == -1) { - lbs_deb_11d("error parsing domain_info from AP\n"); - goto done; - } - - memset(&priv->domainreg, 0, - sizeof(struct lbs_802_11d_domain_reg)); - generate_domain_info_11d(&priv->parsed_region_chan, - &priv->domainreg); - - ret = set_domain_info_11d(priv); - - if (ret) { - lbs_deb_11d("error setting domain info\n"); - goto done; - } - } - ret = 0; - -done: - lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret); - return ret; -} - -/** - * @brief This function generates 11D info from user specified regioncode and download to FW - * @param priv pointer to struct lbs_private - * @return 0; -1 - */ -int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv) -{ - int ret; - struct region_channel *region_chan; - u8 j; - - lbs_deb_enter(LBS_DEB_11D); - lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band); - - if (priv->enable11d) { - /* update parsed_region_chan_11; dnld domaininf to FW */ - - for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) { - region_chan = &priv->region_channel[j]; - - lbs_deb_11d("%d region_chan->band %d\n", j, - region_chan->band); - - if (!region_chan || !region_chan->valid - || !region_chan->CFP) - continue; - if (region_chan->band != priv->curbssparams.band) - continue; - break; - } - - if (j >= ARRAY_SIZE(priv->region_channel)) { - lbs_deb_11d("region_chan not found, band %d\n", - priv->curbssparams.band); - ret = -1; - goto done; - } - - memset(&priv->parsed_region_chan, 0, - sizeof(struct parsed_region_chan_11d)); - lbs_generate_parsed_region_chan_11d(region_chan, - &priv-> - parsed_region_chan); - - memset(&priv->domainreg, 0, - sizeof(struct lbs_802_11d_domain_reg)); - generate_domain_info_11d(&priv->parsed_region_chan, - &priv->domainreg); - - ret = set_domain_info_11d(priv); - - if (ret) { - lbs_deb_11d("error setting domain info\n"); - goto done; - } - - } - ret = 0; - -done: - lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret); - return ret; -} diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h index fb75d3e321a0..a46ae500b250 100644 --- a/drivers/net/wireless/libertas/11d.h +++ b/drivers/net/wireless/libertas/11d.h @@ -79,27 +79,4 @@ struct region_code_mapping { u8 code; }; -struct lbs_private; - -u8 lbs_get_scan_type_11d(u8 chan, - struct parsed_region_chan_11d *parsed_region_chan); - -u32 lbs_chan_2_freq(u8 chan); - -void lbs_init_11d(struct lbs_private *priv); - -int lbs_set_universaltable(struct lbs_private *priv, u8 band); - -int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, - struct cmd_ds_command *cmd, u16 cmdno, - u16 cmdOption); - -int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp); - -struct bss_descriptor; -int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv, - struct bss_descriptor * bss); - -int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv); - #endif diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index e5584dd1c79a..fa37039e0eae 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -1,4 +1,3 @@ -libertas-y += 11d.o libertas-y += assoc.o libertas-y += cfg.o libertas-y += cmd.o diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index dd8732611ba9..f7161b5e070a 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -371,11 +371,6 @@ static int lbs_associate(struct lbs_private *priv, /* update curbssparams */ priv->curbssparams.channel = bss->phy.ds.channel; - if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { - ret = -1; - goto done; - } - ret = lbs_cmd_with_response(priv, command, &cmd); if (ret == 0) { ret = lbs_assoc_post(priv, @@ -633,11 +628,6 @@ static int lbs_adhoc_join(struct lbs_private *priv, } } - if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { - ret = -1; - goto out; - } - ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); if (ret == 0) { ret = lbs_adhoc_post(priv, @@ -737,12 +727,6 @@ static int lbs_adhoc_start(struct lbs_private *priv, lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n", cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]); - if (lbs_create_dnld_countryinfo_11d(priv)) { - lbs_deb_join("ADHOC_START: dnld_countryinfo_11d failed\n"); - ret = -1; - goto out; - } - lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n", assoc_req->channel, assoc_req->band); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 8841a0ecf3b8..4729895c6d0c 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -190,11 +190,6 @@ int lbs_update_hw_spec(struct lbs_private *priv) goto out; } - if (lbs_set_universaltable(priv, 0)) { - ret = -1; - goto out; - } - out: lbs_deb_leave(LBS_DEB_CMD); return ret; @@ -1511,11 +1506,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = 0; goto done; - case CMD_802_11D_DOMAIN_INFO: - ret = lbs_cmd_802_11d_domain_info(priv, cmdptr, - cmd_no, cmd_action); - break; - case CMD_802_11_TPC_CFG: cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); cmdptr->size = diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index a45061b1f33c..384fc6187d85 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -228,10 +228,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_802_11_rssi(priv, resp); break; - case CMD_RET(CMD_802_11D_DOMAIN_INFO): - ret = lbs_ret_802_11d_domain_info(resp); - break; - case CMD_RET(CMD_802_11_TPC_CFG): spin_lock_irqsave(&priv->driver_lock, flags); memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg, diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 191ea33de509..968acdb53f56 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -325,15 +325,6 @@ struct lbs_private { /** region channel data */ struct region_channel region_channel[MAX_REGION_CHANNEL_NUM]; - struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM]; - - /** 11D and Domain Regulatory Data */ - struct lbs_802_11d_domain_reg domainreg; - struct parsed_region_chan_11d parsed_region_chan; - - /** FSM variable for 11d support */ - u32 enable11d; - /** MISCELLANEOUS */ struct lbs_offset_value offsetvalue; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index b7363236cc53..2f87659cc1d3 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1408,9 +1408,6 @@ int lbs_start_card(struct lbs_private *priv) if (ret) goto done; - /* init 802.11d */ - lbs_init_11d(priv); - if (lbs_cfg_register(priv)) { lbs_pr_err("cannot register device\n"); goto done; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index d8fc2b8b3027..584ff76bcf82 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -161,31 +161,15 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, scantype = CMD_SCAN_TYPE_ACTIVE; for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { - if (priv->enable11d && (priv->connect_status != LBS_CONNECTED) - && (priv->mesh_connect_status != LBS_CONNECTED)) { - /* Scan all the supported chan for the first scan */ - if (!priv->universal_channel[rgnidx].valid) - continue; - scanregion = &priv->universal_channel[rgnidx]; - - /* clear the parsed_region_chan for the first scan */ - memset(&priv->parsed_region_chan, 0x00, - sizeof(priv->parsed_region_chan)); - } else { - if (!priv->region_channel[rgnidx].valid) - continue; - scanregion = &priv->region_channel[rgnidx]; - } + if (!priv->region_channel[rgnidx].valid) + continue; + scanregion = &priv->region_channel[rgnidx]; for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) { struct chanscanparamset *chan = &scanchanlist[chanidx]; cfp = scanregion->CFP + nextchan; - if (priv->enable11d) - scantype = lbs_get_scan_type_11d(cfp->channel, - &priv->parsed_region_chan); - if (scanregion->band == BAND_B || scanregion->band == BAND_G) chan->radiotype = CMD_SCAN_RADIO_TYPE_BG; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 4594841cd4af..82a932aef6f9 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -65,8 +65,6 @@ struct chan_freq_power *lbs_find_cfp_by_band_and_channel( for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) { rc = &priv->region_channel[j]; - if (priv->enable11d) - rc = &priv->universal_channel[j]; if (!rc->valid || !rc->CFP) continue; if (rc->band != band) @@ -106,8 +104,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq( for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) { rc = &priv->region_channel[j]; - if (priv->enable11d) - rc = &priv->universal_channel[j]; if (!rc->valid || !rc->CFP) continue; if (rc->band != band) @@ -546,8 +542,6 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, struct chan_freq_power *cfp; u8 rates[MAX_RATES + 1]; - u8 flag = 0; - lbs_deb_enter(LBS_DEB_WEXT); dwrq->length = sizeof(struct iw_range); @@ -569,52 +563,21 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, range->scan_capa = IW_SCAN_CAPA_ESSID; - if (priv->enable11d && - (priv->connect_status == LBS_CONNECTED || - priv->mesh_connect_status == LBS_CONNECTED)) { - u8 chan_no; - u8 band; - - struct parsed_region_chan_11d *parsed_region_chan = - &priv->parsed_region_chan; - - if (parsed_region_chan == NULL) { - lbs_deb_wext("11d: parsed_region_chan is NULL\n"); - goto out; - } - band = parsed_region_chan->band; - lbs_deb_wext("band %d, nr_char %d\n", band, - parsed_region_chan->nr_chan); - + for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES) + && (j < ARRAY_SIZE(priv->region_channel)); j++) { + cfp = priv->region_channel[j].CFP; for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) - && (i < parsed_region_chan->nr_chan); i++) { - chan_no = parsed_region_chan->chanpwr[i].chan; - lbs_deb_wext("chan_no %d\n", chan_no); - range->freq[range->num_frequency].i = (long)chan_no; + && priv->region_channel[j].valid + && cfp + && (i < priv->region_channel[j].nrcfp); i++) { + range->freq[range->num_frequency].i = + (long)cfp->channel; range->freq[range->num_frequency].m = - (long)lbs_chan_2_freq(chan_no) * 100000; + (long)cfp->freq * 100000; range->freq[range->num_frequency].e = 1; + cfp++; range->num_frequency++; } - flag = 1; - } - if (!flag) { - for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES) - && (j < ARRAY_SIZE(priv->region_channel)); j++) { - cfp = priv->region_channel[j].CFP; - for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) - && priv->region_channel[j].valid - && cfp - && (i < priv->region_channel[j].nrcfp); i++) { - range->freq[range->num_frequency].i = - (long)cfp->channel; - range->freq[range->num_frequency].m = - (long)cfp->freq * 100000; - range->freq[range->num_frequency].e = 1; - cfp++; - range->num_frequency++; - } - } } lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n", @@ -699,7 +662,6 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, | IW_ENC_CAPA_CIPHER_CCMP; } -out: lbs_deb_leave(LBS_DEB_WEXT); return 0; } -- cgit v1.2.3 From f4228b4c2e5864ee9d2051176beb2bd5a49a15cc Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:46 +0200 Subject: libertas: remove unused 11d.h as well, priv->countryinfo Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/11d.h | 82 ------------------------------------ drivers/net/wireless/libertas/dev.h | 2 - drivers/net/wireless/libertas/host.h | 6 +-- drivers/net/wireless/libertas/scan.c | 21 --------- 4 files changed, 2 insertions(+), 109 deletions(-) delete mode 100644 drivers/net/wireless/libertas/11d.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h deleted file mode 100644 index a46ae500b250..000000000000 --- a/drivers/net/wireless/libertas/11d.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * This header file contains data structures and - * function declarations of 802.11d - */ -#ifndef _LBS_11D_ -#define _LBS_11D_ - -#include "types.h" -#include "defs.h" - -#define UNIVERSAL_REGION_CODE 0xff - -/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr) - */ -#define MRVDRV_MAX_SUBBAND_802_11D 83 - -#define COUNTRY_CODE_LEN 3 -#define MAX_NO_OF_CHAN 40 - -struct cmd_ds_command; - -/** Data structure for Country IE*/ -struct ieee_subbandset { - u8 firstchan; - u8 nrchan; - u8 maxtxpwr; -} __attribute__ ((packed)); - -struct ieee_ie_country_info_set { - struct ieee_ie_header header; - - u8 countrycode[COUNTRY_CODE_LEN]; - struct ieee_subbandset subband[1]; -}; - -struct ieee_ie_country_info_full_set { - struct ieee_ie_header header; - - u8 countrycode[COUNTRY_CODE_LEN]; - struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; -} __attribute__ ((packed)); - -struct mrvl_ie_domain_param_set { - struct mrvl_ie_header header; - - u8 countrycode[COUNTRY_CODE_LEN]; - struct ieee_subbandset subband[1]; -} __attribute__ ((packed)); - -struct cmd_ds_802_11d_domain_info { - __le16 action; - struct mrvl_ie_domain_param_set domain; -} __attribute__ ((packed)); - -/** domain regulatory information */ -struct lbs_802_11d_domain_reg { - /** country Code*/ - u8 countrycode[COUNTRY_CODE_LEN]; - /** No. of subband*/ - u8 nr_subband; - struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; -}; - -struct chan_power_11d { - u8 chan; - u8 pwr; -} __attribute__ ((packed)); - -struct parsed_region_chan_11d { - u8 band; - u8 region; - s8 countrycode[COUNTRY_CODE_LEN]; - struct chan_power_11d chanpwr[MAX_NO_OF_CHAN]; - u8 nr_chan; -} __attribute__ ((packed)); - -struct region_code_mapping { - u8 region[COUNTRY_CODE_LEN]; - u8 code; -}; - -#endif diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 968acdb53f56..52b5ca1cd57e 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -360,8 +360,6 @@ struct bss_descriptor { union ieee_phy_param_set phy; union ieee_ss_param_set ss; - struct ieee_ie_country_info_full_set countryinfo; - u8 wpa_ie[MAX_WPA_IE_LEN]; size_t wpa_ie_len; u8 rsn_ie[MAX_WPA_IE_LEN]; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 25342743b1f7..d2a8d04d2b45 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -6,7 +6,8 @@ #ifndef _LBS_HOST_H_ #define _LBS_HOST_H_ -#include "11d.h" +#include "types.h" +#include "defs.h" #define DEFAULT_AD_HOC_CHANNEL 6 @@ -961,9 +962,6 @@ struct cmd_ds_command { struct cmd_ds_bbp_reg_access bbpreg; struct cmd_ds_rf_reg_access rfreg; - struct cmd_ds_802_11d_domain_info domaininfo; - struct cmd_ds_802_11d_domain_info domaininforesp; - struct cmd_ds_802_11_tpc_cfg tpccfg; struct cmd_ds_802_11_afc afc; struct cmd_ds_802_11_led_ctrl ledgpio; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 584ff76bcf82..64b404783f44 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -503,7 +503,6 @@ static int lbs_process_bss(struct bss_descriptor *bss, struct ieee_ie_cf_param_set *cf; struct ieee_ie_ibss_param_set *ibss; DECLARE_SSID_BUF(ssid); - struct ieee_ie_country_info_set *pcountryinfo; uint8_t *pos, *end, *p; uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; uint16_t beaconsize = 0; @@ -626,26 +625,6 @@ static int lbs_process_bss(struct bss_descriptor *bss, lbs_deb_scan("got IBSS IE\n"); break; - case WLAN_EID_COUNTRY: - pcountryinfo = (struct ieee_ie_country_info_set *) pos; - lbs_deb_scan("got COUNTRY IE\n"); - if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode) - || pcountryinfo->header.len > 254) { - lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n", - __func__, - pcountryinfo->header.len, - sizeof(pcountryinfo->countrycode)); - ret = -1; - goto done; - } - - memcpy(&bss->countryinfo, pcountryinfo, - pcountryinfo->header.len + 2); - lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", - (uint8_t *) pcountryinfo, - (int) (pcountryinfo->header.len + 2)); - break; - case WLAN_EID_EXT_SUPP_RATES: /* only process extended supported rate if data rate is * already found. Data rate IE should come before -- cgit v1.2.3 From 243e84e91ed810f7dca5ba1c2d1a611811948566 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:47 +0200 Subject: libertas: change IW_ESSID_MAX_SIZE -> IEEE80211_MAX_SSID_LEN Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 10 +++++----- drivers/net/wireless/libertas/cmd.c | 2 +- drivers/net/wireless/libertas/cmdresp.c | 2 +- drivers/net/wireless/libertas/dev.h | 10 +++++----- drivers/net/wireless/libertas/host.h | 4 ++-- drivers/net/wireless/libertas/persistcfg.c | 8 ++++---- drivers/net/wireless/libertas/scan.c | 6 +++--- drivers/net/wireless/libertas/types.h | 4 ++-- drivers/net/wireless/libertas/wext.c | 8 ++++---- 9 files changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index f7161b5e070a..5a280ebadba4 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -226,7 +226,7 @@ static int lbs_assoc_post(struct lbs_private *priv, priv->connect_status = LBS_CONNECTED; /* Update current SSID and BSSID */ - memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN); priv->curbssparams.ssid_len = bss->ssid_len; memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); @@ -467,7 +467,7 @@ static int lbs_adhoc_post(struct lbs_private *priv, memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); /* Set the new SSID to current SSID */ - memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN); priv->curbssparams.ssid_len = bss->ssid_len; netif_carrier_on(priv->dev); @@ -1083,7 +1083,7 @@ static int assoc_helper_essid(struct lbs_private *priv, /* else send START command */ lbs_deb_assoc("SSID not found, creating adhoc network\n"); memcpy(&assoc_req->bss.ssid, &assoc_req->ssid, - IW_ESSID_MAX_SIZE); + IEEE80211_MAX_SSID_LEN); assoc_req->bss.ssid_len = assoc_req->ssid_len; lbs_adhoc_start(priv, assoc_req); } @@ -1541,7 +1541,7 @@ static int lbs_find_best_network_ssid(struct lbs_private *priv, found = lbs_find_best_ssid_in_list(priv, preferred_mode); if (found && (found->ssid_len > 0)) { - memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE); + memcpy(out_ssid, &found->ssid, IEEE80211_MAX_SSID_LEN); *out_ssid_len = found->ssid_len; *out_mode = found->mode; ret = 0; @@ -1759,7 +1759,7 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv) assoc_req = priv->pending_assoc_req; if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { memcpy(&assoc_req->ssid, &priv->curbssparams.ssid, - IW_ESSID_MAX_SIZE); + IEEE80211_MAX_SSID_LEN); assoc_req->ssid_len = priv->curbssparams.ssid_len; } diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 4729895c6d0c..dd4f98231352 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1167,7 +1167,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) ie->val.mesh_id_len = priv->mesh_ssid_len; memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len); ie->len = sizeof(struct mrvl_meshie_val) - - IW_ESSID_MAX_SIZE + priv->mesh_ssid_len; + IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len; cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val)); break; case CMD_ACT_MESH_CONFIG_STOP: diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 384fc6187d85..6e2103885959 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -68,7 +68,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv) * no longer valid. */ memset(&priv->curbssparams.bssid, 0, ETH_ALEN); - memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE); + memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN); priv->curbssparams.ssid_len = 0; if (priv->psstate != PS_STATE_FULL_POWER) { diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 52b5ca1cd57e..50b457706bad 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -65,7 +65,7 @@ struct current_bss_params { /** bssid */ u8 bssid[ETH_ALEN]; /** ssid */ - u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 ssid_len; /** band */ @@ -163,7 +163,7 @@ struct lbs_private { struct work_struct sync_channel; /* remember which channel was scanned last, != 0 if currently scanning */ int scan_channel; - u8 scan_ssid[IW_ESSID_MAX_SIZE + 1]; + u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 scan_ssid_len; /** Hardware access */ @@ -230,7 +230,7 @@ struct lbs_private { struct current_bss_params curbssparams; uint16_t mesh_tlv; - u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1]; + u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 mesh_ssid_len; /* IW_MODE_* */ @@ -340,7 +340,7 @@ extern struct cmd_confirm_sleep confirm_sleep; struct bss_descriptor { u8 bssid[ETH_ALEN]; - u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 ssid_len; u16 capability; @@ -389,7 +389,7 @@ struct assoc_request { #define ASSOC_FLAG_WPA_IE 11 unsigned long flags; - u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 ssid_len; u8 channel; u8 band; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index d2a8d04d2b45..d4b875445f59 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -719,7 +719,7 @@ struct cmd_ds_802_11_rate_adapt_rateset { struct cmd_ds_802_11_ad_hoc_start { struct cmd_header hdr; - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 bsstype; __le16 beaconperiod; u8 dtimperiod; /* Reserved on v9 and later */ @@ -742,7 +742,7 @@ struct cmd_ds_802_11_ad_hoc_result { struct adhoc_bssdesc { u8 bssid[ETH_ALEN]; - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 type; __le16 beaconperiod; u8 dtimperiod; diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c index 18fe29faf99b..871f914a75fc 100644 --- a/drivers/net/wireless/libertas/persistcfg.c +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -187,9 +187,9 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, if (ret) return ret; - if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) { + if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) { lbs_pr_err("inconsistent mesh ID length"); - defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE; + defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN; } /* SSID not null terminated: reserve room for \0 + \n */ @@ -214,7 +214,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, int len; int ret; - if (count < 2 || count > IW_ESSID_MAX_SIZE + 1) + if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1) return -EINVAL; memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); @@ -233,7 +233,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, /* SSID len */ ie->val.mesh_id_len = len; /* IE len */ - ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; + ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len; ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, CMD_TYPE_MESH_SET_MESH_IE); diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 64b404783f44..2700f4b455e3 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -19,11 +19,11 @@ //! Approximate amount of data needed to pass a scan result back to iwlist #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ - + IW_ESSID_MAX_SIZE \ + + IEEE80211_MAX_SSID_LEN \ + IW_EV_UINT_LEN \ + IW_EV_FREQ_LEN \ + IW_EV_QUAL_LEN \ - + IW_ESSID_MAX_SIZE \ + + IEEE80211_MAX_SSID_LEN \ + IW_EV_PARAM_LEN \ + 40) /* 40 for WPAIE */ @@ -775,7 +775,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, /* SSID */ iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; - iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE); + iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN); start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); /* Mode */ diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 99905df65b25..3e72c86ceca8 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -5,8 +5,8 @@ #define _LBS_TYPES_H_ #include +#include #include -#include struct ieee_ie_header { u8 id; @@ -247,7 +247,7 @@ struct mrvl_meshie_val { uint8_t active_metric_id; uint8_t mesh_capability; uint8_t mesh_id_len; - uint8_t mesh_id[IW_ESSID_MAX_SIZE]; + uint8_t mesh_id[IEEE80211_MAX_SSID_LEN]; } __attribute__ ((packed)); struct mrvl_meshie { diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 82a932aef6f9..3e8be9a578e8 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1989,7 +1989,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, { struct lbs_private *priv = dev->ml_priv; int ret = 0; - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len = 0; struct assoc_request * assoc_req; int in_ssid_len = dwrq->length; @@ -2003,7 +2003,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, } /* Check the size of the string */ - if (in_ssid_len > IW_ESSID_MAX_SIZE) { + if (in_ssid_len > IEEE80211_MAX_SSID_LEN) { ret = -E2BIG; goto out; } @@ -2034,7 +2034,7 @@ out: ret = -ENOMEM; } else { /* Copy the SSID to the association request */ - memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE); + memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN); assoc_req->ssid_len = ssid_len; set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); lbs_postpone_association_work(priv); @@ -2085,7 +2085,7 @@ static int lbs_mesh_set_essid(struct net_device *dev, } /* Check the size of the string */ - if (dwrq->length > IW_ESSID_MAX_SIZE) { + if (dwrq->length > IEEE80211_MAX_SSID_LEN) { ret = -E2BIG; goto out; } -- cgit v1.2.3 From 2d46502dce3c79c3c15ac537cb271911f58d12d1 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:48 +0200 Subject: libertas: move scan/assoc related stuff Another cfg80211-preparation patch: removes some code/definitions from main.c and dev.h and put's it into assoc.c/.h, scan.c/.h. No function change. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 7 ++ drivers/net/wireless/libertas/assoc.h | 122 +++++++++++++++++++++- drivers/net/wireless/libertas/cmd.c | 1 + drivers/net/wireless/libertas/decl.h | 6 +- drivers/net/wireless/libertas/defs.h | 1 - drivers/net/wireless/libertas/dev.h | 155 +--------------------------- drivers/net/wireless/libertas/main.c | 182 --------------------------------- drivers/net/wireless/libertas/scan.c | 184 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/libertas/scan.h | 30 ++++++ 9 files changed, 348 insertions(+), 340 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 5a280ebadba4..2ccfeca32cde 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -23,6 +23,13 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = */ #define CAPINFO_MASK (~(0xda00)) +/** + * 802.11b/g supported bitrates (in 500Kb/s units) + */ +u8 lbs_bg_rates[MAX_RATES] = + { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, +0x00, 0x00 }; + /** * @brief This function finds common rates between rates and card rates. diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index 6e765e9f91a3..610d14c14cd4 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -3,7 +3,127 @@ #ifndef _LBS_ASSOC_H_ #define _LBS_ASSOC_H_ -#include "dev.h" + +#include "defs.h" +#include "host.h" + + +struct lbs_private; + +/* + * In theory, the IE is limited to the IE length, 255, + * but in practice 64 bytes are enough. + */ +#define MAX_WPA_IE_LEN 64 + + + +struct lbs_802_11_security { + u8 WPAenabled; + u8 WPA2enabled; + u8 wep_enabled; + u8 auth_mode; + u32 key_mgmt; +}; + +/** Current Basic Service Set State Structure */ +struct current_bss_params { + /** bssid */ + u8 bssid[ETH_ALEN]; + /** ssid */ + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; + u8 ssid_len; + + /** band */ + u8 band; + /** channel */ + u8 channel; + /** zero-terminated array of supported data rates */ + u8 rates[MAX_RATES + 1]; +}; + +/** + * @brief Structure used to store information for each beacon/probe response + */ +struct bss_descriptor { + u8 bssid[ETH_ALEN]; + + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; + u8 ssid_len; + + u16 capability; + u32 rssi; + u32 channel; + u16 beaconperiod; + __le16 atimwindow; + + /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ + u8 mode; + + /* zero-terminated array of supported data rates */ + u8 rates[MAX_RATES + 1]; + + unsigned long last_scanned; + + union ieee_phy_param_set phy; + union ieee_ss_param_set ss; + + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + u8 rsn_ie[MAX_WPA_IE_LEN]; + size_t rsn_ie_len; + + u8 mesh; + + struct list_head list; +}; + +/** Association request + * + * Encapsulates all the options that describe a specific assocation request + * or configuration of the wireless card's radio, mode, and security settings. + */ +struct assoc_request { +#define ASSOC_FLAG_SSID 1 +#define ASSOC_FLAG_CHANNEL 2 +#define ASSOC_FLAG_BAND 3 +#define ASSOC_FLAG_MODE 4 +#define ASSOC_FLAG_BSSID 5 +#define ASSOC_FLAG_WEP_KEYS 6 +#define ASSOC_FLAG_WEP_TX_KEYIDX 7 +#define ASSOC_FLAG_WPA_MCAST_KEY 8 +#define ASSOC_FLAG_WPA_UCAST_KEY 9 +#define ASSOC_FLAG_SECINFO 10 +#define ASSOC_FLAG_WPA_IE 11 + unsigned long flags; + + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; + u8 ssid_len; + u8 channel; + u8 band; + u8 mode; + u8 bssid[ETH_ALEN] __attribute__ ((aligned (2))); + + /** WEP keys */ + struct enc_key wep_keys[4]; + u16 wep_tx_keyidx; + + /** WPA keys */ + struct enc_key wpa_mcast_key; + struct enc_key wpa_unicast_key; + + struct lbs_802_11_security secinfo; + + /** WPA Information Elements*/ + u8 wpa_ie[MAX_WPA_IE_LEN]; + u8 wpa_ie_len; + + /* BSS to associate with for infrastructure of Ad-Hoc join */ + struct bss_descriptor bss; +}; + + +extern u8 lbs_bg_rates[MAX_RATES]; void lbs_association_worker(struct work_struct *work); struct assoc_request *lbs_get_association_request(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index dd4f98231352..ec65be0c4d93 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -12,6 +12,7 @@ #include "dev.h" #include "assoc.h" #include "wext.h" +#include "scan.h" #include "cmd.h" static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 20fa8176cd88..7d8323876c52 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -10,6 +10,9 @@ #include "defs.h" + +extern const struct ethtool_ops lbs_ethtool_ops; + /** Function Prototype Declaration */ struct lbs_private; struct sk_buff; @@ -33,7 +36,6 @@ u8 lbs_data_rate_to_fw_index(u32 rate); /** The proc fs interface */ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); -int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band); int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *); @@ -49,8 +51,6 @@ void lbs_persist_config_init(struct net_device *net); void lbs_persist_config_remove(struct net_device *net); /* main.c */ -struct chan_freq_power *lbs_get_region_cfp_table(u8 region, - int *cfp_no); struct lbs_private *lbs_add_card(void *card, struct device *dmdev); void lbs_remove_card(struct lbs_private *priv); int lbs_start_card(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 1cf5d5985dac..6b6ea9f7bf5b 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -322,7 +322,6 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in extern const char lbs_driver_version[]; extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE]; -extern u8 lbs_bg_rates[MAX_RATES]; /** ENUM definition*/ /** SNRNF_TYPE */ diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 50b457706bad..cc245820d3f2 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -6,75 +6,10 @@ #ifndef _LBS_DEV_H_ #define _LBS_DEV_H_ -#include -#include -#include -#include +#include "scan.h" +#include "assoc.h" -#include "defs.h" -#include "host.h" -extern const struct ethtool_ops lbs_ethtool_ops; - -#define MAX_BSSID_PER_CHANNEL 16 - -#define NR_TX_QUEUE 3 - -/* For the extended Scan */ -#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \ - MRVDRV_MAX_CHANNEL_SIZE + 1 - -#define MAX_REGION_CHANNEL_NUM 2 - -/** Chan-freq-TxPower mapping table*/ -struct chan_freq_power { - /** channel Number */ - u16 channel; - /** frequency of this channel */ - u32 freq; - /** Max allowed Tx power level */ - u16 maxtxpower; - /** TRUE:channel unsupported; FLASE:supported*/ - u8 unsupported; -}; - -/** region-band mapping table*/ -struct region_channel { - /** TRUE if this entry is valid */ - u8 valid; - /** region code for US, Japan ... */ - u8 region; - /** band B/G/A, used for BAND_CONFIG cmd */ - u8 band; - /** Actual No. of elements in the array below */ - u8 nrcfp; - /** chan-freq-txpower mapping table*/ - struct chan_freq_power *CFP; -}; - -struct lbs_802_11_security { - u8 WPAenabled; - u8 WPA2enabled; - u8 wep_enabled; - u8 auth_mode; - u32 key_mgmt; -}; - -/** Current Basic Service Set State Structure */ -struct current_bss_params { - /** bssid */ - u8 bssid[ETH_ALEN]; - /** ssid */ - u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; - u8 ssid_len; - - /** band */ - u8 band; - /** channel */ - u8 channel; - /** zero-terminated array of supported data rates */ - u8 rates[MAX_RATES + 1]; -}; /** sleep_params */ struct sleep_params { @@ -295,12 +230,6 @@ struct lbs_private { struct enc_key wpa_mcast_key; struct enc_key wpa_unicast_key; -/* - * In theory, the IE is limited to the IE length, 255, - * but in practice 64 bytes are enough. - */ -#define MAX_WPA_IE_LEN 64 - /** WPA Information Elements*/ u8 wpa_ie[MAX_WPA_IE_LEN]; u8 wpa_ie_len; @@ -334,84 +263,4 @@ struct lbs_private { extern struct cmd_confirm_sleep confirm_sleep; -/** - * @brief Structure used to store information for each beacon/probe response - */ -struct bss_descriptor { - u8 bssid[ETH_ALEN]; - - u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; - u8 ssid_len; - - u16 capability; - u32 rssi; - u32 channel; - u16 beaconperiod; - __le16 atimwindow; - - /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ - u8 mode; - - /* zero-terminated array of supported data rates */ - u8 rates[MAX_RATES + 1]; - - unsigned long last_scanned; - - union ieee_phy_param_set phy; - union ieee_ss_param_set ss; - - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - u8 rsn_ie[MAX_WPA_IE_LEN]; - size_t rsn_ie_len; - - u8 mesh; - - struct list_head list; -}; - -/** Association request - * - * Encapsulates all the options that describe a specific assocation request - * or configuration of the wireless card's radio, mode, and security settings. - */ -struct assoc_request { -#define ASSOC_FLAG_SSID 1 -#define ASSOC_FLAG_CHANNEL 2 -#define ASSOC_FLAG_BAND 3 -#define ASSOC_FLAG_MODE 4 -#define ASSOC_FLAG_BSSID 5 -#define ASSOC_FLAG_WEP_KEYS 6 -#define ASSOC_FLAG_WEP_TX_KEYIDX 7 -#define ASSOC_FLAG_WPA_MCAST_KEY 8 -#define ASSOC_FLAG_WPA_UCAST_KEY 9 -#define ASSOC_FLAG_SECINFO 10 -#define ASSOC_FLAG_WPA_IE 11 - unsigned long flags; - - u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; - u8 ssid_len; - u8 channel; - u8 band; - u8 mode; - u8 bssid[ETH_ALEN] __attribute__ ((aligned (2))); - - /** WEP keys */ - struct enc_key wep_keys[4]; - u16 wep_tx_keyidx; - - /** WPA keys */ - struct enc_key wpa_mcast_key; - struct enc_key wpa_unicast_key; - - struct lbs_802_11_security secinfo; - - /** WPA Information Elements*/ - u8 wpa_ie[MAX_WPA_IE_LEN]; - u8 wpa_ie_len; - - /* BSS to associate with for infrastructure of Ad-Hoc join */ - struct bss_descriptor bss; -}; - #endif diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 2f87659cc1d3..ee0893334553 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -45,132 +45,12 @@ module_param_named(libertas_debug, lbs_debug, int, 0644); struct cmd_confirm_sleep confirm_sleep; -#define LBS_TX_PWR_DEFAULT 20 /*100mW */ -#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */ -#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */ -#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */ -#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */ - -/* Format { channel, frequency (MHz), maxtxpower } */ -/* band: 'B/G', region: USA FCC/Canada IC */ -static struct chan_freq_power channel_freq_power_US_BG[] = { - {1, 2412, LBS_TX_PWR_US_DEFAULT}, - {2, 2417, LBS_TX_PWR_US_DEFAULT}, - {3, 2422, LBS_TX_PWR_US_DEFAULT}, - {4, 2427, LBS_TX_PWR_US_DEFAULT}, - {5, 2432, LBS_TX_PWR_US_DEFAULT}, - {6, 2437, LBS_TX_PWR_US_DEFAULT}, - {7, 2442, LBS_TX_PWR_US_DEFAULT}, - {8, 2447, LBS_TX_PWR_US_DEFAULT}, - {9, 2452, LBS_TX_PWR_US_DEFAULT}, - {10, 2457, LBS_TX_PWR_US_DEFAULT}, - {11, 2462, LBS_TX_PWR_US_DEFAULT} -}; - -/* band: 'B/G', region: Europe ETSI */ -static struct chan_freq_power channel_freq_power_EU_BG[] = { - {1, 2412, LBS_TX_PWR_EMEA_DEFAULT}, - {2, 2417, LBS_TX_PWR_EMEA_DEFAULT}, - {3, 2422, LBS_TX_PWR_EMEA_DEFAULT}, - {4, 2427, LBS_TX_PWR_EMEA_DEFAULT}, - {5, 2432, LBS_TX_PWR_EMEA_DEFAULT}, - {6, 2437, LBS_TX_PWR_EMEA_DEFAULT}, - {7, 2442, LBS_TX_PWR_EMEA_DEFAULT}, - {8, 2447, LBS_TX_PWR_EMEA_DEFAULT}, - {9, 2452, LBS_TX_PWR_EMEA_DEFAULT}, - {10, 2457, LBS_TX_PWR_EMEA_DEFAULT}, - {11, 2462, LBS_TX_PWR_EMEA_DEFAULT}, - {12, 2467, LBS_TX_PWR_EMEA_DEFAULT}, - {13, 2472, LBS_TX_PWR_EMEA_DEFAULT} -}; - -/* band: 'B/G', region: Spain */ -static struct chan_freq_power channel_freq_power_SPN_BG[] = { - {10, 2457, LBS_TX_PWR_DEFAULT}, - {11, 2462, LBS_TX_PWR_DEFAULT} -}; - -/* band: 'B/G', region: France */ -static struct chan_freq_power channel_freq_power_FR_BG[] = { - {10, 2457, LBS_TX_PWR_FR_DEFAULT}, - {11, 2462, LBS_TX_PWR_FR_DEFAULT}, - {12, 2467, LBS_TX_PWR_FR_DEFAULT}, - {13, 2472, LBS_TX_PWR_FR_DEFAULT} -}; - -/* band: 'B/G', region: Japan */ -static struct chan_freq_power channel_freq_power_JPN_BG[] = { - {1, 2412, LBS_TX_PWR_JP_DEFAULT}, - {2, 2417, LBS_TX_PWR_JP_DEFAULT}, - {3, 2422, LBS_TX_PWR_JP_DEFAULT}, - {4, 2427, LBS_TX_PWR_JP_DEFAULT}, - {5, 2432, LBS_TX_PWR_JP_DEFAULT}, - {6, 2437, LBS_TX_PWR_JP_DEFAULT}, - {7, 2442, LBS_TX_PWR_JP_DEFAULT}, - {8, 2447, LBS_TX_PWR_JP_DEFAULT}, - {9, 2452, LBS_TX_PWR_JP_DEFAULT}, - {10, 2457, LBS_TX_PWR_JP_DEFAULT}, - {11, 2462, LBS_TX_PWR_JP_DEFAULT}, - {12, 2467, LBS_TX_PWR_JP_DEFAULT}, - {13, 2472, LBS_TX_PWR_JP_DEFAULT}, - {14, 2484, LBS_TX_PWR_JP_DEFAULT} -}; - -/** - * the structure for channel, frequency and power - */ -struct region_cfp_table { - u8 region; - struct chan_freq_power *cfp_BG; - int cfp_no_BG; -}; - -/** - * the structure for the mapping between region and CFP - */ -static struct region_cfp_table region_cfp_table[] = { - {0x10, /*US FCC */ - channel_freq_power_US_BG, - ARRAY_SIZE(channel_freq_power_US_BG), - } - , - {0x20, /*CANADA IC */ - channel_freq_power_US_BG, - ARRAY_SIZE(channel_freq_power_US_BG), - } - , - {0x30, /*EU*/ channel_freq_power_EU_BG, - ARRAY_SIZE(channel_freq_power_EU_BG), - } - , - {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, - ARRAY_SIZE(channel_freq_power_SPN_BG), - } - , - {0x32, /*FRANCE*/ channel_freq_power_FR_BG, - ARRAY_SIZE(channel_freq_power_FR_BG), - } - , - {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, - ARRAY_SIZE(channel_freq_power_JPN_BG), - } - , -/*Add new region here */ -}; - /** * the table to keep region code */ u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; -/** - * 802.11b/g supported bitrates (in 500Kb/s units) - */ -u8 lbs_bg_rates[MAX_RATES] = - { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, -0x00, 0x00 }; - /** * FW rate table. FW refers to rates by their index in this table, not by the * rate value itself. Values of 0x00 are @@ -1617,68 +1497,6 @@ static void lbs_remove_mesh(struct lbs_private *priv) lbs_deb_leave(LBS_DEB_MESH); } -/** - * @brief This function finds the CFP in - * region_cfp_table based on region and band parameter. - * - * @param region The region code - * @param band The band - * @param cfp_no A pointer to CFP number - * @return A pointer to CFP - */ -struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no) -{ - int i, end; - - lbs_deb_enter(LBS_DEB_MAIN); - - end = ARRAY_SIZE(region_cfp_table); - - for (i = 0; i < end ; i++) { - lbs_deb_main("region_cfp_table[i].region=%d\n", - region_cfp_table[i].region); - if (region_cfp_table[i].region == region) { - *cfp_no = region_cfp_table[i].cfp_no_BG; - lbs_deb_leave(LBS_DEB_MAIN); - return region_cfp_table[i].cfp_BG; - } - } - - lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL"); - return NULL; -} - -int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band) -{ - int ret = 0; - int i = 0; - - struct chan_freq_power *cfp; - int cfp_no; - - lbs_deb_enter(LBS_DEB_MAIN); - - memset(priv->region_channel, 0, sizeof(priv->region_channel)); - - cfp = lbs_get_region_cfp_table(region, &cfp_no); - if (cfp != NULL) { - priv->region_channel[i].nrcfp = cfp_no; - priv->region_channel[i].CFP = cfp; - } else { - lbs_deb_main("wrong region code %#x in band B/G\n", - region); - ret = -1; - goto out; - } - priv->region_channel[i].valid = 1; - priv->region_channel[i].region = region; - priv->region_channel[i].band = band; - i++; -out: - lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); - return ret; -} - void lbs_queue_event(struct lbs_private *priv, u32 event) { unsigned long flags; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 2700f4b455e3..8273bcd216be 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -15,6 +15,7 @@ #include "decl.h" #include "dev.h" #include "scan.h" +#include "assoc.h" #include "cmd.h" //! Approximate amount of data needed to pass a scan result back to iwlist @@ -121,6 +122,189 @@ static inline int is_same_network(struct bss_descriptor *src, +/*********************************************************************/ +/* */ +/* Region channel support */ +/* */ +/*********************************************************************/ + +#define LBS_TX_PWR_DEFAULT 20 /*100mW */ +#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */ +#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */ +#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */ +#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */ + +/* Format { channel, frequency (MHz), maxtxpower } */ +/* band: 'B/G', region: USA FCC/Canada IC */ +static struct chan_freq_power channel_freq_power_US_BG[] = { + {1, 2412, LBS_TX_PWR_US_DEFAULT}, + {2, 2417, LBS_TX_PWR_US_DEFAULT}, + {3, 2422, LBS_TX_PWR_US_DEFAULT}, + {4, 2427, LBS_TX_PWR_US_DEFAULT}, + {5, 2432, LBS_TX_PWR_US_DEFAULT}, + {6, 2437, LBS_TX_PWR_US_DEFAULT}, + {7, 2442, LBS_TX_PWR_US_DEFAULT}, + {8, 2447, LBS_TX_PWR_US_DEFAULT}, + {9, 2452, LBS_TX_PWR_US_DEFAULT}, + {10, 2457, LBS_TX_PWR_US_DEFAULT}, + {11, 2462, LBS_TX_PWR_US_DEFAULT} +}; + +/* band: 'B/G', region: Europe ETSI */ +static struct chan_freq_power channel_freq_power_EU_BG[] = { + {1, 2412, LBS_TX_PWR_EMEA_DEFAULT}, + {2, 2417, LBS_TX_PWR_EMEA_DEFAULT}, + {3, 2422, LBS_TX_PWR_EMEA_DEFAULT}, + {4, 2427, LBS_TX_PWR_EMEA_DEFAULT}, + {5, 2432, LBS_TX_PWR_EMEA_DEFAULT}, + {6, 2437, LBS_TX_PWR_EMEA_DEFAULT}, + {7, 2442, LBS_TX_PWR_EMEA_DEFAULT}, + {8, 2447, LBS_TX_PWR_EMEA_DEFAULT}, + {9, 2452, LBS_TX_PWR_EMEA_DEFAULT}, + {10, 2457, LBS_TX_PWR_EMEA_DEFAULT}, + {11, 2462, LBS_TX_PWR_EMEA_DEFAULT}, + {12, 2467, LBS_TX_PWR_EMEA_DEFAULT}, + {13, 2472, LBS_TX_PWR_EMEA_DEFAULT} +}; + +/* band: 'B/G', region: Spain */ +static struct chan_freq_power channel_freq_power_SPN_BG[] = { + {10, 2457, LBS_TX_PWR_DEFAULT}, + {11, 2462, LBS_TX_PWR_DEFAULT} +}; + +/* band: 'B/G', region: France */ +static struct chan_freq_power channel_freq_power_FR_BG[] = { + {10, 2457, LBS_TX_PWR_FR_DEFAULT}, + {11, 2462, LBS_TX_PWR_FR_DEFAULT}, + {12, 2467, LBS_TX_PWR_FR_DEFAULT}, + {13, 2472, LBS_TX_PWR_FR_DEFAULT} +}; + +/* band: 'B/G', region: Japan */ +static struct chan_freq_power channel_freq_power_JPN_BG[] = { + {1, 2412, LBS_TX_PWR_JP_DEFAULT}, + {2, 2417, LBS_TX_PWR_JP_DEFAULT}, + {3, 2422, LBS_TX_PWR_JP_DEFAULT}, + {4, 2427, LBS_TX_PWR_JP_DEFAULT}, + {5, 2432, LBS_TX_PWR_JP_DEFAULT}, + {6, 2437, LBS_TX_PWR_JP_DEFAULT}, + {7, 2442, LBS_TX_PWR_JP_DEFAULT}, + {8, 2447, LBS_TX_PWR_JP_DEFAULT}, + {9, 2452, LBS_TX_PWR_JP_DEFAULT}, + {10, 2457, LBS_TX_PWR_JP_DEFAULT}, + {11, 2462, LBS_TX_PWR_JP_DEFAULT}, + {12, 2467, LBS_TX_PWR_JP_DEFAULT}, + {13, 2472, LBS_TX_PWR_JP_DEFAULT}, + {14, 2484, LBS_TX_PWR_JP_DEFAULT} +}; + +/** + * the structure for channel, frequency and power + */ +struct region_cfp_table { + u8 region; + struct chan_freq_power *cfp_BG; + int cfp_no_BG; +}; + +/** + * the structure for the mapping between region and CFP + */ +static struct region_cfp_table region_cfp_table[] = { + {0x10, /*US FCC */ + channel_freq_power_US_BG, + ARRAY_SIZE(channel_freq_power_US_BG), + } + , + {0x20, /*CANADA IC */ + channel_freq_power_US_BG, + ARRAY_SIZE(channel_freq_power_US_BG), + } + , + {0x30, /*EU*/ channel_freq_power_EU_BG, + ARRAY_SIZE(channel_freq_power_EU_BG), + } + , + {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, + ARRAY_SIZE(channel_freq_power_SPN_BG), + } + , + {0x32, /*FRANCE*/ channel_freq_power_FR_BG, + ARRAY_SIZE(channel_freq_power_FR_BG), + } + , + {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, + ARRAY_SIZE(channel_freq_power_JPN_BG), + } + , +/*Add new region here */ +}; + +/** + * @brief This function finds the CFP in + * region_cfp_table based on region and band parameter. + * + * @param region The region code + * @param band The band + * @param cfp_no A pointer to CFP number + * @return A pointer to CFP + */ +static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no) +{ + int i, end; + + lbs_deb_enter(LBS_DEB_MAIN); + + end = ARRAY_SIZE(region_cfp_table); + + for (i = 0; i < end ; i++) { + lbs_deb_main("region_cfp_table[i].region=%d\n", + region_cfp_table[i].region); + if (region_cfp_table[i].region == region) { + *cfp_no = region_cfp_table[i].cfp_no_BG; + lbs_deb_leave(LBS_DEB_MAIN); + return region_cfp_table[i].cfp_BG; + } + } + + lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL"); + return NULL; +} + +int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band) +{ + int ret = 0; + int i = 0; + + struct chan_freq_power *cfp; + int cfp_no; + + lbs_deb_enter(LBS_DEB_MAIN); + + memset(priv->region_channel, 0, sizeof(priv->region_channel)); + + cfp = lbs_get_region_cfp_table(region, &cfp_no); + if (cfp != NULL) { + priv->region_channel[i].nrcfp = cfp_no; + priv->region_channel[i].CFP = cfp; + } else { + lbs_deb_main("wrong region code %#x in band B/G\n", + region); + ret = -1; + goto out; + } + priv->region_channel[i].valid = 1; + priv->region_channel[i].region = region; + priv->region_channel[i].band = band; + i++; +out: + lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); + return ret; +} + + + /*********************************************************************/ /* */ diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index fab7d5d097fc..8fb1706d7526 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -9,8 +9,36 @@ #include +struct lbs_private; + #define MAX_NETWORK_COUNT 128 +/** Chan-freq-TxPower mapping table*/ +struct chan_freq_power { + /** channel Number */ + u16 channel; + /** frequency of this channel */ + u32 freq; + /** Max allowed Tx power level */ + u16 maxtxpower; + /** TRUE:channel unsupported; FLASE:supported*/ + u8 unsupported; +}; + +/** region-band mapping table*/ +struct region_channel { + /** TRUE if this entry is valid */ + u8 valid; + /** region code for US, Japan ... */ + u8 region; + /** band B/G/A, used for BAND_CONFIG cmd */ + u8 band; + /** Actual No. of elements in the array below */ + u8 nrcfp; + /** chan-freq-txpower mapping table*/ + struct chan_freq_power *CFP; +}; + /** * @brief Maximum number of channels that can be sent in a setuserscan ioctl */ @@ -18,6 +46,8 @@ int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len); +int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band); + int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, u8 ssid_len); -- cgit v1.2.3 From 5e047692245c7b8d338ddeece156721d594ca985 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:49 +0200 Subject: libertas: sort variables in struct lbs_private Having the variables in logical groups allows us to easier #ifdef stuff out. No functional change. Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/dev.h | 257 +++++++++++++++--------------------- 1 file changed, 104 insertions(+), 153 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index cc245820d3f2..27f0f1f2a58a 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -35,113 +35,96 @@ struct lbs_mesh_stats { /** Private structure for the MV device */ struct lbs_private { + + /* Basic networking */ + struct net_device *dev; + u32 connect_status; + int infra_open; + struct work_struct mcast_work; + u32 nr_of_multicastmacaddr; + u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; + + /* CFG80211 */ struct wireless_dev *wdev; + + /* Mesh */ + struct net_device *mesh_dev; /* Virtual device */ + u32 mesh_connect_status; + struct lbs_mesh_stats mstats; int mesh_open; int mesh_fw_ver; - int infra_open; int mesh_autostart_enabled; + uint16_t mesh_tlv; + u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1]; + u8 mesh_ssid_len; + struct work_struct sync_channel; - char name[DEV_NAME_LEN]; - - void *card; - struct net_device *dev; - - struct net_device *mesh_dev; /* Virtual device */ + /* Monitor mode */ struct net_device *rtap_net_dev; + u32 monitormode; - struct iw_statistics wstats; - struct lbs_mesh_stats mstats; + /* Debugfs */ struct dentry *debugfs_dir; struct dentry *debugfs_debug; struct dentry *debugfs_files[6]; - struct dentry *events_dir; struct dentry *debugfs_events_files[6]; - struct dentry *regs_dir; struct dentry *debugfs_regs_files[6]; + /* Hardware debugging */ u32 mac_offset; u32 bbp_offset; u32 rf_offset; + struct lbs_offset_value offsetvalue; + + /* Power management */ + u16 psmode; + u32 psstate; + u8 needtowakeup; - /** Deep sleep flag */ + /* Deep sleep */ int is_deep_sleep; - /** Auto deep sleep enabled flag */ int is_auto_deep_sleep_enabled; - /** Device wakeup required flag */ int wakeup_dev_required; - /** Auto deep sleep flag*/ int is_activity_detected; - /** Auto deep sleep timeout (in miliseconds) */ - int auto_deep_sleep_timeout; - - /** Deep sleep wait queue */ - wait_queue_head_t ds_awake_q; - - /* Download sent: - bit0 1/0=data_sent/data_tx_done, - bit1 1/0=cmd_sent/cmd_tx_done, - all other bits reserved 0 */ - u8 dnld_sent; - - /** thread to service interrupts */ - struct task_struct *main_thread; - wait_queue_head_t waitq; - struct workqueue_struct *work_thread; - - struct work_struct mcast_work; - - /** Scanning */ - struct delayed_work scan_work; - struct delayed_work assoc_work; - struct work_struct sync_channel; - /* remember which channel was scanned last, != 0 if currently scanning */ - int scan_channel; - u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1]; - u8 scan_ssid_len; + int auto_deep_sleep_timeout; /* in ms */ + wait_queue_head_t ds_awake_q; + struct timer_list auto_deepsleep_timer; - /** Hardware access */ + /* Hardware access */ + void *card; + u8 fw_ready; + u8 surpriseremoved; int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); void (*reset_card) (struct lbs_private *priv); int (*enter_deep_sleep) (struct lbs_private *priv); int (*exit_deep_sleep) (struct lbs_private *priv); int (*reset_deep_sleep_wakeup) (struct lbs_private *priv); - /* Wake On LAN */ - uint32_t wol_criteria; - uint8_t wol_gpio; - uint8_t wol_gap; - - /** Wlan adapter data structure*/ - /** STATUS variables */ + /* Adapter info (from EEPROM) */ u32 fwrelease; u32 fwcapinfo; + u16 regioncode; + u8 current_addr[ETH_ALEN]; - struct mutex lock; - - /* TX packet ready to be sent... */ - int tx_pending_len; /* -1 while building packet */ - - u8 tx_pending_buf[LBS_UPLD_SIZE]; - /* protected by hard_start_xmit serialization */ - - /** command-related variables */ + /* Command download */ + u8 dnld_sent; + /* bit0 1/0=data_sent/data_tx_done, + bit1 1/0=cmd_sent/cmd_tx_done, + all other bits reserved 0 */ u16 seqnum; - struct cmd_ctrl_node *cmd_array; - /** Current command */ struct cmd_ctrl_node *cur_cmd; - int cur_cmd_retcode; - /** command Queues */ - /** Free command buffers */ - struct list_head cmdfreeq; - /** Pending command buffers */ - struct list_head cmdpendingq; - + struct list_head cmdfreeq; /* free command buffers */ + struct list_head cmdpendingq; /* pending command buffers */ wait_queue_head_t cmd_pending; + struct timer_list command_timer; + int nr_retries; + int cmd_timed_out; /* Command responses sent from the hardware to the driver */ + int cur_cmd_retcode; u8 resp_idx; u8 resp_buf[2][LBS_UPLD_SIZE]; u32 resp_len[2]; @@ -149,90 +132,75 @@ struct lbs_private { /* Events sent from hardware to driver */ struct kfifo *event_fifo; - /* nickname */ - u8 nodename[16]; - - /** spin locks */ - spinlock_t driver_lock; - - /** Timers */ - struct timer_list command_timer; - struct timer_list auto_deepsleep_timer; - int nr_retries; - int cmd_timed_out; - - /** current ssid/bssid related parameters*/ - struct current_bss_params curbssparams; - - uint16_t mesh_tlv; - u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1]; - u8 mesh_ssid_len; - - /* IW_MODE_* */ - u8 mode; - - /* Scan results list */ - struct list_head network_list; - struct list_head network_free_list; - struct bss_descriptor *networks; - - u16 beacon_period; - u8 beacon_enable; - u8 adhoccreate; - - /** capability Info used in Association, start, join */ - u16 capability; - - /** MAC address information */ - u8 current_addr[ETH_ALEN]; - u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; - u32 nr_of_multicastmacaddr; + /** thread to service interrupts */ + struct task_struct *main_thread; + wait_queue_head_t waitq; + struct workqueue_struct *work_thread; - /** 802.11 statistics */ -// struct cmd_DS_802_11_GET_STAT wlan802_11Stat; + /** Encryption stuff */ + struct lbs_802_11_security secinfo; + struct enc_key wpa_mcast_key; + struct enc_key wpa_unicast_key; + u8 wpa_ie[MAX_WPA_IE_LEN]; + u8 wpa_ie_len; + u16 wep_tx_keyidx; + struct enc_key wep_keys[4]; - uint16_t enablehwauto; - uint16_t ratebitmap; + /* Wake On LAN */ + uint32_t wol_criteria; + uint8_t wol_gpio; + uint8_t wol_gap; + /* Transmitting */ + int tx_pending_len; /* -1 while building packet */ + u8 tx_pending_buf[LBS_UPLD_SIZE]; + /* protected by hard_start_xmit serialization */ u8 txretrycount; - - /** Tx-related variables (for single packet tx) */ struct sk_buff *currenttxskb; - /** NIC Operation characteristics */ + /* Locks */ + struct mutex lock; + spinlock_t driver_lock; + + /* NIC/link operation characteristics */ u16 mac_control; - u32 connect_status; - u32 mesh_connect_status; - u16 regioncode; + u8 radio_on; s16 txpower_cur; s16 txpower_min; s16 txpower_max; - /** POWER MANAGEMENT AND PnP SUPPORT */ - u8 surpriseremoved; - - u16 psmode; /* Wlan802_11PowermodeCAM=disable - Wlan802_11PowermodeMAX_PSP=enable */ - u32 psstate; - u8 needtowakeup; + /** Scanning */ + struct delayed_work scan_work; + int scan_channel; + /* remember which channel was scanned last, != 0 if currently scanning */ + u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1]; + u8 scan_ssid_len; + /* Associating */ + struct delayed_work assoc_work; + struct current_bss_params curbssparams; + u8 mode; + struct list_head network_list; + struct list_head network_free_list; + struct bss_descriptor *networks; struct assoc_request * pending_assoc_req; struct assoc_request * in_progress_assoc_req; + u16 capability; + uint16_t enablehwauto; + uint16_t ratebitmap; - /** Encryption parameter */ - struct lbs_802_11_security secinfo; - - /** WEP keys */ - struct enc_key wep_keys[4]; - u16 wep_tx_keyidx; - - /** WPA keys */ - struct enc_key wpa_mcast_key; - struct enc_key wpa_unicast_key; + /* ADHOC */ + u16 beacon_period; + u8 beacon_enable; + u8 adhoccreate; - /** WPA Information Elements*/ - u8 wpa_ie[MAX_WPA_IE_LEN]; - u8 wpa_ie_len; + /* WEXT */ + char name[DEV_NAME_LEN]; + u8 nodename[16]; + struct iw_statistics wstats; + u8 cur_rate; +#define MAX_REGION_CHANNEL_NUM 2 + struct region_channel region_channel[MAX_REGION_CHANNEL_NUM]; /** Requested Signal Strength*/ u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG]; @@ -242,23 +210,6 @@ struct lbs_private { u8 rawNF[DEFAULT_DATA_AVG_FACTOR]; u16 nextSNRNF; u16 numSNRNF; - - u8 radio_on; - - /** data rate stuff */ - u8 cur_rate; - - /** RF calibration data */ - -#define MAX_REGION_CHANNEL_NUM 2 - /** region channel data */ - struct region_channel region_channel[MAX_REGION_CHANNEL_NUM]; - - /** MISCELLANEOUS */ - struct lbs_offset_value offsetvalue; - - u32 monitormode; - u8 fw_ready; }; extern struct cmd_confirm_sleep confirm_sleep; -- cgit v1.2.3 From c14951fec6c292dca60e3cf8ab0edfdf11e6c0e2 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:50 +0200 Subject: libertas: get current channel out of priv->curbssparams ... as priv->curbssparams won't exist once libertas+cfg80211 lands. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 18 +++++++++--------- drivers/net/wireless/libertas/assoc.h | 3 +-- drivers/net/wireless/libertas/cmd.c | 8 ++++---- drivers/net/wireless/libertas/dev.h | 1 + drivers/net/wireless/libertas/main.c | 10 +++++----- drivers/net/wireless/libertas/wext.c | 10 +++++----- 6 files changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 2ccfeca32cde..b8bdba67ad17 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -376,7 +376,7 @@ static int lbs_associate(struct lbs_private *priv, (u16)(pos - (u8 *) &cmd.iebuf)); /* update curbssparams */ - priv->curbssparams.channel = bss->phy.ds.channel; + priv->channel = bss->phy.ds.channel; ret = lbs_cmd_with_response(priv, command, &cmd); if (ret == 0) { @@ -489,7 +489,7 @@ static int lbs_adhoc_post(struct lbs_private *priv, lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", print_ssid(ssid, bss->ssid, bss->ssid_len), priv->curbssparams.bssid, - priv->curbssparams.channel); + priv->channel); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); @@ -562,7 +562,7 @@ static int lbs_adhoc_join(struct lbs_private *priv, lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); priv->adhoccreate = 0; - priv->curbssparams.channel = bss->channel; + priv->channel = bss->channel; /* Build the join command */ memset(&cmd, 0, sizeof(cmd)); @@ -1196,7 +1196,7 @@ static int assoc_helper_channel(struct lbs_private *priv, goto done; } - if (assoc_req->channel == priv->curbssparams.channel) + if (assoc_req->channel == priv->channel) goto done; if (priv->mesh_dev) { @@ -1208,7 +1208,7 @@ static int assoc_helper_channel(struct lbs_private *priv, } lbs_deb_assoc("ASSOC: channel: %d -> %d\n", - priv->curbssparams.channel, assoc_req->channel); + priv->channel, assoc_req->channel); ret = lbs_set_channel(priv, assoc_req->channel); if (ret < 0) @@ -1223,7 +1223,7 @@ static int assoc_helper_channel(struct lbs_private *priv, goto done; } - if (assoc_req->channel != priv->curbssparams.channel) { + if (assoc_req->channel != priv->channel) { lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n", assoc_req->channel); goto restore_mesh; @@ -1244,7 +1244,7 @@ static int assoc_helper_channel(struct lbs_private *priv, restore_mesh: if (priv->mesh_dev) lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, - priv->curbssparams.channel); + priv->channel); done: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -1466,7 +1466,7 @@ static int should_stop_adhoc(struct lbs_private *priv, } if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { - if (assoc_req->channel != priv->curbssparams.channel) + if (assoc_req->channel != priv->channel) return 1; } @@ -1771,7 +1771,7 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv) } if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) - assoc_req->channel = priv->curbssparams.channel; + assoc_req->channel = priv->channel; if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags)) assoc_req->band = priv->curbssparams.band; diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index 610d14c14cd4..d8c266895dd3 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -36,8 +36,7 @@ struct current_bss_params { /** band */ u8 band; - /** channel */ - u8 channel; + /** channel is directly in priv->channel */ /** zero-terminated array of supported data rates */ u8 rates[MAX_RATES + 1]; }; diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index ec65be0c4d93..076cf7e625fb 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -880,7 +880,7 @@ int lbs_update_channel(struct lbs_private *priv) ret = lbs_get_channel(priv); if (ret > 0) { - priv->curbssparams.channel = ret; + priv->channel = ret; ret = 0; } lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -899,7 +899,7 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel) { struct cmd_ds_802_11_rf_channel cmd; #ifdef DEBUG - u8 old_channel = priv->curbssparams.channel; + u8 old_channel = priv->channel; #endif int ret = 0; @@ -914,9 +914,9 @@ int lbs_set_channel(struct lbs_private *priv, u8 channel) if (ret) goto out; - priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel); + priv->channel = (uint8_t) le16_to_cpu(cmd.channel); lbs_deb_cmd("channel switch from %d to %d\n", old_channel, - priv->curbssparams.channel); + priv->channel); out: lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 27f0f1f2a58a..1a675111300d 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -165,6 +165,7 @@ struct lbs_private { /* NIC/link operation characteristics */ u16 mac_control; u8 radio_on; + u8 channel; s16 txpower_cur; s16 txpower_min; s16 txpower_max; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ee0893334553..eb61f6955e9e 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -285,7 +285,7 @@ static ssize_t lbs_mesh_set(struct device *dev, return count; if (enable) action = CMD_ACT_MESH_CONFIG_START; - ret = lbs_mesh_config(priv, action, priv->curbssparams.channel); + ret = lbs_mesh_config(priv, action, priv->channel); if (ret) return ret; @@ -1046,7 +1046,7 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->mesh_connect_status = LBS_DISCONNECTED; priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; priv->mode = IW_MODE_INFRA; - priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; + priv->channel = DEFAULT_AD_HOC_CHANNEL; priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->radio_on = 1; priv->enablehwauto = 1; @@ -1314,10 +1314,10 @@ int lbs_start_card(struct lbs_private *priv) priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, - priv->curbssparams.channel)) { + priv->channel)) { priv->mesh_tlv = TLV_TYPE_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, - priv->curbssparams.channel)) + priv->channel)) priv->mesh_tlv = 0; } } else if (priv->mesh_fw_ver == MESH_FW_NEW) { @@ -1326,7 +1326,7 @@ int lbs_start_card(struct lbs_private *priv) */ priv->mesh_tlv = TLV_TYPE_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, - priv->curbssparams.channel)) + priv->channel)) priv->mesh_tlv = 0; } if (priv->mesh_tlv) { diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 3e8be9a578e8..c688ca7ab322 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -164,12 +164,12 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); cfp = lbs_find_cfp_by_band_and_channel(priv, 0, - priv->curbssparams.channel); + priv->channel); if (!cfp) { - if (priv->curbssparams.channel) + if (priv->channel) lbs_deb_wext("invalid channel %d\n", - priv->curbssparams.channel); + priv->channel); return -EINVAL; } @@ -986,7 +986,7 @@ static int lbs_mesh_set_freq(struct net_device *dev, goto out; } - if (fwrq->m != priv->curbssparams.channel) { + if (fwrq->m != priv->channel) { lbs_deb_wext("mesh channel change forces eth disconnect\n"); if (priv->mode == IW_MODE_INFRA) lbs_cmd_80211_deauthenticate(priv, @@ -2100,7 +2100,7 @@ static int lbs_mesh_set_essid(struct net_device *dev, } lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, - priv->curbssparams.channel); + priv->channel); out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; -- cgit v1.2.3 From d0de37417e51219d7d56a452d18fa7b829342fcc Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:51 +0200 Subject: libertas: move association related commands into assoc.c That's because the new cfg80211 implementation will provide cleaner implementations. No functional changes. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 390 ++++++++++++++++++++++++++++++++ drivers/net/wireless/libertas/assoc.h | 20 ++ drivers/net/wireless/libertas/cmd.c | 340 ---------------------------- drivers/net/wireless/libertas/cmd.h | 9 - drivers/net/wireless/libertas/cmdresp.c | 47 ---- 5 files changed, 410 insertions(+), 396 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index b8bdba67ad17..17e76ac4179c 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -154,6 +154,396 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth } +int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, + struct assoc_request *assoc) +{ + struct cmd_ds_802_11_set_wep cmd; + int ret = 0; + + lbs_deb_enter(LBS_DEB_CMD); + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + + cmd.action = cpu_to_le16(cmd_action); + + if (cmd_action == CMD_ACT_ADD) { + int i; + + /* default tx key index */ + cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx & + CMD_WEP_KEY_INDEX_MASK); + + /* Copy key types and material to host command structure */ + for (i = 0; i < 4; i++) { + struct enc_key *pkey = &assoc->wep_keys[i]; + + switch (pkey->len) { + case KEY_LEN_WEP_40: + cmd.keytype[i] = CMD_TYPE_WEP_40_BIT; + memmove(cmd.keymaterial[i], pkey->key, pkey->len); + lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); + break; + case KEY_LEN_WEP_104: + cmd.keytype[i] = CMD_TYPE_WEP_104_BIT; + memmove(cmd.keymaterial[i], pkey->key, pkey->len); + lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); + break; + case 0: + break; + default: + lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n", + i, pkey->len); + ret = -1; + goto done; + break; + } + } + } else if (cmd_action == CMD_ACT_REMOVE) { + /* ACT_REMOVE clears _all_ WEP keys */ + + /* default tx key index */ + cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx & + CMD_WEP_KEY_INDEX_MASK); + lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx); + } + + ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd); +done: + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} + +int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, + uint16_t *enable) +{ + struct cmd_ds_802_11_enable_rsn cmd; + int ret; + + lbs_deb_enter(LBS_DEB_CMD); + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(cmd_action); + + if (cmd_action == CMD_ACT_GET) + cmd.enable = 0; + else { + if (*enable) + cmd.enable = cpu_to_le16(CMD_ENABLE_RSN); + else + cmd.enable = cpu_to_le16(CMD_DISABLE_RSN); + lbs_deb_cmd("ENABLE_RSN: %d\n", *enable); + } + + ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd); + if (!ret && cmd_action == CMD_ACT_GET) + *enable = le16_to_cpu(cmd.enable); + + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} + +static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam, + struct enc_key *key) +{ + lbs_deb_enter(LBS_DEB_CMD); + + if (key->flags & KEY_INFO_WPA_ENABLED) + keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); + if (key->flags & KEY_INFO_WPA_UNICAST) + keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST); + if (key->flags & KEY_INFO_WPA_MCAST) + keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST); + + keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + keyparam->keytypeid = cpu_to_le16(key->type); + keyparam->keylen = cpu_to_le16(key->len); + memcpy(keyparam->key, key->key, key->len); + + /* Length field doesn't include the {type,length} header */ + keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4); + lbs_deb_leave(LBS_DEB_CMD); +} + +int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, + struct assoc_request *assoc) +{ + struct cmd_ds_802_11_key_material cmd; + int ret = 0; + int index = 0; + + lbs_deb_enter(LBS_DEB_CMD); + + cmd.action = cpu_to_le16(cmd_action); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + + if (cmd_action == CMD_ACT_GET) { + cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2); + } else { + memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet)); + + if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) { + set_one_wpa_key(&cmd.keyParamSet[index], + &assoc->wpa_unicast_key); + index++; + } + + if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) { + set_one_wpa_key(&cmd.keyParamSet[index], + &assoc->wpa_mcast_key); + index++; + } + + /* The common header and as many keys as we included */ + cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd), + keyParamSet[index])); + } + ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd); + /* Copy the returned key to driver private data */ + if (!ret && cmd_action == CMD_ACT_GET) { + void *buf_ptr = cmd.keyParamSet; + void *resp_end = &(&cmd)[1]; + + while (buf_ptr < resp_end) { + struct MrvlIEtype_keyParamSet *keyparam = buf_ptr; + struct enc_key *key; + uint16_t param_set_len = le16_to_cpu(keyparam->length); + uint16_t key_len = le16_to_cpu(keyparam->keylen); + uint16_t key_flags = le16_to_cpu(keyparam->keyinfo); + uint16_t key_type = le16_to_cpu(keyparam->keytypeid); + void *end; + + end = (void *)keyparam + sizeof(keyparam->type) + + sizeof(keyparam->length) + param_set_len; + + /* Make sure we don't access past the end of the IEs */ + if (end > resp_end) + break; + + if (key_flags & KEY_INFO_WPA_UNICAST) + key = &priv->wpa_unicast_key; + else if (key_flags & KEY_INFO_WPA_MCAST) + key = &priv->wpa_mcast_key; + else + break; + + /* Copy returned key into driver */ + memset(key, 0, sizeof(struct enc_key)); + if (key_len > sizeof(key->key)) + break; + key->type = key_type; + key->flags = key_flags; + key->len = key_len; + memcpy(key->key, keyparam->key, key->len); + + buf_ptr = end + 1; + } + } + + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} + +static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok) +{ +/* Bit Rate +* 15:13 Reserved +* 12 54 Mbps +* 11 48 Mbps +* 10 36 Mbps +* 9 24 Mbps +* 8 18 Mbps +* 7 12 Mbps +* 6 9 Mbps +* 5 6 Mbps +* 4 Reserved +* 3 11 Mbps +* 2 5.5 Mbps +* 1 2 Mbps +* 0 1 Mbps +**/ + + uint16_t ratemask; + int i = lbs_data_rate_to_fw_index(rate); + if (lower_rates_ok) + ratemask = (0x1fef >> (12 - i)); + else + ratemask = (1 << i); + return cpu_to_le16(ratemask); +} + +int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, + uint16_t cmd_action) +{ + struct cmd_ds_802_11_rate_adapt_rateset cmd; + int ret; + + lbs_deb_enter(LBS_DEB_CMD); + + if (!priv->cur_rate && !priv->enablehwauto) + return -EINVAL; + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + + cmd.action = cpu_to_le16(cmd_action); + cmd.enablehwauto = cpu_to_le16(priv->enablehwauto); + cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto); + ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd); + if (!ret && cmd_action == CMD_ACT_GET) { + priv->ratebitmap = le16_to_cpu(cmd.bitmap); + priv->enablehwauto = le16_to_cpu(cmd.enablehwauto); + } + + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} + +/** + * @brief Set the data rate + * + * @param priv A pointer to struct lbs_private structure + * @param rate The desired data rate, or 0 to clear a locked rate + * + * @return 0 on success, error on failure + */ +int lbs_set_data_rate(struct lbs_private *priv, u8 rate) +{ + struct cmd_ds_802_11_data_rate cmd; + int ret = 0; + + lbs_deb_enter(LBS_DEB_CMD); + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + + if (rate > 0) { + cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE); + cmd.rates[0] = lbs_data_rate_to_fw_index(rate); + if (cmd.rates[0] == 0) { + lbs_deb_cmd("DATA_RATE: invalid requested rate of" + " 0x%02X\n", rate); + ret = 0; + goto out; + } + lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]); + } else { + cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO); + lbs_deb_cmd("DATA_RATE: setting auto\n"); + } + + ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd); + if (ret) + goto out; + + lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd)); + + /* FIXME: get actual rates FW can do if this command actually returns + * all data rates supported. + */ + priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]); + lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate); + +out: + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} + + +int lbs_cmd_802_11_rssi(struct lbs_private *priv, + struct cmd_ds_command *cmd) +{ + + lbs_deb_enter(LBS_DEB_CMD); + cmd->command = cpu_to_le16(CMD_802_11_RSSI); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); + cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR); + + /* reset Beacon SNR/NF/RSSI values */ + priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; + priv->SNR[TYPE_BEACON][TYPE_AVG] = 0; + priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0; + priv->NF[TYPE_BEACON][TYPE_AVG] = 0; + priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; + priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0; + + lbs_deb_leave(LBS_DEB_CMD); + return 0; +} + +int lbs_ret_802_11_rssi(struct lbs_private *priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; + + lbs_deb_enter(LBS_DEB_CMD); + + /* store the non average value */ + priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR); + priv->NF[TYPE_BEACON][TYPE_NOAVG] = + get_unaligned_le16(&rssirsp->noisefloor); + + priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR); + priv->NF[TYPE_BEACON][TYPE_AVG] = + get_unaligned_le16(&rssirsp->avgnoisefloor); + + priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = + CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], + priv->NF[TYPE_BEACON][TYPE_NOAVG]); + + priv->RSSI[TYPE_BEACON][TYPE_AVG] = + CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, + priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); + + lbs_deb_cmd("RSSI: beacon %d, avg %d\n", + priv->RSSI[TYPE_BEACON][TYPE_NOAVG], + priv->RSSI[TYPE_BEACON][TYPE_AVG]); + + lbs_deb_leave(LBS_DEB_CMD); + return 0; +} + + +int lbs_cmd_bcn_ctrl(struct lbs_private *priv, + struct cmd_ds_command *cmd, + u16 cmd_action) +{ + struct cmd_ds_802_11_beacon_control + *bcn_ctrl = &cmd->params.bcn_ctrl; + + lbs_deb_enter(LBS_DEB_CMD); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control) + + S_DS_GEN); + cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL); + + bcn_ctrl->action = cpu_to_le16(cmd_action); + bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable); + bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period); + + lbs_deb_leave(LBS_DEB_CMD); + return 0; +} + +int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_beacon_control *bcn_ctrl = + &resp->params.bcn_ctrl; + + lbs_deb_enter(LBS_DEB_CMD); + + if (bcn_ctrl->action == CMD_ACT_GET) { + priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable); + priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period); + } + + lbs_deb_enter(LBS_DEB_CMD); + return 0; +} + + + static int lbs_assoc_post(struct lbs_private *priv, struct cmd_ds_802_11_associate_response *resp) { diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index d8c266895dd3..40621b789fc5 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -132,4 +132,24 @@ int lbs_adhoc_stop(struct lbs_private *priv); int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], u16 reason); +int lbs_cmd_802_11_rssi(struct lbs_private *priv, + struct cmd_ds_command *cmd); +int lbs_ret_802_11_rssi(struct lbs_private *priv, + struct cmd_ds_command *resp); + +int lbs_cmd_bcn_ctrl(struct lbs_private *priv, + struct cmd_ds_command *cmd, + u16 cmd_action); +int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv, + struct cmd_ds_command *resp); + +int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, + struct assoc_request *assoc); + +int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, + uint16_t *enable); + +int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, + struct assoc_request *assoc); + #endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 076cf7e625fb..d1cfcd25a506 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -364,197 +364,6 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep) return ret; } -int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, - struct assoc_request *assoc) -{ - struct cmd_ds_802_11_set_wep cmd; - int ret = 0; - - lbs_deb_enter(LBS_DEB_CMD); - - memset(&cmd, 0, sizeof(cmd)); - cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - - cmd.action = cpu_to_le16(cmd_action); - - if (cmd_action == CMD_ACT_ADD) { - int i; - - /* default tx key index */ - cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx & - CMD_WEP_KEY_INDEX_MASK); - - /* Copy key types and material to host command structure */ - for (i = 0; i < 4; i++) { - struct enc_key *pkey = &assoc->wep_keys[i]; - - switch (pkey->len) { - case KEY_LEN_WEP_40: - cmd.keytype[i] = CMD_TYPE_WEP_40_BIT; - memmove(cmd.keymaterial[i], pkey->key, pkey->len); - lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); - break; - case KEY_LEN_WEP_104: - cmd.keytype[i] = CMD_TYPE_WEP_104_BIT; - memmove(cmd.keymaterial[i], pkey->key, pkey->len); - lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); - break; - case 0: - break; - default: - lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n", - i, pkey->len); - ret = -1; - goto done; - break; - } - } - } else if (cmd_action == CMD_ACT_REMOVE) { - /* ACT_REMOVE clears _all_ WEP keys */ - - /* default tx key index */ - cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx & - CMD_WEP_KEY_INDEX_MASK); - lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx); - } - - ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd); -done: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); - return ret; -} - -int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, - uint16_t *enable) -{ - struct cmd_ds_802_11_enable_rsn cmd; - int ret; - - lbs_deb_enter(LBS_DEB_CMD); - - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - cmd.action = cpu_to_le16(cmd_action); - - if (cmd_action == CMD_ACT_GET) - cmd.enable = 0; - else { - if (*enable) - cmd.enable = cpu_to_le16(CMD_ENABLE_RSN); - else - cmd.enable = cpu_to_le16(CMD_DISABLE_RSN); - lbs_deb_cmd("ENABLE_RSN: %d\n", *enable); - } - - ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd); - if (!ret && cmd_action == CMD_ACT_GET) - *enable = le16_to_cpu(cmd.enable); - - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); - return ret; -} - -static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam, - struct enc_key *key) -{ - lbs_deb_enter(LBS_DEB_CMD); - - if (key->flags & KEY_INFO_WPA_ENABLED) - keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); - if (key->flags & KEY_INFO_WPA_UNICAST) - keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST); - if (key->flags & KEY_INFO_WPA_MCAST) - keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST); - - keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); - keyparam->keytypeid = cpu_to_le16(key->type); - keyparam->keylen = cpu_to_le16(key->len); - memcpy(keyparam->key, key->key, key->len); - - /* Length field doesn't include the {type,length} header */ - keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4); - lbs_deb_leave(LBS_DEB_CMD); -} - -int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, - struct assoc_request *assoc) -{ - struct cmd_ds_802_11_key_material cmd; - int ret = 0; - int index = 0; - - lbs_deb_enter(LBS_DEB_CMD); - - cmd.action = cpu_to_le16(cmd_action); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - - if (cmd_action == CMD_ACT_GET) { - cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2); - } else { - memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet)); - - if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) { - set_one_wpa_key(&cmd.keyParamSet[index], - &assoc->wpa_unicast_key); - index++; - } - - if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) { - set_one_wpa_key(&cmd.keyParamSet[index], - &assoc->wpa_mcast_key); - index++; - } - - /* The common header and as many keys as we included */ - cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd), - keyParamSet[index])); - } - ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd); - /* Copy the returned key to driver private data */ - if (!ret && cmd_action == CMD_ACT_GET) { - void *buf_ptr = cmd.keyParamSet; - void *resp_end = &(&cmd)[1]; - - while (buf_ptr < resp_end) { - struct MrvlIEtype_keyParamSet *keyparam = buf_ptr; - struct enc_key *key; - uint16_t param_set_len = le16_to_cpu(keyparam->length); - uint16_t key_len = le16_to_cpu(keyparam->keylen); - uint16_t key_flags = le16_to_cpu(keyparam->keyinfo); - uint16_t key_type = le16_to_cpu(keyparam->keytypeid); - void *end; - - end = (void *)keyparam + sizeof(keyparam->type) - + sizeof(keyparam->length) + param_set_len; - - /* Make sure we don't access past the end of the IEs */ - if (end > resp_end) - break; - - if (key_flags & KEY_INFO_WPA_UNICAST) - key = &priv->wpa_unicast_key; - else if (key_flags & KEY_INFO_WPA_MCAST) - key = &priv->wpa_mcast_key; - else - break; - - /* Copy returned key into driver */ - memset(key, 0, sizeof(struct enc_key)); - if (key_len > sizeof(key->key)) - break; - key->type = key_type; - key->flags = key_flags; - key->len = key_len; - memcpy(key->key, keyparam->key, key->len); - - buf_ptr = end + 1; - } - } - - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); - return ret; -} - /** * @brief Set an SNMP MIB value * @@ -736,111 +545,6 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd, return 0; } -static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok) -{ -/* Bit Rate -* 15:13 Reserved -* 12 54 Mbps -* 11 48 Mbps -* 10 36 Mbps -* 9 24 Mbps -* 8 18 Mbps -* 7 12 Mbps -* 6 9 Mbps -* 5 6 Mbps -* 4 Reserved -* 3 11 Mbps -* 2 5.5 Mbps -* 1 2 Mbps -* 0 1 Mbps -**/ - - uint16_t ratemask; - int i = lbs_data_rate_to_fw_index(rate); - if (lower_rates_ok) - ratemask = (0x1fef >> (12 - i)); - else - ratemask = (1 << i); - return cpu_to_le16(ratemask); -} - -int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, - uint16_t cmd_action) -{ - struct cmd_ds_802_11_rate_adapt_rateset cmd; - int ret; - - lbs_deb_enter(LBS_DEB_CMD); - - if (!priv->cur_rate && !priv->enablehwauto) - return -EINVAL; - - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - - cmd.action = cpu_to_le16(cmd_action); - cmd.enablehwauto = cpu_to_le16(priv->enablehwauto); - cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto); - ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd); - if (!ret && cmd_action == CMD_ACT_GET) { - priv->ratebitmap = le16_to_cpu(cmd.bitmap); - priv->enablehwauto = le16_to_cpu(cmd.enablehwauto); - } - - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); - return ret; -} -EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset); - -/** - * @brief Set the data rate - * - * @param priv A pointer to struct lbs_private structure - * @param rate The desired data rate, or 0 to clear a locked rate - * - * @return 0 on success, error on failure - */ -int lbs_set_data_rate(struct lbs_private *priv, u8 rate) -{ - struct cmd_ds_802_11_data_rate cmd; - int ret = 0; - - lbs_deb_enter(LBS_DEB_CMD); - - memset(&cmd, 0, sizeof(cmd)); - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - - if (rate > 0) { - cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE); - cmd.rates[0] = lbs_data_rate_to_fw_index(rate); - if (cmd.rates[0] == 0) { - lbs_deb_cmd("DATA_RATE: invalid requested rate of" - " 0x%02X\n", rate); - ret = 0; - goto out; - } - lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]); - } else { - cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO); - lbs_deb_cmd("DATA_RATE: setting auto\n"); - } - - ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd); - if (ret) - goto out; - - lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd)); - - /* FIXME: get actual rates FW can do if this command actually returns - * all data rates supported. - */ - priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]); - lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate); - -out: - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); - return ret; -} - /** * @brief Get the radio channel * @@ -923,27 +627,6 @@ out: return ret; } -static int lbs_cmd_802_11_rssi(struct lbs_private *priv, - struct cmd_ds_command *cmd) -{ - - lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_802_11_RSSI); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); - cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR); - - /* reset Beacon SNR/NF/RSSI values */ - priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; - priv->SNR[TYPE_BEACON][TYPE_AVG] = 0; - priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0; - priv->NF[TYPE_BEACON][TYPE_AVG] = 0; - priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; - priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0; - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr, u8 cmd_action, void *pdata_buf) { @@ -1183,27 +866,6 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); } -static int lbs_cmd_bcn_ctrl(struct lbs_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action) -{ - struct cmd_ds_802_11_beacon_control - *bcn_ctrl = &cmd->params.bcn_ctrl; - - lbs_deb_enter(LBS_DEB_CMD); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control) - + S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL); - - bcn_ctrl->action = cpu_to_le16(cmd_action); - bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable); - bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static void lbs_queue_cmd(struct lbs_private *priv, struct cmd_ctrl_node *cmdnode) { @@ -2179,5 +1841,3 @@ done: return ret; } EXPORT_SYMBOL_GPL(__lbs_cmd); - - diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 9d29b578799a..2862748aef70 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -135,15 +135,6 @@ int lbs_set_data_rate(struct lbs_private *priv, u8 rate); int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, uint16_t cmd_action); -int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, - struct assoc_request *assoc); - -int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, - uint16_t *enable); - -int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, - struct assoc_request *assoc); - int lbs_set_tx_power(struct lbs_private *priv, s16 dbm); int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 6e2103885959..0312f2496f74 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -148,53 +148,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv, return ret; } -static int lbs_ret_802_11_rssi(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; - - lbs_deb_enter(LBS_DEB_CMD); - - /* store the non average value */ - priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR); - priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor); - - priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR); - priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor); - - priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = - CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], - priv->NF[TYPE_BEACON][TYPE_NOAVG]); - - priv->RSSI[TYPE_BEACON][TYPE_AVG] = - CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, - priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); - - lbs_deb_cmd("RSSI: beacon %d, avg %d\n", - priv->RSSI[TYPE_BEACON][TYPE_NOAVG], - priv->RSSI[TYPE_BEACON][TYPE_AVG]); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - -static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_beacon_control *bcn_ctrl = - &resp->params.bcn_ctrl; - - lbs_deb_enter(LBS_DEB_CMD); - - if (bcn_ctrl->action == CMD_ACT_GET) { - priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable); - priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period); - } - - lbs_deb_enter(LBS_DEB_CMD); - return 0; -} - static inline int handle_cmd_response(struct lbs_private *priv, struct cmd_header *cmd_response) { -- cgit v1.2.3 From 6e85e0b7ab1cafd6ff63c391d231b5a39934802e Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:52 +0200 Subject: libertas: move lbs_send_iwevcustom_event() to wext.c ... because it's purely a WEXT function. No functional change. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 24 ------------------------ drivers/net/wireless/libertas/decl.h | 2 -- drivers/net/wireless/libertas/wext.c | 24 ++++++++++++++++++++++++ drivers/net/wireless/libertas/wext.h | 2 ++ 4 files changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index d1cfcd25a506..7ddab10f0bd5 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1542,30 +1542,6 @@ done: return ret; } -void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str) -{ - union iwreq_data iwrq; - u8 buf[50]; - - lbs_deb_enter(LBS_DEB_WEXT); - - memset(&iwrq, 0, sizeof(union iwreq_data)); - memset(buf, 0, sizeof(buf)); - - snprintf(buf, sizeof(buf) - 1, "%s", str); - - iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN; - - /* Send Event to upper layer */ - lbs_deb_wext("event indication string %s\n", (char *)buf); - lbs_deb_wext("event indication length %d\n", iwrq.data.length); - lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str); - - wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf); - - lbs_deb_leave(LBS_DEB_WEXT); -} - static void lbs_send_confirmsleep(struct lbs_private *priv) { unsigned long flags; diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 7d8323876c52..d609a57750de 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -44,8 +44,6 @@ struct chan_freq_power *lbs_find_cfp_by_band_and_channel( u8 band, u16 channel); -void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); - /* persistcfg.c */ void lbs_persist_config_init(struct net_device *net); void lbs_persist_config_remove(struct net_device *net); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index c688ca7ab322..18c045bcc947 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -45,6 +45,30 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv) priv->pending_assoc_req = NULL; } +void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str) +{ + union iwreq_data iwrq; + u8 buf[50]; + + lbs_deb_enter(LBS_DEB_WEXT); + + memset(&iwrq, 0, sizeof(union iwreq_data)); + memset(buf, 0, sizeof(buf)); + + snprintf(buf, sizeof(buf) - 1, "%s", str); + + iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN; + + /* Send Event to upper layer */ + lbs_deb_wext("event indication string %s\n", (char *)buf); + lbs_deb_wext("event indication length %d\n", iwrq.data.length); + lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str); + + wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf); + + lbs_deb_leave(LBS_DEB_WEXT); +} + /** * @brief Find the channel frequency power info with specific channel * diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index 4c08db497606..607d0ffefddb 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -4,6 +4,8 @@ #ifndef _LBS_WEXT_H_ #define _LBS_WEXT_H_ +void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); + extern struct iw_handler_def lbs_handler_def; extern struct iw_handler_def mesh_handler_def; -- cgit v1.2.3 From f57bd284e435d1ddf69b4266f63d856865152271 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:53 +0200 Subject: libertas: remove handling for CMD_802_11_LED_GPIO_CTRL ... which just resided as an old-style command in cmd/cmdresp, but was nowhere useed. If we ever need it, we can re-add it as a newstyle command. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 23 ----------------------- drivers/net/wireless/libertas/cmdresp.c | 6 ------ 2 files changed, 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 7ddab10f0bd5..5faa987a8c72 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1180,29 +1180,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = 0; break; - case CMD_802_11_LED_GPIO_CTRL: - { - struct mrvl_ie_ledgpio *gpio = - (struct mrvl_ie_ledgpio*) - cmdptr->params.ledgpio.data; - - memmove(&cmdptr->params.ledgpio, - pdata_buf, - sizeof(struct cmd_ds_802_11_led_ctrl)); - - cmdptr->command = - cpu_to_le16(CMD_802_11_LED_GPIO_CTRL); - -#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8 - cmdptr->size = - cpu_to_le16(le16_to_cpu(gpio->header.len) - + S_DS_GEN - + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN); - gpio->header.len = gpio->header.len; - - ret = 0; - break; - } case CMD_BT_ACCESS: ret = lbs_cmd_bt_access(cmdptr, cmd_action, pdata_buf); diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 0312f2496f74..87c24e5a173b 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -187,12 +187,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, sizeof(struct cmd_ds_802_11_tpc_cfg)); spin_unlock_irqrestore(&priv->driver_lock, flags); break; - case CMD_RET(CMD_802_11_LED_GPIO_CTRL): - spin_lock_irqsave(&priv->driver_lock, flags); - memmove((void *)priv->cur_cmd->callback_arg, &resp->params.ledgpio, - sizeof(struct cmd_ds_802_11_led_ctrl)); - spin_unlock_irqrestore(&priv->driver_lock, flags); - break; case CMD_RET(CMD_GET_TSF): spin_lock_irqsave(&priv->driver_lock, flags); -- cgit v1.2.3 From b856f73b39ca6b619e6e8d088141aec3ff62852c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:54 +0200 Subject: libertas: remove handling for CMD_GET_TSF ... which just resided as an old-style command in cmd/cmdresp, but was nowhere useed. If we ever need it, we can re-add it as a newstyle command. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 6 ------ drivers/net/wireless/libertas/cmdresp.c | 6 ------ drivers/net/wireless/libertas/host.h | 1 - 3 files changed, 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 5faa987a8c72..b7b562445cf1 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1189,12 +1189,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_fwt_access(cmdptr, cmd_action, pdata_buf); break; - case CMD_GET_TSF: - cmdptr->command = cpu_to_le16(CMD_GET_TSF); - cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) + - S_DS_GEN); - ret = 0; - break; case CMD_802_11_BEACON_CTRL: ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); break; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 87c24e5a173b..e3b854cce69c 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -188,12 +188,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, spin_unlock_irqrestore(&priv->driver_lock, flags); break; - case CMD_RET(CMD_GET_TSF): - spin_lock_irqsave(&priv->driver_lock, flags); - memcpy((void *)priv->cur_cmd->callback_arg, - &resp->params.gettsf.tsfvalue, sizeof(u64)); - spin_unlock_irqrestore(&priv->driver_lock, flags); - break; case CMD_RET(CMD_BT_ACCESS): spin_lock_irqsave(&priv->driver_lock, flags); if (priv->cur_cmd->callback_arg) diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index d4b875445f59..c600f67b2de3 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -968,7 +968,6 @@ struct cmd_ds_command { struct cmd_ds_bt_access bt; struct cmd_ds_fwt_access fwt; - struct cmd_ds_get_tsf gettsf; struct cmd_ds_802_11_beacon_control bcn_ctrl; } params; } __attribute__ ((packed)); -- cgit v1.2.3 From 8ec97cc803e1d52022e916074415acaec276288c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:55 +0200 Subject: libertas: remove "struct cmd_ds_gen" It was only used as a source for S_DS_GEN, but the size of this struct is equal to the size of "struct cmd_header". Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 7 ++++--- drivers/net/wireless/libertas/cmd.c | 22 ++++++++++++---------- drivers/net/wireless/libertas/host.h | 13 ------------- drivers/net/wireless/libertas/scan.c | 4 ++-- 4 files changed, 18 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 17e76ac4179c..4ce554ac900f 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -279,7 +279,7 @@ int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, cmd.hdr.size = cpu_to_le16(sizeof(cmd)); if (cmd_action == CMD_ACT_GET) { - cmd.hdr.size = cpu_to_le16(S_DS_GEN + 2); + cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2); } else { memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet)); @@ -456,7 +456,8 @@ int lbs_cmd_802_11_rssi(struct lbs_private *priv, lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_RSSI); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + + sizeof(struct cmd_header)); cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR); /* reset Beacon SNR/NF/RSSI values */ @@ -514,7 +515,7 @@ int lbs_cmd_bcn_ctrl(struct lbs_private *priv, lbs_deb_enter(LBS_DEB_CMD); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control) - + S_DS_GEN); + + sizeof(struct cmd_header)); cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL); bcn_ctrl->action = cpu_to_le16(cmd_action); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index b7b562445cf1..5326483b50d2 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -239,7 +239,7 @@ static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd, cmd->command = cpu_to_le16(CMD_802_11_PS_MODE); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) + - S_DS_GEN); + sizeof(struct cmd_header)); psm->action = cpu_to_le16(cmd_action); psm->multipledtim = 0; switch (cmd_action) { @@ -534,7 +534,7 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd, cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) + - S_DS_GEN); + sizeof(struct cmd_header)); monitor->action = cpu_to_le16(cmd_action); if (cmd_action == CMD_ACT_SET) { @@ -643,7 +643,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr, cmdptr->size = cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access) - + S_DS_GEN); + + sizeof(struct cmd_header)); macreg = (struct cmd_ds_mac_reg_access *)&cmdptr->params. macreg; @@ -662,7 +662,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr, cmdptr->size = cpu_to_le16(sizeof (struct cmd_ds_bbp_reg_access) - + S_DS_GEN); + + sizeof(struct cmd_header)); bbpreg = (struct cmd_ds_bbp_reg_access *)&cmdptr->params. bbpreg; @@ -681,7 +681,7 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr, cmdptr->size = cpu_to_le16(sizeof (struct cmd_ds_rf_reg_access) + - S_DS_GEN); + sizeof(struct cmd_header)); rfreg = (struct cmd_ds_rf_reg_access *)&cmdptr->params. rfreg; @@ -708,7 +708,8 @@ static int lbs_cmd_bt_access(struct cmd_ds_command *cmd, lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); cmd->command = cpu_to_le16(CMD_BT_ACCESS); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + + sizeof(struct cmd_header)); cmd->result = 0; bt_access->action = cpu_to_le16(cmd_action); @@ -745,7 +746,8 @@ static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd, lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); cmd->command = cpu_to_le16(CMD_FWT_ACCESS); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + + sizeof(struct cmd_header)); cmd->result = 0; if (pdata_buf) @@ -1161,7 +1163,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, cmdptr->command = cpu_to_le16(cmd_no); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) + - S_DS_GEN); + sizeof(struct cmd_header)); memmove(&cmdptr->params.afc, pdata_buf, sizeof(struct cmd_ds_802_11_afc)); @@ -1173,7 +1175,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) + - S_DS_GEN); + sizeof(struct cmd_header)); memmove(&cmdptr->params.tpccfg, pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg)); @@ -1194,7 +1196,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, break; case CMD_802_11_DEEP_SLEEP: cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP); - cmdptr->size = cpu_to_le16(S_DS_GEN); + cmdptr->size = cpu_to_le16(sizeof(struct cmd_header)); break; default: lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no); diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index c600f67b2de3..3809c0b49464 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -389,19 +389,6 @@ struct lbs_offset_value { u32 value; } __attribute__ ((packed)); -/* Define general data structure */ -/* cmd_DS_GEN */ -struct cmd_ds_gen { - __le16 command; - __le16 size; - __le16 seqnum; - __le16 result; - void *cmdresp[0]; -} __attribute__ ((packed)); - -#define S_DS_GEN sizeof(struct cmd_ds_gen) - - /* * Define data structure for CMD_GET_HW_SPEC * This structure defines the response for the GET_HW_SPEC command diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 8273bcd216be..5f0a598a3b50 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -1291,11 +1291,11 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, /* The size of the TLV buffer is equal to the entire command response * size (scanrespsize) minus the fixed fields (sizeof()'s), the * BSS Descriptions (bssdescriptsize as bytesLef) and the command - * response header (S_DS_GEN) + * response header (sizeof(struct cmd_header)) */ tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize) + sizeof(scanresp->nr_sets) - + S_DS_GEN); + + sizeof(struct cmd_header)); /* * Process each scan response returned (scanresp->nr_sets). Save -- cgit v1.2.3 From fea2b8ec8192c62dbf5347c873cb1c8a87717a6a Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:56 +0200 Subject: libertas: move SIOCGIWAP calls to wext.c Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 8 +------- drivers/net/wireless/libertas/main.c | 5 +---- drivers/net/wireless/libertas/wext.c | 9 +++++++++ drivers/net/wireless/libertas/wext.h | 1 + 4 files changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index e3b854cce69c..abd20ea92553 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -27,23 +27,17 @@ */ void lbs_mac_event_disconnected(struct lbs_private *priv) { - union iwreq_data wrqu; - if (priv->connect_status != LBS_CONNECTED) return; lbs_deb_enter(LBS_DEB_ASSOC); - memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - /* * Cisco AP sends EAP failure and de-auth in less than 0.5 ms. * It causes problem in the Supplicant */ - msleep_interruptible(1000); - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + lbs_send_disconnect_notification(priv); /* report disconnect to upper layer */ netif_stop_queue(priv->dev); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index eb61f6955e9e..01f46cf288d7 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1227,7 +1227,6 @@ EXPORT_SYMBOL_GPL(lbs_add_card); void lbs_remove_card(struct lbs_private *priv) { struct net_device *dev = priv->dev; - union iwreq_data wrqu; lbs_deb_enter(LBS_DEB_MAIN); @@ -1252,9 +1251,7 @@ void lbs_remove_card(struct lbs_private *priv) lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); } - memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); + lbs_send_disconnect_notification(priv); if (priv->is_deep_sleep) { priv->is_deep_sleep = 0; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 18c045bcc947..dc63b33b01f0 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -45,6 +45,15 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv) priv->pending_assoc_req = NULL; } +void lbs_send_disconnect_notification(struct lbs_private *priv) +{ + union iwreq_data wrqu; + + memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); +} + void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str) { union iwreq_data iwrq; diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index 607d0ffefddb..50558262ecc3 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -4,6 +4,7 @@ #ifndef _LBS_WEXT_H_ #define _LBS_WEXT_H_ +void lbs_send_disconnect_notification(struct lbs_private *priv); void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); extern struct iw_handler_def lbs_handler_def; -- cgit v1.2.3 From 560c63383f060b5ea68834e4720ab7bfb4303ff7 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:57 +0200 Subject: libertas: move mic failure event to wext.c ... because for cfg80211 we'll need a completely different implementation. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmdresp.c | 30 ++---------------------------- drivers/net/wireless/libertas/wext.c | 27 ++++++++++++++++++++++++++- drivers/net/wireless/libertas/wext.h | 2 +- 3 files changed, 29 insertions(+), 30 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index abd20ea92553..21d57690c20a 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -73,32 +73,6 @@ void lbs_mac_event_disconnected(struct lbs_private *priv) lbs_deb_leave(LBS_DEB_ASSOC); } -/** - * @brief This function handles MIC failure event. - * - * @param priv A pointer to struct lbs_private structure - * @para event the event id - * @return n/a - */ -static void handle_mic_failureevent(struct lbs_private *priv, u32 event) -{ - char buf[50]; - - lbs_deb_enter(LBS_DEB_CMD); - memset(buf, 0, sizeof(buf)); - - sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); - - if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) { - strcat(buf, "unicast "); - } else { - strcat(buf, "multicast "); - } - - lbs_send_iwevcustom_event(priv, buf); - lbs_deb_leave(LBS_DEB_CMD); -} - static int lbs_ret_reg_access(struct lbs_private *priv, u16 type, struct cmd_ds_command *resp) { @@ -477,12 +451,12 @@ int lbs_process_event(struct lbs_private *priv, u32 event) case MACREG_INT_CODE_MIC_ERR_UNICAST: lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n"); - handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST); + lbs_send_mic_failureevent(priv, event); break; case MACREG_INT_CODE_MIC_ERR_MULTICAST: lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n"); - handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); + lbs_send_mic_failureevent(priv, event); break; case MACREG_INT_CODE_MIB_CHANGED: diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index dc63b33b01f0..a8eb9e1fcf36 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -54,7 +54,7 @@ void lbs_send_disconnect_notification(struct lbs_private *priv) wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); } -void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str) +static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str) { union iwreq_data iwrq; u8 buf[50]; @@ -78,6 +78,31 @@ void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str) lbs_deb_leave(LBS_DEB_WEXT); } +/** + * @brief This function handles MIC failure event. + * + * @param priv A pointer to struct lbs_private structure + * @para event the event id + * @return n/a + */ +void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) +{ + char buf[50]; + + lbs_deb_enter(LBS_DEB_CMD); + memset(buf, 0, sizeof(buf)); + + sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); + + if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) + strcat(buf, "unicast "); + else + strcat(buf, "multicast "); + + lbs_send_iwevcustom_event(priv, buf); + lbs_deb_leave(LBS_DEB_CMD); +} + /** * @brief Find the channel frequency power info with specific channel * diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index 50558262ecc3..5e041e64ecfe 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -5,7 +5,7 @@ #define _LBS_WEXT_H_ void lbs_send_disconnect_notification(struct lbs_private *priv); -void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); +void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); extern struct iw_handler_def lbs_handler_def; extern struct iw_handler_def mesh_handler_def; -- cgit v1.2.3 From e93156e7c4c3e2be355cac27c58664e4385c58fd Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:58 +0200 Subject: libertas: sort and categorize entries in decl.h This now makes decl.h only contain declarations for functions that don't have their own *.h file. No function change. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 4 +++- drivers/net/wireless/libertas/decl.h | 40 ++++++++++++++++-------------------- drivers/net/wireless/libertas/scan.c | 2 +- drivers/net/wireless/libertas/wext.h | 5 +++++ 4 files changed, 27 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 5326483b50d2..65fd50d31764 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -3,9 +3,10 @@ * It prepares command and sends it to firmware when it is ready. */ -#include #include #include +#include + #include "host.h" #include "decl.h" #include "defs.h" @@ -15,6 +16,7 @@ #include "scan.h" #include "cmd.h" + static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv); /** diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index d609a57750de..678f7c9f7503 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -8,46 +8,30 @@ #include -#include "defs.h" - -extern const struct ethtool_ops lbs_ethtool_ops; - -/** Function Prototype Declaration */ struct lbs_private; struct sk_buff; struct net_device; -struct cmd_ctrl_node; -struct cmd_ds_command; -int lbs_suspend(struct lbs_private *priv); -void lbs_resume(struct lbs_private *priv); - -void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count); -void lbs_queue_event(struct lbs_private *priv, u32 event); -void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); -int lbs_enter_auto_deep_sleep(struct lbs_private *priv); -int lbs_exit_auto_deep_sleep(struct lbs_private *priv); +/* ethtool.c */ +extern const struct ethtool_ops lbs_ethtool_ops; -u32 lbs_fw_index_to_data_rate(u8 index); -u8 lbs_data_rate_to_fw_index(u32 rate); -/** The proc fs interface */ +/* tx.c */ +void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count); netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); +/* rx.c */ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *); -struct chan_freq_power *lbs_find_cfp_by_band_and_channel( - struct lbs_private *priv, - u8 band, - u16 channel); /* persistcfg.c */ void lbs_persist_config_init(struct net_device *net); void lbs_persist_config_remove(struct net_device *net); + /* main.c */ struct lbs_private *lbs_add_card(void *card, struct device *dmdev); void lbs_remove_card(struct lbs_private *priv); @@ -55,5 +39,17 @@ int lbs_start_card(struct lbs_private *priv); void lbs_stop_card(struct lbs_private *priv); void lbs_host_to_card_done(struct lbs_private *priv); +int lbs_suspend(struct lbs_private *priv); +void lbs_resume(struct lbs_private *priv); + +void lbs_queue_event(struct lbs_private *priv, u32 event); +void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); + +int lbs_enter_auto_deep_sleep(struct lbs_private *priv); +int lbs_exit_auto_deep_sleep(struct lbs_private *priv); + +u32 lbs_fw_index_to_data_rate(u8 index); +u8 lbs_data_rate_to_fw_index(u32 rate); + #endif diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 5f0a598a3b50..c6a6c042b82f 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -12,10 +12,10 @@ #include #include "host.h" -#include "decl.h" #include "dev.h" #include "scan.h" #include "assoc.h" +#include "wext.h" #include "cmd.h" //! Approximate amount of data needed to pass a scan result back to iwlist diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index 5e041e64ecfe..7863baf7d234 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -10,4 +10,9 @@ void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); extern struct iw_handler_def lbs_handler_def; extern struct iw_handler_def mesh_handler_def; +struct chan_freq_power *lbs_find_cfp_by_band_and_channel( + struct lbs_private *priv, + u8 band, + u16 channel); + #endif -- cgit v1.2.3 From fef0640e1e5d5f79c48d1de1f54ed285429b4a6c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Thu, 22 Oct 2009 15:30:59 +0200 Subject: libertas: remove some references to IW_MODE_abc ... in pursue to quaff the wide-spread references to WEXT constants. When setting SNMP_MIB_OID_BSS_TYPE, wext.c can directly calculate the value the firmware wants. Reading of SNMP_MIB_OID_BSS_TYPE doesn't happen anywhere, so no need to convert the firmware value into WEXT values anyway. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/assoc.c | 3 ++- drivers/net/wireless/libertas/cmd.c | 10 ++-------- 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 4ce554ac900f..751067369ba8 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1567,7 +1567,8 @@ static int assoc_helper_mode(struct lbs_private *priv, } priv->mode = assoc_req->mode; - ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, assoc_req->mode); + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, + assoc_req->mode == IW_MODE_ADHOC ? 2 : 1); done: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 65fd50d31764..1065ce29cd08 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -390,7 +390,7 @@ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) switch (oid) { case SNMP_MIB_OID_BSS_TYPE: cmd.bufsize = cpu_to_le16(sizeof(u8)); - cmd.value[0] = (val == IW_MODE_ADHOC) ? 2 : 1; + cmd.value[0] = val; break; case SNMP_MIB_OID_11D_ENABLE: case SNMP_MIB_OID_FRAG_THRESHOLD: @@ -443,13 +443,7 @@ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) switch (le16_to_cpu(cmd.bufsize)) { case sizeof(u8): - if (oid == SNMP_MIB_OID_BSS_TYPE) { - if (cmd.value[0] == 2) - *out_val = IW_MODE_ADHOC; - else - *out_val = IW_MODE_INFRA; - } else - *out_val = cmd.value[0]; + *out_val = cmd.value[0]; break; case sizeof(u16): *out_val = le16_to_cpu(*((__le16 *)(&cmd.value))); -- cgit v1.2.3 From 1a5c3d61993f56daf15c35bea8d3943f4e835638 Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Fri, 23 Oct 2009 13:42:19 -0700 Subject: iwlwifi: add missing commands to syslog messages Two commands missing from list of commands such that when debug is enabled, these commands are shown as UNKNOWN. Missing commands are TX_ANT_CONFIGURATION_CMD and TEMPERATURE_NOTIFICATION. Signed-off-by: Jay Sternberg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 1 + drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 7d4f131708f3..1a7c0d02c19c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -114,6 +114,7 @@ enum { COEX_EVENT_CMD = 0x5c, /* Calibration */ + TEMPERATURE_NOTIFICATION = 0x62, CALIBRATION_CFG_CMD = 0x65, CALIBRATION_RES_NOTIFICATION = 0x66, CALIBRATION_COMPLETE_NOTIFICATION = 0x67, diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 22a21a1c7f49..f2a60dc4109f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -92,6 +92,8 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(CALIBRATION_RES_NOTIFICATION); IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); IWL_CMD(REPLY_TX_POWER_DBM_CMD); + IWL_CMD(TEMPERATURE_NOTIFICATION); + IWL_CMD(TX_ANT_CONFIGURATION_CMD); default: return "UNKNOWN"; -- cgit v1.2.3 From 065e63b00cf13919010bbeff48f7a120033be448 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:20 -0700 Subject: iwlwifi: fix gain computation for 5000 series and up In Rx gain balancing (chain noise) computation for 5000 series and up, the delta gain calculation should use the average noise of default chain, not "chain 0" which do not exist for all the devices. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 17555c7c1d67..afa88a304158 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -236,7 +236,7 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, data->delta_gain_code[i] = 0; continue; } - delta_g = (1000 * ((s32)average_noise[0] - + delta_g = (1000 * ((s32)average_noise[default_chain] - (s32)average_noise[i])) / 1500; /* bound gain by 2 bits value max, 3rd bit is sign */ data->delta_gain_code[i] = -- cgit v1.2.3 From fadb3582a38c33d0f7c58ab7905d4dbc67f4c4d9 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 23 Oct 2009 13:42:21 -0700 Subject: iwlwifi: consolidate apm_init() functions Consolidate most iwlXXXX_apm_init() functions into single iwl_apm_init(). Keep iwl3945_apm_init(), but leverage iwl_apm_init() for most functionality. Update 4965 init sequence to follow most recent factory recommendations. Add following members to struct iwl_cfg to guide the init sequence: pll_cfg_val (replaces needs_pll_cfg), set_l0s, use_bsm Move L0S enable/disable from nic_config() functions to iwl_apm_init(). This satisifies the "FIXME: put here L1A -L0S w/a" notice, and complies with factory-recommended sequence. Add debug info message in iwl_apm_init(), and symmetrical message in iwl_apm_stop(). Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 10 ++- drivers/net/wireless/iwlwifi/iwl-3945.c | 56 ++-------------- drivers/net/wireless/iwlwifi/iwl-4965.c | 56 ++-------------- drivers/net/wireless/iwlwifi/iwl-5000.c | 86 ++++++------------------ drivers/net/wireless/iwlwifi/iwl-6000.c | 42 +++++++++--- drivers/net/wireless/iwlwifi/iwl-core.c | 114 ++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 8 ++- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 8 files changed, 190 insertions(+), 183 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index a00f947bd59c..3da5913225e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -110,7 +110,7 @@ static struct iwl_lib_ops iwl1000_lib = { .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { - .init = iwl5000_apm_init, + .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl1000_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -163,7 +163,9 @@ struct iwl_cfg iwl1000_bgn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = false, + .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, .ht_greenfield_support = true, @@ -186,7 +188,9 @@ struct iwl_cfg iwl1000_bg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = false, + .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, .ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 9f18b4cba952..7142aa5dbdb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1013,55 +1013,15 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) return rc; } + /* - * Start up NIC's basic functionality after it has been reset - * (e.g. after platform boot, or shutdown via iwl3945_apm_stop()) + * Start up 3945's basic functionality after it has been reset + * (e.g. after platform boot, or shutdown via iwl_apm_stop()) * NOTE: This does not load uCode nor start the embedded processor */ static int iwl3945_apm_init(struct iwl_priv *priv) { - int ret; - - /* Configure chip clock phase-lock-loop */ - iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL); - - /* - * Disable L0S exit timer (platform NMI Work/Around) - * (does this do anything on 3945, or just 4965 and beyond?) - */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - /* Disable L0s without affecting L1; don't wait for ICH (L0s bug W/A) */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - - /* Set FH wait threshold to maximum (HW error during stress W/A) */ - iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); - - /* - * Set "initialization complete" bit to move adapter from - * D0U* --> D0A* (powered-up active) state. - */ - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - /* - * Wait for clock stabilization; once stabilized, access to - * device-internal resources is supported, e.g. iwl_write_prph() - * and accesses to uCode SRAM. - */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret < 0) { - IWL_DEBUG_INFO(priv, "Failed to init the card\n"); - goto out; - } - - /* Enable DMA and BSM clocks, wait for them to stabilize */ - iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); - udelay(20); + int ret = iwl_apm_init(priv); /* Clear APMG (NIC's internal power management) interrupts */ iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); @@ -1072,11 +1032,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv) udelay(5); iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - /* Disable L1-Active */ - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - -out: return ret; } @@ -2876,6 +2831,9 @@ static struct iwl_cfg iwl3945_bg_cfg = { .ops = &iwl3945_ops, .num_of_queues = IWL39_NUM_QUEUES, .mod_params = &iwl3945_mod_params, + .pll_cfg_val = CSR39_ANA_PLL_CFG_VAL, + .set_l0s = false, + .use_bsm = true, .use_isr_legacy = true, .ht_greenfield_support = false, .led_compensation = 64, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1a622aa5a160..32d5f3de429f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -317,64 +317,13 @@ static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask) iwl_write_prph(priv, IWL49_SCD_TXFACT, mask); } -static int iwl4965_apm_init(struct iwl_priv *priv) -{ - int ret = 0; - - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - - /* set "initialization complete" bit to move adapter - * D0U* --> D0A* state */ - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret < 0) { - IWL_DEBUG_INFO(priv, "Failed to init the card\n"); - goto out; - } - - /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | - APMG_CLK_VAL_BSM_CLK_RQT); - - udelay(20); - - /* disable L1-Active */ - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - -out: - return ret; -} - - static void iwl4965_nic_config(struct iwl_priv *priv) { unsigned long flags; u16 radio_cfg; - u16 lctl; spin_lock_irqsave(&priv->lock, flags); - lctl = iwl_pcie_link_ctl(priv); - - /* HW bug W/A - negligible power consumption */ - /* L1-ASPM is enabled by BIOS */ - if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) - /* L1-ASPM enabled: disable L0S */ - iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - else - /* L1-ASPM disabled: enable L0S */ - iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); /* write radio config values to register */ @@ -2223,7 +2172,7 @@ static struct iwl_lib_ops iwl4965_lib = { .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, .apm_ops = { - .init = iwl4965_apm_init, + .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl4965_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -2276,6 +2225,9 @@ struct iwl_cfg iwl4965_agn_cfg = { .num_of_queues = IWL49_NUM_QUEUES, .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, .mod_params = &iwl4965_mod_params, + .pll_cfg_val = 0, + .set_l0s = true, + .use_bsm = true, .use_isr_legacy = true, .ht_greenfield_support = false, .broken_powersave = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index afa88a304158..a6e347b9799a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -72,72 +72,14 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = { IWL_TX_FIFO_HCCA_2 }; -int iwl5000_apm_init(struct iwl_priv *priv) -{ - int ret = 0; - - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - - /* Set FH wait threshold to maximum (HW error during stress W/A) */ - iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); - - /* enable HAP INTA to move device L1a -> L0s */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); - - if (priv->cfg->need_pll_cfg) - iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); - - /* set "initialization complete" bit to move adapter - * D0U* --> D0A* state */ - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - - /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret < 0) { - IWL_DEBUG_INFO(priv, "Failed to init the card\n"); - return ret; - } - - /* enable DMA */ - iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); - - udelay(20); - - /* disable L1-Active */ - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - - return ret; -} - /* NIC configuration for 5000 series */ void iwl5000_nic_config(struct iwl_priv *priv) { unsigned long flags; u16 radio_cfg; - u16 lctl; spin_lock_irqsave(&priv->lock, flags); - lctl = iwl_pcie_link_ctl(priv); - - /* HW bug W/A */ - /* L1-ASPM is enabled by BIOS */ - if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) - /* L1-APSM enabled: disable L0S */ - iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - else - /* L1-ASPM disabled: enable L0S */ - iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); /* write radio config values to register */ @@ -1488,7 +1430,7 @@ struct iwl_lib_ops iwl5000_lib = { .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { - .init = iwl5000_apm_init, + .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -1539,7 +1481,7 @@ static struct iwl_lib_ops iwl5150_lib = { .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { - .init = iwl5000_apm_init, + .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl5000_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -1607,7 +1549,9 @@ struct iwl_cfg iwl5300_agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, @@ -1628,7 +1572,9 @@ struct iwl_cfg iwl5100_bg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, @@ -1649,7 +1595,9 @@ struct iwl_cfg iwl5100_abg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, @@ -1670,7 +1618,9 @@ struct iwl_cfg iwl5100_agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_B, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, @@ -1691,7 +1641,9 @@ struct iwl_cfg iwl5350_agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, @@ -1712,7 +1664,9 @@ struct iwl_cfg iwl5150_agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index b53181324487..5211872da880 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -193,7 +193,7 @@ static struct iwl_lib_ops iwl6000_lib = { .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, .apm_ops = { - .init = iwl5000_apm_init, + .init = iwl_apm_init, .stop = iwl_apm_stop, .config = iwl6000_nic_config, .set_pwr_src = iwl_set_pwr_src, @@ -266,7 +266,9 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -292,7 +294,9 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -317,7 +321,9 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -345,7 +351,9 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -371,7 +379,9 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -396,7 +406,9 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -421,7 +433,9 @@ struct iwl_cfg iwl6050_2agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, @@ -447,7 +461,9 @@ struct iwl_cfg iwl6050_2abg_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, @@ -472,7 +488,9 @@ struct iwl_cfg iwl6000_3agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, @@ -498,7 +516,9 @@ struct iwl_cfg iwl6050_3agn_cfg = { .mod_params = &iwl50_mod_params, .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, - .need_pll_cfg = false, + .pll_cfg_val = 0, + .set_l0s = false, + .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7ce8663fdb7b..1d7248cd1969 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1369,6 +1369,8 @@ void iwl_apm_stop(struct iwl_priv *priv) { unsigned long flags; + IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n"); + iwl_apm_stop_master(priv); spin_lock_irqsave(&priv->lock, flags); @@ -1382,6 +1384,118 @@ void iwl_apm_stop(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_apm_stop); + +/* + * Start up NIC's basic functionality after it has been reset + * (e.g. after platform boot, or shutdown via iwl_apm_stop()) + * NOTE: This does not load uCode nor start the embedded processor + */ +int iwl_apm_init(struct iwl_priv *priv) +{ + int ret = 0; + u16 lctl; + + IWL_DEBUG_INFO(priv, "Init card's basic functions\n"); + + /* + * Use "set_bit" below rather than "write", to preserve any hardware + * bits already set by default after reset. + */ + + /* Disable L0S exit timer (platform NMI Work/Around) */ + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + + /* + * Disable L0s without affecting L1; + * don't wait for ICH L0s (ICH bug W/A) + */ + iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + + /* Set FH wait threshold to maximum (HW error during stress W/A) */ + iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); + + /* + * Enable HAP INTA (interrupt from management bus) to + * wake device's PCI Express link L1a -> L0s + * NOTE: This is no-op for 3945 (non-existant bit) + */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); + + /* + * HW bug W/A - costs negligible power consumption ... + * Check if BIOS (or OS) enabled L1-ASPM on this device + */ + if (priv->cfg->set_l0s) { + lctl = iwl_pcie_link_ctl(priv); + if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == + PCI_CFG_LINK_CTRL_VAL_L1_EN) { + /* L1-ASPM enabled; disable(!) L0S */ + iwl_set_bit(priv, CSR_GIO_REG, + CSR_GIO_REG_VAL_L0S_ENABLED); + IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n"); + } else { + /* L1-ASPM disabled; enable(!) L0S */ + iwl_clear_bit(priv, CSR_GIO_REG, + CSR_GIO_REG_VAL_L0S_ENABLED); + IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n"); + } + } + + /* Configure analog phase-lock-loop before activating to D0A */ + if (priv->cfg->pll_cfg_val) + iwl_set_bit(priv, CSR_ANA_PLL_CFG, priv->cfg->pll_cfg_val); + + /* + * Set "initialization complete" bit to move adapter from + * D0U* --> D0A* (powered-up active) state. + */ + iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + + /* + * Wait for clock stabilization; once stabilized, access to + * device-internal resources is supported, e.g. iwl_write_prph() + * and accesses to uCode SRAM. + */ + ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) { + IWL_DEBUG_INFO(priv, "Failed to init the card\n"); + goto out; + } + + /* + * Enable DMA and BSM (if used) clocks, wait for them to stabilize. + * BSM (Boostrap State Machine) is only in 3945 and 4965; + * later devices (i.e. 5000 and later) have non-volatile SRAM, + * and don't need BSM to restore data after power-saving sleep. + * + * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits + * do not disable clocks. This preserves any hardware bits already + * set by default in "CLK_CTRL_REG" after reset. + */ + if (priv->cfg->use_bsm) + iwl_write_prph(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); + else + iwl_write_prph(priv, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + udelay(20); + + /* Disable L1-Active */ + iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + +out: + return ret; +} +EXPORT_SYMBOL(iwl_apm_init); + + + void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a2a580df3d99..a2d526a7b4ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -262,7 +262,12 @@ struct iwl_cfg { const struct iwl_mod_params *mod_params; u8 valid_tx_ant; u8 valid_rx_ant; - bool need_pll_cfg; + + /* for iwl_apm_init() */ + u32 pll_cfg_val; + bool set_l0s; + bool use_bsm; + bool use_isr_legacy; enum iwl_pa_type pa_type; const u16 max_ll_items; @@ -663,6 +668,7 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwl_apm_stop(struct iwl_priv *priv); int iwl_apm_stop_master(struct iwl_priv *priv); +int iwl_apm_init(struct iwl_priv *priv); void iwl_setup_rxon_timing(struct iwl_priv *priv); static inline int iwl_send_rxon_assoc(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 6ba082d6ab16..1378654801ca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -85,7 +85,6 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags); extern int iwl5000_calc_rssi(struct iwl_priv *priv, struct iwl_rx_phy_res *rx_resp); -extern int iwl5000_apm_init(struct iwl_priv *priv); extern void iwl5000_nic_config(struct iwl_priv *priv); extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv); extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, -- cgit v1.2.3 From 1ed2a3d29ac304092f588a47a9ed2b83d4d8c835 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:22 -0700 Subject: iwlwifi: separate led function from statistic notification Detach led background task from statistic notification routine. if led blinking is required; the blink rate is based on the traffic condition. It do not relate to statistics notification. In addition to that, there is not a requirement for statistics notification has to occur all the time. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 -- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-rx.c | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7142aa5dbdb5..269b9889e39e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -359,8 +359,6 @@ void iwl3945_hw_rx_statistics(struct iwl_priv *priv, le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39)); - - iwl_leds_background(priv); } /****************************************************************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 64d918787e88..a34acb7e44c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1019,6 +1019,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { iwl_rx_handle(priv); priv->isr_stats.rx++; + iwl_leds_background(priv); handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } @@ -1220,6 +1221,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) CSR_INT_PERIODIC_ENA); priv->isr_stats.rx++; + iwl_leds_background(priv); } if (inta & CSR_INT_BIT_FH_TX) { diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 0a407f79de01..cfc31ae4712b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -627,9 +627,6 @@ void iwl_rx_statistics(struct iwl_priv *priv, iwl_rx_calc_noise(priv); queue_work(priv->workqueue, &priv->run_time_calib_work); } - - iwl_leds_background(priv); - if (priv->cfg->ops->lib->temp_ops.temperature && change) priv->cfg->ops->lib->temp_ops.temperature(priv); } -- cgit v1.2.3 From 456d0f76727ba6f97aa1cee63f1bae84642768c4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:23 -0700 Subject: iwlwifi: update bt co-exit configuration parameter Adding parameter ranges for bt co-exist configuration command. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 13 +++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 6 +++--- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 1a7c0d02c19c..0d660a7475a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2218,6 +2218,19 @@ struct iwl_link_quality_cmd { __le32 reserved2; } __attribute__ ((packed)); +#define BT_COEX_DISABLE (0x0) +#define BT_COEX_MODE_2W (0x1) +#define BT_COEX_MODE_3W (0x2) +#define BT_COEX_MODE_4W (0x3) + +#define BT_LEAD_TIME_MIN (0x0) +#define BT_LEAD_TIME_DEF (0x1E) +#define BT_LEAD_TIME_MAX (0xFF) + +#define BT_MAX_KILL_MIN (0x1) +#define BT_MAX_KILL_DEF (0x5) +#define BT_MAX_KILL_MAX (0xFF) + /* * REPLY_BT_CONFIG = 0x9b (command, has simple generic response) * diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1d7248cd1969..77b9825f79ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2003,9 +2003,9 @@ EXPORT_SYMBOL(iwl_isr_legacy); int iwl_send_bt_config(struct iwl_priv *priv) { struct iwl_bt_cmd bt_cmd = { - .flags = 3, - .lead_time = 0xAA, - .max_kill = 1, + .flags = BT_COEX_MODE_4W, + .lead_time = BT_LEAD_TIME_DEF, + .max_kill = BT_MAX_KILL_DEF, .kill_ack_mask = 0, .kill_cts_mask = 0, }; -- cgit v1.2.3 From 52aa081c40324ecb04a47864e4e56dafc5a72a34 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:24 -0700 Subject: iwlwifi: specify the valid tx/rx chain in device config structure Specify both Tx and Rx chain in device configuration structure instead of hard code in set_hw_params() for 4965 Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 32d5f3de429f..bd856df5b04d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -653,10 +653,10 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR; - priv->hw_params.tx_chains_num = 2; - priv->hw_params.rx_chains_num = 2; - priv->hw_params.valid_tx_ant = ANT_A | ANT_B; - priv->hw_params.valid_rx_ant = ANT_A | ANT_B; + priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); + priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; + priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; if (priv->cfg->ops->lib->temp_ops.set_ct_kill) priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); @@ -2225,6 +2225,8 @@ struct iwl_cfg iwl4965_agn_cfg = { .num_of_queues = IWL49_NUM_QUEUES, .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, .mod_params = &iwl4965_mod_params, + .valid_tx_ant = ANT_AB, + .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, .set_l0s = true, .use_bsm = true, -- cgit v1.2.3 From 29b1b2688fd71346f78f175d9669c006686b6dc3 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 23 Oct 2009 13:42:25 -0700 Subject: iwlwifi: fix use after free bug for paged rx In the paged rx patch (4854fde2), I introduced a bug that could possibly touch an already freed page. It is fixed by avoiding the access in this patch. I've also added some comments so that other people touching the code won't make the same mistake. In the future, if we cannot avoid access the page after being handled to the upper layer, we can use get_page/put_page to handle it. For now, it's just not necessary. It also fixed a debug message print bug reported by Stanislaw Gruszka . Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 15 ++++++++++----- drivers/net/wireless/iwlwifi/iwl-agn.c | 11 +++++++++-- drivers/net/wireless/iwlwifi/iwl-rx.c | 21 ++++++++++++++------- drivers/net/wireless/iwlwifi/iwl3945-base.c | 18 +++++++++++++----- 4 files changed, 46 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 269b9889e39e..f5d75288bd27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -548,6 +548,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, u16 len = le16_to_cpu(rx_hdr->len); struct sk_buff *skb; int ret; + __le16 fc = hdr->frame_control; /* We received data from the HW, so stop the watchdog */ if (unlikely(len + IWL39_RX_FRAME_SIZE > @@ -580,9 +581,9 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, /* mac80211 currently doesn't support paged SKB. Convert it to * linear SKB for management frame and data frame requires * software decryption or software defragementation. */ - if (ieee80211_is_mgmt(hdr->frame_control) || - ieee80211_has_protected(hdr->frame_control) || - ieee80211_has_morefrags(hdr->frame_control) || + if (ieee80211_is_mgmt(fc) || + ieee80211_has_protected(fc) || + ieee80211_has_morefrags(fc) || le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) ret = skb_linearize(skb); else @@ -594,11 +595,15 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, goto out; } - iwl_update_stats(priv, false, hdr->frame_control, len); + /* + * XXX: We cannot touch the page and its virtual memory (pkt) after + * here. It might have already been freed by the above skb change. + */ + iwl_update_stats(priv, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); - ieee80211_rx(priv->hw, skb); + ieee80211_rx(priv->hw, skb); out: priv->alloc_rxb_page--; rxb->page = NULL; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a34acb7e44c3..0d3886505205 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -814,8 +814,8 @@ void iwl_rx_handle(struct iwl_priv *priv) if (priv->rx_handlers[pkt->hdr.cmd]) { IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); - priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; + priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); } else { /* No handling needed */ IWL_DEBUG_RX(priv, @@ -824,11 +824,18 @@ void iwl_rx_handle(struct iwl_priv *priv) pkt->hdr.cmd); } + /* + * XXX: After here, we should always check rxb->page + * against NULL before touching it or its virtual + * memory (pkt). Because some rx_handler might have + * already taken or freed the pages. + */ + if (reclaim) { /* Invoke any callbacks, transfer the buffer to caller, * and fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ - if (rxb && rxb->page) + if (rxb->page) iwl_tx_cmd_complete(priv, rxb); else IWL_WARN(priv, "Claim null rxb?\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index cfc31ae4712b..e5339c9ad13e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -241,6 +241,7 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) struct iwl_rx_mem_buffer *rxb; struct page *page; unsigned long flags; + gfp_t gfp_mask = priority; while (1) { spin_lock_irqsave(&rxq->lock, flags); @@ -251,13 +252,13 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) spin_unlock_irqrestore(&rxq->lock, flags); if (rxq->free_count > RX_LOW_WATERMARK) - priority |= __GFP_NOWARN; + gfp_mask |= __GFP_NOWARN; if (priv->hw_params.rx_page_order > 0) - priority |= __GFP_COMP; + gfp_mask |= __GFP_COMP; /* Alloc a new receive buffer */ - page = alloc_pages(priority, priv->hw_params.rx_page_order); + page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order); if (!page) { if (net_ratelimit()) IWL_DEBUG_INFO(priv, "alloc_pages failed, " @@ -922,6 +923,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, { struct sk_buff *skb; int ret = 0; + __le16 fc = hdr->frame_control; /* We only process data packets if the interface is open */ if (unlikely(!priv->is_open)) { @@ -946,9 +948,9 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, /* mac80211 currently doesn't support paged SKB. Convert it to * linear SKB for management frame and data frame requires * software decryption or software defragementation. */ - if (ieee80211_is_mgmt(hdr->frame_control) || - ieee80211_has_protected(hdr->frame_control) || - ieee80211_has_morefrags(hdr->frame_control) || + if (ieee80211_is_mgmt(fc) || + ieee80211_has_protected(fc) || + ieee80211_has_morefrags(fc) || le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) ret = skb_linearize(skb); else @@ -960,7 +962,12 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, goto out; } - iwl_update_stats(priv, false, hdr->frame_control, len); + /* + * XXX: We cannot touch the page and its virtual memory (hdr) after + * here. It might have already been freed by the above skb change. + */ + + iwl_update_stats(priv, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx(priv->hw, skb); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5977a57a234c..8b08bdc10bc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1124,6 +1124,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) struct iwl_rx_mem_buffer *rxb; struct page *page; unsigned long flags; + gfp_t gfp_mask = priority; while (1) { spin_lock_irqsave(&rxq->lock, flags); @@ -1135,13 +1136,13 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) spin_unlock_irqrestore(&rxq->lock, flags); if (rxq->free_count > RX_LOW_WATERMARK) - priority |= __GFP_NOWARN; + gfp_mask |= __GFP_NOWARN; if (priv->hw_params.rx_page_order > 0) - priority |= __GFP_COMP; + gfp_mask |= __GFP_COMP; /* Alloc a new receive buffer */ - page = alloc_pages(priority, priv->hw_params.rx_page_order); + page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order); if (!page) { if (net_ratelimit()) IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n"); @@ -1410,8 +1411,8 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) if (priv->rx_handlers[pkt->hdr.cmd]) { IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); - priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; + priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); } else { /* No handling needed */ IWL_DEBUG_RX(priv, @@ -1420,11 +1421,18 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) pkt->hdr.cmd); } + /* + * XXX: After here, we should always check rxb->page + * against NULL before touching it or its virtual + * memory (pkt). Because some rx_handler might have + * already taken or freed the pages. + */ + if (reclaim) { /* Invoke any callbacks, transfer the buffer to caller, * and fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ - if (rxb && rxb->page) + if (rxb->page) iwl_tx_cmd_complete(priv, rxb); else IWL_WARN(priv, "Claim null rxb?\n"); -- cgit v1.2.3 From c8c24872c6a90ef0298491a1c14326861ab74cab Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:26 -0700 Subject: iwlwifi: increase max tfd payload size Increase the size of TFD_MAX_PAYLOAD_SIZE (the size of iwl_device_cmd) to accommodate iwl6000_channel_switch_cmd data structure. Signed-off-by: Wey-Yi Guy Acked-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1378654801ca..b520e551f7f8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -364,7 +364,7 @@ enum { CMD_WANT_SKB = (1 << 2), }; -#define IWL_CMD_MAX_PAYLOAD 320 +#define DEF_CMD_PAYLOAD_SIZE 320 /* * IWL_LINK_HDR_MAX should include ieee80211_hdr, radiotap header, @@ -388,7 +388,8 @@ struct iwl_device_cmd { u16 val16; u32 val32; struct iwl_tx_cmd tx; - u8 payload[IWL_CMD_MAX_PAYLOAD]; + struct iwl6000_channel_switch_cmd chswitch; + u8 payload[DEF_CMD_PAYLOAD_SIZE]; } __attribute__ ((packed)) cmd; } __attribute__ ((packed)); @@ -741,7 +742,11 @@ static inline int iwl_queue_used(const struct iwl_queue *q, int i) static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) { - /* This is for scan command, the big buffer at end of command array */ + /* + * This is for init calibration result and scan command which + * required buffer > TFD_MAX_PAYLOAD_SIZE, + * the big buffer at end of command array + */ if (is_huge) return q->n_window; /* must be power of 2 */ -- cgit v1.2.3 From 6047b4f939682ae9bf839fd00c80029cb8f073bb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:27 -0700 Subject: iwlwifi: choose thermal throttle method based on device config Using device configuration structure to decide the type of thermal throttle method for the device. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-power.c | 8 ++------ 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 5211872da880..0873322755aa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -277,6 +277,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6000h_2abg_cfg = { @@ -304,6 +305,7 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6000h_2bg_cfg = { @@ -331,6 +333,7 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; /* @@ -362,6 +365,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -389,6 +393,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -416,6 +421,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -444,6 +450,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -471,6 +478,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -499,6 +507,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -527,6 +536,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, + .adv_thermal_throttle = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a2d526a7b4ce..9dbf59811f45 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -225,6 +225,7 @@ struct iwl_mod_params { * The detail algorithm is described in iwl-led.c * @use_rts_for_ht: use rts/cts protection for HT traffic * @chain_noise_num_beacons: number of beacons used to compute chain noise + * @adv_thermal_throttle: support advance thermal throttle * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -278,6 +279,7 @@ struct iwl_cfg { bool use_rts_for_ht; int chain_noise_num_beacons; const bool supports_idle; + bool adv_thermal_throttle; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 150ff87af33b..432f4650cf2e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -893,9 +893,7 @@ void iwl_tt_initialize(struct iwl_priv *priv) INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { - case CSR_HW_REV_TYPE_6x00: - case CSR_HW_REV_TYPE_6x50: + if (priv->cfg->adv_thermal_throttle) { IWL_DEBUG_POWER(priv, "Advanced Thermal Throttling\n"); tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) * IWL_TI_STATE_MAX, GFP_KERNEL); @@ -928,11 +926,9 @@ void iwl_tt_initialize(struct iwl_priv *priv) &restriction_range[0], size); priv->thermal_throttle.advanced_tt = true; } - break; - default: + } else { IWL_DEBUG_POWER(priv, "Legacy Thermal Throttling\n"); priv->thermal_throttle.advanced_tt = false; - break; } } EXPORT_SYMBOL(iwl_tt_initialize); -- cgit v1.2.3 From 480e8407dc0bccdd8d7cfe29b8fcaaa21dd20e68 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:28 -0700 Subject: iwlwifi: issue ct_kill host command based on device config Using device configuration structure to decide how to configure ct_kill host command. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-6000.c | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 9 ++------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ 4 files changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 3da5913225e2..3a645e485dda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -171,6 +171,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl1000_bg_cfg = { @@ -196,6 +197,7 @@ struct iwl_cfg iwl1000_bg_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .support_ct_kill_exit = true, }; MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 0873322755aa..f5855293c767 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -278,6 +278,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6000h_2abg_cfg = { @@ -306,6 +307,7 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6000h_2bg_cfg = { @@ -334,6 +336,7 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; /* @@ -366,6 +369,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -394,6 +398,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6000i_2bg_cfg = { @@ -422,6 +427,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6050_2agn_cfg = { @@ -451,6 +457,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -479,6 +486,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -508,6 +516,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; struct iwl_cfg iwl6050_3agn_cfg = { @@ -537,6 +546,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .supports_idle = true, .adv_thermal_throttle = true, + .support_ct_kill_exit = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 77b9825f79ba..e43469cfbbc0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2165,10 +2165,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); priv->thermal_throttle.ct_kill_toggle = false; - switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { - case CSR_HW_REV_TYPE_1000: - case CSR_HW_REV_TYPE_6x00: - case CSR_HW_REV_TYPE_6x50: + if (priv->cfg->support_ct_kill_exit) { adv_cmd.critical_temperature_enter = cpu_to_le32(priv->hw_params.ct_kill_threshold); adv_cmd.critical_temperature_exit = @@ -2185,8 +2182,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) "exit is %d\n", priv->hw_params.ct_kill_threshold, priv->hw_params.ct_kill_exit_threshold); - break; - default: + } else { cmd.critical_temperature_R = cpu_to_le32(priv->hw_params.ct_kill_threshold); @@ -2199,7 +2195,6 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) "succeeded, " "critical temperature is %d\n", priv->hw_params.ct_kill_threshold); - break; } } EXPORT_SYMBOL(iwl_rf_kill_ct_config); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 9dbf59811f45..02bacc4975f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -226,6 +226,7 @@ struct iwl_mod_params { * @use_rts_for_ht: use rts/cts protection for HT traffic * @chain_noise_num_beacons: number of beacons used to compute chain noise * @adv_thermal_throttle: support advance thermal throttle + * @support_ct_kill_exit: support ct kill exit condition * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -280,6 +281,7 @@ struct iwl_cfg { int chain_noise_num_beacons; const bool supports_idle; bool adv_thermal_throttle; + bool support_ct_kill_exit; }; /*************************** -- cgit v1.2.3 From 4a56e9652ec2ffce87b099aa2fc5b4eb2d5b2666 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:29 -0700 Subject: iwlwifi: add channel switch support to 5000 series and up Support "channel switch" request by issue "channel switch" host command to uCode. There is no separated "channel switch" indication from mac80211, when detected "IEEE80211_CONF_CHANGE_CHANNEL" flag in iwl_mac_config(), if the station is in "associated" state, then assume "channel switch announcement" IE was received by mac80211. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 6 ------ drivers/net/wireless/iwlwifi/iwl-3945.h | 2 -- drivers/net/wireless/iwlwifi/iwl-4965.c | 12 +++++++----- drivers/net/wireless/iwlwifi/iwl-5000.c | 32 ++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-6000.c | 32 ++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 21 +++++++++++++++++---- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + 7 files changed, 89 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index f5d75288bd27..09a7bd2c0be4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1982,12 +1982,6 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) return 0; } -/* will add 3945 channel switch cmd handling later */ -int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel) -{ - return 0; -} - /** * iwl3945_reg_txpower_periodic - called when time to check our temperature. * diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index f3907c1079f5..964c01980ac0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -280,8 +280,6 @@ extern void iwl3945_config_ap(struct iwl_priv *priv); */ extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid); -extern int iwl3945_hw_channel_switch(struct iwl_priv *priv, u16 channel); - /* * Forward declare iwl-3945.c functions for iwl-base.c */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index bd856df5b04d..1ff465ad40d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1433,14 +1433,13 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) return ret; } -#ifdef IEEE80211_CONF_CHANNEL_SWITCH static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) { int rc; u8 band = 0; bool is_ht40 = false; u8 ctrl_chan_high = 0; - struct iwl4965_channel_switch_cmd cmd = { 0 }; + struct iwl4965_channel_switch_cmd cmd; const struct iwl_channel_info *ch_info; band = priv->band == IEEE80211_BAND_2GHZ; @@ -1461,8 +1460,11 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); if (ch_info) cmd.expect_beacon = is_channel_radar(ch_info); - else - cmd.expect_beacon = 1; + else { + IWL_ERR(priv, "invalid channel switch from %u to %u\n", + priv->active_rxon.channel, channel); + return -EFAULT; + } rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40, ctrl_chan_high, &cmd.tx_power); @@ -1474,7 +1476,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); return rc; } -#endif /** * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array @@ -2171,6 +2172,7 @@ static struct iwl_lib_ops iwl4965_lib = { .load_ucode = iwl4965_load_bsm, .dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_error_log = iwl_dump_nic_error_log, + .set_channel_switch = iwl4965_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, .stop = iwl_apm_stop, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a6e347b9799a..d256fecc6cda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1382,6 +1382,36 @@ IWL5000_UCODE_GET(init_size); IWL5000_UCODE_GET(init_data_size); IWL5000_UCODE_GET(boot_size); +static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) +{ + struct iwl5000_channel_switch_cmd cmd; + const struct iwl_channel_info *ch_info; + struct iwl_host_cmd hcmd = { + .id = REPLY_CHANNEL_SWITCH, + .len = sizeof(cmd), + .flags = CMD_SIZE_HUGE, + .data = &cmd, + }; + + IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", + priv->active_rxon.channel, channel); + cmd.band = priv->band == IEEE80211_BAND_2GHZ; + cmd.channel = cpu_to_le16(channel); + cmd.rxon_flags = priv->active_rxon.flags; + cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + ch_info = iwl_get_channel_info(priv, priv->band, channel); + if (ch_info) + cmd.expect_beacon = is_channel_radar(ch_info); + else { + IWL_ERR(priv, "invalid channel switch from %u to %u\n", + priv->active_rxon.channel, channel); + return -EFAULT; + } + + return iwl_send_cmd_sync(priv, &hcmd); +} + struct iwl_hcmd_ops iwl5000_hcmd = { .rxon_assoc = iwl5000_send_rxon_assoc, .commit_rxon = iwl_commit_rxon, @@ -1429,6 +1459,7 @@ struct iwl_lib_ops iwl5000_lib = { .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl5000_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, .stop = iwl_apm_stop, @@ -1480,6 +1511,7 @@ static struct iwl_lib_ops iwl5150_lib = { .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl5000_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, .stop = iwl_apm_stop, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index f5855293c767..f5639b47668a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -172,6 +172,37 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) return 0; } +static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) +{ + struct iwl6000_channel_switch_cmd cmd; + const struct iwl_channel_info *ch_info; + struct iwl_host_cmd hcmd = { + .id = REPLY_CHANNEL_SWITCH, + .len = sizeof(cmd), + .flags = CMD_SIZE_HUGE, + .data = &cmd, + }; + + IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", + priv->active_rxon.channel, channel); + + cmd.band = priv->band == IEEE80211_BAND_2GHZ; + cmd.channel = cpu_to_le16(channel); + cmd.rxon_flags = priv->active_rxon.flags; + cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); + ch_info = iwl_get_channel_info(priv, priv->band, channel); + if (ch_info) + cmd.expect_beacon = is_channel_radar(ch_info); + else { + IWL_ERR(priv, "invalid channel switch from %u to %u\n", + priv->active_rxon.channel, channel); + return -EFAULT; + } + + return iwl_send_cmd_sync(priv, &hcmd); +} + static struct iwl_lib_ops iwl6000_lib = { .set_hw_params = iwl6000_hw_set_hw_params, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, @@ -192,6 +223,7 @@ static struct iwl_lib_ops iwl6000_lib = { .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, .update_chain_flags = iwl_update_chain_flags, + .set_channel_switch = iwl6000_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, .stop = iwl_apm_stop, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e43469cfbbc0..d2b56baf98fb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1284,10 +1284,15 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; struct iwl_csa_notification *csa = &(pkt->u.csa_notif); - IWL_DEBUG_11H(priv, "CSA notif: channel %d, status %d\n", - le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); - rxon->channel = csa->channel; - priv->staging_rxon.channel = csa->channel; + + if (!le32_to_cpu(csa->status)) { + rxon->channel = csa->channel; + priv->staging_rxon.channel = csa->channel; + IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", + le16_to_cpu(csa->channel)); + } else + IWL_ERR(priv, "CSA notif (fail) : channel %d\n", + le16_to_cpu(csa->channel)); } EXPORT_SYMBOL(iwl_rx_csa); @@ -2714,6 +2719,14 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) goto set_ch_out; } + if (iwl_is_associated(priv) && + (le16_to_cpu(priv->active_rxon.channel) != ch) && + priv->cfg->ops->lib->set_channel_switch) { + ret = priv->cfg->ops->lib->set_channel_switch(priv, + ch); + goto out; + } + spin_lock_irqsave(&priv->lock, flags); /* Configure HT40 channels */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 02bacc4975f0..b875dcfca2d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -169,6 +169,7 @@ struct iwl_lib_ops { int (*load_ucode)(struct iwl_priv *priv); void (*dump_nic_event_log)(struct iwl_priv *priv); void (*dump_nic_error_log)(struct iwl_priv *priv); + int (*set_channel_switch)(struct iwl_priv *priv, u16 channel); /* power management */ struct iwl_apm_ops apm_ops; -- cgit v1.2.3 From 6c5cd9d524a3393f6450ee523f4a942d4404f7de Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 23 Oct 2009 13:42:30 -0700 Subject: iwlwifi: remove duplicate defines RX_FREE_BUFFERS and RX_LOW_WATERMARK are currently defined in four places. Based on how files are included we only need the definition in iwl-fh.h Signed-off-by: Reinette Chatre Reported-by: Frans Pop Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-hw.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-3945.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-dev.h | 6 ------ 3 files changed, 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index ccdac69838dd..6fd10d443ba3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -248,12 +248,6 @@ struct iwl3945_eeprom { #define TFD_CTL_PAD_SET(n) (n << 28) #define TFD_CTL_PAD_GET(ctl) (ctl >> 28) -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 64 -#define RX_LOW_WATERMARK 8 - /* Sizes and addresses for instruction and data memory (SRAM) in * 3945's embedded processor. Driver access is via HBUS_TARG_MEM_* regs. */ #define IWL39_RTC_INST_LOWER_BOUND (0x000000) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 964c01980ac0..ebb999a51b58 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -130,12 +130,6 @@ struct iwl3945_frame { #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 64 -#define RX_LOW_WATERMARK 8 - #define SUP_RATE_11A_MAX_NUM_CHANNELS 8 #define SUP_RATE_11B_MAX_NUM_CHANNELS 4 #define SUP_RATE_11G_MAX_NUM_CHANNELS 12 diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b520e551f7f8..e7ce67387662 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -407,12 +407,6 @@ struct iwl_host_cmd { u8 id; }; -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 64 -#define RX_LOW_WATERMARK 8 - #define SUP_RATE_11A_MAX_NUM_CHANNELS 8 #define SUP_RATE_11B_MAX_NUM_CHANNELS 4 #define SUP_RATE_11G_MAX_NUM_CHANNELS 12 -- cgit v1.2.3 From 71c55d90f9733abdf5e4e0bc24f71e189cefeea6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:31 -0700 Subject: iwlwifi: remove unused parameters parameters "len" is not used in both iwl_tx_queue_free() and iwl_cmd_queue_free() functions Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 5c43d7c43b30..8ae4c9b614e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -131,7 +131,7 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; - int i, len; + int i; if (q->n_bd == 0) return; @@ -141,8 +141,6 @@ void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) priv->cfg->ops->lib->txq_free_tfd(priv, txq); - len = sizeof(struct iwl_device_cmd) * q->n_window; - /* De-alloc array of command/tx buffers */ for (i = 0; i < TFD_TX_CMD_SLOTS; i++) kfree(txq->cmd[i]); @@ -180,14 +178,11 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; - int i, len; + int i; if (q->n_bd == 0) return; - len = sizeof(struct iwl_device_cmd) * q->n_window; - len += IWL_MAX_SCAN_SIZE; - /* De-alloc array of command/tx buffers */ for (i = 0; i <= TFD_CMD_SLOTS; i++) kfree(txq->cmd[i]); -- cgit v1.2.3 From 7300515d1095aa11731866da7c9b000f2edb4626 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 23 Oct 2009 13:42:32 -0700 Subject: iwlwifi: reuse page for notification packets For notification packets and SKBs that fail to rx correctly, add them back into the rx_free list so that the pages can be reused later. This avoids allocating new rx pages unnecessarily. Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 27 +++++++++++++++------------ drivers/net/wireless/iwlwifi/iwl3945-base.c | 27 +++++++++++++++------------ 2 files changed, 30 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0d3886505205..ea1b9315f17c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -769,7 +769,7 @@ void iwl_rx_handle(struct iwl_priv *priv) IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); /* calculate total frames need to be restock after handling RX */ - total_empty = r - priv->rxq.write_actual; + total_empty = r - rxq->write_actual; if (total_empty < 0) total_empty += RX_QUEUE_SIZE; @@ -841,25 +841,28 @@ void iwl_rx_handle(struct iwl_priv *priv) IWL_WARN(priv, "Claim null rxb?\n"); } - /* For now we just don't re-use anything. We can tweak this - * later to try and re-use notification packets and SKBs that - * fail to Rx correctly */ + /* Reuse the page if possible. For notification packets and + * SKBs that fail to Rx correctly, add them back into the + * rx_free list for reuse later. */ + spin_lock_irqsave(&rxq->lock, flags); if (rxb->page != NULL) { - priv->alloc_rxb_page--; - __free_pages(rxb->page, priv->hw_params.rx_page_order); - rxb->page = NULL; - } + rxb->page_dma = pci_map_page(priv->pci_dev, rxb->page, + 0, PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } else + list_add_tail(&rxb->list, &rxq->rx_used); - spin_lock_irqsave(&rxq->lock, flags); - list_add_tail(&rxb->list, &priv->rxq.rx_used); spin_unlock_irqrestore(&rxq->lock, flags); + i = (i + 1) & RX_QUEUE_MASK; /* If there are a lot of unused frames, * restock the Rx queue so ucode wont assert. */ if (fill_rx) { count++; if (count >= 8) { - priv->rxq.read = i; + rxq->read = i; iwl_rx_replenish_now(priv); count = 0; } @@ -867,7 +870,7 @@ void iwl_rx_handle(struct iwl_priv *priv) } /* Backtrack one entry */ - priv->rxq.read = i; + rxq->read = i; if (fill_rx) iwl_rx_replenish_now(priv); else diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8b08bdc10bc9..9a430eed34ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1367,7 +1367,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) i = rxq->read; /* calculate total frames need to be restock after handling RX */ - total_empty = r - priv->rxq.write_actual; + total_empty = r - rxq->write_actual; if (total_empty < 0) total_empty += RX_QUEUE_SIZE; @@ -1438,25 +1438,28 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) IWL_WARN(priv, "Claim null rxb?\n"); } - /* For now we just don't re-use anything. We can tweak this - * later to try and re-use notification packets and SKBs that - * fail to Rx correctly */ + /* Reuse the page if possible. For notification packets and + * SKBs that fail to Rx correctly, add them back into the + * rx_free list for reuse later. */ + spin_lock_irqsave(&rxq->lock, flags); if (rxb->page != NULL) { - priv->alloc_rxb_page--; - __free_pages(rxb->page, priv->hw_params.rx_page_order); - rxb->page = NULL; - } + rxb->page_dma = pci_map_page(priv->pci_dev, rxb->page, + 0, PAGE_SIZE << priv->hw_params.rx_page_order, + PCI_DMA_FROMDEVICE); + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } else + list_add_tail(&rxb->list, &rxq->rx_used); - spin_lock_irqsave(&rxq->lock, flags); - list_add_tail(&rxb->list, &priv->rxq.rx_used); spin_unlock_irqrestore(&rxq->lock, flags); + i = (i + 1) & RX_QUEUE_MASK; /* If there are a lot of unused frames, * restock the Rx queue so ucode won't assert. */ if (fill_rx) { count++; if (count >= 8) { - priv->rxq.read = i; + rxq->read = i; iwl3945_rx_replenish_now(priv); count = 0; } @@ -1464,7 +1467,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) } /* Backtrack one entry */ - priv->rxq.read = i; + rxq->read = i; if (fill_rx) iwl3945_rx_replenish_now(priv); else -- cgit v1.2.3 From 570af86e0ab7e7b42b2562ff3209c16ab1ebd5f8 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:33 -0700 Subject: iwlwifi: remove duplicated define Duplicated define for listen interval (IWL_CONN_MAX_LISTEN_INTERVAL and IWL_CONN_LISTEN_INTERVAL), remove IWL_CONN_LISTEN_INTERVAL Signed-off-by: Wey-Yi Guy Reported-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-power.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-power.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 432f4650cf2e..9bce2c1625e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -163,9 +163,9 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; slp_itrvl = le32_to_cpu(cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]); - if (slp_itrvl > IWL_CONN_LISTEN_INTERVAL) + if (slp_itrvl > IWL_CONN_MAX_LISTEN_INTERVAL) cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1] = - cpu_to_le32(IWL_CONN_LISTEN_INTERVAL); + cpu_to_le32(IWL_CONN_MAX_LISTEN_INTERVAL); /* enforce max sleep interval */ for (i = IWL_POWER_VEC_SIZE - 1; i >= 0 ; i--) { diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 0755518f86e1..310c32e8f698 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -30,8 +30,6 @@ #include "iwl-commands.h" -#define IWL_CONN_LISTEN_INTERVAL 10 - #define IWL_ABSOLUTE_ZERO 0 #define IWL_ABSOLUTE_MAX 0xFFFFFFFF #define IWL_TT_INCREASE_MARGIN 5 -- cgit v1.2.3 From 442464218d93aa0aacc55c3a7ac908ae00abff5f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:34 -0700 Subject: iwlwifi: update lowest API version support for 6x00 & 6x50 series For 6x00 and 6x50 series devices, APIv4 is the lowest firmware version driver can support. This is also the lowest API version available to the public so there is no need for backward compatibility support for the earlier API versions. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index f5639b47668a..32466d38d1ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -52,8 +52,8 @@ #define IWL6050_UCODE_API_MAX 4 /* Lowest firmware API version supported */ -#define IWL6000_UCODE_API_MIN 1 -#define IWL6050_UCODE_API_MIN 1 +#define IWL6000_UCODE_API_MIN 4 +#define IWL6050_UCODE_API_MIN 4 #define IWL6000_FW_PRE "iwlwifi-6000-" #define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" -- cgit v1.2.3 From c166b25a5c02d881b1da15f3afe9dc9e56b206a8 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 23 Oct 2009 13:42:35 -0700 Subject: iwlwifi: make sure device is reset when unloading driver Add unconditional call to apm_ops.stop() to reset device to low power state when unloading driver. Some paths have existed to unload driver *without* resetting device, therefore some errors have persisted through multiple load/unload cycles, until the whole platform gets rebooted; this is an attempt to remedy some of those situations. Sorry, I can't seem to find a bughost.org bug that specifically has these symptoms, but I had it happen recently here. Note that this will *not* fix situations in which the PCI express bus has crashed (evidenced by register reads showing "0xffffffff"), e.g. bughost.org 1855 and 2096; device is unreachable from driver in those cases. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 9 +++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 9 +++++++++ 2 files changed, 18 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ea1b9315f17c..fa1672e99e4b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3256,6 +3256,15 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_down(priv); } + /* + * Make sure device is reset to low power before unloading driver. + * This may be redundant with iwl_down(), but there are paths to + * run iwl_down() without calling apm_ops.stop(), and there are + * paths to avoid running iwl_down() at all before leaving driver. + * This (inexpensive) call *makes sure* device is reset. + */ + priv->cfg->ops->lib->apm_ops.stop(priv); + iwl_tt_exit(priv); /* make sure we flush any pending irq or diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 9a430eed34ad..bfd7f497157f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4135,6 +4135,15 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) iwl3945_down(priv); } + /* + * Make sure device is reset to low power before unloading driver. + * This may be redundant with iwl_down(), but there are paths to + * run iwl_down() without calling apm_ops.stop(), and there are + * paths to avoid running iwl_down() at all before leaving driver. + * This (inexpensive) call *makes sure* device is reset. + */ + priv->cfg->ops->lib->apm_ops.stop(priv); + /* make sure we flush any pending irq or * tasklet for the driver */ -- cgit v1.2.3 From d23000cd8992823e06ca0745564f2c25fe923ce4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Oct 2009 13:42:36 -0700 Subject: iwlwifi: minor comments changes for wimax co-exist command 'COEX_PRIORITY_TABLE_CMD' host command will be supported for 5000 series and up. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 0d660a7475a0..954bad60355d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -109,7 +109,7 @@ enum { REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ /* WiMAX coexistence */ - COEX_PRIORITY_TABLE_CMD = 0x5a, /*5000 only */ + COEX_PRIORITY_TABLE_CMD = 0x5a, /* for 5000 series and up */ COEX_MEDIUM_NOTIFICATION = 0x5b, COEX_EVENT_CMD = 0x5c, -- cgit v1.2.3 From bd6b4442ff3cee73f73987cf0c0e66ea677aa075 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Tue, 27 Oct 2009 11:32:52 +0530 Subject: ath: Updates for regulatory and country codes. Add a few new country codes and update the regulatory domain for some countries. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.h | 8 ++++++++ drivers/net/wireless/ath/regd_common.h | 32 ++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index c1dd857697a7..a1c39526161a 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -65,10 +65,13 @@ enum CountryCode { CTRY_ALGERIA = 12, CTRY_ARGENTINA = 32, CTRY_ARMENIA = 51, + CTRY_ARUBA = 533, CTRY_AUSTRALIA = 36, CTRY_AUSTRIA = 40, CTRY_AZERBAIJAN = 31, CTRY_BAHRAIN = 48, + CTRY_BANGLADESH = 50, + CTRY_BARBADOS = 52, CTRY_BELARUS = 112, CTRY_BELGIUM = 56, CTRY_BELIZE = 84, @@ -77,6 +80,7 @@ enum CountryCode { CTRY_BRAZIL = 76, CTRY_BRUNEI_DARUSSALAM = 96, CTRY_BULGARIA = 100, + CTRY_CAMBODIA = 116, CTRY_CANADA = 124, CTRY_CHILE = 152, CTRY_CHINA = 156, @@ -97,7 +101,11 @@ enum CountryCode { CTRY_GEORGIA = 268, CTRY_GERMANY = 276, CTRY_GREECE = 300, + CTRY_GREENLAND = 304, + CTRY_GRENEDA = 308, + CTRY_GUAM = 316, CTRY_GUATEMALA = 320, + CTRY_HAITI = 332, CTRY_HONDURAS = 340, CTRY_HONG_KONG = 344, CTRY_HUNGARY = 348, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 9847af72208c..248c670fdfbe 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -288,13 +288,16 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_DEFAULT, FCC1_FCCA, "CO"}, {CTRY_ALBANIA, NULL1_WORLD, "AL"}, {CTRY_ALGERIA, NULL1_WORLD, "DZ"}, - {CTRY_ARGENTINA, APL3_WORLD, "AR"}, + {CTRY_ARGENTINA, FCC3_WORLD, "AR"}, {CTRY_ARMENIA, ETSI4_WORLD, "AM"}, + {CTRY_ARUBA, ETSI1_WORLD, "AW"}, {CTRY_AUSTRALIA, FCC2_WORLD, "AU"}, {CTRY_AUSTRALIA2, FCC6_WORLD, "AU"}, {CTRY_AUSTRIA, ETSI1_WORLD, "AT"}, {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"}, {CTRY_BAHRAIN, APL6_WORLD, "BH"}, + {CTRY_BANGLADESH, NULL1_WORLD, "BD"}, + {CTRY_BARBADOS, FCC2_WORLD, "BB"}, {CTRY_BELARUS, ETSI1_WORLD, "BY"}, {CTRY_BELGIUM, ETSI1_WORLD, "BE"}, {CTRY_BELGIUM2, ETSI4_WORLD, "BL"}, @@ -304,13 +307,14 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_BRAZIL, FCC3_WORLD, "BR"}, {CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN"}, {CTRY_BULGARIA, ETSI6_WORLD, "BG"}, - {CTRY_CANADA, FCC2_FCCA, "CA"}, + {CTRY_CAMBODIA, ETSI1_WORLD, "KH"}, + {CTRY_CANADA, FCC3_FCCA, "CA"}, {CTRY_CANADA2, FCC6_FCCA, "CA"}, {CTRY_CHILE, APL6_WORLD, "CL"}, {CTRY_CHINA, APL1_WORLD, "CN"}, {CTRY_COLOMBIA, FCC1_FCCA, "CO"}, {CTRY_COSTA_RICA, FCC1_WORLD, "CR"}, - {CTRY_CROATIA, ETSI3_WORLD, "HR"}, + {CTRY_CROATIA, ETSI1_WORLD, "HR"}, {CTRY_CYPRUS, ETSI1_WORLD, "CY"}, {CTRY_CZECH, ETSI3_WORLD, "CZ"}, {CTRY_DENMARK, ETSI1_WORLD, "DK"}, @@ -324,18 +328,22 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_GEORGIA, ETSI4_WORLD, "GE"}, {CTRY_GERMANY, ETSI1_WORLD, "DE"}, {CTRY_GREECE, ETSI1_WORLD, "GR"}, + {CTRY_GREENLAND, ETSI1_WORLD, "GL"}, + {CTRY_GRENEDA, FCC3_FCCA, "GD"}, + {CTRY_GUAM, FCC1_FCCA, "GU"}, {CTRY_GUATEMALA, FCC1_FCCA, "GT"}, + {CTRY_HAITI, ETSI1_WORLD, "HT"}, {CTRY_HONDURAS, NULL1_WORLD, "HN"}, - {CTRY_HONG_KONG, FCC2_WORLD, "HK"}, + {CTRY_HONG_KONG, FCC3_WORLD, "HK"}, {CTRY_HUNGARY, ETSI1_WORLD, "HU"}, {CTRY_ICELAND, ETSI1_WORLD, "IS"}, {CTRY_INDIA, APL6_WORLD, "IN"}, - {CTRY_INDONESIA, APL1_WORLD, "ID"}, + {CTRY_INDONESIA, NULL1_WORLD, "ID"}, {CTRY_IRAN, APL1_WORLD, "IR"}, {CTRY_IRELAND, ETSI1_WORLD, "IE"}, {CTRY_ISRAEL, NULL1_WORLD, "IL"}, {CTRY_ITALY, ETSI1_WORLD, "IT"}, - {CTRY_JAMAICA, ETSI1_WORLD, "JM"}, + {CTRY_JAMAICA, FCC3_WORLD, "JM"}, {CTRY_JAPAN, MKK1_MKKA, "JP"}, {CTRY_JAPAN1, MKK1_MKKB, "JP"}, @@ -402,7 +410,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_KOREA_ROC, APL9_WORLD, "KR"}, {CTRY_KOREA_ROC2, APL2_WORLD, "K2"}, {CTRY_KOREA_ROC3, APL9_WORLD, "K3"}, - {CTRY_KUWAIT, NULL1_WORLD, "KW"}, + {CTRY_KUWAIT, ETSI3_WORLD, "KW"}, {CTRY_LATVIA, ETSI1_WORLD, "LV"}, {CTRY_LEBANON, NULL1_WORLD, "LB"}, {CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI"}, @@ -414,13 +422,13 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_MALTA, ETSI1_WORLD, "MT"}, {CTRY_MEXICO, FCC1_FCCA, "MX"}, {CTRY_MONACO, ETSI4_WORLD, "MC"}, - {CTRY_MOROCCO, NULL1_WORLD, "MA"}, + {CTRY_MOROCCO, APL4_WORLD, "MA"}, {CTRY_NEPAL, APL1_WORLD, "NP"}, {CTRY_NETHERLANDS, ETSI1_WORLD, "NL"}, {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"}, {CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"}, {CTRY_NORWAY, ETSI1_WORLD, "NO"}, - {CTRY_OMAN, APL6_WORLD, "OM"}, + {CTRY_OMAN, FCC3_WORLD, "OM"}, {CTRY_PAKISTAN, NULL1_WORLD, "PK"}, {CTRY_PANAMA, FCC1_FCCA, "PA"}, {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"}, @@ -429,7 +437,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_POLAND, ETSI1_WORLD, "PL"}, {CTRY_PORTUGAL, ETSI1_WORLD, "PT"}, {CTRY_PUERTO_RICO, FCC1_FCCA, "PR"}, - {CTRY_QATAR, NULL1_WORLD, "QA"}, + {CTRY_QATAR, APL1_WORLD, "QA"}, {CTRY_ROMANIA, NULL1_WORLD, "RO"}, {CTRY_RUSSIA, NULL1_WORLD, "RU"}, {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"}, @@ -445,7 +453,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_SYRIA, NULL1_WORLD, "SY"}, {CTRY_TAIWAN, APL3_FCCA, "TW"}, {CTRY_THAILAND, FCC3_WORLD, "TH"}, - {CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT"}, + {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"}, {CTRY_TUNISIA, ETSI3_WORLD, "TN"}, {CTRY_TURKEY, ETSI3_WORLD, "TR"}, {CTRY_UKRAINE, NULL1_WORLD, "UA"}, @@ -456,7 +464,7 @@ static struct country_code_to_enum_rd allCountries[] = { * would need to assign new special alpha2 to CRDA db as with the world * regdomain and use another alpha2 */ {CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS"}, - {CTRY_URUGUAY, APL2_WORLD, "UY"}, + {CTRY_URUGUAY, FCC3_WORLD, "UY"}, {CTRY_UZBEKISTAN, FCC3_FCCA, "UZ"}, {CTRY_VENEZUELA, APL2_ETSIC, "VE"}, {CTRY_VIET_NAM, NULL1_WORLD, "VN"}, -- cgit v1.2.3 From 2c0d6100da3ee9b0f0cc46add9bb8a8161299a92 Mon Sep 17 00:00:00 2001 From: Gábor Stefanik Date: Sun, 25 Oct 2009 16:26:36 +0100 Subject: b43: LP-PHY: Begin implementing calibration & software RFKILL support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements the following calibration functions: -Set TX IQCC -Set TX Power by Index -PR41573 workaround (incomplete, needs PHY reset) -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. Signed-off-by: Gábor Stefanik Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_lp.c | 783 +++++++++++++++++++++++++++++++------- drivers/net/wireless/b43/phy_lp.h | 11 +- 2 files changed, 658 insertions(+), 136 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index c6987b147af4..3e046ec1ff86 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c @@ -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 } @@ -379,8 +380,6 @@ static void lpphy_save_dig_flt_state(struct b43_wldev *dev) } } -/* lpphy_restore_dig_flt_state is unused but kept as a reference */ -#if 0 static void lpphy_restore_dig_flt_state(struct b43_wldev *dev) { static const u16 addr[] = { @@ -401,7 +400,6 @@ static void lpphy_restore_dig_flt_state(struct b43_wldev *dev) for (i = 0; i < ARRAY_SIZE(addr); i++) b43_phy_write(dev, addr[i], lpphy->dig_flt_state[i]); } -#endif static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev) { @@ -754,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); @@ -793,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; @@ -822,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) { @@ -832,25 +901,22 @@ 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); + /* + * SPEC FIXME The spec calls for (pa_gain << 8) here, but that + * conflicts with the spec for set_pa_gain! Vendor driver bug? + */ b43_phy_maskset(dev, B43_PHY_OFDM(0xFB), - 0x8000, gains.pad | pa_gain); + 0x8000, gains.pad | (pa_gain << 6)); 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); + 0x8000, gains.pad | (pa_gain << 8)); } 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) @@ -890,41 +956,6 @@ static void lpphy_rev2plus_set_rx_gain(struct b43_wldev *dev, u32 gain) } } -/* lpphy_disable_rx_gain_override is unused but kept as a reference */ -#if 0 -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); - } -} -#endif - -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) @@ -1009,8 +1040,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); @@ -1132,7 +1162,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; } } @@ -1318,15 +1348,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) @@ -1335,58 +1423,45 @@ static void lpphy_btcoex_override(struct b43_wldev *dev) b43_write16(dev, B43_MMIO_BTCOEX_TXCTL, 0xFF); } -static void lpphy_pr41573_workaround(struct b43_wldev *dev) +static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, + bool blocked) { - struct b43_phy_lp *lpphy = dev->phy.lp; - u32 *saved_tab; - const unsigned int saved_tab_size = 256; - enum b43_lpphy_txpctl_mode txpctl_mode; - s8 tx_pwr_idx_over; - u16 tssi_npt, tssi_idx; - - saved_tab = kcalloc(saved_tab_size, sizeof(saved_tab[0]), GFP_KERNEL); - if (!saved_tab) { - b43err(dev->wl, "PR41573 failed. Out of memory!\n"); - return; - } - - lpphy_read_tx_pctl_mode_from_hardware(dev); - txpctl_mode = lpphy->txpctl_mode; - tx_pwr_idx_over = lpphy->tx_pwr_idx_over; - tssi_npt = lpphy->tssi_npt; - tssi_idx = lpphy->tssi_idx; - - if (dev->phy.rev < 2) { - b43_lptab_read_bulk(dev, B43_LPTAB32(10, 0x140), - saved_tab_size, saved_tab); + //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_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140), - saved_tab_size, saved_tab); + 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); } - //TODO - - kfree(saved_tab); } -static void lpphy_calibration(struct b43_wldev *dev) +/* 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; - enum b43_lpphy_txpctl_mode saved_pctl_mode; - - b43_mac_suspend(dev); - - lpphy_btcoex_override(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 - lpphy_set_tx_power_control(dev, saved_pctl_mode); - //TODO Perform I/Q calibration with a single control value set + u16 tmp = (channel == 14); //SPEC FIXME check japanwidefilter! - b43_mac_enable(dev); + 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_set_tssi_mux(struct b43_wldev *dev, enum tssi_mux_mode mode) @@ -1495,6 +1570,473 @@ static void lpphy_tx_pctl_init(struct b43_wldev *dev) } } +static void lpphy_pr41573_workaround(struct b43_wldev *dev) +{ + struct b43_phy_lp *lpphy = dev->phy.lp; + u32 *saved_tab; + const unsigned int saved_tab_size = 256; + enum b43_lpphy_txpctl_mode txpctl_mode; + s8 tx_pwr_idx_over; + u16 tssi_npt, tssi_idx; + + saved_tab = kcalloc(saved_tab_size, sizeof(saved_tab[0]), GFP_KERNEL); + if (!saved_tab) { + b43err(dev->wl, "PR41573 failed. Out of memory!\n"); + return; + } + + lpphy_read_tx_pctl_mode_from_hardware(dev); + txpctl_mode = lpphy->txpctl_mode; + tx_pwr_idx_over = lpphy->tx_pwr_idx_over; + tssi_npt = lpphy->tssi_npt; + tssi_idx = lpphy->tssi_idx; + + if (dev->phy.rev < 2) { + b43_lptab_read_bulk(dev, B43_LPTAB32(10, 0x140), + saved_tab_size, saved_tab); + } else { + b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140), + saved_tab_size, saved_tab); + } + //FIXME PHY reset + lpphy_table_init(dev); //FIXME is table init needed? + lpphy_baseband_init(dev); + lpphy_tx_pctl_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 = 0, 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 +} + +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); + } + lpphy_clear_deaf(dev, false); + 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); + if ((dev->phy.rev >= 2) && full_cal) { + lpphy_papd_cal_txpwr(dev); + } + lpphy_set_tx_power_control(dev, saved_pctl_mode); + 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); +} + static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg) { b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); @@ -1539,12 +2081,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; @@ -2010,22 +2546,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; @@ -2210,18 +2730,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 @@ -2244,6 +2752,11 @@ void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on) } } +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, @@ -2261,4 +2774,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, }; diff --git a/drivers/net/wireless/b43/phy_lp.h b/drivers/net/wireless/b43/phy_lp.h index c3232c17b60a..62737f700cbc 100644 --- a/drivers/net/wireless/b43/phy_lp.h +++ b/drivers/net/wireless/b43/phy_lp.h @@ -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 { -- cgit v1.2.3 From 8c8746f9db8b1f644695050703e2d38cd5964ba7 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 27 Oct 2009 17:36:25 +0200 Subject: wl1251: enable power save wl1251 supports power save and it can be enabled now. Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 48b0bfd6c55a..da3bf1cebc08 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1311,7 +1311,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->channel_change_time = 10000; wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; + IEEE80211_HW_NOISE_DBM | + IEEE80211_HW_SUPPORTS_PS; wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wl->hw->wiphy->max_scan_ssids = 1; -- cgit v1.2.3 From 2da4f01a0938b688f92f9ee380013cfb8653510f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 27 Oct 2009 12:59:33 -0400 Subject: ath9k_hw: move mac name and rf name helpers to hw code These are shared between ath9k and the future ath9k_htc driver. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 5 +-- drivers/net/wireless/ath/ath9k/hw.c | 62 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/hw.h | 3 ++ drivers/net/wireless/ath/ath9k/main.c | 58 -------------------------------- drivers/net/wireless/ath/ath9k/pci.c | 5 +-- 5 files changed, 71 insertions(+), 62 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 25531f231b67..41422c449696 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -137,9 +137,10 @@ static int ath_ahb_probe(struct platform_device *pdev) "%s: Atheros AR%s MAC/BB Rev:%x, " "AR%s RF Rev:%x, mem=0x%lx, irq=%d\n", wiphy_name(hw->wiphy), - ath_mac_bb_name(ah->hw_version.macVersion), + ath9k_hw_mac_bb_name(ah->hw_version.macVersion), ah->hw_version.macRev, - ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)), + ath9k_hw_rf_name((ah->hw_version.analog5GhzRev & + AR_RADIO_SREV_MAJOR)), ah->hw_version.phyRev, (unsigned long)mem, irq); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index cab17c6c8a37..bba923135b0e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4350,3 +4350,65 @@ void ath_gen_timer_isr(struct ath_hw *ah) } } EXPORT_SYMBOL(ath_gen_timer_isr); + +static struct { + u32 version; + const char * name; +} ath_mac_bb_names[] = { + /* Devices with external radios */ + { AR_SREV_VERSION_5416_PCI, "5416" }, + { AR_SREV_VERSION_5416_PCIE, "5418" }, + { AR_SREV_VERSION_9100, "9100" }, + { AR_SREV_VERSION_9160, "9160" }, + /* Single-chip solutions */ + { AR_SREV_VERSION_9280, "9280" }, + { AR_SREV_VERSION_9285, "9285" }, + { AR_SREV_VERSION_9287, "9287" } +}; + +/* For devices with external radios */ +static struct { + u16 version; + const char * name; +} ath_rf_names[] = { + { 0, "5133" }, + { AR_RAD5133_SREV_MAJOR, "5133" }, + { AR_RAD5122_SREV_MAJOR, "5122" }, + { AR_RAD2133_SREV_MAJOR, "2133" }, + { AR_RAD2122_SREV_MAJOR, "2122" } +}; + +/* + * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. + */ +const char *ath9k_hw_mac_bb_name(u32 mac_bb_version) +{ + int i; + + for (i=0; iwiphy), - ath_mac_bb_name(ah->hw_version.macVersion), + ath9k_hw_mac_bb_name(ah->hw_version.macVersion), ah->hw_version.macRev, - ath_rf_name((ah->hw_version.analog5GhzRev & AR_RADIO_SREV_MAJOR)), + ath9k_hw_rf_name((ah->hw_version.analog5GhzRev & + AR_RADIO_SREV_MAJOR)), ah->hw_version.phyRev, (unsigned long)mem, pdev->irq); -- cgit v1.2.3 From f934c4d9de85571ff792360aa72dd26e00e1afc7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 27 Oct 2009 12:59:34 -0400 Subject: ath9k_hw: distinguish single-chip solutions on initial probe print Devices with external radios have revisions which we can count on. On single chip solutions these EEPROM values for these radio revision also exist but are not meaningful as the radios are embedded onto the same chip. Each single-chip device evolves together as one device. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ahb.c | 11 ++++------- drivers/net/wireless/ath/ath9k/hw.c | 31 +++++++++++++++++++++++++++---- drivers/net/wireless/ath/ath9k/hw.h | 3 +-- drivers/net/wireless/ath/ath9k/pci.c | 11 ++++------- 4 files changed, 36 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 41422c449696..329e6bc137ab 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -69,6 +69,7 @@ static int ath_ahb_probe(struct platform_device *pdev) int irq; int ret = 0; struct ath_hw *ah; + char hw_name[64]; if (!pdev->dev.platform_data) { dev_err(&pdev->dev, "no platform data specified\n"); @@ -133,15 +134,11 @@ static int ath_ahb_probe(struct platform_device *pdev) } ah = sc->sc_ah; + ath9k_hw_name(ah, hw_name, sizeof(hw_name)); printk(KERN_INFO - "%s: Atheros AR%s MAC/BB Rev:%x, " - "AR%s RF Rev:%x, mem=0x%lx, irq=%d\n", + "%s: %s mem=0x%lx, irq=%d\n", wiphy_name(hw->wiphy), - ath9k_hw_mac_bb_name(ah->hw_version.macVersion), - ah->hw_version.macRev, - ath9k_hw_rf_name((ah->hw_version.analog5GhzRev & - AR_RADIO_SREV_MAJOR)), - ah->hw_version.phyRev, + hw_name, (unsigned long)mem, irq); return 0; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index bba923135b0e..5d7a5b177a39 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4381,7 +4381,7 @@ static struct { /* * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. */ -const char *ath9k_hw_mac_bb_name(u32 mac_bb_version) +static const char *ath9k_hw_mac_bb_name(u32 mac_bb_version) { int i; @@ -4393,13 +4393,12 @@ const char *ath9k_hw_mac_bb_name(u32 mac_bb_version) return "????"; } -EXPORT_SYMBOL(ath9k_hw_mac_bb_name); /* * Return the RF name. "????" is returned if the RF is unknown. * Used for devices with external radios. */ -const char *ath9k_hw_rf_name(u16 rf_version) +static const char *ath9k_hw_rf_name(u16 rf_version) { int i; @@ -4411,4 +4410,28 @@ const char *ath9k_hw_rf_name(u16 rf_version) return "????"; } -EXPORT_SYMBOL(ath9k_hw_rf_name); + +void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len) +{ + int used; + + /* chipsets >= AR9280 are single-chip */ + if (AR_SREV_9280_10_OR_LATER(ah)) { + used = snprintf(hw_name, len, + "Atheros AR%s Rev:%x", + ath9k_hw_mac_bb_name(ah->hw_version.macVersion), + ah->hw_version.macRev); + } + else { + used = snprintf(hw_name, len, + "Atheros AR%s MAC/BB Rev:%x AR%s RF Rev:%x", + ath9k_hw_mac_bb_name(ah->hw_version.macVersion), + ah->hw_version.macRev, + ath9k_hw_rf_name((ah->hw_version.analog5GhzRev & + AR_RADIO_SREV_MAJOR)), + ah->hw_version.phyRev); + } + + hw_name[used] = '\0'; +} +EXPORT_SYMBOL(ath9k_hw_name); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 979a594f93d1..33a5aec1856d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -704,8 +704,7 @@ void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_isr(struct ath_hw *hw); u32 ath9k_hw_gettsf32(struct ath_hw *ah); -const char *ath9k_hw_mac_bb_name(u32 mac_bb_version); -const char *ath9k_hw_rf_name(u16 rf_version); +void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len); #define ATH_PCIE_CAP_LINK_CTRL 0x70 #define ATH_PCIE_CAP_LINK_L0S 1 diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 76f3890d0a9c..5321f735e5a0 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -114,6 +114,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) u32 val; int ret = 0; struct ath_hw *ah; + char hw_name[64]; if (pci_enable_device(pdev)) return -EIO; @@ -218,15 +219,11 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->irq = pdev->irq; ah = sc->sc_ah; + ath9k_hw_name(ah, hw_name, sizeof(hw_name)); printk(KERN_INFO - "%s: Atheros AR%s MAC/BB Rev:%x " - "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", + "%s: %s mem=0x%lx, irq=%d\n", wiphy_name(hw->wiphy), - ath9k_hw_mac_bb_name(ah->hw_version.macVersion), - ah->hw_version.macRev, - ath9k_hw_rf_name((ah->hw_version.analog5GhzRev & - AR_RADIO_SREV_MAJOR)), - ah->hw_version.phyRev, + hw_name, (unsigned long)mem, pdev->irq); return 0; -- cgit v1.2.3 From 11158472c4ea7a4817d85912c491afa36a244192 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 27 Oct 2009 12:59:35 -0400 Subject: ath9k_hw: add AR9271 single chip name mapping Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 5d7a5b177a39..ea6965134c07 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -4363,7 +4363,8 @@ static struct { /* Single-chip solutions */ { AR_SREV_VERSION_9280, "9280" }, { AR_SREV_VERSION_9285, "9285" }, - { AR_SREV_VERSION_9287, "9287" } + { AR_SREV_VERSION_9287, "9287" }, + { AR_SREV_VERSION_9271, "9271" }, }; /* For devices with external radios */ -- cgit v1.2.3 From ec11bb88f977321f117865b4d21079bbacc474ee Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 27 Oct 2009 12:59:36 -0400 Subject: ath9k_hw: correct AR_PHY_SPECTRAL_SCAN register offset We had 0x9912 but AR_PHY_SPECTRAL_SCAN is 0x9910. By using the 0x9912 we were making the hardware unresponsive. This allows us to move forward with hardware reset on ar9271 on the ath9k_htc driver. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 3 ++- drivers/net/wireless/ath/ath9k/phy.h | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ea6965134c07..2fbadbee1aa2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1274,7 +1274,8 @@ static void ath9k_hw_override_ini(struct ath_hw *ah, * AR9271 1.1 */ if (AR_SREV_9271_10(ah)) { - val = REG_READ(ah, AR_PHY_SPECTRAL_SCAN) | AR_PHY_SPECTRAL_SCAN_ENABLE; + val = REG_READ(ah, AR_PHY_SPECTRAL_SCAN) | + AR_PHY_SPECTRAL_SCAN_ENABLE; REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val); } else if (AR_SREV_9271_11(ah)) diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 140fef74c666..b64bc69d7bbb 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -186,8 +186,20 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, #define AR_PHY_PLL_CTL_44_2133 0xeb #define AR_PHY_PLL_CTL_40_2133 0xea -#define AR_PHY_SPECTRAL_SCAN 0x9912 -#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x1 +#define AR_PHY_SPECTRAL_SCAN 0x9910 /* AR9280 spectral scan configuration register */ +#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x1 +#define AR_PHY_SPECTRAL_SCAN_ENA 0x00000001 /* Enable spectral scan, reg 68, bit 0 */ +#define AR_PHY_SPECTRAL_SCAN_ENA_S 0 /* Enable spectral scan, reg 68, bit 0 */ +#define AR_PHY_SPECTRAL_SCAN_ACTIVE 0x00000002 /* Activate spectral scan reg 68, bit 1*/ +#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S 1 /* Activate spectral scan reg 68, bit 1*/ +#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD 0x000000F0 /* Interval for FFT reports, reg 68, bits 4-7*/ +#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S 4 +#define AR_PHY_SPECTRAL_SCAN_PERIOD 0x0000FF00 /* Interval for FFT reports, reg 68, bits 8-15*/ +#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8 +#define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 /* Number of reports, reg 68, bits 16-23*/ +#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16 +#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 /* Short repeat, reg 68, bit 24*/ +#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 /* Short repeat, reg 68, bit 24*/ #define AR_PHY_RX_DELAY 0x9914 #define AR_PHY_SEARCH_START_DELAY 0x9918 -- cgit v1.2.3 From 1d9c185d67e61737562befdc6b0c4f19b6a85be6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 27 Oct 2009 12:59:37 -0400 Subject: ath9k_hw: remove bogus register write on ath9k_hw_9271_pa_cal() An extra register was being written to for PA calibration making the hardware unresponsive, remove it. Hardware reset should now complete fine on ar9271. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 551f8801459f..238a5744d8e9 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -877,7 +877,7 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah, bool is_reset) REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0); /* find off_6_1; */ - for (i = 6; i >= 0; i--) { + for (i = 6; i > 0; i--) { regVal = REG_READ(ah, 0x7834); regVal |= (1 << (20 + i)); REG_WRITE(ah, 0x7834, regVal); -- cgit v1.2.3 From d130eb498c75095297debbca596b19fcdc823924 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 27 Oct 2009 20:53:58 +0100 Subject: mac80211_hwsim: don't register CCK rates on 5ghz This buglet confused me a lot just now ... Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 38cfd79e0590..d2b2e5e739b7 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1045,19 +1045,20 @@ static int __init init_mac80211_hwsim(void) sband->channels = data->channels_2ghz; sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz); + sband->bitrates = data->rates; + sband->n_bitrates = ARRAY_SIZE(hwsim_rates); break; case IEEE80211_BAND_5GHZ: sband->channels = data->channels_5ghz; sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz); + sband->bitrates = data->rates + 4; + sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; break; default: break; } - sband->bitrates = data->rates; - sband->n_bitrates = ARRAY_SIZE(hwsim_rates); - sband->ht_cap.ht_supported = true; sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_GRN_FLD | -- cgit v1.2.3 From 0869aea0eb711982cd2b8bebf41b3c0191c89cde Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Oct 2009 10:03:35 +0100 Subject: mac80211: remove RX_FLAG_RADIOTAP While there may be a case for a driver adding its own bits of radiotap information, none currently does. Also, drivers would have to copy the code to generate the radiotap bits that now mac80211 generates. If some driver in the future needs to add some driver-specific information I'd expect that to be in a radiotap vendor namespace and we can add a different way of passing such data up and having mac80211 include it. Additionally, rename IEEE80211_CONF_RADIOTAP to IEEE80211_CONF_MONITOR since it's still used by b43(legacy) to obtain per-frame timestamps. The purpose of this patch is to simplify the RX code in mac80211 to make it easier to add paged skb support. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/b43legacy/main.c | 2 +- include/net/mac80211.h | 15 +++++++-------- net/mac80211/iface.c | 8 ++++---- net/mac80211/rx.c | 33 ++++++++++++--------------------- 5 files changed, 25 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ed6e96a34743..c806924c7b5c 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3573,7 +3573,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) if (conf->channel->hw_value != phy->channel) b43_switch_channel(dev, conf->channel->hw_value); - dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR); /* Adjust the desired TX power level. */ if (conf->power_level != 0) { diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 0983406f4630..d579bb9035c4 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2676,7 +2676,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, if (conf->channel->hw_value != phy->channel) b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0); - dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR); /* Adjust the desired TX power level. */ if (conf->power_level != 0) { diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c42c4a820b89..2c9d3c719d8a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -494,7 +494,6 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_MMIC_ERROR: Michael MIC error was reported on this frame. * Use together with %RX_FLAG_MMIC_STRIPPED. * @RX_FLAG_DECRYPTED: This frame was decrypted in hardware. - * @RX_FLAG_RADIOTAP: This frame starts with a radiotap header. * @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame, * verification has been done by the hardware. * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame. @@ -515,7 +514,6 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, RX_FLAG_DECRYPTED = 1<<1, - RX_FLAG_RADIOTAP = 1<<2, RX_FLAG_MMIC_STRIPPED = 1<<3, RX_FLAG_IV_STRIPPED = 1<<4, RX_FLAG_FAILED_FCS_CRC = 1<<5, @@ -565,7 +563,9 @@ struct ieee80211_rx_status { * * Flags to define PHY configuration options * - * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported) + * @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this + * to determine for example whether to calculate timestamps for packets + * or not, do not use instead of filter flags! * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only) * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set * the driver should be prepared to handle configuration requests but @@ -574,7 +574,7 @@ struct ieee80211_rx_status { * it can also be unset in that case when monitor interfaces are active. */ enum ieee80211_conf_flags { - IEEE80211_CONF_RADIOTAP = (1<<0), + IEEE80211_CONF_MONITOR = (1<<0), IEEE80211_CONF_PS = (1<<1), IEEE80211_CONF_IDLE = (1<<2), }; @@ -584,7 +584,7 @@ enum ieee80211_conf_flags { * enum ieee80211_conf_changed - denotes which configuration changed * * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed - * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed + * @IEEE80211_CONF_CHANGE_MONITOR: the monitor flag changed * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed * @IEEE80211_CONF_CHANGE_POWER: the TX power changed * @IEEE80211_CONF_CHANGE_CHANNEL: the channel/channel_type changed @@ -593,7 +593,7 @@ enum ieee80211_conf_flags { */ enum ieee80211_conf_changed { IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), - IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), + IEEE80211_CONF_CHANGE_MONITOR = BIT(3), IEEE80211_CONF_CHANGE_PS = BIT(4), IEEE80211_CONF_CHANGE_POWER = BIT(5), IEEE80211_CONF_CHANGE_CHANNEL = BIT(6), @@ -1661,8 +1661,7 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw); * ieee80211_rx - receive frame * * Use this function to hand received frames to mac80211. The receive - * buffer in @skb must start with an IEEE 802.11 header or a radiotap - * header if %RX_FLAG_RADIOTAP is set in the @status flags. + * buffer in @skb must start with an IEEE 802.11 header. * * This function may not be called in IRQ context. Calls to this function * for a single hardware must be synchronized against each other. Calls to diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 14f10eb91c5c..8495161b99b8 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -214,8 +214,8 @@ static int ieee80211_open(struct net_device *dev) /* must be before the call to ieee80211_configure_filter */ local->monitors++; if (local->monitors == 1) { - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP; + local->hw.conf.flags |= IEEE80211_CONF_MONITOR; + hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; } if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) @@ -435,8 +435,8 @@ static int ieee80211_stop(struct net_device *dev) local->monitors--; if (local->monitors == 0) { - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP; + local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; + hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; } if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 01df328530ad..798fa82b6ae3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -39,11 +39,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, * only useful for monitoring. */ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, - struct sk_buff *skb, - int rtap_len) + struct sk_buff *skb) { - skb_pull(skb, rtap_len); - if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { if (likely(skb->len > FCS_LEN)) skb_trim(skb, skb->len - FCS_LEN); @@ -59,15 +56,14 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, } static inline int should_drop_frame(struct sk_buff *skb, - int present_fcs_len, - int radiotap_len) + int present_fcs_len) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) return 1; - if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len)) + if (unlikely(skb->len < 16 + present_fcs_len)) return 1; if (ieee80211_is_ctl(hdr->frame_control) && !ieee80211_is_pspoll(hdr->frame_control) && @@ -225,7 +221,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, struct sk_buff *skb, *skb2; struct net_device *prev_dev = NULL; int present_fcs_len = 0; - int rtap_len = 0; /* * First, we may need to make a copy of the skb because @@ -235,25 +230,23 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, * We don't need to, of course, if we aren't going to return * the SKB because it has a bad FCS/PLCP checksum. */ - if (status->flag & RX_FLAG_RADIOTAP) - rtap_len = ieee80211_get_radiotap_len(origskb->data); - else - /* room for the radiotap header based on driver features */ - needed_headroom = ieee80211_rx_radiotap_len(local, status); + + /* room for the radiotap header based on driver features */ + needed_headroom = ieee80211_rx_radiotap_len(local, status); if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) present_fcs_len = FCS_LEN; if (!local->monitors) { - if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { + if (should_drop_frame(origskb, present_fcs_len)) { dev_kfree_skb(origskb); return NULL; } - return remove_monitor_info(local, origskb, rtap_len); + return remove_monitor_info(local, origskb); } - if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { + if (should_drop_frame(origskb, present_fcs_len)) { /* only need to expand headroom if necessary */ skb = origskb; origskb = NULL; @@ -277,16 +270,14 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, */ skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); - origskb = remove_monitor_info(local, origskb, rtap_len); + origskb = remove_monitor_info(local, origskb); if (!skb) return origskb; } - /* if necessary, prepend radiotap information */ - if (!(status->flag & RX_FLAG_RADIOTAP)) - ieee80211_add_rx_radiotap_header(local, skb, rate, - needed_headroom); + /* prepend radiotap information */ + ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom); skb_reset_mac_header(skb); skb->ip_summed = CHECKSUM_UNNECESSARY; -- cgit v1.2.3 From 955015bb0b42167d14f776ff5947ae2463a974dc Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 20 Oct 2009 13:38:11 +0900 Subject: strip: move driver to staging Move the strip ("Starmode Radio IP") driver to drivers/staging. For several years this driver has only seen API "bombing-run" changes, and few people ever had the hardware. This driver represents unnecessary ongoing maintenance for no clear benefit. This patch brought to you by the "hacking" session at the 2009 Kernel Summit in Tokyo, Japan... Acked-by: Greg Kroah-Hartman Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 23 - drivers/net/wireless/Makefile | 1 - drivers/net/wireless/strip.c | 2805 ---------------------------------------- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/strip/Kconfig | 22 + drivers/staging/strip/Makefile | 1 + drivers/staging/strip/strip.c | 2805 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 2831 insertions(+), 2829 deletions(-) delete mode 100644 drivers/net/wireless/strip.c create mode 100644 drivers/staging/strip/Kconfig create mode 100644 drivers/staging/strip/Makefile create mode 100644 drivers/staging/strip/strip.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 85f8bf4112c1..5df47486e358 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -25,29 +25,6 @@ menuconfig WLAN_PRE80211 This option does not affect the kernel build, it only lets you choose drivers. -config STRIP - tristate "STRIP (Metricom starmode radio IP)" - depends on INET && WLAN_PRE80211 - select WIRELESS_EXT - ---help--- - Say Y if you have a Metricom radio and intend to use Starmode Radio - IP. STRIP is a radio protocol developed for the MosquitoNet project - to send Internet traffic using Metricom radios. Metricom radios are - small, battery powered, 100kbit/sec packet radio transceivers, about - the size and weight of a cellular telephone. (You may also have heard - them called "Metricom modems" but we avoid the term "modem" because - it misleads many people into thinking that you can plug a Metricom - modem into a phone line and use it as a modem.) - - You can use STRIP on any Linux machine with a serial port, although - it is obviously most useful for people with laptop computers. If you - think you might get a Metricom radio in the future, there is no harm - in saying Y to STRIP now, except that it makes the kernel a bit - bigger. - - To compile this as a module, choose M here: the module will be - called strip. - config ARLAN tristate "Aironet Arlan 655 & IC2200 DS support" depends on ISA && !64BIT && WLAN_PRE80211 diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 7a4647e78fd3..527c272aa1af 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_IPW2100) += ipw2x00/ obj-$(CONFIG_IPW2200) += ipw2x00/ -obj-$(CONFIG_STRIP) += strip.o obj-$(CONFIG_ARLAN) += arlan.o arlan-objs := arlan-main.o arlan-proc.o diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c deleted file mode 100644 index ea6a87c19319..000000000000 --- a/drivers/net/wireless/strip.c +++ /dev/null @@ -1,2805 +0,0 @@ -/* - * Copyright 1996 The Board of Trustees of The Leland Stanford - * Junior University. All Rights Reserved. - * - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies. Stanford University - * makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without - * express or implied warranty. - * - * strip.c This module implements Starmode Radio IP (STRIP) - * for kernel-based devices like TTY. It interfaces between a - * raw TTY, and the kernel's INET protocol layers (via DDI). - * - * Version: @(#)strip.c 1.3 July 1997 - * - * Author: Stuart Cheshire - * - * Fixes: v0.9 12th Feb 1996 (SC) - * New byte stuffing (2+6 run-length encoding) - * New watchdog timer task - * New Protocol key (SIP0) - * - * v0.9.1 3rd March 1996 (SC) - * Changed to dynamic device allocation -- no more compile - * time (or boot time) limit on the number of STRIP devices. - * - * v0.9.2 13th March 1996 (SC) - * Uses arp cache lookups (but doesn't send arp packets yet) - * - * v0.9.3 17th April 1996 (SC) - * Fixed bug where STR_ERROR flag was getting set unneccessarily - * (causing otherwise good packets to be unneccessarily dropped) - * - * v0.9.4 27th April 1996 (SC) - * First attempt at using "&COMMAND" Starmode AT commands - * - * v0.9.5 29th May 1996 (SC) - * First attempt at sending (unicast) ARP packets - * - * v0.9.6 5th June 1996 (Elliot) - * Put "message level" tags in every "printk" statement - * - * v0.9.7 13th June 1996 (laik) - * Added support for the /proc fs - * - * v0.9.8 July 1996 (Mema) - * Added packet logging - * - * v1.0 November 1996 (SC) - * Fixed (severe) memory leaks in the /proc fs code - * Fixed race conditions in the logging code - * - * v1.1 January 1997 (SC) - * Deleted packet logging (use tcpdump instead) - * Added support for Metricom Firmware v204 features - * (like message checksums) - * - * v1.2 January 1997 (SC) - * Put portables list back in - * - * v1.3 July 1997 (SC) - * Made STRIP driver set the radio's baud rate automatically. - * It is no longer necessarily to manually set the radio's - * rate permanently to 115200 -- the driver handles setting - * the rate automatically. - */ - -#ifdef MODULE -static const char StripVersion[] = "1.3A-STUART.CHESHIRE-MODULAR"; -#else -static const char StripVersion[] = "1.3A-STUART.CHESHIRE"; -#endif - -#define TICKLE_TIMERS 0 -#define EXT_COUNTERS 1 - - -/************************************************************************/ -/* Header files */ - -#include -#include -#include -#include -#include -#include - -# include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/************************************************************************/ -/* Useful structures and definitions */ - -/* - * A MetricomKey identifies the protocol being carried inside a Metricom - * Starmode packet. - */ - -typedef union { - __u8 c[4]; - __u32 l; -} MetricomKey; - -/* - * An IP address can be viewed as four bytes in memory (which is what it is) or as - * a single 32-bit long (which is convenient for assignment, equality testing etc.) - */ - -typedef union { - __u8 b[4]; - __u32 l; -} IPaddr; - -/* - * A MetricomAddressString is used to hold a printable representation of - * a Metricom address. - */ - -typedef struct { - __u8 c[24]; -} MetricomAddressString; - -/* Encapsulation can expand packet of size x to 65/64x + 1 - * Sent packet looks like "*
*" - * 1 1 1-18 1 4 ? 1 - * eg. *0000-1234*SIP0 - * We allow 31 bytes for the stars, the key, the address and the s - */ -#define STRIP_ENCAP_SIZE(X) (32 + (X)*65L/64L) - -/* - * A STRIP_Header is never really sent over the radio, but making a dummy - * header for internal use within the kernel that looks like an Ethernet - * header makes certain other software happier. For example, tcpdump - * already understands Ethernet headers. - */ - -typedef struct { - MetricomAddress dst_addr; /* Destination address, e.g. "0000-1234" */ - MetricomAddress src_addr; /* Source address, e.g. "0000-5678" */ - unsigned short protocol; /* The protocol type, using Ethernet codes */ -} STRIP_Header; - -typedef struct { - char c[60]; -} MetricomNode; - -#define NODE_TABLE_SIZE 32 -typedef struct { - struct timeval timestamp; - int num_nodes; - MetricomNode node[NODE_TABLE_SIZE]; -} MetricomNodeTable; - -enum { FALSE = 0, TRUE = 1 }; - -/* - * Holds the radio's firmware version. - */ -typedef struct { - char c[50]; -} FirmwareVersion; - -/* - * Holds the radio's serial number. - */ -typedef struct { - char c[18]; -} SerialNumber; - -/* - * Holds the radio's battery voltage. - */ -typedef struct { - char c[11]; -} BatteryVoltage; - -typedef struct { - char c[8]; -} char8; - -enum { - NoStructure = 0, /* Really old firmware */ - StructuredMessages = 1, /* Parsable AT response msgs */ - ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */ -}; - -struct strip { - int magic; - /* - * These are pointers to the malloc()ed frame buffers. - */ - - unsigned char *rx_buff; /* buffer for received IP packet */ - unsigned char *sx_buff; /* buffer for received serial data */ - int sx_count; /* received serial data counter */ - int sx_size; /* Serial buffer size */ - unsigned char *tx_buff; /* transmitter buffer */ - unsigned char *tx_head; /* pointer to next byte to XMIT */ - int tx_left; /* bytes left in XMIT queue */ - int tx_size; /* Serial buffer size */ - - /* - * STRIP interface statistics. - */ - - unsigned long rx_packets; /* inbound frames counter */ - unsigned long tx_packets; /* outbound frames counter */ - unsigned long rx_errors; /* Parity, etc. errors */ - unsigned long tx_errors; /* Planned stuff */ - unsigned long rx_dropped; /* No memory for skb */ - unsigned long tx_dropped; /* When MTU change */ - unsigned long rx_over_errors; /* Frame bigger than STRIP buf. */ - - unsigned long pps_timer; /* Timer to determine pps */ - unsigned long rx_pps_count; /* Counter to determine pps */ - unsigned long tx_pps_count; /* Counter to determine pps */ - unsigned long sx_pps_count; /* Counter to determine pps */ - unsigned long rx_average_pps; /* rx packets per second * 8 */ - unsigned long tx_average_pps; /* tx packets per second * 8 */ - unsigned long sx_average_pps; /* sent packets per second * 8 */ - -#ifdef EXT_COUNTERS - unsigned long rx_bytes; /* total received bytes */ - unsigned long tx_bytes; /* total received bytes */ - unsigned long rx_rbytes; /* bytes thru radio i/f */ - unsigned long tx_rbytes; /* bytes thru radio i/f */ - unsigned long rx_sbytes; /* tot bytes thru serial i/f */ - unsigned long tx_sbytes; /* tot bytes thru serial i/f */ - unsigned long rx_ebytes; /* tot stat/err bytes */ - unsigned long tx_ebytes; /* tot stat/err bytes */ -#endif - - /* - * Internal variables. - */ - - struct list_head list; /* Linked list of devices */ - - int discard; /* Set if serial error */ - int working; /* Is radio working correctly? */ - int firmware_level; /* Message structuring level */ - int next_command; /* Next periodic command */ - unsigned int user_baud; /* The user-selected baud rate */ - int mtu; /* Our mtu (to spot changes!) */ - long watchdog_doprobe; /* Next time to test the radio */ - long watchdog_doreset; /* Time to do next reset */ - long gratuitous_arp; /* Time to send next ARP refresh */ - long arp_interval; /* Next ARP interval */ - struct timer_list idle_timer; /* For periodic wakeup calls */ - MetricomAddress true_dev_addr; /* True address of radio */ - int manual_dev_addr; /* Hack: See note below */ - - FirmwareVersion firmware_version; /* The radio's firmware version */ - SerialNumber serial_number; /* The radio's serial number */ - BatteryVoltage battery_voltage; /* The radio's battery voltage */ - - /* - * Other useful structures. - */ - - struct tty_struct *tty; /* ptr to TTY structure */ - struct net_device *dev; /* Our device structure */ - - /* - * Neighbour radio records - */ - - MetricomNodeTable portables; - MetricomNodeTable poletops; -}; - -/* - * Note: manual_dev_addr hack - * - * It is not possible to change the hardware address of a Metricom radio, - * or to send packets with a user-specified hardware source address, thus - * trying to manually set a hardware source address is a questionable - * thing to do. However, if the user *does* manually set the hardware - * source address of a STRIP interface, then the kernel will believe it, - * and use it in certain places. For example, the hardware address listed - * by ifconfig will be the manual address, not the true one. - * (Both addresses are listed in /proc/net/strip.) - * Also, ARP packets will be sent out giving the user-specified address as - * the source address, not the real address. This is dangerous, because - * it means you won't receive any replies -- the ARP replies will go to - * the specified address, which will be some other radio. The case where - * this is useful is when that other radio is also connected to the same - * machine. This allows you to connect a pair of radios to one machine, - * and to use one exclusively for inbound traffic, and the other - * exclusively for outbound traffic. Pretty neat, huh? - * - * Here's the full procedure to set this up: - * - * 1. "slattach" two interfaces, e.g. st0 for outgoing packets, - * and st1 for incoming packets - * - * 2. "ifconfig" st0 (outbound radio) to have the hardware address - * which is the real hardware address of st1 (inbound radio). - * Now when it sends out packets, it will masquerade as st1, and - * replies will be sent to that radio, which is exactly what we want. - * - * 3. Set the route table entry ("route add default ..." or - * "route add -net ...", as appropriate) to send packets via the st0 - * interface (outbound radio). Do not add any route which sends packets - * out via the st1 interface -- that radio is for inbound traffic only. - * - * 4. "ifconfig" st1 (inbound radio) to have hardware address zero. - * This tells the STRIP driver to "shut down" that interface and not - * send any packets through it. In particular, it stops sending the - * periodic gratuitous ARP packets that a STRIP interface normally sends. - * Also, when packets arrive on that interface, it will search the - * interface list to see if there is another interface who's manual - * hardware address matches its own real address (i.e. st0 in this - * example) and if so it will transfer ownership of the skbuff to - * that interface, so that it looks to the kernel as if the packet - * arrived on that interface. This is necessary because when the - * kernel sends an ARP packet on st0, it expects to get a reply on - * st0, and if it sees the reply come from st1 then it will ignore - * it (to be accurate, it puts the entry in the ARP table, but - * labelled in such a way that st0 can't use it). - * - * Thanks to Petros Maniatis for coming up with the idea of splitting - * inbound and outbound traffic between two interfaces, which turned - * out to be really easy to implement, even if it is a bit of a hack. - * - * Having set a manual address on an interface, you can restore it - * to automatic operation (where the address is automatically kept - * consistent with the real address of the radio) by setting a manual - * address of all ones, e.g. "ifconfig st0 hw strip FFFFFFFFFFFF" - * This 'turns off' manual override mode for the device address. - * - * Note: The IEEE 802 headers reported in tcpdump will show the *real* - * radio addresses the packets were sent and received from, so that you - * can see what is really going on with packets, and which interfaces - * they are really going through. - */ - - -/************************************************************************/ -/* Constants */ - -/* - * CommandString1 works on all radios - * Other CommandStrings are only used with firmware that provides structured responses. - * - * ats319=1 Enables Info message for node additions and deletions - * ats319=2 Enables Info message for a new best node - * ats319=4 Enables checksums - * ats319=8 Enables ACK messages - */ - -static const int MaxCommandStringLength = 32; -static const int CompatibilityCommand = 1; - -static const char CommandString0[] = "*&COMMAND*ATS319=7"; /* Turn on checksums & info messages */ -static const char CommandString1[] = "*&COMMAND*ATS305?"; /* Query radio name */ -static const char CommandString2[] = "*&COMMAND*ATS325?"; /* Query battery voltage */ -static const char CommandString3[] = "*&COMMAND*ATS300?"; /* Query version information */ -static const char CommandString4[] = "*&COMMAND*ATS311?"; /* Query poletop list */ -static const char CommandString5[] = "*&COMMAND*AT~LA"; /* Query portables list */ -typedef struct { - const char *string; - long length; -} StringDescriptor; - -static const StringDescriptor CommandString[] = { - {CommandString0, sizeof(CommandString0) - 1}, - {CommandString1, sizeof(CommandString1) - 1}, - {CommandString2, sizeof(CommandString2) - 1}, - {CommandString3, sizeof(CommandString3) - 1}, - {CommandString4, sizeof(CommandString4) - 1}, - {CommandString5, sizeof(CommandString5) - 1} -}; - -#define GOT_ALL_RADIO_INFO(S) \ - ((S)->firmware_version.c[0] && \ - (S)->battery_voltage.c[0] && \ - memcmp(&(S)->true_dev_addr, zero_address.c, sizeof(zero_address))) - -static const char hextable[16] = "0123456789ABCDEF"; - -static const MetricomAddress zero_address; -static const MetricomAddress broadcast_address = - { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} }; - -static const MetricomKey SIP0Key = { "SIP0" }; -static const MetricomKey ARP0Key = { "ARP0" }; -static const MetricomKey ATR_Key = { "ATR " }; -static const MetricomKey ACK_Key = { "ACK_" }; -static const MetricomKey INF_Key = { "INF_" }; -static const MetricomKey ERR_Key = { "ERR_" }; - -static const long MaxARPInterval = 60 * HZ; /* One minute */ - -/* - * Maximum Starmode packet length is 1183 bytes. Allowing 4 bytes for - * protocol key, 4 bytes for checksum, one byte for CR, and 65/64 expansion - * for STRIP encoding, that translates to a maximum payload MTU of 1155. - * Note: A standard NFS 1K data packet is a total of 0x480 (1152) bytes - * long, including IP header, UDP header, and NFS header. Setting the STRIP - * MTU to 1152 allows us to send default sized NFS packets without fragmentation. - */ -static const unsigned short MAX_SEND_MTU = 1152; -static const unsigned short MAX_RECV_MTU = 1500; /* Hoping for Ethernet sized packets in the future! */ -static const unsigned short DEFAULT_STRIP_MTU = 1152; -static const int STRIP_MAGIC = 0x5303; -static const long LongTime = 0x7FFFFFFF; - -/************************************************************************/ -/* Global variables */ - -static LIST_HEAD(strip_list); -static DEFINE_SPINLOCK(strip_lock); - -/************************************************************************/ -/* Macros */ - -/* Returns TRUE if text T begins with prefix P */ -#define has_prefix(T,L,P) (((L) >= sizeof(P)-1) && !strncmp((T), (P), sizeof(P)-1)) - -/* Returns TRUE if text T of length L is equal to string S */ -#define text_equal(T,L,S) (((L) == sizeof(S)-1) && !strncmp((T), (S), sizeof(S)-1)) - -#define READHEX(X) ((X)>='0' && (X)<='9' ? (X)-'0' : \ - (X)>='a' && (X)<='f' ? (X)-'a'+10 : \ - (X)>='A' && (X)<='F' ? (X)-'A'+10 : 0 ) - -#define READHEX16(X) ((__u16)(READHEX(X))) - -#define READDEC(X) ((X)>='0' && (X)<='9' ? (X)-'0' : 0) - -#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)])) - -#define JIFFIE_TO_SEC(X) ((X) / HZ) - - -/************************************************************************/ -/* Utility routines */ - -static int arp_query(unsigned char *haddr, u32 paddr, - struct net_device *dev) -{ - struct neighbour *neighbor_entry; - int ret = 0; - - neighbor_entry = neigh_lookup(&arp_tbl, &paddr, dev); - - if (neighbor_entry != NULL) { - neighbor_entry->used = jiffies; - if (neighbor_entry->nud_state & NUD_VALID) { - memcpy(haddr, neighbor_entry->ha, dev->addr_len); - ret = 1; - } - neigh_release(neighbor_entry); - } - return ret; -} - -static void DumpData(char *msg, struct strip *strip_info, __u8 * ptr, - __u8 * end) -{ - static const int MAX_DumpData = 80; - __u8 pkt_text[MAX_DumpData], *p = pkt_text; - - *p++ = '\"'; - - while (ptr < end && p < &pkt_text[MAX_DumpData - 4]) { - if (*ptr == '\\') { - *p++ = '\\'; - *p++ = '\\'; - } else { - if (*ptr >= 32 && *ptr <= 126) { - *p++ = *ptr; - } else { - sprintf(p, "\\%02X", *ptr); - p += 3; - } - } - ptr++; - } - - if (ptr == end) - *p++ = '\"'; - *p++ = 0; - - printk(KERN_INFO "%s: %-13s%s\n", strip_info->dev->name, msg, pkt_text); -} - - -/************************************************************************/ -/* Byte stuffing/unstuffing routines */ - -/* Stuffing scheme: - * 00 Unused (reserved character) - * 01-3F Run of 2-64 different characters - * 40-7F Run of 1-64 different characters plus a single zero at the end - * 80-BF Run of 1-64 of the same character - * C0-FF Run of 1-64 zeroes (ASCII 0) - */ - -typedef enum { - Stuff_Diff = 0x00, - Stuff_DiffZero = 0x40, - Stuff_Same = 0x80, - Stuff_Zero = 0xC0, - Stuff_NoCode = 0xFF, /* Special code, meaning no code selected */ - - Stuff_CodeMask = 0xC0, - Stuff_CountMask = 0x3F, - Stuff_MaxCount = 0x3F, - Stuff_Magic = 0x0D /* The value we are eliminating */ -} StuffingCode; - -/* StuffData encodes the data starting at "src" for "length" bytes. - * It writes it to the buffer pointed to by "dst" (which must be at least - * as long as 1 + 65/64 of the input length). The output may be up to 1.6% - * larger than the input for pathological input, but will usually be smaller. - * StuffData returns the new value of the dst pointer as its result. - * "code_ptr_ptr" points to a "__u8 *" which is used to hold encoding state - * between calls, allowing an encoded packet to be incrementally built up - * from small parts. On the first call, the "__u8 *" pointed to should be - * initialized to NULL; between subsequent calls the calling routine should - * leave the value alone and simply pass it back unchanged so that the - * encoder can recover its current state. - */ - -#define StuffData_FinishBlock(X) \ -(*code_ptr = (X) ^ Stuff_Magic, code = Stuff_NoCode) - -static __u8 *StuffData(__u8 * src, __u32 length, __u8 * dst, - __u8 ** code_ptr_ptr) -{ - __u8 *end = src + length; - __u8 *code_ptr = *code_ptr_ptr; - __u8 code = Stuff_NoCode, count = 0; - - if (!length) - return (dst); - - if (code_ptr) { - /* - * Recover state from last call, if applicable - */ - code = (*code_ptr ^ Stuff_Magic) & Stuff_CodeMask; - count = (*code_ptr ^ Stuff_Magic) & Stuff_CountMask; - } - - while (src < end) { - switch (code) { - /* Stuff_NoCode: If no current code, select one */ - case Stuff_NoCode: - /* Record where we're going to put this code */ - code_ptr = dst++; - count = 0; /* Reset the count (zero means one instance) */ - /* Tentatively start a new block */ - if (*src == 0) { - code = Stuff_Zero; - src++; - } else { - code = Stuff_Same; - *dst++ = *src++ ^ Stuff_Magic; - } - /* Note: We optimistically assume run of same -- */ - /* which will be fixed later in Stuff_Same */ - /* if it turns out not to be true. */ - break; - - /* Stuff_Zero: We already have at least one zero encoded */ - case Stuff_Zero: - /* If another zero, count it, else finish this code block */ - if (*src == 0) { - count++; - src++; - } else { - StuffData_FinishBlock(Stuff_Zero + count); - } - break; - - /* Stuff_Same: We already have at least one byte encoded */ - case Stuff_Same: - /* If another one the same, count it */ - if ((*src ^ Stuff_Magic) == code_ptr[1]) { - count++; - src++; - break; - } - /* else, this byte does not match this block. */ - /* If we already have two or more bytes encoded, finish this code block */ - if (count) { - StuffData_FinishBlock(Stuff_Same + count); - break; - } - /* else, we only have one so far, so switch to Stuff_Diff code */ - code = Stuff_Diff; - /* and fall through to Stuff_Diff case below - * Note cunning cleverness here: case Stuff_Diff compares - * the current character with the previous two to see if it - * has a run of three the same. Won't this be an error if - * there aren't two previous characters stored to compare with? - * No. Because we know the current character is *not* the same - * as the previous one, the first test below will necessarily - * fail and the send half of the "if" won't be executed. - */ - - /* Stuff_Diff: We have at least two *different* bytes encoded */ - case Stuff_Diff: - /* If this is a zero, must encode a Stuff_DiffZero, and begin a new block */ - if (*src == 0) { - StuffData_FinishBlock(Stuff_DiffZero + - count); - } - /* else, if we have three in a row, it is worth starting a Stuff_Same block */ - else if ((*src ^ Stuff_Magic) == dst[-1] - && dst[-1] == dst[-2]) { - /* Back off the last two characters we encoded */ - code += count - 2; - /* Note: "Stuff_Diff + 0" is an illegal code */ - if (code == Stuff_Diff + 0) { - code = Stuff_Same + 0; - } - StuffData_FinishBlock(code); - code_ptr = dst - 2; - /* dst[-1] already holds the correct value */ - count = 2; /* 2 means three bytes encoded */ - code = Stuff_Same; - } - /* else, another different byte, so add it to the block */ - else { - *dst++ = *src ^ Stuff_Magic; - count++; - } - src++; /* Consume the byte */ - break; - } - if (count == Stuff_MaxCount) { - StuffData_FinishBlock(code + count); - } - } - if (code == Stuff_NoCode) { - *code_ptr_ptr = NULL; - } else { - *code_ptr_ptr = code_ptr; - StuffData_FinishBlock(code + count); - } - return (dst); -} - -/* - * UnStuffData decodes the data at "src", up to (but not including) "end". - * It writes the decoded data into the buffer pointed to by "dst", up to a - * maximum of "dst_length", and returns the new value of "src" so that a - * follow-on call can read more data, continuing from where the first left off. - * - * There are three types of results: - * 1. The source data runs out before extracting "dst_length" bytes: - * UnStuffData returns NULL to indicate failure. - * 2. The source data produces exactly "dst_length" bytes: - * UnStuffData returns new_src = end to indicate that all bytes were consumed. - * 3. "dst_length" bytes are extracted, with more remaining. - * UnStuffData returns new_src < end to indicate that there are more bytes - * to be read. - * - * Note: The decoding may be destructive, in that it may alter the source - * data in the process of decoding it (this is necessary to allow a follow-on - * call to resume correctly). - */ - -static __u8 *UnStuffData(__u8 * src, __u8 * end, __u8 * dst, - __u32 dst_length) -{ - __u8 *dst_end = dst + dst_length; - /* Sanity check */ - if (!src || !end || !dst || !dst_length) - return (NULL); - while (src < end && dst < dst_end) { - int count = (*src ^ Stuff_Magic) & Stuff_CountMask; - switch ((*src ^ Stuff_Magic) & Stuff_CodeMask) { - case Stuff_Diff: - if (src + 1 + count >= end) - return (NULL); - do { - *dst++ = *++src ^ Stuff_Magic; - } - while (--count >= 0 && dst < dst_end); - if (count < 0) - src += 1; - else { - if (count == 0) - *src = Stuff_Same ^ Stuff_Magic; - else - *src = - (Stuff_Diff + - count) ^ Stuff_Magic; - } - break; - case Stuff_DiffZero: - if (src + 1 + count >= end) - return (NULL); - do { - *dst++ = *++src ^ Stuff_Magic; - } - while (--count >= 0 && dst < dst_end); - if (count < 0) - *src = Stuff_Zero ^ Stuff_Magic; - else - *src = - (Stuff_DiffZero + count) ^ Stuff_Magic; - break; - case Stuff_Same: - if (src + 1 >= end) - return (NULL); - do { - *dst++ = src[1] ^ Stuff_Magic; - } - while (--count >= 0 && dst < dst_end); - if (count < 0) - src += 2; - else - *src = (Stuff_Same + count) ^ Stuff_Magic; - break; - case Stuff_Zero: - do { - *dst++ = 0; - } - while (--count >= 0 && dst < dst_end); - if (count < 0) - src += 1; - else - *src = (Stuff_Zero + count) ^ Stuff_Magic; - break; - } - } - if (dst < dst_end) - return (NULL); - else - return (src); -} - - -/************************************************************************/ -/* General routines for STRIP */ - -/* - * set_baud sets the baud rate to the rate defined by baudcode - */ -static void set_baud(struct tty_struct *tty, speed_t baudrate) -{ - struct ktermios old_termios; - - mutex_lock(&tty->termios_mutex); - old_termios =*(tty->termios); - tty_encode_baud_rate(tty, baudrate, baudrate); - tty->ops->set_termios(tty, &old_termios); - mutex_unlock(&tty->termios_mutex); -} - -/* - * Convert a string to a Metricom Address. - */ - -#define IS_RADIO_ADDRESS(p) ( \ - isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \ - (p)[4] == '-' && \ - isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8]) ) - -static int string_to_radio_address(MetricomAddress * addr, __u8 * p) -{ - if (!IS_RADIO_ADDRESS(p)) - return (1); - addr->c[0] = 0; - addr->c[1] = 0; - addr->c[2] = READHEX(p[0]) << 4 | READHEX(p[1]); - addr->c[3] = READHEX(p[2]) << 4 | READHEX(p[3]); - addr->c[4] = READHEX(p[5]) << 4 | READHEX(p[6]); - addr->c[5] = READHEX(p[7]) << 4 | READHEX(p[8]); - return (0); -} - -/* - * Convert a Metricom Address to a string. - */ - -static __u8 *radio_address_to_string(const MetricomAddress * addr, - MetricomAddressString * p) -{ - sprintf(p->c, "%02X%02X-%02X%02X", addr->c[2], addr->c[3], - addr->c[4], addr->c[5]); - return (p->c); -} - -/* - * Note: Must make sure sx_size is big enough to receive a stuffed - * MAX_RECV_MTU packet. Additionally, we also want to ensure that it's - * big enough to receive a large radio neighbour list (currently 4K). - */ - -static int allocate_buffers(struct strip *strip_info, int mtu) -{ - struct net_device *dev = strip_info->dev; - int sx_size = max_t(int, STRIP_ENCAP_SIZE(MAX_RECV_MTU), 4096); - int tx_size = STRIP_ENCAP_SIZE(mtu) + MaxCommandStringLength; - __u8 *r = kmalloc(MAX_RECV_MTU, GFP_ATOMIC); - __u8 *s = kmalloc(sx_size, GFP_ATOMIC); - __u8 *t = kmalloc(tx_size, GFP_ATOMIC); - if (r && s && t) { - strip_info->rx_buff = r; - strip_info->sx_buff = s; - strip_info->tx_buff = t; - strip_info->sx_size = sx_size; - strip_info->tx_size = tx_size; - strip_info->mtu = dev->mtu = mtu; - return (1); - } - kfree(r); - kfree(s); - kfree(t); - return (0); -} - -/* - * MTU has been changed by the IP layer. - * We could be in - * an upcall from the tty driver, or in an ip packet queue. - */ -static int strip_change_mtu(struct net_device *dev, int new_mtu) -{ - struct strip *strip_info = netdev_priv(dev); - int old_mtu = strip_info->mtu; - unsigned char *orbuff = strip_info->rx_buff; - unsigned char *osbuff = strip_info->sx_buff; - unsigned char *otbuff = strip_info->tx_buff; - - if (new_mtu > MAX_SEND_MTU) { - printk(KERN_ERR - "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n", - strip_info->dev->name, MAX_SEND_MTU); - return -EINVAL; - } - - spin_lock_bh(&strip_lock); - if (!allocate_buffers(strip_info, new_mtu)) { - printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n", - strip_info->dev->name); - spin_unlock_bh(&strip_lock); - return -ENOMEM; - } - - if (strip_info->sx_count) { - if (strip_info->sx_count <= strip_info->sx_size) - memcpy(strip_info->sx_buff, osbuff, - strip_info->sx_count); - else { - strip_info->discard = strip_info->sx_count; - strip_info->rx_over_errors++; - } - } - - if (strip_info->tx_left) { - if (strip_info->tx_left <= strip_info->tx_size) - memcpy(strip_info->tx_buff, strip_info->tx_head, - strip_info->tx_left); - else { - strip_info->tx_left = 0; - strip_info->tx_dropped++; - } - } - strip_info->tx_head = strip_info->tx_buff; - spin_unlock_bh(&strip_lock); - - printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n", - strip_info->dev->name, old_mtu, strip_info->mtu); - - kfree(orbuff); - kfree(osbuff); - kfree(otbuff); - return 0; -} - -static void strip_unlock(struct strip *strip_info) -{ - /* - * Set the timer to go off in one second. - */ - strip_info->idle_timer.expires = jiffies + 1 * HZ; - add_timer(&strip_info->idle_timer); - netif_wake_queue(strip_info->dev); -} - - - -/* - * If the time is in the near future, time_delta prints the number of - * seconds to go into the buffer and returns the address of the buffer. - * If the time is not in the near future, it returns the address of the - * string "Not scheduled" The buffer must be long enough to contain the - * ascii representation of the number plus 9 charactes for the " seconds" - * and the null character. - */ -#ifdef CONFIG_PROC_FS -static char *time_delta(char buffer[], long time) -{ - time -= jiffies; - if (time > LongTime / 2) - return ("Not scheduled"); - if (time < 0) - time = 0; /* Don't print negative times */ - sprintf(buffer, "%ld seconds", time / HZ); - return (buffer); -} - -/* get Nth element of the linked list */ -static struct strip *strip_get_idx(loff_t pos) -{ - struct strip *str; - int i = 0; - - list_for_each_entry_rcu(str, &strip_list, list) { - if (pos == i) - return str; - ++i; - } - return NULL; -} - -static void *strip_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) -{ - rcu_read_lock(); - return *pos ? strip_get_idx(*pos - 1) : SEQ_START_TOKEN; -} - -static void *strip_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct list_head *l; - struct strip *s; - - ++*pos; - if (v == SEQ_START_TOKEN) - return strip_get_idx(1); - - s = v; - l = &s->list; - list_for_each_continue_rcu(l, &strip_list) { - return list_entry(l, struct strip, list); - } - return NULL; -} - -static void strip_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) -{ - rcu_read_unlock(); -} - -static void strip_seq_neighbours(struct seq_file *seq, - const MetricomNodeTable * table, - const char *title) -{ - /* We wrap this in a do/while loop, so if the table changes */ - /* while we're reading it, we just go around and try again. */ - struct timeval t; - - do { - int i; - t = table->timestamp; - if (table->num_nodes) - seq_printf(seq, "\n %s\n", title); - for (i = 0; i < table->num_nodes; i++) { - MetricomNode node; - - spin_lock_bh(&strip_lock); - node = table->node[i]; - spin_unlock_bh(&strip_lock); - seq_printf(seq, " %s\n", node.c); - } - } while (table->timestamp.tv_sec != t.tv_sec - || table->timestamp.tv_usec != t.tv_usec); -} - -/* - * This function prints radio status information via the seq_file - * interface. The interface takes care of buffer size and over - * run issues. - * - * The buffer in seq_file is PAGESIZE (4K) - * so this routine should never print more or it will get truncated. - * With the maximum of 32 portables and 32 poletops - * reported, the routine outputs 3107 bytes into the buffer. - */ -static void strip_seq_status_info(struct seq_file *seq, - const struct strip *strip_info) -{ - char temp[32]; - MetricomAddressString addr_string; - - /* First, we must copy all of our data to a safe place, */ - /* in case a serial interrupt comes in and changes it. */ - int tx_left = strip_info->tx_left; - unsigned long rx_average_pps = strip_info->rx_average_pps; - unsigned long tx_average_pps = strip_info->tx_average_pps; - unsigned long sx_average_pps = strip_info->sx_average_pps; - int working = strip_info->working; - int firmware_level = strip_info->firmware_level; - long watchdog_doprobe = strip_info->watchdog_doprobe; - long watchdog_doreset = strip_info->watchdog_doreset; - long gratuitous_arp = strip_info->gratuitous_arp; - long arp_interval = strip_info->arp_interval; - FirmwareVersion firmware_version = strip_info->firmware_version; - SerialNumber serial_number = strip_info->serial_number; - BatteryVoltage battery_voltage = strip_info->battery_voltage; - char *if_name = strip_info->dev->name; - MetricomAddress true_dev_addr = strip_info->true_dev_addr; - MetricomAddress dev_dev_addr = - *(MetricomAddress *) strip_info->dev->dev_addr; - int manual_dev_addr = strip_info->manual_dev_addr; -#ifdef EXT_COUNTERS - unsigned long rx_bytes = strip_info->rx_bytes; - unsigned long tx_bytes = strip_info->tx_bytes; - unsigned long rx_rbytes = strip_info->rx_rbytes; - unsigned long tx_rbytes = strip_info->tx_rbytes; - unsigned long rx_sbytes = strip_info->rx_sbytes; - unsigned long tx_sbytes = strip_info->tx_sbytes; - unsigned long rx_ebytes = strip_info->rx_ebytes; - unsigned long tx_ebytes = strip_info->tx_ebytes; -#endif - - seq_printf(seq, "\nInterface name\t\t%s\n", if_name); - seq_printf(seq, " Radio working:\t\t%s\n", working ? "Yes" : "No"); - radio_address_to_string(&true_dev_addr, &addr_string); - seq_printf(seq, " Radio address:\t\t%s\n", addr_string.c); - if (manual_dev_addr) { - radio_address_to_string(&dev_dev_addr, &addr_string); - seq_printf(seq, " Device address:\t%s\n", addr_string.c); - } - seq_printf(seq, " Firmware version:\t%s", !working ? "Unknown" : - !firmware_level ? "Should be upgraded" : - firmware_version.c); - if (firmware_level >= ChecksummedMessages) - seq_printf(seq, " (Checksums Enabled)"); - seq_printf(seq, "\n"); - seq_printf(seq, " Serial number:\t\t%s\n", serial_number.c); - seq_printf(seq, " Battery voltage:\t%s\n", battery_voltage.c); - seq_printf(seq, " Transmit queue (bytes):%d\n", tx_left); - seq_printf(seq, " Receive packet rate: %ld packets per second\n", - rx_average_pps / 8); - seq_printf(seq, " Transmit packet rate: %ld packets per second\n", - tx_average_pps / 8); - seq_printf(seq, " Sent packet rate: %ld packets per second\n", - sx_average_pps / 8); - seq_printf(seq, " Next watchdog probe:\t%s\n", - time_delta(temp, watchdog_doprobe)); - seq_printf(seq, " Next watchdog reset:\t%s\n", - time_delta(temp, watchdog_doreset)); - seq_printf(seq, " Next gratuitous ARP:\t"); - - if (!memcmp - (strip_info->dev->dev_addr, zero_address.c, - sizeof(zero_address))) - seq_printf(seq, "Disabled\n"); - else { - seq_printf(seq, "%s\n", time_delta(temp, gratuitous_arp)); - seq_printf(seq, " Next ARP interval:\t%ld seconds\n", - JIFFIE_TO_SEC(arp_interval)); - } - - if (working) { -#ifdef EXT_COUNTERS - seq_printf(seq, "\n"); - seq_printf(seq, - " Total bytes: \trx:\t%lu\ttx:\t%lu\n", - rx_bytes, tx_bytes); - seq_printf(seq, - " thru radio: \trx:\t%lu\ttx:\t%lu\n", - rx_rbytes, tx_rbytes); - seq_printf(seq, - " thru serial port: \trx:\t%lu\ttx:\t%lu\n", - rx_sbytes, tx_sbytes); - seq_printf(seq, - " Total stat/err bytes:\trx:\t%lu\ttx:\t%lu\n", - rx_ebytes, tx_ebytes); -#endif - strip_seq_neighbours(seq, &strip_info->poletops, - "Poletops:"); - strip_seq_neighbours(seq, &strip_info->portables, - "Portables:"); - } -} - -/* - * This function is exports status information from the STRIP driver through - * the /proc file system. - */ -static int strip_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_printf(seq, "strip_version: %s\n", StripVersion); - else - strip_seq_status_info(seq, (const struct strip *)v); - return 0; -} - - -static const struct seq_operations strip_seq_ops = { - .start = strip_seq_start, - .next = strip_seq_next, - .stop = strip_seq_stop, - .show = strip_seq_show, -}; - -static int strip_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &strip_seq_ops); -} - -static const struct file_operations strip_seq_fops = { - .owner = THIS_MODULE, - .open = strip_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -#endif - - - -/************************************************************************/ -/* Sending routines */ - -static void ResetRadio(struct strip *strip_info) -{ - struct tty_struct *tty = strip_info->tty; - static const char init[] = "ate0q1dt**starmode\r**"; - StringDescriptor s = { init, sizeof(init) - 1 }; - - /* - * If the radio isn't working anymore, - * we should clear the old status information. - */ - if (strip_info->working) { - printk(KERN_INFO "%s: No response: Resetting radio.\n", - strip_info->dev->name); - strip_info->firmware_version.c[0] = '\0'; - strip_info->serial_number.c[0] = '\0'; - strip_info->battery_voltage.c[0] = '\0'; - strip_info->portables.num_nodes = 0; - do_gettimeofday(&strip_info->portables.timestamp); - strip_info->poletops.num_nodes = 0; - do_gettimeofday(&strip_info->poletops.timestamp); - } - - strip_info->pps_timer = jiffies; - strip_info->rx_pps_count = 0; - strip_info->tx_pps_count = 0; - strip_info->sx_pps_count = 0; - strip_info->rx_average_pps = 0; - strip_info->tx_average_pps = 0; - strip_info->sx_average_pps = 0; - - /* Mark radio address as unknown */ - *(MetricomAddress *) & strip_info->true_dev_addr = zero_address; - if (!strip_info->manual_dev_addr) - *(MetricomAddress *) strip_info->dev->dev_addr = - zero_address; - strip_info->working = FALSE; - strip_info->firmware_level = NoStructure; - strip_info->next_command = CompatibilityCommand; - strip_info->watchdog_doprobe = jiffies + 10 * HZ; - strip_info->watchdog_doreset = jiffies + 1 * HZ; - - /* If the user has selected a baud rate above 38.4 see what magic we have to do */ - if (strip_info->user_baud > 38400) { - /* - * Subtle stuff: Pay attention :-) - * If the serial port is currently at the user's selected (>38.4) rate, - * then we temporarily switch to 19.2 and issue the ATS304 command - * to tell the radio to switch to the user's selected rate. - * If the serial port is not currently at that rate, that means we just - * issued the ATS304 command last time through, so this time we restore - * the user's selected rate and issue the normal starmode reset string. - */ - if (strip_info->user_baud == tty_get_baud_rate(tty)) { - static const char b0[] = "ate0q1s304=57600\r"; - static const char b1[] = "ate0q1s304=115200\r"; - static const StringDescriptor baudstring[2] = - { {b0, sizeof(b0) - 1} - , {b1, sizeof(b1) - 1} - }; - set_baud(tty, 19200); - if (strip_info->user_baud == 57600) - s = baudstring[0]; - else if (strip_info->user_baud == 115200) - s = baudstring[1]; - else - s = baudstring[1]; /* For now */ - } else - set_baud(tty, strip_info->user_baud); - } - - tty->ops->write(tty, s.string, s.length); -#ifdef EXT_COUNTERS - strip_info->tx_ebytes += s.length; -#endif -} - -/* - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - */ - -static void strip_write_some_more(struct tty_struct *tty) -{ - struct strip *strip_info = tty->disc_data; - - /* First make sure we're connected. */ - if (!strip_info || strip_info->magic != STRIP_MAGIC || - !netif_running(strip_info->dev)) - return; - - if (strip_info->tx_left > 0) { - int num_written = - tty->ops->write(tty, strip_info->tx_head, - strip_info->tx_left); - strip_info->tx_left -= num_written; - strip_info->tx_head += num_written; -#ifdef EXT_COUNTERS - strip_info->tx_sbytes += num_written; -#endif - } else { /* Else start transmission of another packet */ - - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - strip_unlock(strip_info); - } -} - -static __u8 *add_checksum(__u8 * buffer, __u8 * end) -{ - __u16 sum = 0; - __u8 *p = buffer; - while (p < end) - sum += *p++; - end[3] = hextable[sum & 0xF]; - sum >>= 4; - end[2] = hextable[sum & 0xF]; - sum >>= 4; - end[1] = hextable[sum & 0xF]; - sum >>= 4; - end[0] = hextable[sum & 0xF]; - return (end + 4); -} - -static unsigned char *strip_make_packet(unsigned char *buffer, - struct strip *strip_info, - struct sk_buff *skb) -{ - __u8 *ptr = buffer; - __u8 *stuffstate = NULL; - STRIP_Header *header = (STRIP_Header *) skb->data; - MetricomAddress haddr = header->dst_addr; - int len = skb->len - sizeof(STRIP_Header); - MetricomKey key; - - /*HexDump("strip_make_packet", strip_info, skb->data, skb->data + skb->len); */ - - if (header->protocol == htons(ETH_P_IP)) - key = SIP0Key; - else if (header->protocol == htons(ETH_P_ARP)) - key = ARP0Key; - else { - printk(KERN_ERR - "%s: strip_make_packet: Unknown packet type 0x%04X\n", - strip_info->dev->name, ntohs(header->protocol)); - return (NULL); - } - - if (len > strip_info->mtu) { - printk(KERN_ERR - "%s: Dropping oversized transmit packet: %d bytes\n", - strip_info->dev->name, len); - return (NULL); - } - - /* - * If we're sending to ourselves, discard the packet. - * (Metricom radios choke if they try to send a packet to their own address.) - */ - if (!memcmp(haddr.c, strip_info->true_dev_addr.c, sizeof(haddr))) { - printk(KERN_ERR "%s: Dropping packet addressed to self\n", - strip_info->dev->name); - return (NULL); - } - - /* - * If this is a broadcast packet, send it to our designated Metricom - * 'broadcast hub' radio (First byte of address being 0xFF means broadcast) - */ - if (haddr.c[0] == 0xFF) { - __be32 brd = 0; - struct in_device *in_dev; - - rcu_read_lock(); - in_dev = __in_dev_get_rcu(strip_info->dev); - if (in_dev == NULL) { - rcu_read_unlock(); - return NULL; - } - if (in_dev->ifa_list) - brd = in_dev->ifa_list->ifa_broadcast; - rcu_read_unlock(); - - /* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */ - if (!arp_query(haddr.c, brd, strip_info->dev)) { - printk(KERN_ERR - "%s: Unable to send packet (no broadcast hub configured)\n", - strip_info->dev->name); - return (NULL); - } - /* - * If we are the broadcast hub, don't bother sending to ourselves. - * (Metricom radios choke if they try to send a packet to their own address.) - */ - if (!memcmp - (haddr.c, strip_info->true_dev_addr.c, sizeof(haddr))) - return (NULL); - } - - *ptr++ = 0x0D; - *ptr++ = '*'; - *ptr++ = hextable[haddr.c[2] >> 4]; - *ptr++ = hextable[haddr.c[2] & 0xF]; - *ptr++ = hextable[haddr.c[3] >> 4]; - *ptr++ = hextable[haddr.c[3] & 0xF]; - *ptr++ = '-'; - *ptr++ = hextable[haddr.c[4] >> 4]; - *ptr++ = hextable[haddr.c[4] & 0xF]; - *ptr++ = hextable[haddr.c[5] >> 4]; - *ptr++ = hextable[haddr.c[5] & 0xF]; - *ptr++ = '*'; - *ptr++ = key.c[0]; - *ptr++ = key.c[1]; - *ptr++ = key.c[2]; - *ptr++ = key.c[3]; - - ptr = - StuffData(skb->data + sizeof(STRIP_Header), len, ptr, - &stuffstate); - - if (strip_info->firmware_level >= ChecksummedMessages) - ptr = add_checksum(buffer + 1, ptr); - - *ptr++ = 0x0D; - return (ptr); -} - -static void strip_send(struct strip *strip_info, struct sk_buff *skb) -{ - MetricomAddress haddr; - unsigned char *ptr = strip_info->tx_buff; - int doreset = (long) jiffies - strip_info->watchdog_doreset >= 0; - int doprobe = (long) jiffies - strip_info->watchdog_doprobe >= 0 - && !doreset; - __be32 addr, brd; - - /* - * 1. If we have a packet, encapsulate it and put it in the buffer - */ - if (skb) { - char *newptr = strip_make_packet(ptr, strip_info, skb); - strip_info->tx_pps_count++; - if (!newptr) - strip_info->tx_dropped++; - else { - ptr = newptr; - strip_info->sx_pps_count++; - strip_info->tx_packets++; /* Count another successful packet */ -#ifdef EXT_COUNTERS - strip_info->tx_bytes += skb->len; - strip_info->tx_rbytes += ptr - strip_info->tx_buff; -#endif - /*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr); */ - /*HexDump("Sending", strip_info, strip_info->tx_buff, ptr); */ - } - } - - /* - * 2. If it is time for another tickle, tack it on, after the packet - */ - if (doprobe) { - StringDescriptor ts = CommandString[strip_info->next_command]; -#if TICKLE_TIMERS - { - struct timeval tv; - do_gettimeofday(&tv); - printk(KERN_INFO "**** Sending tickle string %d at %02d.%06d\n", - strip_info->next_command, tv.tv_sec % 100, - tv.tv_usec); - } -#endif - if (ptr == strip_info->tx_buff) - *ptr++ = 0x0D; - - *ptr++ = '*'; /* First send "**" to provoke an error message */ - *ptr++ = '*'; - - /* Then add the command */ - memcpy(ptr, ts.string, ts.length); - - /* Add a checksum ? */ - if (strip_info->firmware_level < ChecksummedMessages) - ptr += ts.length; - else - ptr = add_checksum(ptr, ptr + ts.length); - - *ptr++ = 0x0D; /* Terminate the command with a */ - - /* Cycle to next periodic command? */ - if (strip_info->firmware_level >= StructuredMessages) - if (++strip_info->next_command >= - ARRAY_SIZE(CommandString)) - strip_info->next_command = 0; -#ifdef EXT_COUNTERS - strip_info->tx_ebytes += ts.length; -#endif - strip_info->watchdog_doprobe = jiffies + 10 * HZ; - strip_info->watchdog_doreset = jiffies + 1 * HZ; - /*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev->name); */ - } - - /* - * 3. Set up the strip_info ready to send the data (if any). - */ - strip_info->tx_head = strip_info->tx_buff; - strip_info->tx_left = ptr - strip_info->tx_buff; - set_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags); - /* - * 4. Debugging check to make sure we're not overflowing the buffer. - */ - if (strip_info->tx_size - strip_info->tx_left < 20) - printk(KERN_ERR "%s: Sending%5d bytes;%5d bytes free.\n", - strip_info->dev->name, strip_info->tx_left, - strip_info->tx_size - strip_info->tx_left); - - /* - * 5. If watchdog has expired, reset the radio. Note: if there's data waiting in - * the buffer, strip_write_some_more will send it after the reset has finished - */ - if (doreset) { - ResetRadio(strip_info); - return; - } - - if (1) { - struct in_device *in_dev; - - brd = addr = 0; - rcu_read_lock(); - in_dev = __in_dev_get_rcu(strip_info->dev); - if (in_dev) { - if (in_dev->ifa_list) { - brd = in_dev->ifa_list->ifa_broadcast; - addr = in_dev->ifa_list->ifa_local; - } - } - rcu_read_unlock(); - } - - - /* - * 6. If it is time for a periodic ARP, queue one up to be sent. - * We only do this if: - * 1. The radio is working - * 2. It's time to send another periodic ARP - * 3. We really know what our address is (and it is not manually set to zero) - * 4. We have a designated broadcast address configured - * If we queue up an ARP packet when we don't have a designated broadcast - * address configured, then the packet will just have to be discarded in - * strip_make_packet. This is not fatal, but it causes misleading information - * to be displayed in tcpdump. tcpdump will report that periodic APRs are - * being sent, when in fact they are not, because they are all being dropped - * in the strip_make_packet routine. - */ - if (strip_info->working - && (long) jiffies - strip_info->gratuitous_arp >= 0 - && memcmp(strip_info->dev->dev_addr, zero_address.c, - sizeof(zero_address)) - && arp_query(haddr.c, brd, strip_info->dev)) { - /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n", - strip_info->dev->name, strip_info->arp_interval / HZ); */ - strip_info->gratuitous_arp = - jiffies + strip_info->arp_interval; - strip_info->arp_interval *= 2; - if (strip_info->arp_interval > MaxARPInterval) - strip_info->arp_interval = MaxARPInterval; - if (addr) - arp_send(ARPOP_REPLY, ETH_P_ARP, addr, /* Target address of ARP packet is our address */ - strip_info->dev, /* Device to send packet on */ - addr, /* Source IP address this ARP packet comes from */ - NULL, /* Destination HW address is NULL (broadcast it) */ - strip_info->dev->dev_addr, /* Source HW address is our HW address */ - strip_info->dev->dev_addr); /* Target HW address is our HW address (redundant) */ - } - - /* - * 7. All ready. Start the transmission - */ - strip_write_some_more(strip_info->tty); -} - -/* Encapsulate a datagram and kick it into a TTY queue. */ -static netdev_tx_t strip_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct strip *strip_info = netdev_priv(dev); - - if (!netif_running(dev)) { - printk(KERN_ERR "%s: xmit call when iface is down\n", - dev->name); - return NETDEV_TX_BUSY; - } - - netif_stop_queue(dev); - - del_timer(&strip_info->idle_timer); - - - if (time_after(jiffies, strip_info->pps_timer + HZ)) { - unsigned long t = jiffies - strip_info->pps_timer; - unsigned long rx_pps_count = - DIV_ROUND_CLOSEST(strip_info->rx_pps_count*HZ*8, t); - unsigned long tx_pps_count = - DIV_ROUND_CLOSEST(strip_info->tx_pps_count*HZ*8, t); - unsigned long sx_pps_count = - DIV_ROUND_CLOSEST(strip_info->sx_pps_count*HZ*8, t); - - strip_info->pps_timer = jiffies; - strip_info->rx_pps_count = 0; - strip_info->tx_pps_count = 0; - strip_info->sx_pps_count = 0; - - strip_info->rx_average_pps = (strip_info->rx_average_pps + rx_pps_count + 1) / 2; - strip_info->tx_average_pps = (strip_info->tx_average_pps + tx_pps_count + 1) / 2; - strip_info->sx_average_pps = (strip_info->sx_average_pps + sx_pps_count + 1) / 2; - - if (rx_pps_count / 8 >= 10) - printk(KERN_INFO "%s: WARNING: Receiving %ld packets per second.\n", - strip_info->dev->name, rx_pps_count / 8); - if (tx_pps_count / 8 >= 10) - printk(KERN_INFO "%s: WARNING: Tx %ld packets per second.\n", - strip_info->dev->name, tx_pps_count / 8); - if (sx_pps_count / 8 >= 10) - printk(KERN_INFO "%s: WARNING: Sending %ld packets per second.\n", - strip_info->dev->name, sx_pps_count / 8); - } - - spin_lock_bh(&strip_lock); - - strip_send(strip_info, skb); - - spin_unlock_bh(&strip_lock); - - if (skb) - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -/* - * IdleTask periodically calls strip_xmit, so even when we have no IP packets - * to send for an extended period of time, the watchdog processing still gets - * done to ensure that the radio stays in Starmode - */ - -static void strip_IdleTask(unsigned long parameter) -{ - strip_xmit(NULL, (struct net_device *) parameter); -} - -/* - * Create the MAC header for an arbitrary protocol layer - * - * saddr!=NULL means use this specific address (n/a for Metricom) - * saddr==NULL means use default device source address - * daddr!=NULL means use this destination address - * daddr==NULL means leave destination address alone - * (e.g. unresolved arp -- kernel will call - * rebuild_header later to fill in the address) - */ - -static int strip_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *daddr, - const void *saddr, unsigned len) -{ - struct strip *strip_info = netdev_priv(dev); - STRIP_Header *header = (STRIP_Header *) skb_push(skb, sizeof(STRIP_Header)); - - /*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type, - type == ETH_P_IP ? "IP" : type == ETH_P_ARP ? "ARP" : ""); */ - - header->src_addr = strip_info->true_dev_addr; - header->protocol = htons(type); - - /*HexDump("strip_header", netdev_priv(dev), skb->data, skb->data + skb->len); */ - - if (!daddr) - return (-dev->hard_header_len); - - header->dst_addr = *(MetricomAddress *) daddr; - return (dev->hard_header_len); -} - -/* - * Rebuild the MAC header. This is called after an ARP - * (or in future other address resolution) has completed on this - * sk_buff. We now let ARP fill in the other fields. - * I think this should return zero if packet is ready to send, - * or non-zero if it needs more time to do an address lookup - */ - -static int strip_rebuild_header(struct sk_buff *skb) -{ -#ifdef CONFIG_INET - STRIP_Header *header = (STRIP_Header *) skb->data; - - /* Arp find returns zero if if knows the address, */ - /* or if it doesn't know the address it sends an ARP packet and returns non-zero */ - return arp_find(header->dst_addr.c, skb) ? 1 : 0; -#else - return 0; -#endif -} - - -/************************************************************************/ -/* Receiving routines */ - -/* - * This function parses the response to the ATS300? command, - * extracting the radio version and serial number. - */ -static void get_radio_version(struct strip *strip_info, __u8 * ptr, __u8 * end) -{ - __u8 *p, *value_begin, *value_end; - int len; - - /* Determine the beginning of the second line of the payload */ - p = ptr; - while (p < end && *p != 10) - p++; - if (p >= end) - return; - p++; - value_begin = p; - - /* Determine the end of line */ - while (p < end && *p != 10) - p++; - if (p >= end) - return; - value_end = p; - p++; - - len = value_end - value_begin; - len = min_t(int, len, sizeof(FirmwareVersion) - 1); - if (strip_info->firmware_version.c[0] == 0) - printk(KERN_INFO "%s: Radio Firmware: %.*s\n", - strip_info->dev->name, len, value_begin); - sprintf(strip_info->firmware_version.c, "%.*s", len, value_begin); - - /* Look for the first colon */ - while (p < end && *p != ':') - p++; - if (p >= end) - return; - /* Skip over the space */ - p += 2; - len = sizeof(SerialNumber) - 1; - if (p + len <= end) { - sprintf(strip_info->serial_number.c, "%.*s", len, p); - } else { - printk(KERN_DEBUG - "STRIP: radio serial number shorter (%zd) than expected (%d)\n", - end - p, len); - } -} - -/* - * This function parses the response to the ATS325? command, - * extracting the radio battery voltage. - */ -static void get_radio_voltage(struct strip *strip_info, __u8 * ptr, __u8 * end) -{ - int len; - - len = sizeof(BatteryVoltage) - 1; - if (ptr + len <= end) { - sprintf(strip_info->battery_voltage.c, "%.*s", len, ptr); - } else { - printk(KERN_DEBUG - "STRIP: radio voltage string shorter (%zd) than expected (%d)\n", - end - ptr, len); - } -} - -/* - * This function parses the responses to the AT~LA and ATS311 commands, - * which list the radio's neighbours. - */ -static void get_radio_neighbours(MetricomNodeTable * table, __u8 * ptr, __u8 * end) -{ - table->num_nodes = 0; - while (ptr < end && table->num_nodes < NODE_TABLE_SIZE) { - MetricomNode *node = &table->node[table->num_nodes++]; - char *dst = node->c, *limit = dst + sizeof(*node) - 1; - while (ptr < end && *ptr <= 32) - ptr++; - while (ptr < end && dst < limit && *ptr != 10) - *dst++ = *ptr++; - *dst++ = 0; - while (ptr < end && ptr[-1] != 10) - ptr++; - } - do_gettimeofday(&table->timestamp); -} - -static int get_radio_address(struct strip *strip_info, __u8 * p) -{ - MetricomAddress addr; - - if (string_to_radio_address(&addr, p)) - return (1); - - /* See if our radio address has changed */ - if (memcmp(strip_info->true_dev_addr.c, addr.c, sizeof(addr))) { - MetricomAddressString addr_string; - radio_address_to_string(&addr, &addr_string); - printk(KERN_INFO "%s: Radio address = %s\n", - strip_info->dev->name, addr_string.c); - strip_info->true_dev_addr = addr; - if (!strip_info->manual_dev_addr) - *(MetricomAddress *) strip_info->dev->dev_addr = - addr; - /* Give the radio a few seconds to get its head straight, then send an arp */ - strip_info->gratuitous_arp = jiffies + 15 * HZ; - strip_info->arp_interval = 1 * HZ; - } - return (0); -} - -static int verify_checksum(struct strip *strip_info) -{ - __u8 *p = strip_info->sx_buff; - __u8 *end = strip_info->sx_buff + strip_info->sx_count - 4; - u_short sum = - (READHEX16(end[0]) << 12) | (READHEX16(end[1]) << 8) | - (READHEX16(end[2]) << 4) | (READHEX16(end[3])); - while (p < end) - sum -= *p++; - if (sum == 0 && strip_info->firmware_level == StructuredMessages) { - strip_info->firmware_level = ChecksummedMessages; - printk(KERN_INFO "%s: Radio provides message checksums\n", - strip_info->dev->name); - } - return (sum == 0); -} - -static void RecvErr(char *msg, struct strip *strip_info) -{ - __u8 *ptr = strip_info->sx_buff; - __u8 *end = strip_info->sx_buff + strip_info->sx_count; - DumpData(msg, strip_info, ptr, end); - strip_info->rx_errors++; -} - -static void RecvErr_Message(struct strip *strip_info, __u8 * sendername, - const __u8 * msg, u_long len) -{ - if (has_prefix(msg, len, "001")) { /* Not in StarMode! */ - RecvErr("Error Msg:", strip_info); - printk(KERN_INFO "%s: Radio %s is not in StarMode\n", - strip_info->dev->name, sendername); - } - - else if (has_prefix(msg, len, "002")) { /* Remap handle */ - /* We ignore "Remap handle" messages for now */ - } - - else if (has_prefix(msg, len, "003")) { /* Can't resolve name */ - RecvErr("Error Msg:", strip_info); - printk(KERN_INFO "%s: Destination radio name is unknown\n", - strip_info->dev->name); - } - - else if (has_prefix(msg, len, "004")) { /* Name too small or missing */ - strip_info->watchdog_doreset = jiffies + LongTime; -#if TICKLE_TIMERS - { - struct timeval tv; - do_gettimeofday(&tv); - printk(KERN_INFO - "**** Got ERR_004 response at %02d.%06d\n", - tv.tv_sec % 100, tv.tv_usec); - } -#endif - if (!strip_info->working) { - strip_info->working = TRUE; - printk(KERN_INFO "%s: Radio now in starmode\n", - strip_info->dev->name); - /* - * If the radio has just entered a working state, we should do our first - * probe ASAP, so that we find out our radio address etc. without delay. - */ - strip_info->watchdog_doprobe = jiffies; - } - if (strip_info->firmware_level == NoStructure && sendername) { - strip_info->firmware_level = StructuredMessages; - strip_info->next_command = 0; /* Try to enable checksums ASAP */ - printk(KERN_INFO - "%s: Radio provides structured messages\n", - strip_info->dev->name); - } - if (strip_info->firmware_level >= StructuredMessages) { - /* - * If this message has a valid checksum on the end, then the call to verify_checksum - * will elevate the firmware_level to ChecksummedMessages for us. (The actual return - * code from verify_checksum is ignored here.) - */ - verify_checksum(strip_info); - /* - * If the radio has structured messages but we don't yet have all our information about it, - * we should do probes without delay, until we have gathered all the information - */ - if (!GOT_ALL_RADIO_INFO(strip_info)) - strip_info->watchdog_doprobe = jiffies; - } - } - - else if (has_prefix(msg, len, "005")) /* Bad count specification */ - RecvErr("Error Msg:", strip_info); - - else if (has_prefix(msg, len, "006")) /* Header too big */ - RecvErr("Error Msg:", strip_info); - - else if (has_prefix(msg, len, "007")) { /* Body too big */ - RecvErr("Error Msg:", strip_info); - printk(KERN_ERR - "%s: Error! Packet size too big for radio.\n", - strip_info->dev->name); - } - - else if (has_prefix(msg, len, "008")) { /* Bad character in name */ - RecvErr("Error Msg:", strip_info); - printk(KERN_ERR - "%s: Radio name contains illegal character\n", - strip_info->dev->name); - } - - else if (has_prefix(msg, len, "009")) /* No count or line terminator */ - RecvErr("Error Msg:", strip_info); - - else if (has_prefix(msg, len, "010")) /* Invalid checksum */ - RecvErr("Error Msg:", strip_info); - - else if (has_prefix(msg, len, "011")) /* Checksum didn't match */ - RecvErr("Error Msg:", strip_info); - - else if (has_prefix(msg, len, "012")) /* Failed to transmit packet */ - RecvErr("Error Msg:", strip_info); - - else - RecvErr("Error Msg:", strip_info); -} - -static void process_AT_response(struct strip *strip_info, __u8 * ptr, - __u8 * end) -{ - u_long len; - __u8 *p = ptr; - while (p < end && p[-1] != 10) - p++; /* Skip past first newline character */ - /* Now ptr points to the AT command, and p points to the text of the response. */ - len = p - ptr; - -#if TICKLE_TIMERS - { - struct timeval tv; - do_gettimeofday(&tv); - printk(KERN_INFO "**** Got AT response %.7s at %02d.%06d\n", - ptr, tv.tv_sec % 100, tv.tv_usec); - } -#endif - - if (has_prefix(ptr, len, "ATS300?")) - get_radio_version(strip_info, p, end); - else if (has_prefix(ptr, len, "ATS305?")) - get_radio_address(strip_info, p); - else if (has_prefix(ptr, len, "ATS311?")) - get_radio_neighbours(&strip_info->poletops, p, end); - else if (has_prefix(ptr, len, "ATS319=7")) - verify_checksum(strip_info); - else if (has_prefix(ptr, len, "ATS325?")) - get_radio_voltage(strip_info, p, end); - else if (has_prefix(ptr, len, "AT~LA")) - get_radio_neighbours(&strip_info->portables, p, end); - else - RecvErr("Unknown AT Response:", strip_info); -} - -static void process_ACK(struct strip *strip_info, __u8 * ptr, __u8 * end) -{ - /* Currently we don't do anything with ACKs from the radio */ -} - -static void process_Info(struct strip *strip_info, __u8 * ptr, __u8 * end) -{ - if (ptr + 16 > end) - RecvErr("Bad Info Msg:", strip_info); -} - -static struct net_device *get_strip_dev(struct strip *strip_info) -{ - /* If our hardware address is *manually set* to zero, and we know our */ - /* real radio hardware address, try to find another strip device that has been */ - /* manually set to that address that we can 'transfer ownership' of this packet to */ - if (strip_info->manual_dev_addr && - !memcmp(strip_info->dev->dev_addr, zero_address.c, - sizeof(zero_address)) - && memcmp(&strip_info->true_dev_addr, zero_address.c, - sizeof(zero_address))) { - struct net_device *dev; - read_lock_bh(&dev_base_lock); - for_each_netdev(&init_net, dev) { - if (dev->type == strip_info->dev->type && - !memcmp(dev->dev_addr, - &strip_info->true_dev_addr, - sizeof(MetricomAddress))) { - printk(KERN_INFO - "%s: Transferred packet ownership to %s.\n", - strip_info->dev->name, dev->name); - read_unlock_bh(&dev_base_lock); - return (dev); - } - } - read_unlock_bh(&dev_base_lock); - } - return (strip_info->dev); -} - -/* - * Send one completely decapsulated datagram to the next layer. - */ - -static void deliver_packet(struct strip *strip_info, STRIP_Header * header, - __u16 packetlen) -{ - struct sk_buff *skb = dev_alloc_skb(sizeof(STRIP_Header) + packetlen); - if (!skb) { - printk(KERN_ERR "%s: memory squeeze, dropping packet.\n", - strip_info->dev->name); - strip_info->rx_dropped++; - } else { - memcpy(skb_put(skb, sizeof(STRIP_Header)), header, - sizeof(STRIP_Header)); - memcpy(skb_put(skb, packetlen), strip_info->rx_buff, - packetlen); - skb->dev = get_strip_dev(strip_info); - skb->protocol = header->protocol; - skb_reset_mac_header(skb); - - /* Having put a fake header on the front of the sk_buff for the */ - /* benefit of tools like tcpdump, skb_pull now 'consumes' that */ - /* fake header before we hand the packet up to the next layer. */ - skb_pull(skb, sizeof(STRIP_Header)); - - /* Finally, hand the packet up to the next layer (e.g. IP or ARP, etc.) */ - strip_info->rx_packets++; - strip_info->rx_pps_count++; -#ifdef EXT_COUNTERS - strip_info->rx_bytes += packetlen; -#endif - netif_rx(skb); - } -} - -static void process_IP_packet(struct strip *strip_info, - STRIP_Header * header, __u8 * ptr, - __u8 * end) -{ - __u16 packetlen; - - /* Decode start of the IP packet header */ - ptr = UnStuffData(ptr, end, strip_info->rx_buff, 4); - if (!ptr) { - RecvErr("IP Packet too short", strip_info); - return; - } - - packetlen = ((__u16) strip_info->rx_buff[2] << 8) | strip_info->rx_buff[3]; - - if (packetlen > MAX_RECV_MTU) { - printk(KERN_INFO "%s: Dropping oversized received IP packet: %d bytes\n", - strip_info->dev->name, packetlen); - strip_info->rx_dropped++; - return; - } - - /*printk(KERN_INFO "%s: Got %d byte IP packet\n", strip_info->dev->name, packetlen); */ - - /* Decode remainder of the IP packet */ - ptr = - UnStuffData(ptr, end, strip_info->rx_buff + 4, packetlen - 4); - if (!ptr) { - RecvErr("IP Packet too short", strip_info); - return; - } - - if (ptr < end) { - RecvErr("IP Packet too long", strip_info); - return; - } - - header->protocol = htons(ETH_P_IP); - - deliver_packet(strip_info, header, packetlen); -} - -static void process_ARP_packet(struct strip *strip_info, - STRIP_Header * header, __u8 * ptr, - __u8 * end) -{ - __u16 packetlen; - struct arphdr *arphdr = (struct arphdr *) strip_info->rx_buff; - - /* Decode start of the ARP packet */ - ptr = UnStuffData(ptr, end, strip_info->rx_buff, 8); - if (!ptr) { - RecvErr("ARP Packet too short", strip_info); - return; - } - - packetlen = 8 + (arphdr->ar_hln + arphdr->ar_pln) * 2; - - if (packetlen > MAX_RECV_MTU) { - printk(KERN_INFO - "%s: Dropping oversized received ARP packet: %d bytes\n", - strip_info->dev->name, packetlen); - strip_info->rx_dropped++; - return; - } - - /*printk(KERN_INFO "%s: Got %d byte ARP %s\n", - strip_info->dev->name, packetlen, - ntohs(arphdr->ar_op) == ARPOP_REQUEST ? "request" : "reply"); */ - - /* Decode remainder of the ARP packet */ - ptr = - UnStuffData(ptr, end, strip_info->rx_buff + 8, packetlen - 8); - if (!ptr) { - RecvErr("ARP Packet too short", strip_info); - return; - } - - if (ptr < end) { - RecvErr("ARP Packet too long", strip_info); - return; - } - - header->protocol = htons(ETH_P_ARP); - - deliver_packet(strip_info, header, packetlen); -} - -/* - * process_text_message processes a -terminated block of data received - * from the radio that doesn't begin with a '*' character. All normal - * Starmode communication messages with the radio begin with a '*', - * so any text that does not indicates a serial port error, a radio that - * is in Hayes command mode instead of Starmode, or a radio with really - * old firmware that doesn't frame its Starmode responses properly. - */ -static void process_text_message(struct strip *strip_info) -{ - __u8 *msg = strip_info->sx_buff; - int len = strip_info->sx_count; - - /* Check for anything that looks like it might be our radio name */ - /* (This is here for backwards compatibility with old firmware) */ - if (len == 9 && get_radio_address(strip_info, msg) == 0) - return; - - if (text_equal(msg, len, "OK")) - return; /* Ignore 'OK' responses from prior commands */ - if (text_equal(msg, len, "ERROR")) - return; /* Ignore 'ERROR' messages */ - if (has_prefix(msg, len, "ate0q1")) - return; /* Ignore character echo back from the radio */ - - /* Catch other error messages */ - /* (This is here for backwards compatibility with old firmware) */ - if (has_prefix(msg, len, "ERR_")) { - RecvErr_Message(strip_info, NULL, &msg[4], len - 4); - return; - } - - RecvErr("No initial *", strip_info); -} - -/* - * process_message processes a -terminated block of data received - * from the radio. If the radio is not in Starmode or has old firmware, - * it may be a line of text in response to an AT command. Ideally, with - * a current radio that's properly in Starmode, all data received should - * be properly framed and checksummed radio message blocks, containing - * either a starmode packet, or a other communication from the radio - * firmware, like "INF_" Info messages and &COMMAND responses. - */ -static void process_message(struct strip *strip_info) -{ - STRIP_Header header = { zero_address, zero_address, 0 }; - __u8 *ptr = strip_info->sx_buff; - __u8 *end = strip_info->sx_buff + strip_info->sx_count; - __u8 sendername[32], *sptr = sendername; - MetricomKey key; - - /*HexDump("Receiving", strip_info, ptr, end); */ - - /* Check for start of address marker, and then skip over it */ - if (*ptr == '*') - ptr++; - else { - process_text_message(strip_info); - return; - } - - /* Copy out the return address */ - while (ptr < end && *ptr != '*' - && sptr < ARRAY_END(sendername) - 1) - *sptr++ = *ptr++; - *sptr = 0; /* Null terminate the sender name */ - - /* Check for end of address marker, and skip over it */ - if (ptr >= end || *ptr != '*') { - RecvErr("No second *", strip_info); - return; - } - ptr++; /* Skip the second '*' */ - - /* If the sender name is "&COMMAND", ignore this 'packet' */ - /* (This is here for backwards compatibility with old firmware) */ - if (!strcmp(sendername, "&COMMAND")) { - strip_info->firmware_level = NoStructure; - strip_info->next_command = CompatibilityCommand; - return; - } - - if (ptr + 4 > end) { - RecvErr("No proto key", strip_info); - return; - } - - /* Get the protocol key out of the buffer */ - key.c[0] = *ptr++; - key.c[1] = *ptr++; - key.c[2] = *ptr++; - key.c[3] = *ptr++; - - /* If we're using checksums, verify the checksum at the end of the packet */ - if (strip_info->firmware_level >= ChecksummedMessages) { - end -= 4; /* Chop the last four bytes off the packet (they're the checksum) */ - if (ptr > end) { - RecvErr("Missing Checksum", strip_info); - return; - } - if (!verify_checksum(strip_info)) { - RecvErr("Bad Checksum", strip_info); - return; - } - } - - /*printk(KERN_INFO "%s: Got packet from \"%s\".\n", strip_info->dev->name, sendername); */ - - /* - * Fill in (pseudo) source and destination addresses in the packet. - * We assume that the destination address was our address (the radio does not - * tell us this). If the radio supplies a source address, then we use it. - */ - header.dst_addr = strip_info->true_dev_addr; - string_to_radio_address(&header.src_addr, sendername); - -#ifdef EXT_COUNTERS - if (key.l == SIP0Key.l) { - strip_info->rx_rbytes += (end - ptr); - process_IP_packet(strip_info, &header, ptr, end); - } else if (key.l == ARP0Key.l) { - strip_info->rx_rbytes += (end - ptr); - process_ARP_packet(strip_info, &header, ptr, end); - } else if (key.l == ATR_Key.l) { - strip_info->rx_ebytes += (end - ptr); - process_AT_response(strip_info, ptr, end); - } else if (key.l == ACK_Key.l) { - strip_info->rx_ebytes += (end - ptr); - process_ACK(strip_info, ptr, end); - } else if (key.l == INF_Key.l) { - strip_info->rx_ebytes += (end - ptr); - process_Info(strip_info, ptr, end); - } else if (key.l == ERR_Key.l) { - strip_info->rx_ebytes += (end - ptr); - RecvErr_Message(strip_info, sendername, ptr, end - ptr); - } else - RecvErr("Unrecognized protocol key", strip_info); -#else - if (key.l == SIP0Key.l) - process_IP_packet(strip_info, &header, ptr, end); - else if (key.l == ARP0Key.l) - process_ARP_packet(strip_info, &header, ptr, end); - else if (key.l == ATR_Key.l) - process_AT_response(strip_info, ptr, end); - else if (key.l == ACK_Key.l) - process_ACK(strip_info, ptr, end); - else if (key.l == INF_Key.l) - process_Info(strip_info, ptr, end); - else if (key.l == ERR_Key.l) - RecvErr_Message(strip_info, sendername, ptr, end - ptr); - else - RecvErr("Unrecognized protocol key", strip_info); -#endif -} - -#define TTYERROR(X) ((X) == TTY_BREAK ? "Break" : \ - (X) == TTY_FRAME ? "Framing Error" : \ - (X) == TTY_PARITY ? "Parity Error" : \ - (X) == TTY_OVERRUN ? "Hardware Overrun" : "Unknown Error") - -/* - * Handle the 'receiver data ready' interrupt. - * This function is called by the 'tty_io' module in the kernel when - * a block of STRIP data has been received, which can now be decapsulated - * and sent on to some IP layer for further processing. - */ - -static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - struct strip *strip_info = tty->disc_data; - const unsigned char *end = cp + count; - - if (!strip_info || strip_info->magic != STRIP_MAGIC - || !netif_running(strip_info->dev)) - return; - - spin_lock_bh(&strip_lock); -#if 0 - { - struct timeval tv; - do_gettimeofday(&tv); - printk(KERN_INFO - "**** strip_receive_buf: %3d bytes at %02d.%06d\n", - count, tv.tv_sec % 100, tv.tv_usec); - } -#endif - -#ifdef EXT_COUNTERS - strip_info->rx_sbytes += count; -#endif - - /* Read the characters out of the buffer */ - while (cp < end) { - if (fp && *fp) - printk(KERN_INFO "%s: %s on serial port\n", - strip_info->dev->name, TTYERROR(*fp)); - if (fp && *fp++ && !strip_info->discard) { /* If there's a serial error, record it */ - /* If we have some characters in the buffer, discard them */ - strip_info->discard = strip_info->sx_count; - strip_info->rx_errors++; - } - - /* Leading control characters (CR, NL, Tab, etc.) are ignored */ - if (strip_info->sx_count > 0 || *cp >= ' ') { - if (*cp == 0x0D) { /* If end of packet, decide what to do with it */ - if (strip_info->sx_count > 3000) - printk(KERN_INFO - "%s: Cut a %d byte packet (%zd bytes remaining)%s\n", - strip_info->dev->name, - strip_info->sx_count, - end - cp - 1, - strip_info-> - discard ? " (discarded)" : - ""); - if (strip_info->sx_count > - strip_info->sx_size) { - strip_info->rx_over_errors++; - printk(KERN_INFO - "%s: sx_buff overflow (%d bytes total)\n", - strip_info->dev->name, - strip_info->sx_count); - } else if (strip_info->discard) - printk(KERN_INFO - "%s: Discarding bad packet (%d/%d)\n", - strip_info->dev->name, - strip_info->discard, - strip_info->sx_count); - else - process_message(strip_info); - strip_info->discard = 0; - strip_info->sx_count = 0; - } else { - /* Make sure we have space in the buffer */ - if (strip_info->sx_count < - strip_info->sx_size) - strip_info->sx_buff[strip_info-> - sx_count] = - *cp; - strip_info->sx_count++; - } - } - cp++; - } - spin_unlock_bh(&strip_lock); -} - - -/************************************************************************/ -/* General control routines */ - -static int set_mac_address(struct strip *strip_info, - MetricomAddress * addr) -{ - /* - * We're using a manually specified address if the address is set - * to anything other than all ones. Setting the address to all ones - * disables manual mode and goes back to automatic address determination - * (tracking the true address that the radio has). - */ - strip_info->manual_dev_addr = - memcmp(addr->c, broadcast_address.c, - sizeof(broadcast_address)); - if (strip_info->manual_dev_addr) - *(MetricomAddress *) strip_info->dev->dev_addr = *addr; - else - *(MetricomAddress *) strip_info->dev->dev_addr = - strip_info->true_dev_addr; - return 0; -} - -static int strip_set_mac_address(struct net_device *dev, void *addr) -{ - struct strip *strip_info = netdev_priv(dev); - struct sockaddr *sa = addr; - printk(KERN_INFO "%s: strip_set_dev_mac_address called\n", dev->name); - set_mac_address(strip_info, (MetricomAddress *) sa->sa_data); - return 0; -} - -static struct net_device_stats *strip_get_stats(struct net_device *dev) -{ - struct strip *strip_info = netdev_priv(dev); - static struct net_device_stats stats; - - memset(&stats, 0, sizeof(struct net_device_stats)); - - stats.rx_packets = strip_info->rx_packets; - stats.tx_packets = strip_info->tx_packets; - stats.rx_dropped = strip_info->rx_dropped; - stats.tx_dropped = strip_info->tx_dropped; - stats.tx_errors = strip_info->tx_errors; - stats.rx_errors = strip_info->rx_errors; - stats.rx_over_errors = strip_info->rx_over_errors; - return (&stats); -} - - -/************************************************************************/ -/* Opening and closing */ - -/* - * Here's the order things happen: - * When the user runs "slattach -p strip ..." - * 1. The TTY module calls strip_open;; - * 2. strip_open calls strip_alloc - * 3. strip_alloc calls register_netdev - * 4. register_netdev calls strip_dev_init - * 5. then strip_open finishes setting up the strip_info - * - * When the user runs "ifconfig st up address netmask ..." - * 6. strip_open_low gets called - * - * When the user runs "ifconfig st down" - * 7. strip_close_low gets called - * - * When the user kills the slattach process - * 8. strip_close gets called - * 9. strip_close calls dev_close - * 10. if the device is still up, then dev_close calls strip_close_low - * 11. strip_close calls strip_free - */ - -/* Open the low-level part of the STRIP channel. Easy! */ - -static int strip_open_low(struct net_device *dev) -{ - struct strip *strip_info = netdev_priv(dev); - - if (strip_info->tty == NULL) - return (-ENODEV); - - if (!allocate_buffers(strip_info, dev->mtu)) - return (-ENOMEM); - - strip_info->sx_count = 0; - strip_info->tx_left = 0; - - strip_info->discard = 0; - strip_info->working = FALSE; - strip_info->firmware_level = NoStructure; - strip_info->next_command = CompatibilityCommand; - strip_info->user_baud = tty_get_baud_rate(strip_info->tty); - - printk(KERN_INFO "%s: Initializing Radio.\n", - strip_info->dev->name); - ResetRadio(strip_info); - strip_info->idle_timer.expires = jiffies + 1 * HZ; - add_timer(&strip_info->idle_timer); - netif_wake_queue(dev); - return (0); -} - - -/* - * Close the low-level part of the STRIP channel. Easy! - */ - -static int strip_close_low(struct net_device *dev) -{ - struct strip *strip_info = netdev_priv(dev); - - if (strip_info->tty == NULL) - return -EBUSY; - clear_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags); - netif_stop_queue(dev); - - /* - * Free all STRIP frame buffers. - */ - kfree(strip_info->rx_buff); - strip_info->rx_buff = NULL; - kfree(strip_info->sx_buff); - strip_info->sx_buff = NULL; - kfree(strip_info->tx_buff); - strip_info->tx_buff = NULL; - - del_timer(&strip_info->idle_timer); - return 0; -} - -static const struct header_ops strip_header_ops = { - .create = strip_header, - .rebuild = strip_rebuild_header, -}; - - -static const struct net_device_ops strip_netdev_ops = { - .ndo_open = strip_open_low, - .ndo_stop = strip_close_low, - .ndo_start_xmit = strip_xmit, - .ndo_set_mac_address = strip_set_mac_address, - .ndo_get_stats = strip_get_stats, - .ndo_change_mtu = strip_change_mtu, -}; - -/* - * This routine is called by DDI when the - * (dynamically assigned) device is registered - */ - -static void strip_dev_setup(struct net_device *dev) -{ - /* - * Finish setting up the DEVICE info. - */ - - dev->trans_start = 0; - dev->tx_queue_len = 30; /* Drop after 30 frames queued */ - - dev->flags = 0; - dev->mtu = DEFAULT_STRIP_MTU; - dev->type = ARPHRD_METRICOM; /* dtang */ - dev->hard_header_len = sizeof(STRIP_Header); - /* - * netdev_priv(dev) Already holds a pointer to our struct strip - */ - - *(MetricomAddress *)dev->broadcast = broadcast_address; - dev->dev_addr[0] = 0; - dev->addr_len = sizeof(MetricomAddress); - - dev->header_ops = &strip_header_ops, - dev->netdev_ops = &strip_netdev_ops; -} - -/* - * Free a STRIP channel. - */ - -static void strip_free(struct strip *strip_info) -{ - spin_lock_bh(&strip_lock); - list_del_rcu(&strip_info->list); - spin_unlock_bh(&strip_lock); - - strip_info->magic = 0; - - free_netdev(strip_info->dev); -} - - -/* - * Allocate a new free STRIP channel - */ -static struct strip *strip_alloc(void) -{ - struct list_head *n; - struct net_device *dev; - struct strip *strip_info; - - dev = alloc_netdev(sizeof(struct strip), "st%d", - strip_dev_setup); - - if (!dev) - return NULL; /* If no more memory, return */ - - - strip_info = netdev_priv(dev); - strip_info->dev = dev; - - strip_info->magic = STRIP_MAGIC; - strip_info->tty = NULL; - - strip_info->gratuitous_arp = jiffies + LongTime; - strip_info->arp_interval = 0; - init_timer(&strip_info->idle_timer); - strip_info->idle_timer.data = (long) dev; - strip_info->idle_timer.function = strip_IdleTask; - - - spin_lock_bh(&strip_lock); - rescan: - /* - * Search the list to find where to put our new entry - * (and in the process decide what channel number it is - * going to be) - */ - list_for_each(n, &strip_list) { - struct strip *s = hlist_entry(n, struct strip, list); - - if (s->dev->base_addr == dev->base_addr) { - ++dev->base_addr; - goto rescan; - } - } - - sprintf(dev->name, "st%ld", dev->base_addr); - - list_add_tail_rcu(&strip_info->list, &strip_list); - spin_unlock_bh(&strip_lock); - - return strip_info; -} - -/* - * Open the high-level part of the STRIP channel. - * This function is called by the TTY module when the - * STRIP line discipline is called for. Because we are - * sure the tty line exists, we only have to link it to - * a free STRIP channel... - */ - -static int strip_open(struct tty_struct *tty) -{ - struct strip *strip_info = tty->disc_data; - - /* - * First make sure we're not already connected. - */ - - if (strip_info && strip_info->magic == STRIP_MAGIC) - return -EEXIST; - - /* - * We need a write method. - */ - - if (tty->ops->write == NULL || tty->ops->set_termios == NULL) - return -EOPNOTSUPP; - - /* - * OK. Find a free STRIP channel to use. - */ - if ((strip_info = strip_alloc()) == NULL) - return -ENFILE; - - /* - * Register our newly created device so it can be ifconfig'd - * strip_dev_init() will be called as a side-effect - */ - - if (register_netdev(strip_info->dev) != 0) { - printk(KERN_ERR "strip: register_netdev() failed.\n"); - strip_free(strip_info); - return -ENFILE; - } - - strip_info->tty = tty; - tty->disc_data = strip_info; - tty->receive_room = 65536; - - tty_driver_flush_buffer(tty); - - /* - * Restore default settings - */ - - strip_info->dev->type = ARPHRD_METRICOM; /* dtang */ - - /* - * Set tty options - */ - - tty->termios->c_iflag |= IGNBRK | IGNPAR; /* Ignore breaks and parity errors. */ - tty->termios->c_cflag |= CLOCAL; /* Ignore modem control signals. */ - tty->termios->c_cflag &= ~HUPCL; /* Don't close on hup */ - - printk(KERN_INFO "STRIP: device \"%s\" activated\n", - strip_info->dev->name); - - /* - * Done. We have linked the TTY line to a channel. - */ - return (strip_info->dev->base_addr); -} - -/* - * Close down a STRIP channel. - * This means flushing out any pending queues, and then restoring the - * TTY line discipline to what it was before it got hooked to STRIP - * (which usually is TTY again). - */ - -static void strip_close(struct tty_struct *tty) -{ - struct strip *strip_info = tty->disc_data; - - /* - * First make sure we're connected. - */ - - if (!strip_info || strip_info->magic != STRIP_MAGIC) - return; - - unregister_netdev(strip_info->dev); - - tty->disc_data = NULL; - strip_info->tty = NULL; - printk(KERN_INFO "STRIP: device \"%s\" closed down\n", - strip_info->dev->name); - strip_free(strip_info); - tty->disc_data = NULL; -} - - -/************************************************************************/ -/* Perform I/O control calls on an active STRIP channel. */ - -static int strip_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct strip *strip_info = tty->disc_data; - - /* - * First make sure we're connected. - */ - - if (!strip_info || strip_info->magic != STRIP_MAGIC) - return -EINVAL; - - switch (cmd) { - case SIOCGIFNAME: - if(copy_to_user((void __user *) arg, strip_info->dev->name, strlen(strip_info->dev->name) + 1)) - return -EFAULT; - break; - case SIOCSIFHWADDR: - { - MetricomAddress addr; - //printk(KERN_INFO "%s: SIOCSIFHWADDR\n", strip_info->dev->name); - if(copy_from_user(&addr, (void __user *) arg, sizeof(MetricomAddress))) - return -EFAULT; - return set_mac_address(strip_info, &addr); - } - default: - return tty_mode_ioctl(tty, file, cmd, arg); - break; - } - return 0; -} - - -/************************************************************************/ -/* Initialization */ - -static struct tty_ldisc_ops strip_ldisc = { - .magic = TTY_LDISC_MAGIC, - .name = "strip", - .owner = THIS_MODULE, - .open = strip_open, - .close = strip_close, - .ioctl = strip_ioctl, - .receive_buf = strip_receive_buf, - .write_wakeup = strip_write_some_more, -}; - -/* - * Initialize the STRIP driver. - * This routine is called at boot time, to bootstrap the multi-channel - * STRIP driver - */ - -static char signon[] __initdata = - KERN_INFO "STRIP: Version %s (unlimited channels)\n"; - -static int __init strip_init_driver(void) -{ - int status; - - printk(signon, StripVersion); - - - /* - * Fill in our line protocol discipline, and register it - */ - if ((status = tty_register_ldisc(N_STRIP, &strip_ldisc))) - printk(KERN_ERR "STRIP: can't register line discipline (err = %d)\n", - status); - - /* - * Register the status file with /proc - */ - proc_net_fops_create(&init_net, "strip", S_IFREG | S_IRUGO, &strip_seq_fops); - - return status; -} - -module_init(strip_init_driver); - -static const char signoff[] __exitdata = - KERN_INFO "STRIP: Module Unloaded\n"; - -static void __exit strip_exit_driver(void) -{ - int i; - struct list_head *p,*n; - - /* module ref count rules assure that all entries are unregistered */ - list_for_each_safe(p, n, &strip_list) { - struct strip *s = list_entry(p, struct strip, list); - strip_free(s); - } - - /* Unregister with the /proc/net file here. */ - proc_net_remove(&init_net, "strip"); - - if ((i = tty_unregister_ldisc(N_STRIP))) - printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i); - - printk(signoff); -} - -module_exit(strip_exit_driver); - -MODULE_AUTHOR("Stuart Cheshire "); -MODULE_DESCRIPTION("Starmode Radio IP (STRIP) Device Driver"); -MODULE_LICENSE("Dual BSD/GPL"); - -MODULE_SUPPORTED_DEVICE("Starmode Radio IP (STRIP) modem"); diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 9a4dd5992f65..7ddc5c8d8956 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -131,5 +131,7 @@ source "drivers/staging/iio/Kconfig" source "drivers/staging/cowloop/Kconfig" +source "drivers/staging/strip/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 104f2f8897ec..4386a620e9b2 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -47,3 +47,4 @@ obj-$(CONFIG_RAR_REGISTER) += rar/ obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_COWLOOP) += cowloop/ +obj-$(CONFIG_STRIP) += strip/ diff --git a/drivers/staging/strip/Kconfig b/drivers/staging/strip/Kconfig new file mode 100644 index 000000000000..36257b5cd6e1 --- /dev/null +++ b/drivers/staging/strip/Kconfig @@ -0,0 +1,22 @@ +config STRIP + tristate "STRIP (Metricom starmode radio IP)" + depends on INET + select WIRELESS_EXT + ---help--- + Say Y if you have a Metricom radio and intend to use Starmode Radio + IP. STRIP is a radio protocol developed for the MosquitoNet project + to send Internet traffic using Metricom radios. Metricom radios are + small, battery powered, 100kbit/sec packet radio transceivers, about + the size and weight of a cellular telephone. (You may also have heard + them called "Metricom modems" but we avoid the term "modem" because + it misleads many people into thinking that you can plug a Metricom + modem into a phone line and use it as a modem.) + + You can use STRIP on any Linux machine with a serial port, although + it is obviously most useful for people with laptop computers. If you + think you might get a Metricom radio in the future, there is no harm + in saying Y to STRIP now, except that it makes the kernel a bit + bigger. + + To compile this as a module, choose M here: the module will be + called strip. diff --git a/drivers/staging/strip/Makefile b/drivers/staging/strip/Makefile new file mode 100644 index 000000000000..6417bdcac2fb --- /dev/null +++ b/drivers/staging/strip/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_STRIP) += strip.o diff --git a/drivers/staging/strip/strip.c b/drivers/staging/strip/strip.c new file mode 100644 index 000000000000..ea6a87c19319 --- /dev/null +++ b/drivers/staging/strip/strip.c @@ -0,0 +1,2805 @@ +/* + * Copyright 1996 The Board of Trustees of The Leland Stanford + * Junior University. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. Stanford University + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * strip.c This module implements Starmode Radio IP (STRIP) + * for kernel-based devices like TTY. It interfaces between a + * raw TTY, and the kernel's INET protocol layers (via DDI). + * + * Version: @(#)strip.c 1.3 July 1997 + * + * Author: Stuart Cheshire + * + * Fixes: v0.9 12th Feb 1996 (SC) + * New byte stuffing (2+6 run-length encoding) + * New watchdog timer task + * New Protocol key (SIP0) + * + * v0.9.1 3rd March 1996 (SC) + * Changed to dynamic device allocation -- no more compile + * time (or boot time) limit on the number of STRIP devices. + * + * v0.9.2 13th March 1996 (SC) + * Uses arp cache lookups (but doesn't send arp packets yet) + * + * v0.9.3 17th April 1996 (SC) + * Fixed bug where STR_ERROR flag was getting set unneccessarily + * (causing otherwise good packets to be unneccessarily dropped) + * + * v0.9.4 27th April 1996 (SC) + * First attempt at using "&COMMAND" Starmode AT commands + * + * v0.9.5 29th May 1996 (SC) + * First attempt at sending (unicast) ARP packets + * + * v0.9.6 5th June 1996 (Elliot) + * Put "message level" tags in every "printk" statement + * + * v0.9.7 13th June 1996 (laik) + * Added support for the /proc fs + * + * v0.9.8 July 1996 (Mema) + * Added packet logging + * + * v1.0 November 1996 (SC) + * Fixed (severe) memory leaks in the /proc fs code + * Fixed race conditions in the logging code + * + * v1.1 January 1997 (SC) + * Deleted packet logging (use tcpdump instead) + * Added support for Metricom Firmware v204 features + * (like message checksums) + * + * v1.2 January 1997 (SC) + * Put portables list back in + * + * v1.3 July 1997 (SC) + * Made STRIP driver set the radio's baud rate automatically. + * It is no longer necessarily to manually set the radio's + * rate permanently to 115200 -- the driver handles setting + * the rate automatically. + */ + +#ifdef MODULE +static const char StripVersion[] = "1.3A-STUART.CHESHIRE-MODULAR"; +#else +static const char StripVersion[] = "1.3A-STUART.CHESHIRE"; +#endif + +#define TICKLE_TIMERS 0 +#define EXT_COUNTERS 1 + + +/************************************************************************/ +/* Header files */ + +#include +#include +#include +#include +#include +#include + +# include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/************************************************************************/ +/* Useful structures and definitions */ + +/* + * A MetricomKey identifies the protocol being carried inside a Metricom + * Starmode packet. + */ + +typedef union { + __u8 c[4]; + __u32 l; +} MetricomKey; + +/* + * An IP address can be viewed as four bytes in memory (which is what it is) or as + * a single 32-bit long (which is convenient for assignment, equality testing etc.) + */ + +typedef union { + __u8 b[4]; + __u32 l; +} IPaddr; + +/* + * A MetricomAddressString is used to hold a printable representation of + * a Metricom address. + */ + +typedef struct { + __u8 c[24]; +} MetricomAddressString; + +/* Encapsulation can expand packet of size x to 65/64x + 1 + * Sent packet looks like "*
*" + * 1 1 1-18 1 4 ? 1 + * eg. *0000-1234*SIP0 + * We allow 31 bytes for the stars, the key, the address and the s + */ +#define STRIP_ENCAP_SIZE(X) (32 + (X)*65L/64L) + +/* + * A STRIP_Header is never really sent over the radio, but making a dummy + * header for internal use within the kernel that looks like an Ethernet + * header makes certain other software happier. For example, tcpdump + * already understands Ethernet headers. + */ + +typedef struct { + MetricomAddress dst_addr; /* Destination address, e.g. "0000-1234" */ + MetricomAddress src_addr; /* Source address, e.g. "0000-5678" */ + unsigned short protocol; /* The protocol type, using Ethernet codes */ +} STRIP_Header; + +typedef struct { + char c[60]; +} MetricomNode; + +#define NODE_TABLE_SIZE 32 +typedef struct { + struct timeval timestamp; + int num_nodes; + MetricomNode node[NODE_TABLE_SIZE]; +} MetricomNodeTable; + +enum { FALSE = 0, TRUE = 1 }; + +/* + * Holds the radio's firmware version. + */ +typedef struct { + char c[50]; +} FirmwareVersion; + +/* + * Holds the radio's serial number. + */ +typedef struct { + char c[18]; +} SerialNumber; + +/* + * Holds the radio's battery voltage. + */ +typedef struct { + char c[11]; +} BatteryVoltage; + +typedef struct { + char c[8]; +} char8; + +enum { + NoStructure = 0, /* Really old firmware */ + StructuredMessages = 1, /* Parsable AT response msgs */ + ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */ +}; + +struct strip { + int magic; + /* + * These are pointers to the malloc()ed frame buffers. + */ + + unsigned char *rx_buff; /* buffer for received IP packet */ + unsigned char *sx_buff; /* buffer for received serial data */ + int sx_count; /* received serial data counter */ + int sx_size; /* Serial buffer size */ + unsigned char *tx_buff; /* transmitter buffer */ + unsigned char *tx_head; /* pointer to next byte to XMIT */ + int tx_left; /* bytes left in XMIT queue */ + int tx_size; /* Serial buffer size */ + + /* + * STRIP interface statistics. + */ + + unsigned long rx_packets; /* inbound frames counter */ + unsigned long tx_packets; /* outbound frames counter */ + unsigned long rx_errors; /* Parity, etc. errors */ + unsigned long tx_errors; /* Planned stuff */ + unsigned long rx_dropped; /* No memory for skb */ + unsigned long tx_dropped; /* When MTU change */ + unsigned long rx_over_errors; /* Frame bigger than STRIP buf. */ + + unsigned long pps_timer; /* Timer to determine pps */ + unsigned long rx_pps_count; /* Counter to determine pps */ + unsigned long tx_pps_count; /* Counter to determine pps */ + unsigned long sx_pps_count; /* Counter to determine pps */ + unsigned long rx_average_pps; /* rx packets per second * 8 */ + unsigned long tx_average_pps; /* tx packets per second * 8 */ + unsigned long sx_average_pps; /* sent packets per second * 8 */ + +#ifdef EXT_COUNTERS + unsigned long rx_bytes; /* total received bytes */ + unsigned long tx_bytes; /* total received bytes */ + unsigned long rx_rbytes; /* bytes thru radio i/f */ + unsigned long tx_rbytes; /* bytes thru radio i/f */ + unsigned long rx_sbytes; /* tot bytes thru serial i/f */ + unsigned long tx_sbytes; /* tot bytes thru serial i/f */ + unsigned long rx_ebytes; /* tot stat/err bytes */ + unsigned long tx_ebytes; /* tot stat/err bytes */ +#endif + + /* + * Internal variables. + */ + + struct list_head list; /* Linked list of devices */ + + int discard; /* Set if serial error */ + int working; /* Is radio working correctly? */ + int firmware_level; /* Message structuring level */ + int next_command; /* Next periodic command */ + unsigned int user_baud; /* The user-selected baud rate */ + int mtu; /* Our mtu (to spot changes!) */ + long watchdog_doprobe; /* Next time to test the radio */ + long watchdog_doreset; /* Time to do next reset */ + long gratuitous_arp; /* Time to send next ARP refresh */ + long arp_interval; /* Next ARP interval */ + struct timer_list idle_timer; /* For periodic wakeup calls */ + MetricomAddress true_dev_addr; /* True address of radio */ + int manual_dev_addr; /* Hack: See note below */ + + FirmwareVersion firmware_version; /* The radio's firmware version */ + SerialNumber serial_number; /* The radio's serial number */ + BatteryVoltage battery_voltage; /* The radio's battery voltage */ + + /* + * Other useful structures. + */ + + struct tty_struct *tty; /* ptr to TTY structure */ + struct net_device *dev; /* Our device structure */ + + /* + * Neighbour radio records + */ + + MetricomNodeTable portables; + MetricomNodeTable poletops; +}; + +/* + * Note: manual_dev_addr hack + * + * It is not possible to change the hardware address of a Metricom radio, + * or to send packets with a user-specified hardware source address, thus + * trying to manually set a hardware source address is a questionable + * thing to do. However, if the user *does* manually set the hardware + * source address of a STRIP interface, then the kernel will believe it, + * and use it in certain places. For example, the hardware address listed + * by ifconfig will be the manual address, not the true one. + * (Both addresses are listed in /proc/net/strip.) + * Also, ARP packets will be sent out giving the user-specified address as + * the source address, not the real address. This is dangerous, because + * it means you won't receive any replies -- the ARP replies will go to + * the specified address, which will be some other radio. The case where + * this is useful is when that other radio is also connected to the same + * machine. This allows you to connect a pair of radios to one machine, + * and to use one exclusively for inbound traffic, and the other + * exclusively for outbound traffic. Pretty neat, huh? + * + * Here's the full procedure to set this up: + * + * 1. "slattach" two interfaces, e.g. st0 for outgoing packets, + * and st1 for incoming packets + * + * 2. "ifconfig" st0 (outbound radio) to have the hardware address + * which is the real hardware address of st1 (inbound radio). + * Now when it sends out packets, it will masquerade as st1, and + * replies will be sent to that radio, which is exactly what we want. + * + * 3. Set the route table entry ("route add default ..." or + * "route add -net ...", as appropriate) to send packets via the st0 + * interface (outbound radio). Do not add any route which sends packets + * out via the st1 interface -- that radio is for inbound traffic only. + * + * 4. "ifconfig" st1 (inbound radio) to have hardware address zero. + * This tells the STRIP driver to "shut down" that interface and not + * send any packets through it. In particular, it stops sending the + * periodic gratuitous ARP packets that a STRIP interface normally sends. + * Also, when packets arrive on that interface, it will search the + * interface list to see if there is another interface who's manual + * hardware address matches its own real address (i.e. st0 in this + * example) and if so it will transfer ownership of the skbuff to + * that interface, so that it looks to the kernel as if the packet + * arrived on that interface. This is necessary because when the + * kernel sends an ARP packet on st0, it expects to get a reply on + * st0, and if it sees the reply come from st1 then it will ignore + * it (to be accurate, it puts the entry in the ARP table, but + * labelled in such a way that st0 can't use it). + * + * Thanks to Petros Maniatis for coming up with the idea of splitting + * inbound and outbound traffic between two interfaces, which turned + * out to be really easy to implement, even if it is a bit of a hack. + * + * Having set a manual address on an interface, you can restore it + * to automatic operation (where the address is automatically kept + * consistent with the real address of the radio) by setting a manual + * address of all ones, e.g. "ifconfig st0 hw strip FFFFFFFFFFFF" + * This 'turns off' manual override mode for the device address. + * + * Note: The IEEE 802 headers reported in tcpdump will show the *real* + * radio addresses the packets were sent and received from, so that you + * can see what is really going on with packets, and which interfaces + * they are really going through. + */ + + +/************************************************************************/ +/* Constants */ + +/* + * CommandString1 works on all radios + * Other CommandStrings are only used with firmware that provides structured responses. + * + * ats319=1 Enables Info message for node additions and deletions + * ats319=2 Enables Info message for a new best node + * ats319=4 Enables checksums + * ats319=8 Enables ACK messages + */ + +static const int MaxCommandStringLength = 32; +static const int CompatibilityCommand = 1; + +static const char CommandString0[] = "*&COMMAND*ATS319=7"; /* Turn on checksums & info messages */ +static const char CommandString1[] = "*&COMMAND*ATS305?"; /* Query radio name */ +static const char CommandString2[] = "*&COMMAND*ATS325?"; /* Query battery voltage */ +static const char CommandString3[] = "*&COMMAND*ATS300?"; /* Query version information */ +static const char CommandString4[] = "*&COMMAND*ATS311?"; /* Query poletop list */ +static const char CommandString5[] = "*&COMMAND*AT~LA"; /* Query portables list */ +typedef struct { + const char *string; + long length; +} StringDescriptor; + +static const StringDescriptor CommandString[] = { + {CommandString0, sizeof(CommandString0) - 1}, + {CommandString1, sizeof(CommandString1) - 1}, + {CommandString2, sizeof(CommandString2) - 1}, + {CommandString3, sizeof(CommandString3) - 1}, + {CommandString4, sizeof(CommandString4) - 1}, + {CommandString5, sizeof(CommandString5) - 1} +}; + +#define GOT_ALL_RADIO_INFO(S) \ + ((S)->firmware_version.c[0] && \ + (S)->battery_voltage.c[0] && \ + memcmp(&(S)->true_dev_addr, zero_address.c, sizeof(zero_address))) + +static const char hextable[16] = "0123456789ABCDEF"; + +static const MetricomAddress zero_address; +static const MetricomAddress broadcast_address = + { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} }; + +static const MetricomKey SIP0Key = { "SIP0" }; +static const MetricomKey ARP0Key = { "ARP0" }; +static const MetricomKey ATR_Key = { "ATR " }; +static const MetricomKey ACK_Key = { "ACK_" }; +static const MetricomKey INF_Key = { "INF_" }; +static const MetricomKey ERR_Key = { "ERR_" }; + +static const long MaxARPInterval = 60 * HZ; /* One minute */ + +/* + * Maximum Starmode packet length is 1183 bytes. Allowing 4 bytes for + * protocol key, 4 bytes for checksum, one byte for CR, and 65/64 expansion + * for STRIP encoding, that translates to a maximum payload MTU of 1155. + * Note: A standard NFS 1K data packet is a total of 0x480 (1152) bytes + * long, including IP header, UDP header, and NFS header. Setting the STRIP + * MTU to 1152 allows us to send default sized NFS packets without fragmentation. + */ +static const unsigned short MAX_SEND_MTU = 1152; +static const unsigned short MAX_RECV_MTU = 1500; /* Hoping for Ethernet sized packets in the future! */ +static const unsigned short DEFAULT_STRIP_MTU = 1152; +static const int STRIP_MAGIC = 0x5303; +static const long LongTime = 0x7FFFFFFF; + +/************************************************************************/ +/* Global variables */ + +static LIST_HEAD(strip_list); +static DEFINE_SPINLOCK(strip_lock); + +/************************************************************************/ +/* Macros */ + +/* Returns TRUE if text T begins with prefix P */ +#define has_prefix(T,L,P) (((L) >= sizeof(P)-1) && !strncmp((T), (P), sizeof(P)-1)) + +/* Returns TRUE if text T of length L is equal to string S */ +#define text_equal(T,L,S) (((L) == sizeof(S)-1) && !strncmp((T), (S), sizeof(S)-1)) + +#define READHEX(X) ((X)>='0' && (X)<='9' ? (X)-'0' : \ + (X)>='a' && (X)<='f' ? (X)-'a'+10 : \ + (X)>='A' && (X)<='F' ? (X)-'A'+10 : 0 ) + +#define READHEX16(X) ((__u16)(READHEX(X))) + +#define READDEC(X) ((X)>='0' && (X)<='9' ? (X)-'0' : 0) + +#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)])) + +#define JIFFIE_TO_SEC(X) ((X) / HZ) + + +/************************************************************************/ +/* Utility routines */ + +static int arp_query(unsigned char *haddr, u32 paddr, + struct net_device *dev) +{ + struct neighbour *neighbor_entry; + int ret = 0; + + neighbor_entry = neigh_lookup(&arp_tbl, &paddr, dev); + + if (neighbor_entry != NULL) { + neighbor_entry->used = jiffies; + if (neighbor_entry->nud_state & NUD_VALID) { + memcpy(haddr, neighbor_entry->ha, dev->addr_len); + ret = 1; + } + neigh_release(neighbor_entry); + } + return ret; +} + +static void DumpData(char *msg, struct strip *strip_info, __u8 * ptr, + __u8 * end) +{ + static const int MAX_DumpData = 80; + __u8 pkt_text[MAX_DumpData], *p = pkt_text; + + *p++ = '\"'; + + while (ptr < end && p < &pkt_text[MAX_DumpData - 4]) { + if (*ptr == '\\') { + *p++ = '\\'; + *p++ = '\\'; + } else { + if (*ptr >= 32 && *ptr <= 126) { + *p++ = *ptr; + } else { + sprintf(p, "\\%02X", *ptr); + p += 3; + } + } + ptr++; + } + + if (ptr == end) + *p++ = '\"'; + *p++ = 0; + + printk(KERN_INFO "%s: %-13s%s\n", strip_info->dev->name, msg, pkt_text); +} + + +/************************************************************************/ +/* Byte stuffing/unstuffing routines */ + +/* Stuffing scheme: + * 00 Unused (reserved character) + * 01-3F Run of 2-64 different characters + * 40-7F Run of 1-64 different characters plus a single zero at the end + * 80-BF Run of 1-64 of the same character + * C0-FF Run of 1-64 zeroes (ASCII 0) + */ + +typedef enum { + Stuff_Diff = 0x00, + Stuff_DiffZero = 0x40, + Stuff_Same = 0x80, + Stuff_Zero = 0xC0, + Stuff_NoCode = 0xFF, /* Special code, meaning no code selected */ + + Stuff_CodeMask = 0xC0, + Stuff_CountMask = 0x3F, + Stuff_MaxCount = 0x3F, + Stuff_Magic = 0x0D /* The value we are eliminating */ +} StuffingCode; + +/* StuffData encodes the data starting at "src" for "length" bytes. + * It writes it to the buffer pointed to by "dst" (which must be at least + * as long as 1 + 65/64 of the input length). The output may be up to 1.6% + * larger than the input for pathological input, but will usually be smaller. + * StuffData returns the new value of the dst pointer as its result. + * "code_ptr_ptr" points to a "__u8 *" which is used to hold encoding state + * between calls, allowing an encoded packet to be incrementally built up + * from small parts. On the first call, the "__u8 *" pointed to should be + * initialized to NULL; between subsequent calls the calling routine should + * leave the value alone and simply pass it back unchanged so that the + * encoder can recover its current state. + */ + +#define StuffData_FinishBlock(X) \ +(*code_ptr = (X) ^ Stuff_Magic, code = Stuff_NoCode) + +static __u8 *StuffData(__u8 * src, __u32 length, __u8 * dst, + __u8 ** code_ptr_ptr) +{ + __u8 *end = src + length; + __u8 *code_ptr = *code_ptr_ptr; + __u8 code = Stuff_NoCode, count = 0; + + if (!length) + return (dst); + + if (code_ptr) { + /* + * Recover state from last call, if applicable + */ + code = (*code_ptr ^ Stuff_Magic) & Stuff_CodeMask; + count = (*code_ptr ^ Stuff_Magic) & Stuff_CountMask; + } + + while (src < end) { + switch (code) { + /* Stuff_NoCode: If no current code, select one */ + case Stuff_NoCode: + /* Record where we're going to put this code */ + code_ptr = dst++; + count = 0; /* Reset the count (zero means one instance) */ + /* Tentatively start a new block */ + if (*src == 0) { + code = Stuff_Zero; + src++; + } else { + code = Stuff_Same; + *dst++ = *src++ ^ Stuff_Magic; + } + /* Note: We optimistically assume run of same -- */ + /* which will be fixed later in Stuff_Same */ + /* if it turns out not to be true. */ + break; + + /* Stuff_Zero: We already have at least one zero encoded */ + case Stuff_Zero: + /* If another zero, count it, else finish this code block */ + if (*src == 0) { + count++; + src++; + } else { + StuffData_FinishBlock(Stuff_Zero + count); + } + break; + + /* Stuff_Same: We already have at least one byte encoded */ + case Stuff_Same: + /* If another one the same, count it */ + if ((*src ^ Stuff_Magic) == code_ptr[1]) { + count++; + src++; + break; + } + /* else, this byte does not match this block. */ + /* If we already have two or more bytes encoded, finish this code block */ + if (count) { + StuffData_FinishBlock(Stuff_Same + count); + break; + } + /* else, we only have one so far, so switch to Stuff_Diff code */ + code = Stuff_Diff; + /* and fall through to Stuff_Diff case below + * Note cunning cleverness here: case Stuff_Diff compares + * the current character with the previous two to see if it + * has a run of three the same. Won't this be an error if + * there aren't two previous characters stored to compare with? + * No. Because we know the current character is *not* the same + * as the previous one, the first test below will necessarily + * fail and the send half of the "if" won't be executed. + */ + + /* Stuff_Diff: We have at least two *different* bytes encoded */ + case Stuff_Diff: + /* If this is a zero, must encode a Stuff_DiffZero, and begin a new block */ + if (*src == 0) { + StuffData_FinishBlock(Stuff_DiffZero + + count); + } + /* else, if we have three in a row, it is worth starting a Stuff_Same block */ + else if ((*src ^ Stuff_Magic) == dst[-1] + && dst[-1] == dst[-2]) { + /* Back off the last two characters we encoded */ + code += count - 2; + /* Note: "Stuff_Diff + 0" is an illegal code */ + if (code == Stuff_Diff + 0) { + code = Stuff_Same + 0; + } + StuffData_FinishBlock(code); + code_ptr = dst - 2; + /* dst[-1] already holds the correct value */ + count = 2; /* 2 means three bytes encoded */ + code = Stuff_Same; + } + /* else, another different byte, so add it to the block */ + else { + *dst++ = *src ^ Stuff_Magic; + count++; + } + src++; /* Consume the byte */ + break; + } + if (count == Stuff_MaxCount) { + StuffData_FinishBlock(code + count); + } + } + if (code == Stuff_NoCode) { + *code_ptr_ptr = NULL; + } else { + *code_ptr_ptr = code_ptr; + StuffData_FinishBlock(code + count); + } + return (dst); +} + +/* + * UnStuffData decodes the data at "src", up to (but not including) "end". + * It writes the decoded data into the buffer pointed to by "dst", up to a + * maximum of "dst_length", and returns the new value of "src" so that a + * follow-on call can read more data, continuing from where the first left off. + * + * There are three types of results: + * 1. The source data runs out before extracting "dst_length" bytes: + * UnStuffData returns NULL to indicate failure. + * 2. The source data produces exactly "dst_length" bytes: + * UnStuffData returns new_src = end to indicate that all bytes were consumed. + * 3. "dst_length" bytes are extracted, with more remaining. + * UnStuffData returns new_src < end to indicate that there are more bytes + * to be read. + * + * Note: The decoding may be destructive, in that it may alter the source + * data in the process of decoding it (this is necessary to allow a follow-on + * call to resume correctly). + */ + +static __u8 *UnStuffData(__u8 * src, __u8 * end, __u8 * dst, + __u32 dst_length) +{ + __u8 *dst_end = dst + dst_length; + /* Sanity check */ + if (!src || !end || !dst || !dst_length) + return (NULL); + while (src < end && dst < dst_end) { + int count = (*src ^ Stuff_Magic) & Stuff_CountMask; + switch ((*src ^ Stuff_Magic) & Stuff_CodeMask) { + case Stuff_Diff: + if (src + 1 + count >= end) + return (NULL); + do { + *dst++ = *++src ^ Stuff_Magic; + } + while (--count >= 0 && dst < dst_end); + if (count < 0) + src += 1; + else { + if (count == 0) + *src = Stuff_Same ^ Stuff_Magic; + else + *src = + (Stuff_Diff + + count) ^ Stuff_Magic; + } + break; + case Stuff_DiffZero: + if (src + 1 + count >= end) + return (NULL); + do { + *dst++ = *++src ^ Stuff_Magic; + } + while (--count >= 0 && dst < dst_end); + if (count < 0) + *src = Stuff_Zero ^ Stuff_Magic; + else + *src = + (Stuff_DiffZero + count) ^ Stuff_Magic; + break; + case Stuff_Same: + if (src + 1 >= end) + return (NULL); + do { + *dst++ = src[1] ^ Stuff_Magic; + } + while (--count >= 0 && dst < dst_end); + if (count < 0) + src += 2; + else + *src = (Stuff_Same + count) ^ Stuff_Magic; + break; + case Stuff_Zero: + do { + *dst++ = 0; + } + while (--count >= 0 && dst < dst_end); + if (count < 0) + src += 1; + else + *src = (Stuff_Zero + count) ^ Stuff_Magic; + break; + } + } + if (dst < dst_end) + return (NULL); + else + return (src); +} + + +/************************************************************************/ +/* General routines for STRIP */ + +/* + * set_baud sets the baud rate to the rate defined by baudcode + */ +static void set_baud(struct tty_struct *tty, speed_t baudrate) +{ + struct ktermios old_termios; + + mutex_lock(&tty->termios_mutex); + old_termios =*(tty->termios); + tty_encode_baud_rate(tty, baudrate, baudrate); + tty->ops->set_termios(tty, &old_termios); + mutex_unlock(&tty->termios_mutex); +} + +/* + * Convert a string to a Metricom Address. + */ + +#define IS_RADIO_ADDRESS(p) ( \ + isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \ + (p)[4] == '-' && \ + isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8]) ) + +static int string_to_radio_address(MetricomAddress * addr, __u8 * p) +{ + if (!IS_RADIO_ADDRESS(p)) + return (1); + addr->c[0] = 0; + addr->c[1] = 0; + addr->c[2] = READHEX(p[0]) << 4 | READHEX(p[1]); + addr->c[3] = READHEX(p[2]) << 4 | READHEX(p[3]); + addr->c[4] = READHEX(p[5]) << 4 | READHEX(p[6]); + addr->c[5] = READHEX(p[7]) << 4 | READHEX(p[8]); + return (0); +} + +/* + * Convert a Metricom Address to a string. + */ + +static __u8 *radio_address_to_string(const MetricomAddress * addr, + MetricomAddressString * p) +{ + sprintf(p->c, "%02X%02X-%02X%02X", addr->c[2], addr->c[3], + addr->c[4], addr->c[5]); + return (p->c); +} + +/* + * Note: Must make sure sx_size is big enough to receive a stuffed + * MAX_RECV_MTU packet. Additionally, we also want to ensure that it's + * big enough to receive a large radio neighbour list (currently 4K). + */ + +static int allocate_buffers(struct strip *strip_info, int mtu) +{ + struct net_device *dev = strip_info->dev; + int sx_size = max_t(int, STRIP_ENCAP_SIZE(MAX_RECV_MTU), 4096); + int tx_size = STRIP_ENCAP_SIZE(mtu) + MaxCommandStringLength; + __u8 *r = kmalloc(MAX_RECV_MTU, GFP_ATOMIC); + __u8 *s = kmalloc(sx_size, GFP_ATOMIC); + __u8 *t = kmalloc(tx_size, GFP_ATOMIC); + if (r && s && t) { + strip_info->rx_buff = r; + strip_info->sx_buff = s; + strip_info->tx_buff = t; + strip_info->sx_size = sx_size; + strip_info->tx_size = tx_size; + strip_info->mtu = dev->mtu = mtu; + return (1); + } + kfree(r); + kfree(s); + kfree(t); + return (0); +} + +/* + * MTU has been changed by the IP layer. + * We could be in + * an upcall from the tty driver, or in an ip packet queue. + */ +static int strip_change_mtu(struct net_device *dev, int new_mtu) +{ + struct strip *strip_info = netdev_priv(dev); + int old_mtu = strip_info->mtu; + unsigned char *orbuff = strip_info->rx_buff; + unsigned char *osbuff = strip_info->sx_buff; + unsigned char *otbuff = strip_info->tx_buff; + + if (new_mtu > MAX_SEND_MTU) { + printk(KERN_ERR + "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n", + strip_info->dev->name, MAX_SEND_MTU); + return -EINVAL; + } + + spin_lock_bh(&strip_lock); + if (!allocate_buffers(strip_info, new_mtu)) { + printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n", + strip_info->dev->name); + spin_unlock_bh(&strip_lock); + return -ENOMEM; + } + + if (strip_info->sx_count) { + if (strip_info->sx_count <= strip_info->sx_size) + memcpy(strip_info->sx_buff, osbuff, + strip_info->sx_count); + else { + strip_info->discard = strip_info->sx_count; + strip_info->rx_over_errors++; + } + } + + if (strip_info->tx_left) { + if (strip_info->tx_left <= strip_info->tx_size) + memcpy(strip_info->tx_buff, strip_info->tx_head, + strip_info->tx_left); + else { + strip_info->tx_left = 0; + strip_info->tx_dropped++; + } + } + strip_info->tx_head = strip_info->tx_buff; + spin_unlock_bh(&strip_lock); + + printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n", + strip_info->dev->name, old_mtu, strip_info->mtu); + + kfree(orbuff); + kfree(osbuff); + kfree(otbuff); + return 0; +} + +static void strip_unlock(struct strip *strip_info) +{ + /* + * Set the timer to go off in one second. + */ + strip_info->idle_timer.expires = jiffies + 1 * HZ; + add_timer(&strip_info->idle_timer); + netif_wake_queue(strip_info->dev); +} + + + +/* + * If the time is in the near future, time_delta prints the number of + * seconds to go into the buffer and returns the address of the buffer. + * If the time is not in the near future, it returns the address of the + * string "Not scheduled" The buffer must be long enough to contain the + * ascii representation of the number plus 9 charactes for the " seconds" + * and the null character. + */ +#ifdef CONFIG_PROC_FS +static char *time_delta(char buffer[], long time) +{ + time -= jiffies; + if (time > LongTime / 2) + return ("Not scheduled"); + if (time < 0) + time = 0; /* Don't print negative times */ + sprintf(buffer, "%ld seconds", time / HZ); + return (buffer); +} + +/* get Nth element of the linked list */ +static struct strip *strip_get_idx(loff_t pos) +{ + struct strip *str; + int i = 0; + + list_for_each_entry_rcu(str, &strip_list, list) { + if (pos == i) + return str; + ++i; + } + return NULL; +} + +static void *strip_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(RCU) +{ + rcu_read_lock(); + return *pos ? strip_get_idx(*pos - 1) : SEQ_START_TOKEN; +} + +static void *strip_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct list_head *l; + struct strip *s; + + ++*pos; + if (v == SEQ_START_TOKEN) + return strip_get_idx(1); + + s = v; + l = &s->list; + list_for_each_continue_rcu(l, &strip_list) { + return list_entry(l, struct strip, list); + } + return NULL; +} + +static void strip_seq_stop(struct seq_file *seq, void *v) + __releases(RCU) +{ + rcu_read_unlock(); +} + +static void strip_seq_neighbours(struct seq_file *seq, + const MetricomNodeTable * table, + const char *title) +{ + /* We wrap this in a do/while loop, so if the table changes */ + /* while we're reading it, we just go around and try again. */ + struct timeval t; + + do { + int i; + t = table->timestamp; + if (table->num_nodes) + seq_printf(seq, "\n %s\n", title); + for (i = 0; i < table->num_nodes; i++) { + MetricomNode node; + + spin_lock_bh(&strip_lock); + node = table->node[i]; + spin_unlock_bh(&strip_lock); + seq_printf(seq, " %s\n", node.c); + } + } while (table->timestamp.tv_sec != t.tv_sec + || table->timestamp.tv_usec != t.tv_usec); +} + +/* + * This function prints radio status information via the seq_file + * interface. The interface takes care of buffer size and over + * run issues. + * + * The buffer in seq_file is PAGESIZE (4K) + * so this routine should never print more or it will get truncated. + * With the maximum of 32 portables and 32 poletops + * reported, the routine outputs 3107 bytes into the buffer. + */ +static void strip_seq_status_info(struct seq_file *seq, + const struct strip *strip_info) +{ + char temp[32]; + MetricomAddressString addr_string; + + /* First, we must copy all of our data to a safe place, */ + /* in case a serial interrupt comes in and changes it. */ + int tx_left = strip_info->tx_left; + unsigned long rx_average_pps = strip_info->rx_average_pps; + unsigned long tx_average_pps = strip_info->tx_average_pps; + unsigned long sx_average_pps = strip_info->sx_average_pps; + int working = strip_info->working; + int firmware_level = strip_info->firmware_level; + long watchdog_doprobe = strip_info->watchdog_doprobe; + long watchdog_doreset = strip_info->watchdog_doreset; + long gratuitous_arp = strip_info->gratuitous_arp; + long arp_interval = strip_info->arp_interval; + FirmwareVersion firmware_version = strip_info->firmware_version; + SerialNumber serial_number = strip_info->serial_number; + BatteryVoltage battery_voltage = strip_info->battery_voltage; + char *if_name = strip_info->dev->name; + MetricomAddress true_dev_addr = strip_info->true_dev_addr; + MetricomAddress dev_dev_addr = + *(MetricomAddress *) strip_info->dev->dev_addr; + int manual_dev_addr = strip_info->manual_dev_addr; +#ifdef EXT_COUNTERS + unsigned long rx_bytes = strip_info->rx_bytes; + unsigned long tx_bytes = strip_info->tx_bytes; + unsigned long rx_rbytes = strip_info->rx_rbytes; + unsigned long tx_rbytes = strip_info->tx_rbytes; + unsigned long rx_sbytes = strip_info->rx_sbytes; + unsigned long tx_sbytes = strip_info->tx_sbytes; + unsigned long rx_ebytes = strip_info->rx_ebytes; + unsigned long tx_ebytes = strip_info->tx_ebytes; +#endif + + seq_printf(seq, "\nInterface name\t\t%s\n", if_name); + seq_printf(seq, " Radio working:\t\t%s\n", working ? "Yes" : "No"); + radio_address_to_string(&true_dev_addr, &addr_string); + seq_printf(seq, " Radio address:\t\t%s\n", addr_string.c); + if (manual_dev_addr) { + radio_address_to_string(&dev_dev_addr, &addr_string); + seq_printf(seq, " Device address:\t%s\n", addr_string.c); + } + seq_printf(seq, " Firmware version:\t%s", !working ? "Unknown" : + !firmware_level ? "Should be upgraded" : + firmware_version.c); + if (firmware_level >= ChecksummedMessages) + seq_printf(seq, " (Checksums Enabled)"); + seq_printf(seq, "\n"); + seq_printf(seq, " Serial number:\t\t%s\n", serial_number.c); + seq_printf(seq, " Battery voltage:\t%s\n", battery_voltage.c); + seq_printf(seq, " Transmit queue (bytes):%d\n", tx_left); + seq_printf(seq, " Receive packet rate: %ld packets per second\n", + rx_average_pps / 8); + seq_printf(seq, " Transmit packet rate: %ld packets per second\n", + tx_average_pps / 8); + seq_printf(seq, " Sent packet rate: %ld packets per second\n", + sx_average_pps / 8); + seq_printf(seq, " Next watchdog probe:\t%s\n", + time_delta(temp, watchdog_doprobe)); + seq_printf(seq, " Next watchdog reset:\t%s\n", + time_delta(temp, watchdog_doreset)); + seq_printf(seq, " Next gratuitous ARP:\t"); + + if (!memcmp + (strip_info->dev->dev_addr, zero_address.c, + sizeof(zero_address))) + seq_printf(seq, "Disabled\n"); + else { + seq_printf(seq, "%s\n", time_delta(temp, gratuitous_arp)); + seq_printf(seq, " Next ARP interval:\t%ld seconds\n", + JIFFIE_TO_SEC(arp_interval)); + } + + if (working) { +#ifdef EXT_COUNTERS + seq_printf(seq, "\n"); + seq_printf(seq, + " Total bytes: \trx:\t%lu\ttx:\t%lu\n", + rx_bytes, tx_bytes); + seq_printf(seq, + " thru radio: \trx:\t%lu\ttx:\t%lu\n", + rx_rbytes, tx_rbytes); + seq_printf(seq, + " thru serial port: \trx:\t%lu\ttx:\t%lu\n", + rx_sbytes, tx_sbytes); + seq_printf(seq, + " Total stat/err bytes:\trx:\t%lu\ttx:\t%lu\n", + rx_ebytes, tx_ebytes); +#endif + strip_seq_neighbours(seq, &strip_info->poletops, + "Poletops:"); + strip_seq_neighbours(seq, &strip_info->portables, + "Portables:"); + } +} + +/* + * This function is exports status information from the STRIP driver through + * the /proc file system. + */ +static int strip_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_printf(seq, "strip_version: %s\n", StripVersion); + else + strip_seq_status_info(seq, (const struct strip *)v); + return 0; +} + + +static const struct seq_operations strip_seq_ops = { + .start = strip_seq_start, + .next = strip_seq_next, + .stop = strip_seq_stop, + .show = strip_seq_show, +}; + +static int strip_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &strip_seq_ops); +} + +static const struct file_operations strip_seq_fops = { + .owner = THIS_MODULE, + .open = strip_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; +#endif + + + +/************************************************************************/ +/* Sending routines */ + +static void ResetRadio(struct strip *strip_info) +{ + struct tty_struct *tty = strip_info->tty; + static const char init[] = "ate0q1dt**starmode\r**"; + StringDescriptor s = { init, sizeof(init) - 1 }; + + /* + * If the radio isn't working anymore, + * we should clear the old status information. + */ + if (strip_info->working) { + printk(KERN_INFO "%s: No response: Resetting radio.\n", + strip_info->dev->name); + strip_info->firmware_version.c[0] = '\0'; + strip_info->serial_number.c[0] = '\0'; + strip_info->battery_voltage.c[0] = '\0'; + strip_info->portables.num_nodes = 0; + do_gettimeofday(&strip_info->portables.timestamp); + strip_info->poletops.num_nodes = 0; + do_gettimeofday(&strip_info->poletops.timestamp); + } + + strip_info->pps_timer = jiffies; + strip_info->rx_pps_count = 0; + strip_info->tx_pps_count = 0; + strip_info->sx_pps_count = 0; + strip_info->rx_average_pps = 0; + strip_info->tx_average_pps = 0; + strip_info->sx_average_pps = 0; + + /* Mark radio address as unknown */ + *(MetricomAddress *) & strip_info->true_dev_addr = zero_address; + if (!strip_info->manual_dev_addr) + *(MetricomAddress *) strip_info->dev->dev_addr = + zero_address; + strip_info->working = FALSE; + strip_info->firmware_level = NoStructure; + strip_info->next_command = CompatibilityCommand; + strip_info->watchdog_doprobe = jiffies + 10 * HZ; + strip_info->watchdog_doreset = jiffies + 1 * HZ; + + /* If the user has selected a baud rate above 38.4 see what magic we have to do */ + if (strip_info->user_baud > 38400) { + /* + * Subtle stuff: Pay attention :-) + * If the serial port is currently at the user's selected (>38.4) rate, + * then we temporarily switch to 19.2 and issue the ATS304 command + * to tell the radio to switch to the user's selected rate. + * If the serial port is not currently at that rate, that means we just + * issued the ATS304 command last time through, so this time we restore + * the user's selected rate and issue the normal starmode reset string. + */ + if (strip_info->user_baud == tty_get_baud_rate(tty)) { + static const char b0[] = "ate0q1s304=57600\r"; + static const char b1[] = "ate0q1s304=115200\r"; + static const StringDescriptor baudstring[2] = + { {b0, sizeof(b0) - 1} + , {b1, sizeof(b1) - 1} + }; + set_baud(tty, 19200); + if (strip_info->user_baud == 57600) + s = baudstring[0]; + else if (strip_info->user_baud == 115200) + s = baudstring[1]; + else + s = baudstring[1]; /* For now */ + } else + set_baud(tty, strip_info->user_baud); + } + + tty->ops->write(tty, s.string, s.length); +#ifdef EXT_COUNTERS + strip_info->tx_ebytes += s.length; +#endif +} + +/* + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + */ + +static void strip_write_some_more(struct tty_struct *tty) +{ + struct strip *strip_info = tty->disc_data; + + /* First make sure we're connected. */ + if (!strip_info || strip_info->magic != STRIP_MAGIC || + !netif_running(strip_info->dev)) + return; + + if (strip_info->tx_left > 0) { + int num_written = + tty->ops->write(tty, strip_info->tx_head, + strip_info->tx_left); + strip_info->tx_left -= num_written; + strip_info->tx_head += num_written; +#ifdef EXT_COUNTERS + strip_info->tx_sbytes += num_written; +#endif + } else { /* Else start transmission of another packet */ + + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + strip_unlock(strip_info); + } +} + +static __u8 *add_checksum(__u8 * buffer, __u8 * end) +{ + __u16 sum = 0; + __u8 *p = buffer; + while (p < end) + sum += *p++; + end[3] = hextable[sum & 0xF]; + sum >>= 4; + end[2] = hextable[sum & 0xF]; + sum >>= 4; + end[1] = hextable[sum & 0xF]; + sum >>= 4; + end[0] = hextable[sum & 0xF]; + return (end + 4); +} + +static unsigned char *strip_make_packet(unsigned char *buffer, + struct strip *strip_info, + struct sk_buff *skb) +{ + __u8 *ptr = buffer; + __u8 *stuffstate = NULL; + STRIP_Header *header = (STRIP_Header *) skb->data; + MetricomAddress haddr = header->dst_addr; + int len = skb->len - sizeof(STRIP_Header); + MetricomKey key; + + /*HexDump("strip_make_packet", strip_info, skb->data, skb->data + skb->len); */ + + if (header->protocol == htons(ETH_P_IP)) + key = SIP0Key; + else if (header->protocol == htons(ETH_P_ARP)) + key = ARP0Key; + else { + printk(KERN_ERR + "%s: strip_make_packet: Unknown packet type 0x%04X\n", + strip_info->dev->name, ntohs(header->protocol)); + return (NULL); + } + + if (len > strip_info->mtu) { + printk(KERN_ERR + "%s: Dropping oversized transmit packet: %d bytes\n", + strip_info->dev->name, len); + return (NULL); + } + + /* + * If we're sending to ourselves, discard the packet. + * (Metricom radios choke if they try to send a packet to their own address.) + */ + if (!memcmp(haddr.c, strip_info->true_dev_addr.c, sizeof(haddr))) { + printk(KERN_ERR "%s: Dropping packet addressed to self\n", + strip_info->dev->name); + return (NULL); + } + + /* + * If this is a broadcast packet, send it to our designated Metricom + * 'broadcast hub' radio (First byte of address being 0xFF means broadcast) + */ + if (haddr.c[0] == 0xFF) { + __be32 brd = 0; + struct in_device *in_dev; + + rcu_read_lock(); + in_dev = __in_dev_get_rcu(strip_info->dev); + if (in_dev == NULL) { + rcu_read_unlock(); + return NULL; + } + if (in_dev->ifa_list) + brd = in_dev->ifa_list->ifa_broadcast; + rcu_read_unlock(); + + /* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */ + if (!arp_query(haddr.c, brd, strip_info->dev)) { + printk(KERN_ERR + "%s: Unable to send packet (no broadcast hub configured)\n", + strip_info->dev->name); + return (NULL); + } + /* + * If we are the broadcast hub, don't bother sending to ourselves. + * (Metricom radios choke if they try to send a packet to their own address.) + */ + if (!memcmp + (haddr.c, strip_info->true_dev_addr.c, sizeof(haddr))) + return (NULL); + } + + *ptr++ = 0x0D; + *ptr++ = '*'; + *ptr++ = hextable[haddr.c[2] >> 4]; + *ptr++ = hextable[haddr.c[2] & 0xF]; + *ptr++ = hextable[haddr.c[3] >> 4]; + *ptr++ = hextable[haddr.c[3] & 0xF]; + *ptr++ = '-'; + *ptr++ = hextable[haddr.c[4] >> 4]; + *ptr++ = hextable[haddr.c[4] & 0xF]; + *ptr++ = hextable[haddr.c[5] >> 4]; + *ptr++ = hextable[haddr.c[5] & 0xF]; + *ptr++ = '*'; + *ptr++ = key.c[0]; + *ptr++ = key.c[1]; + *ptr++ = key.c[2]; + *ptr++ = key.c[3]; + + ptr = + StuffData(skb->data + sizeof(STRIP_Header), len, ptr, + &stuffstate); + + if (strip_info->firmware_level >= ChecksummedMessages) + ptr = add_checksum(buffer + 1, ptr); + + *ptr++ = 0x0D; + return (ptr); +} + +static void strip_send(struct strip *strip_info, struct sk_buff *skb) +{ + MetricomAddress haddr; + unsigned char *ptr = strip_info->tx_buff; + int doreset = (long) jiffies - strip_info->watchdog_doreset >= 0; + int doprobe = (long) jiffies - strip_info->watchdog_doprobe >= 0 + && !doreset; + __be32 addr, brd; + + /* + * 1. If we have a packet, encapsulate it and put it in the buffer + */ + if (skb) { + char *newptr = strip_make_packet(ptr, strip_info, skb); + strip_info->tx_pps_count++; + if (!newptr) + strip_info->tx_dropped++; + else { + ptr = newptr; + strip_info->sx_pps_count++; + strip_info->tx_packets++; /* Count another successful packet */ +#ifdef EXT_COUNTERS + strip_info->tx_bytes += skb->len; + strip_info->tx_rbytes += ptr - strip_info->tx_buff; +#endif + /*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr); */ + /*HexDump("Sending", strip_info, strip_info->tx_buff, ptr); */ + } + } + + /* + * 2. If it is time for another tickle, tack it on, after the packet + */ + if (doprobe) { + StringDescriptor ts = CommandString[strip_info->next_command]; +#if TICKLE_TIMERS + { + struct timeval tv; + do_gettimeofday(&tv); + printk(KERN_INFO "**** Sending tickle string %d at %02d.%06d\n", + strip_info->next_command, tv.tv_sec % 100, + tv.tv_usec); + } +#endif + if (ptr == strip_info->tx_buff) + *ptr++ = 0x0D; + + *ptr++ = '*'; /* First send "**" to provoke an error message */ + *ptr++ = '*'; + + /* Then add the command */ + memcpy(ptr, ts.string, ts.length); + + /* Add a checksum ? */ + if (strip_info->firmware_level < ChecksummedMessages) + ptr += ts.length; + else + ptr = add_checksum(ptr, ptr + ts.length); + + *ptr++ = 0x0D; /* Terminate the command with a */ + + /* Cycle to next periodic command? */ + if (strip_info->firmware_level >= StructuredMessages) + if (++strip_info->next_command >= + ARRAY_SIZE(CommandString)) + strip_info->next_command = 0; +#ifdef EXT_COUNTERS + strip_info->tx_ebytes += ts.length; +#endif + strip_info->watchdog_doprobe = jiffies + 10 * HZ; + strip_info->watchdog_doreset = jiffies + 1 * HZ; + /*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev->name); */ + } + + /* + * 3. Set up the strip_info ready to send the data (if any). + */ + strip_info->tx_head = strip_info->tx_buff; + strip_info->tx_left = ptr - strip_info->tx_buff; + set_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags); + /* + * 4. Debugging check to make sure we're not overflowing the buffer. + */ + if (strip_info->tx_size - strip_info->tx_left < 20) + printk(KERN_ERR "%s: Sending%5d bytes;%5d bytes free.\n", + strip_info->dev->name, strip_info->tx_left, + strip_info->tx_size - strip_info->tx_left); + + /* + * 5. If watchdog has expired, reset the radio. Note: if there's data waiting in + * the buffer, strip_write_some_more will send it after the reset has finished + */ + if (doreset) { + ResetRadio(strip_info); + return; + } + + if (1) { + struct in_device *in_dev; + + brd = addr = 0; + rcu_read_lock(); + in_dev = __in_dev_get_rcu(strip_info->dev); + if (in_dev) { + if (in_dev->ifa_list) { + brd = in_dev->ifa_list->ifa_broadcast; + addr = in_dev->ifa_list->ifa_local; + } + } + rcu_read_unlock(); + } + + + /* + * 6. If it is time for a periodic ARP, queue one up to be sent. + * We only do this if: + * 1. The radio is working + * 2. It's time to send another periodic ARP + * 3. We really know what our address is (and it is not manually set to zero) + * 4. We have a designated broadcast address configured + * If we queue up an ARP packet when we don't have a designated broadcast + * address configured, then the packet will just have to be discarded in + * strip_make_packet. This is not fatal, but it causes misleading information + * to be displayed in tcpdump. tcpdump will report that periodic APRs are + * being sent, when in fact they are not, because they are all being dropped + * in the strip_make_packet routine. + */ + if (strip_info->working + && (long) jiffies - strip_info->gratuitous_arp >= 0 + && memcmp(strip_info->dev->dev_addr, zero_address.c, + sizeof(zero_address)) + && arp_query(haddr.c, brd, strip_info->dev)) { + /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n", + strip_info->dev->name, strip_info->arp_interval / HZ); */ + strip_info->gratuitous_arp = + jiffies + strip_info->arp_interval; + strip_info->arp_interval *= 2; + if (strip_info->arp_interval > MaxARPInterval) + strip_info->arp_interval = MaxARPInterval; + if (addr) + arp_send(ARPOP_REPLY, ETH_P_ARP, addr, /* Target address of ARP packet is our address */ + strip_info->dev, /* Device to send packet on */ + addr, /* Source IP address this ARP packet comes from */ + NULL, /* Destination HW address is NULL (broadcast it) */ + strip_info->dev->dev_addr, /* Source HW address is our HW address */ + strip_info->dev->dev_addr); /* Target HW address is our HW address (redundant) */ + } + + /* + * 7. All ready. Start the transmission + */ + strip_write_some_more(strip_info->tty); +} + +/* Encapsulate a datagram and kick it into a TTY queue. */ +static netdev_tx_t strip_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct strip *strip_info = netdev_priv(dev); + + if (!netif_running(dev)) { + printk(KERN_ERR "%s: xmit call when iface is down\n", + dev->name); + return NETDEV_TX_BUSY; + } + + netif_stop_queue(dev); + + del_timer(&strip_info->idle_timer); + + + if (time_after(jiffies, strip_info->pps_timer + HZ)) { + unsigned long t = jiffies - strip_info->pps_timer; + unsigned long rx_pps_count = + DIV_ROUND_CLOSEST(strip_info->rx_pps_count*HZ*8, t); + unsigned long tx_pps_count = + DIV_ROUND_CLOSEST(strip_info->tx_pps_count*HZ*8, t); + unsigned long sx_pps_count = + DIV_ROUND_CLOSEST(strip_info->sx_pps_count*HZ*8, t); + + strip_info->pps_timer = jiffies; + strip_info->rx_pps_count = 0; + strip_info->tx_pps_count = 0; + strip_info->sx_pps_count = 0; + + strip_info->rx_average_pps = (strip_info->rx_average_pps + rx_pps_count + 1) / 2; + strip_info->tx_average_pps = (strip_info->tx_average_pps + tx_pps_count + 1) / 2; + strip_info->sx_average_pps = (strip_info->sx_average_pps + sx_pps_count + 1) / 2; + + if (rx_pps_count / 8 >= 10) + printk(KERN_INFO "%s: WARNING: Receiving %ld packets per second.\n", + strip_info->dev->name, rx_pps_count / 8); + if (tx_pps_count / 8 >= 10) + printk(KERN_INFO "%s: WARNING: Tx %ld packets per second.\n", + strip_info->dev->name, tx_pps_count / 8); + if (sx_pps_count / 8 >= 10) + printk(KERN_INFO "%s: WARNING: Sending %ld packets per second.\n", + strip_info->dev->name, sx_pps_count / 8); + } + + spin_lock_bh(&strip_lock); + + strip_send(strip_info, skb); + + spin_unlock_bh(&strip_lock); + + if (skb) + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +/* + * IdleTask periodically calls strip_xmit, so even when we have no IP packets + * to send for an extended period of time, the watchdog processing still gets + * done to ensure that the radio stays in Starmode + */ + +static void strip_IdleTask(unsigned long parameter) +{ + strip_xmit(NULL, (struct net_device *) parameter); +} + +/* + * Create the MAC header for an arbitrary protocol layer + * + * saddr!=NULL means use this specific address (n/a for Metricom) + * saddr==NULL means use default device source address + * daddr!=NULL means use this destination address + * daddr==NULL means leave destination address alone + * (e.g. unresolved arp -- kernel will call + * rebuild_header later to fill in the address) + */ + +static int strip_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) +{ + struct strip *strip_info = netdev_priv(dev); + STRIP_Header *header = (STRIP_Header *) skb_push(skb, sizeof(STRIP_Header)); + + /*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type, + type == ETH_P_IP ? "IP" : type == ETH_P_ARP ? "ARP" : ""); */ + + header->src_addr = strip_info->true_dev_addr; + header->protocol = htons(type); + + /*HexDump("strip_header", netdev_priv(dev), skb->data, skb->data + skb->len); */ + + if (!daddr) + return (-dev->hard_header_len); + + header->dst_addr = *(MetricomAddress *) daddr; + return (dev->hard_header_len); +} + +/* + * Rebuild the MAC header. This is called after an ARP + * (or in future other address resolution) has completed on this + * sk_buff. We now let ARP fill in the other fields. + * I think this should return zero if packet is ready to send, + * or non-zero if it needs more time to do an address lookup + */ + +static int strip_rebuild_header(struct sk_buff *skb) +{ +#ifdef CONFIG_INET + STRIP_Header *header = (STRIP_Header *) skb->data; + + /* Arp find returns zero if if knows the address, */ + /* or if it doesn't know the address it sends an ARP packet and returns non-zero */ + return arp_find(header->dst_addr.c, skb) ? 1 : 0; +#else + return 0; +#endif +} + + +/************************************************************************/ +/* Receiving routines */ + +/* + * This function parses the response to the ATS300? command, + * extracting the radio version and serial number. + */ +static void get_radio_version(struct strip *strip_info, __u8 * ptr, __u8 * end) +{ + __u8 *p, *value_begin, *value_end; + int len; + + /* Determine the beginning of the second line of the payload */ + p = ptr; + while (p < end && *p != 10) + p++; + if (p >= end) + return; + p++; + value_begin = p; + + /* Determine the end of line */ + while (p < end && *p != 10) + p++; + if (p >= end) + return; + value_end = p; + p++; + + len = value_end - value_begin; + len = min_t(int, len, sizeof(FirmwareVersion) - 1); + if (strip_info->firmware_version.c[0] == 0) + printk(KERN_INFO "%s: Radio Firmware: %.*s\n", + strip_info->dev->name, len, value_begin); + sprintf(strip_info->firmware_version.c, "%.*s", len, value_begin); + + /* Look for the first colon */ + while (p < end && *p != ':') + p++; + if (p >= end) + return; + /* Skip over the space */ + p += 2; + len = sizeof(SerialNumber) - 1; + if (p + len <= end) { + sprintf(strip_info->serial_number.c, "%.*s", len, p); + } else { + printk(KERN_DEBUG + "STRIP: radio serial number shorter (%zd) than expected (%d)\n", + end - p, len); + } +} + +/* + * This function parses the response to the ATS325? command, + * extracting the radio battery voltage. + */ +static void get_radio_voltage(struct strip *strip_info, __u8 * ptr, __u8 * end) +{ + int len; + + len = sizeof(BatteryVoltage) - 1; + if (ptr + len <= end) { + sprintf(strip_info->battery_voltage.c, "%.*s", len, ptr); + } else { + printk(KERN_DEBUG + "STRIP: radio voltage string shorter (%zd) than expected (%d)\n", + end - ptr, len); + } +} + +/* + * This function parses the responses to the AT~LA and ATS311 commands, + * which list the radio's neighbours. + */ +static void get_radio_neighbours(MetricomNodeTable * table, __u8 * ptr, __u8 * end) +{ + table->num_nodes = 0; + while (ptr < end && table->num_nodes < NODE_TABLE_SIZE) { + MetricomNode *node = &table->node[table->num_nodes++]; + char *dst = node->c, *limit = dst + sizeof(*node) - 1; + while (ptr < end && *ptr <= 32) + ptr++; + while (ptr < end && dst < limit && *ptr != 10) + *dst++ = *ptr++; + *dst++ = 0; + while (ptr < end && ptr[-1] != 10) + ptr++; + } + do_gettimeofday(&table->timestamp); +} + +static int get_radio_address(struct strip *strip_info, __u8 * p) +{ + MetricomAddress addr; + + if (string_to_radio_address(&addr, p)) + return (1); + + /* See if our radio address has changed */ + if (memcmp(strip_info->true_dev_addr.c, addr.c, sizeof(addr))) { + MetricomAddressString addr_string; + radio_address_to_string(&addr, &addr_string); + printk(KERN_INFO "%s: Radio address = %s\n", + strip_info->dev->name, addr_string.c); + strip_info->true_dev_addr = addr; + if (!strip_info->manual_dev_addr) + *(MetricomAddress *) strip_info->dev->dev_addr = + addr; + /* Give the radio a few seconds to get its head straight, then send an arp */ + strip_info->gratuitous_arp = jiffies + 15 * HZ; + strip_info->arp_interval = 1 * HZ; + } + return (0); +} + +static int verify_checksum(struct strip *strip_info) +{ + __u8 *p = strip_info->sx_buff; + __u8 *end = strip_info->sx_buff + strip_info->sx_count - 4; + u_short sum = + (READHEX16(end[0]) << 12) | (READHEX16(end[1]) << 8) | + (READHEX16(end[2]) << 4) | (READHEX16(end[3])); + while (p < end) + sum -= *p++; + if (sum == 0 && strip_info->firmware_level == StructuredMessages) { + strip_info->firmware_level = ChecksummedMessages; + printk(KERN_INFO "%s: Radio provides message checksums\n", + strip_info->dev->name); + } + return (sum == 0); +} + +static void RecvErr(char *msg, struct strip *strip_info) +{ + __u8 *ptr = strip_info->sx_buff; + __u8 *end = strip_info->sx_buff + strip_info->sx_count; + DumpData(msg, strip_info, ptr, end); + strip_info->rx_errors++; +} + +static void RecvErr_Message(struct strip *strip_info, __u8 * sendername, + const __u8 * msg, u_long len) +{ + if (has_prefix(msg, len, "001")) { /* Not in StarMode! */ + RecvErr("Error Msg:", strip_info); + printk(KERN_INFO "%s: Radio %s is not in StarMode\n", + strip_info->dev->name, sendername); + } + + else if (has_prefix(msg, len, "002")) { /* Remap handle */ + /* We ignore "Remap handle" messages for now */ + } + + else if (has_prefix(msg, len, "003")) { /* Can't resolve name */ + RecvErr("Error Msg:", strip_info); + printk(KERN_INFO "%s: Destination radio name is unknown\n", + strip_info->dev->name); + } + + else if (has_prefix(msg, len, "004")) { /* Name too small or missing */ + strip_info->watchdog_doreset = jiffies + LongTime; +#if TICKLE_TIMERS + { + struct timeval tv; + do_gettimeofday(&tv); + printk(KERN_INFO + "**** Got ERR_004 response at %02d.%06d\n", + tv.tv_sec % 100, tv.tv_usec); + } +#endif + if (!strip_info->working) { + strip_info->working = TRUE; + printk(KERN_INFO "%s: Radio now in starmode\n", + strip_info->dev->name); + /* + * If the radio has just entered a working state, we should do our first + * probe ASAP, so that we find out our radio address etc. without delay. + */ + strip_info->watchdog_doprobe = jiffies; + } + if (strip_info->firmware_level == NoStructure && sendername) { + strip_info->firmware_level = StructuredMessages; + strip_info->next_command = 0; /* Try to enable checksums ASAP */ + printk(KERN_INFO + "%s: Radio provides structured messages\n", + strip_info->dev->name); + } + if (strip_info->firmware_level >= StructuredMessages) { + /* + * If this message has a valid checksum on the end, then the call to verify_checksum + * will elevate the firmware_level to ChecksummedMessages for us. (The actual return + * code from verify_checksum is ignored here.) + */ + verify_checksum(strip_info); + /* + * If the radio has structured messages but we don't yet have all our information about it, + * we should do probes without delay, until we have gathered all the information + */ + if (!GOT_ALL_RADIO_INFO(strip_info)) + strip_info->watchdog_doprobe = jiffies; + } + } + + else if (has_prefix(msg, len, "005")) /* Bad count specification */ + RecvErr("Error Msg:", strip_info); + + else if (has_prefix(msg, len, "006")) /* Header too big */ + RecvErr("Error Msg:", strip_info); + + else if (has_prefix(msg, len, "007")) { /* Body too big */ + RecvErr("Error Msg:", strip_info); + printk(KERN_ERR + "%s: Error! Packet size too big for radio.\n", + strip_info->dev->name); + } + + else if (has_prefix(msg, len, "008")) { /* Bad character in name */ + RecvErr("Error Msg:", strip_info); + printk(KERN_ERR + "%s: Radio name contains illegal character\n", + strip_info->dev->name); + } + + else if (has_prefix(msg, len, "009")) /* No count or line terminator */ + RecvErr("Error Msg:", strip_info); + + else if (has_prefix(msg, len, "010")) /* Invalid checksum */ + RecvErr("Error Msg:", strip_info); + + else if (has_prefix(msg, len, "011")) /* Checksum didn't match */ + RecvErr("Error Msg:", strip_info); + + else if (has_prefix(msg, len, "012")) /* Failed to transmit packet */ + RecvErr("Error Msg:", strip_info); + + else + RecvErr("Error Msg:", strip_info); +} + +static void process_AT_response(struct strip *strip_info, __u8 * ptr, + __u8 * end) +{ + u_long len; + __u8 *p = ptr; + while (p < end && p[-1] != 10) + p++; /* Skip past first newline character */ + /* Now ptr points to the AT command, and p points to the text of the response. */ + len = p - ptr; + +#if TICKLE_TIMERS + { + struct timeval tv; + do_gettimeofday(&tv); + printk(KERN_INFO "**** Got AT response %.7s at %02d.%06d\n", + ptr, tv.tv_sec % 100, tv.tv_usec); + } +#endif + + if (has_prefix(ptr, len, "ATS300?")) + get_radio_version(strip_info, p, end); + else if (has_prefix(ptr, len, "ATS305?")) + get_radio_address(strip_info, p); + else if (has_prefix(ptr, len, "ATS311?")) + get_radio_neighbours(&strip_info->poletops, p, end); + else if (has_prefix(ptr, len, "ATS319=7")) + verify_checksum(strip_info); + else if (has_prefix(ptr, len, "ATS325?")) + get_radio_voltage(strip_info, p, end); + else if (has_prefix(ptr, len, "AT~LA")) + get_radio_neighbours(&strip_info->portables, p, end); + else + RecvErr("Unknown AT Response:", strip_info); +} + +static void process_ACK(struct strip *strip_info, __u8 * ptr, __u8 * end) +{ + /* Currently we don't do anything with ACKs from the radio */ +} + +static void process_Info(struct strip *strip_info, __u8 * ptr, __u8 * end) +{ + if (ptr + 16 > end) + RecvErr("Bad Info Msg:", strip_info); +} + +static struct net_device *get_strip_dev(struct strip *strip_info) +{ + /* If our hardware address is *manually set* to zero, and we know our */ + /* real radio hardware address, try to find another strip device that has been */ + /* manually set to that address that we can 'transfer ownership' of this packet to */ + if (strip_info->manual_dev_addr && + !memcmp(strip_info->dev->dev_addr, zero_address.c, + sizeof(zero_address)) + && memcmp(&strip_info->true_dev_addr, zero_address.c, + sizeof(zero_address))) { + struct net_device *dev; + read_lock_bh(&dev_base_lock); + for_each_netdev(&init_net, dev) { + if (dev->type == strip_info->dev->type && + !memcmp(dev->dev_addr, + &strip_info->true_dev_addr, + sizeof(MetricomAddress))) { + printk(KERN_INFO + "%s: Transferred packet ownership to %s.\n", + strip_info->dev->name, dev->name); + read_unlock_bh(&dev_base_lock); + return (dev); + } + } + read_unlock_bh(&dev_base_lock); + } + return (strip_info->dev); +} + +/* + * Send one completely decapsulated datagram to the next layer. + */ + +static void deliver_packet(struct strip *strip_info, STRIP_Header * header, + __u16 packetlen) +{ + struct sk_buff *skb = dev_alloc_skb(sizeof(STRIP_Header) + packetlen); + if (!skb) { + printk(KERN_ERR "%s: memory squeeze, dropping packet.\n", + strip_info->dev->name); + strip_info->rx_dropped++; + } else { + memcpy(skb_put(skb, sizeof(STRIP_Header)), header, + sizeof(STRIP_Header)); + memcpy(skb_put(skb, packetlen), strip_info->rx_buff, + packetlen); + skb->dev = get_strip_dev(strip_info); + skb->protocol = header->protocol; + skb_reset_mac_header(skb); + + /* Having put a fake header on the front of the sk_buff for the */ + /* benefit of tools like tcpdump, skb_pull now 'consumes' that */ + /* fake header before we hand the packet up to the next layer. */ + skb_pull(skb, sizeof(STRIP_Header)); + + /* Finally, hand the packet up to the next layer (e.g. IP or ARP, etc.) */ + strip_info->rx_packets++; + strip_info->rx_pps_count++; +#ifdef EXT_COUNTERS + strip_info->rx_bytes += packetlen; +#endif + netif_rx(skb); + } +} + +static void process_IP_packet(struct strip *strip_info, + STRIP_Header * header, __u8 * ptr, + __u8 * end) +{ + __u16 packetlen; + + /* Decode start of the IP packet header */ + ptr = UnStuffData(ptr, end, strip_info->rx_buff, 4); + if (!ptr) { + RecvErr("IP Packet too short", strip_info); + return; + } + + packetlen = ((__u16) strip_info->rx_buff[2] << 8) | strip_info->rx_buff[3]; + + if (packetlen > MAX_RECV_MTU) { + printk(KERN_INFO "%s: Dropping oversized received IP packet: %d bytes\n", + strip_info->dev->name, packetlen); + strip_info->rx_dropped++; + return; + } + + /*printk(KERN_INFO "%s: Got %d byte IP packet\n", strip_info->dev->name, packetlen); */ + + /* Decode remainder of the IP packet */ + ptr = + UnStuffData(ptr, end, strip_info->rx_buff + 4, packetlen - 4); + if (!ptr) { + RecvErr("IP Packet too short", strip_info); + return; + } + + if (ptr < end) { + RecvErr("IP Packet too long", strip_info); + return; + } + + header->protocol = htons(ETH_P_IP); + + deliver_packet(strip_info, header, packetlen); +} + +static void process_ARP_packet(struct strip *strip_info, + STRIP_Header * header, __u8 * ptr, + __u8 * end) +{ + __u16 packetlen; + struct arphdr *arphdr = (struct arphdr *) strip_info->rx_buff; + + /* Decode start of the ARP packet */ + ptr = UnStuffData(ptr, end, strip_info->rx_buff, 8); + if (!ptr) { + RecvErr("ARP Packet too short", strip_info); + return; + } + + packetlen = 8 + (arphdr->ar_hln + arphdr->ar_pln) * 2; + + if (packetlen > MAX_RECV_MTU) { + printk(KERN_INFO + "%s: Dropping oversized received ARP packet: %d bytes\n", + strip_info->dev->name, packetlen); + strip_info->rx_dropped++; + return; + } + + /*printk(KERN_INFO "%s: Got %d byte ARP %s\n", + strip_info->dev->name, packetlen, + ntohs(arphdr->ar_op) == ARPOP_REQUEST ? "request" : "reply"); */ + + /* Decode remainder of the ARP packet */ + ptr = + UnStuffData(ptr, end, strip_info->rx_buff + 8, packetlen - 8); + if (!ptr) { + RecvErr("ARP Packet too short", strip_info); + return; + } + + if (ptr < end) { + RecvErr("ARP Packet too long", strip_info); + return; + } + + header->protocol = htons(ETH_P_ARP); + + deliver_packet(strip_info, header, packetlen); +} + +/* + * process_text_message processes a -terminated block of data received + * from the radio that doesn't begin with a '*' character. All normal + * Starmode communication messages with the radio begin with a '*', + * so any text that does not indicates a serial port error, a radio that + * is in Hayes command mode instead of Starmode, or a radio with really + * old firmware that doesn't frame its Starmode responses properly. + */ +static void process_text_message(struct strip *strip_info) +{ + __u8 *msg = strip_info->sx_buff; + int len = strip_info->sx_count; + + /* Check for anything that looks like it might be our radio name */ + /* (This is here for backwards compatibility with old firmware) */ + if (len == 9 && get_radio_address(strip_info, msg) == 0) + return; + + if (text_equal(msg, len, "OK")) + return; /* Ignore 'OK' responses from prior commands */ + if (text_equal(msg, len, "ERROR")) + return; /* Ignore 'ERROR' messages */ + if (has_prefix(msg, len, "ate0q1")) + return; /* Ignore character echo back from the radio */ + + /* Catch other error messages */ + /* (This is here for backwards compatibility with old firmware) */ + if (has_prefix(msg, len, "ERR_")) { + RecvErr_Message(strip_info, NULL, &msg[4], len - 4); + return; + } + + RecvErr("No initial *", strip_info); +} + +/* + * process_message processes a -terminated block of data received + * from the radio. If the radio is not in Starmode or has old firmware, + * it may be a line of text in response to an AT command. Ideally, with + * a current radio that's properly in Starmode, all data received should + * be properly framed and checksummed radio message blocks, containing + * either a starmode packet, or a other communication from the radio + * firmware, like "INF_" Info messages and &COMMAND responses. + */ +static void process_message(struct strip *strip_info) +{ + STRIP_Header header = { zero_address, zero_address, 0 }; + __u8 *ptr = strip_info->sx_buff; + __u8 *end = strip_info->sx_buff + strip_info->sx_count; + __u8 sendername[32], *sptr = sendername; + MetricomKey key; + + /*HexDump("Receiving", strip_info, ptr, end); */ + + /* Check for start of address marker, and then skip over it */ + if (*ptr == '*') + ptr++; + else { + process_text_message(strip_info); + return; + } + + /* Copy out the return address */ + while (ptr < end && *ptr != '*' + && sptr < ARRAY_END(sendername) - 1) + *sptr++ = *ptr++; + *sptr = 0; /* Null terminate the sender name */ + + /* Check for end of address marker, and skip over it */ + if (ptr >= end || *ptr != '*') { + RecvErr("No second *", strip_info); + return; + } + ptr++; /* Skip the second '*' */ + + /* If the sender name is "&COMMAND", ignore this 'packet' */ + /* (This is here for backwards compatibility with old firmware) */ + if (!strcmp(sendername, "&COMMAND")) { + strip_info->firmware_level = NoStructure; + strip_info->next_command = CompatibilityCommand; + return; + } + + if (ptr + 4 > end) { + RecvErr("No proto key", strip_info); + return; + } + + /* Get the protocol key out of the buffer */ + key.c[0] = *ptr++; + key.c[1] = *ptr++; + key.c[2] = *ptr++; + key.c[3] = *ptr++; + + /* If we're using checksums, verify the checksum at the end of the packet */ + if (strip_info->firmware_level >= ChecksummedMessages) { + end -= 4; /* Chop the last four bytes off the packet (they're the checksum) */ + if (ptr > end) { + RecvErr("Missing Checksum", strip_info); + return; + } + if (!verify_checksum(strip_info)) { + RecvErr("Bad Checksum", strip_info); + return; + } + } + + /*printk(KERN_INFO "%s: Got packet from \"%s\".\n", strip_info->dev->name, sendername); */ + + /* + * Fill in (pseudo) source and destination addresses in the packet. + * We assume that the destination address was our address (the radio does not + * tell us this). If the radio supplies a source address, then we use it. + */ + header.dst_addr = strip_info->true_dev_addr; + string_to_radio_address(&header.src_addr, sendername); + +#ifdef EXT_COUNTERS + if (key.l == SIP0Key.l) { + strip_info->rx_rbytes += (end - ptr); + process_IP_packet(strip_info, &header, ptr, end); + } else if (key.l == ARP0Key.l) { + strip_info->rx_rbytes += (end - ptr); + process_ARP_packet(strip_info, &header, ptr, end); + } else if (key.l == ATR_Key.l) { + strip_info->rx_ebytes += (end - ptr); + process_AT_response(strip_info, ptr, end); + } else if (key.l == ACK_Key.l) { + strip_info->rx_ebytes += (end - ptr); + process_ACK(strip_info, ptr, end); + } else if (key.l == INF_Key.l) { + strip_info->rx_ebytes += (end - ptr); + process_Info(strip_info, ptr, end); + } else if (key.l == ERR_Key.l) { + strip_info->rx_ebytes += (end - ptr); + RecvErr_Message(strip_info, sendername, ptr, end - ptr); + } else + RecvErr("Unrecognized protocol key", strip_info); +#else + if (key.l == SIP0Key.l) + process_IP_packet(strip_info, &header, ptr, end); + else if (key.l == ARP0Key.l) + process_ARP_packet(strip_info, &header, ptr, end); + else if (key.l == ATR_Key.l) + process_AT_response(strip_info, ptr, end); + else if (key.l == ACK_Key.l) + process_ACK(strip_info, ptr, end); + else if (key.l == INF_Key.l) + process_Info(strip_info, ptr, end); + else if (key.l == ERR_Key.l) + RecvErr_Message(strip_info, sendername, ptr, end - ptr); + else + RecvErr("Unrecognized protocol key", strip_info); +#endif +} + +#define TTYERROR(X) ((X) == TTY_BREAK ? "Break" : \ + (X) == TTY_FRAME ? "Framing Error" : \ + (X) == TTY_PARITY ? "Parity Error" : \ + (X) == TTY_OVERRUN ? "Hardware Overrun" : "Unknown Error") + +/* + * Handle the 'receiver data ready' interrupt. + * This function is called by the 'tty_io' module in the kernel when + * a block of STRIP data has been received, which can now be decapsulated + * and sent on to some IP layer for further processing. + */ + +static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) +{ + struct strip *strip_info = tty->disc_data; + const unsigned char *end = cp + count; + + if (!strip_info || strip_info->magic != STRIP_MAGIC + || !netif_running(strip_info->dev)) + return; + + spin_lock_bh(&strip_lock); +#if 0 + { + struct timeval tv; + do_gettimeofday(&tv); + printk(KERN_INFO + "**** strip_receive_buf: %3d bytes at %02d.%06d\n", + count, tv.tv_sec % 100, tv.tv_usec); + } +#endif + +#ifdef EXT_COUNTERS + strip_info->rx_sbytes += count; +#endif + + /* Read the characters out of the buffer */ + while (cp < end) { + if (fp && *fp) + printk(KERN_INFO "%s: %s on serial port\n", + strip_info->dev->name, TTYERROR(*fp)); + if (fp && *fp++ && !strip_info->discard) { /* If there's a serial error, record it */ + /* If we have some characters in the buffer, discard them */ + strip_info->discard = strip_info->sx_count; + strip_info->rx_errors++; + } + + /* Leading control characters (CR, NL, Tab, etc.) are ignored */ + if (strip_info->sx_count > 0 || *cp >= ' ') { + if (*cp == 0x0D) { /* If end of packet, decide what to do with it */ + if (strip_info->sx_count > 3000) + printk(KERN_INFO + "%s: Cut a %d byte packet (%zd bytes remaining)%s\n", + strip_info->dev->name, + strip_info->sx_count, + end - cp - 1, + strip_info-> + discard ? " (discarded)" : + ""); + if (strip_info->sx_count > + strip_info->sx_size) { + strip_info->rx_over_errors++; + printk(KERN_INFO + "%s: sx_buff overflow (%d bytes total)\n", + strip_info->dev->name, + strip_info->sx_count); + } else if (strip_info->discard) + printk(KERN_INFO + "%s: Discarding bad packet (%d/%d)\n", + strip_info->dev->name, + strip_info->discard, + strip_info->sx_count); + else + process_message(strip_info); + strip_info->discard = 0; + strip_info->sx_count = 0; + } else { + /* Make sure we have space in the buffer */ + if (strip_info->sx_count < + strip_info->sx_size) + strip_info->sx_buff[strip_info-> + sx_count] = + *cp; + strip_info->sx_count++; + } + } + cp++; + } + spin_unlock_bh(&strip_lock); +} + + +/************************************************************************/ +/* General control routines */ + +static int set_mac_address(struct strip *strip_info, + MetricomAddress * addr) +{ + /* + * We're using a manually specified address if the address is set + * to anything other than all ones. Setting the address to all ones + * disables manual mode and goes back to automatic address determination + * (tracking the true address that the radio has). + */ + strip_info->manual_dev_addr = + memcmp(addr->c, broadcast_address.c, + sizeof(broadcast_address)); + if (strip_info->manual_dev_addr) + *(MetricomAddress *) strip_info->dev->dev_addr = *addr; + else + *(MetricomAddress *) strip_info->dev->dev_addr = + strip_info->true_dev_addr; + return 0; +} + +static int strip_set_mac_address(struct net_device *dev, void *addr) +{ + struct strip *strip_info = netdev_priv(dev); + struct sockaddr *sa = addr; + printk(KERN_INFO "%s: strip_set_dev_mac_address called\n", dev->name); + set_mac_address(strip_info, (MetricomAddress *) sa->sa_data); + return 0; +} + +static struct net_device_stats *strip_get_stats(struct net_device *dev) +{ + struct strip *strip_info = netdev_priv(dev); + static struct net_device_stats stats; + + memset(&stats, 0, sizeof(struct net_device_stats)); + + stats.rx_packets = strip_info->rx_packets; + stats.tx_packets = strip_info->tx_packets; + stats.rx_dropped = strip_info->rx_dropped; + stats.tx_dropped = strip_info->tx_dropped; + stats.tx_errors = strip_info->tx_errors; + stats.rx_errors = strip_info->rx_errors; + stats.rx_over_errors = strip_info->rx_over_errors; + return (&stats); +} + + +/************************************************************************/ +/* Opening and closing */ + +/* + * Here's the order things happen: + * When the user runs "slattach -p strip ..." + * 1. The TTY module calls strip_open;; + * 2. strip_open calls strip_alloc + * 3. strip_alloc calls register_netdev + * 4. register_netdev calls strip_dev_init + * 5. then strip_open finishes setting up the strip_info + * + * When the user runs "ifconfig st up address netmask ..." + * 6. strip_open_low gets called + * + * When the user runs "ifconfig st down" + * 7. strip_close_low gets called + * + * When the user kills the slattach process + * 8. strip_close gets called + * 9. strip_close calls dev_close + * 10. if the device is still up, then dev_close calls strip_close_low + * 11. strip_close calls strip_free + */ + +/* Open the low-level part of the STRIP channel. Easy! */ + +static int strip_open_low(struct net_device *dev) +{ + struct strip *strip_info = netdev_priv(dev); + + if (strip_info->tty == NULL) + return (-ENODEV); + + if (!allocate_buffers(strip_info, dev->mtu)) + return (-ENOMEM); + + strip_info->sx_count = 0; + strip_info->tx_left = 0; + + strip_info->discard = 0; + strip_info->working = FALSE; + strip_info->firmware_level = NoStructure; + strip_info->next_command = CompatibilityCommand; + strip_info->user_baud = tty_get_baud_rate(strip_info->tty); + + printk(KERN_INFO "%s: Initializing Radio.\n", + strip_info->dev->name); + ResetRadio(strip_info); + strip_info->idle_timer.expires = jiffies + 1 * HZ; + add_timer(&strip_info->idle_timer); + netif_wake_queue(dev); + return (0); +} + + +/* + * Close the low-level part of the STRIP channel. Easy! + */ + +static int strip_close_low(struct net_device *dev) +{ + struct strip *strip_info = netdev_priv(dev); + + if (strip_info->tty == NULL) + return -EBUSY; + clear_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags); + netif_stop_queue(dev); + + /* + * Free all STRIP frame buffers. + */ + kfree(strip_info->rx_buff); + strip_info->rx_buff = NULL; + kfree(strip_info->sx_buff); + strip_info->sx_buff = NULL; + kfree(strip_info->tx_buff); + strip_info->tx_buff = NULL; + + del_timer(&strip_info->idle_timer); + return 0; +} + +static const struct header_ops strip_header_ops = { + .create = strip_header, + .rebuild = strip_rebuild_header, +}; + + +static const struct net_device_ops strip_netdev_ops = { + .ndo_open = strip_open_low, + .ndo_stop = strip_close_low, + .ndo_start_xmit = strip_xmit, + .ndo_set_mac_address = strip_set_mac_address, + .ndo_get_stats = strip_get_stats, + .ndo_change_mtu = strip_change_mtu, +}; + +/* + * This routine is called by DDI when the + * (dynamically assigned) device is registered + */ + +static void strip_dev_setup(struct net_device *dev) +{ + /* + * Finish setting up the DEVICE info. + */ + + dev->trans_start = 0; + dev->tx_queue_len = 30; /* Drop after 30 frames queued */ + + dev->flags = 0; + dev->mtu = DEFAULT_STRIP_MTU; + dev->type = ARPHRD_METRICOM; /* dtang */ + dev->hard_header_len = sizeof(STRIP_Header); + /* + * netdev_priv(dev) Already holds a pointer to our struct strip + */ + + *(MetricomAddress *)dev->broadcast = broadcast_address; + dev->dev_addr[0] = 0; + dev->addr_len = sizeof(MetricomAddress); + + dev->header_ops = &strip_header_ops, + dev->netdev_ops = &strip_netdev_ops; +} + +/* + * Free a STRIP channel. + */ + +static void strip_free(struct strip *strip_info) +{ + spin_lock_bh(&strip_lock); + list_del_rcu(&strip_info->list); + spin_unlock_bh(&strip_lock); + + strip_info->magic = 0; + + free_netdev(strip_info->dev); +} + + +/* + * Allocate a new free STRIP channel + */ +static struct strip *strip_alloc(void) +{ + struct list_head *n; + struct net_device *dev; + struct strip *strip_info; + + dev = alloc_netdev(sizeof(struct strip), "st%d", + strip_dev_setup); + + if (!dev) + return NULL; /* If no more memory, return */ + + + strip_info = netdev_priv(dev); + strip_info->dev = dev; + + strip_info->magic = STRIP_MAGIC; + strip_info->tty = NULL; + + strip_info->gratuitous_arp = jiffies + LongTime; + strip_info->arp_interval = 0; + init_timer(&strip_info->idle_timer); + strip_info->idle_timer.data = (long) dev; + strip_info->idle_timer.function = strip_IdleTask; + + + spin_lock_bh(&strip_lock); + rescan: + /* + * Search the list to find where to put our new entry + * (and in the process decide what channel number it is + * going to be) + */ + list_for_each(n, &strip_list) { + struct strip *s = hlist_entry(n, struct strip, list); + + if (s->dev->base_addr == dev->base_addr) { + ++dev->base_addr; + goto rescan; + } + } + + sprintf(dev->name, "st%ld", dev->base_addr); + + list_add_tail_rcu(&strip_info->list, &strip_list); + spin_unlock_bh(&strip_lock); + + return strip_info; +} + +/* + * Open the high-level part of the STRIP channel. + * This function is called by the TTY module when the + * STRIP line discipline is called for. Because we are + * sure the tty line exists, we only have to link it to + * a free STRIP channel... + */ + +static int strip_open(struct tty_struct *tty) +{ + struct strip *strip_info = tty->disc_data; + + /* + * First make sure we're not already connected. + */ + + if (strip_info && strip_info->magic == STRIP_MAGIC) + return -EEXIST; + + /* + * We need a write method. + */ + + if (tty->ops->write == NULL || tty->ops->set_termios == NULL) + return -EOPNOTSUPP; + + /* + * OK. Find a free STRIP channel to use. + */ + if ((strip_info = strip_alloc()) == NULL) + return -ENFILE; + + /* + * Register our newly created device so it can be ifconfig'd + * strip_dev_init() will be called as a side-effect + */ + + if (register_netdev(strip_info->dev) != 0) { + printk(KERN_ERR "strip: register_netdev() failed.\n"); + strip_free(strip_info); + return -ENFILE; + } + + strip_info->tty = tty; + tty->disc_data = strip_info; + tty->receive_room = 65536; + + tty_driver_flush_buffer(tty); + + /* + * Restore default settings + */ + + strip_info->dev->type = ARPHRD_METRICOM; /* dtang */ + + /* + * Set tty options + */ + + tty->termios->c_iflag |= IGNBRK | IGNPAR; /* Ignore breaks and parity errors. */ + tty->termios->c_cflag |= CLOCAL; /* Ignore modem control signals. */ + tty->termios->c_cflag &= ~HUPCL; /* Don't close on hup */ + + printk(KERN_INFO "STRIP: device \"%s\" activated\n", + strip_info->dev->name); + + /* + * Done. We have linked the TTY line to a channel. + */ + return (strip_info->dev->base_addr); +} + +/* + * Close down a STRIP channel. + * This means flushing out any pending queues, and then restoring the + * TTY line discipline to what it was before it got hooked to STRIP + * (which usually is TTY again). + */ + +static void strip_close(struct tty_struct *tty) +{ + struct strip *strip_info = tty->disc_data; + + /* + * First make sure we're connected. + */ + + if (!strip_info || strip_info->magic != STRIP_MAGIC) + return; + + unregister_netdev(strip_info->dev); + + tty->disc_data = NULL; + strip_info->tty = NULL; + printk(KERN_INFO "STRIP: device \"%s\" closed down\n", + strip_info->dev->name); + strip_free(strip_info); + tty->disc_data = NULL; +} + + +/************************************************************************/ +/* Perform I/O control calls on an active STRIP channel. */ + +static int strip_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct strip *strip_info = tty->disc_data; + + /* + * First make sure we're connected. + */ + + if (!strip_info || strip_info->magic != STRIP_MAGIC) + return -EINVAL; + + switch (cmd) { + case SIOCGIFNAME: + if(copy_to_user((void __user *) arg, strip_info->dev->name, strlen(strip_info->dev->name) + 1)) + return -EFAULT; + break; + case SIOCSIFHWADDR: + { + MetricomAddress addr; + //printk(KERN_INFO "%s: SIOCSIFHWADDR\n", strip_info->dev->name); + if(copy_from_user(&addr, (void __user *) arg, sizeof(MetricomAddress))) + return -EFAULT; + return set_mac_address(strip_info, &addr); + } + default: + return tty_mode_ioctl(tty, file, cmd, arg); + break; + } + return 0; +} + + +/************************************************************************/ +/* Initialization */ + +static struct tty_ldisc_ops strip_ldisc = { + .magic = TTY_LDISC_MAGIC, + .name = "strip", + .owner = THIS_MODULE, + .open = strip_open, + .close = strip_close, + .ioctl = strip_ioctl, + .receive_buf = strip_receive_buf, + .write_wakeup = strip_write_some_more, +}; + +/* + * Initialize the STRIP driver. + * This routine is called at boot time, to bootstrap the multi-channel + * STRIP driver + */ + +static char signon[] __initdata = + KERN_INFO "STRIP: Version %s (unlimited channels)\n"; + +static int __init strip_init_driver(void) +{ + int status; + + printk(signon, StripVersion); + + + /* + * Fill in our line protocol discipline, and register it + */ + if ((status = tty_register_ldisc(N_STRIP, &strip_ldisc))) + printk(KERN_ERR "STRIP: can't register line discipline (err = %d)\n", + status); + + /* + * Register the status file with /proc + */ + proc_net_fops_create(&init_net, "strip", S_IFREG | S_IRUGO, &strip_seq_fops); + + return status; +} + +module_init(strip_init_driver); + +static const char signoff[] __exitdata = + KERN_INFO "STRIP: Module Unloaded\n"; + +static void __exit strip_exit_driver(void) +{ + int i; + struct list_head *p,*n; + + /* module ref count rules assure that all entries are unregistered */ + list_for_each_safe(p, n, &strip_list) { + struct strip *s = list_entry(p, struct strip, list); + strip_free(s); + } + + /* Unregister with the /proc/net file here. */ + proc_net_remove(&init_net, "strip"); + + if ((i = tty_unregister_ldisc(N_STRIP))) + printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i); + + printk(signoff); +} + +module_exit(strip_exit_driver); + +MODULE_AUTHOR("Stuart Cheshire "); +MODULE_DESCRIPTION("Starmode Radio IP (STRIP) Device Driver"); +MODULE_LICENSE("Dual BSD/GPL"); + +MODULE_SUPPORTED_DEVICE("Starmode Radio IP (STRIP) modem"); -- cgit v1.2.3 From e38879efd336fb78b288dcebdc9ca030fd24f449 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 20 Oct 2009 13:53:08 +0900 Subject: arlan: move driver to staging Move the arlan driver to drivers/staging. This is another pre-802.11 driver that has seen virtually no non-API-fixup activity in years, and for which no active hardware is likely to still exist. This driver represents unnecessary ongoing maintenance for no clear benefit. This patch brought to you by the "hacking" session at the 2009 Kernel Summit in Tokyo, Japan... Acked-by: Greg Kroah-Hartman Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 16 - drivers/net/wireless/Makefile | 4 - drivers/net/wireless/arlan-main.c | 1887 ------------------------------------ drivers/net/wireless/arlan-proc.c | 1253 ------------------------ drivers/net/wireless/arlan.h | 539 ---------- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/arlan/Kconfig | 15 + drivers/staging/arlan/Makefile | 3 + drivers/staging/arlan/arlan-main.c | 1887 ++++++++++++++++++++++++++++++++++++ drivers/staging/arlan/arlan-proc.c | 1253 ++++++++++++++++++++++++ drivers/staging/arlan/arlan.h | 539 ++++++++++ 12 files changed, 3700 insertions(+), 3699 deletions(-) delete mode 100644 drivers/net/wireless/arlan-main.c delete mode 100644 drivers/net/wireless/arlan-proc.c delete mode 100644 drivers/net/wireless/arlan.h create mode 100644 drivers/staging/arlan/Kconfig create mode 100644 drivers/staging/arlan/Makefile create mode 100644 drivers/staging/arlan/arlan-main.c create mode 100644 drivers/staging/arlan/arlan-proc.c create mode 100644 drivers/staging/arlan/arlan.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 5df47486e358..d50b3bee9a9b 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -25,22 +25,6 @@ menuconfig WLAN_PRE80211 This option does not affect the kernel build, it only lets you choose drivers. -config ARLAN - tristate "Aironet Arlan 655 & IC2200 DS support" - depends on ISA && !64BIT && WLAN_PRE80211 - select WIRELESS_EXT - ---help--- - Aironet makes Arlan, a class of wireless LAN adapters. These use the - www.Telxon.com chip, which is also used on several similar cards. - This driver is tested on the 655 and IC2200 series cards. Look at - for the latest information. - - The driver is built as two modules, arlan and arlan-proc. The latter - is the /proc interface and is not needed most of time. - - On some computers the card ends up in non-valid state after some - time. Use a ping-reset script to clear it. - config WAVELAN tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support" depends on ISA && WLAN_PRE80211 diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 527c272aa1af..b56c70f4ca75 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -5,10 +5,6 @@ obj-$(CONFIG_IPW2100) += ipw2x00/ obj-$(CONFIG_IPW2200) += ipw2x00/ -obj-$(CONFIG_ARLAN) += arlan.o - -arlan-objs := arlan-main.o arlan-proc.o - # Obsolete cards obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c deleted file mode 100644 index 921a082487a1..000000000000 --- a/drivers/net/wireless/arlan-main.c +++ /dev/null @@ -1,1887 +0,0 @@ -/* - * Copyright (C) 1997 Cullen Jennings - * Copyright (C) 1998 Elmer Joandiu, elmer@ylenurme.ee - * GNU General Public License applies - * This module provides support for the Arlan 655 card made by Aironet - */ - -#include "arlan.h" - -#if BITS_PER_LONG != 32 -# error FIXME: this driver requires a 32-bit platform -#endif - -static const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee Oct'98, http://www.ylenurme.ee/~elmer/655/"; - -struct net_device *arlan_device[MAX_ARLANS]; - -static int SID = SIDUNKNOWN; -static int radioNodeId = radioNodeIdUNKNOWN; -static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; -int arlan_debug = debugUNKNOWN; -static int spreadingCode = spreadingCodeUNKNOWN; -static int channelNumber = channelNumberUNKNOWN; -static int channelSet = channelSetUNKNOWN; -static int systemId = systemIdUNKNOWN; -static int registrationMode = registrationModeUNKNOWN; -static int keyStart; -static int tx_delay_ms; -static int retries = 5; -static int tx_queue_len = 1; -static int arlan_EEPROM_bad; - -#ifdef ARLAN_DEBUGGING - -static int testMemory = testMemoryUNKNOWN; -static int irq = irqUNKNOWN; -static int txScrambled = 1; -static int mdebug; - -module_param(irq, int, 0); -module_param(mdebug, int, 0); -module_param(testMemory, int, 0); -module_param(txScrambled, int, 0); -MODULE_PARM_DESC(irq, "(unused)"); -MODULE_PARM_DESC(testMemory, "(unused)"); -MODULE_PARM_DESC(mdebug, "Arlan multicast debugging (0-1)"); -#endif - -module_param_named(debug, arlan_debug, int, 0); -module_param(spreadingCode, int, 0); -module_param(channelNumber, int, 0); -module_param(channelSet, int, 0); -module_param(systemId, int, 0); -module_param(registrationMode, int, 0); -module_param(radioNodeId, int, 0); -module_param(SID, int, 0); -module_param(keyStart, int, 0); -module_param(tx_delay_ms, int, 0); -module_param(retries, int, 0); -module_param(tx_queue_len, int, 0); -module_param_named(EEPROM_bad, arlan_EEPROM_bad, int, 0); -MODULE_PARM_DESC(debug, "Arlan debug enable (0-1)"); -MODULE_PARM_DESC(retries, "Arlan maximum packet retransmisions"); -#ifdef ARLAN_ENTRY_EXIT_DEBUGGING -static int arlan_entry_debug; -static int arlan_exit_debug; -static int arlan_entry_and_exit_debug; -module_param_named(entry_debug, arlan_entry_debug, int, 0); -module_param_named(exit_debug, arlan_exit_debug, int, 0); -module_param_named(entry_and_exit_debug, arlan_entry_and_exit_debug, int, 0); -MODULE_PARM_DESC(entry_debug, "Arlan driver function entry debugging"); -MODULE_PARM_DESC(exit_debug, "Arlan driver function exit debugging"); -MODULE_PARM_DESC(entry_and_exit_debug, "Arlan driver function entry and exit debugging"); -#endif - -struct arlan_conf_stru arlan_conf[MAX_ARLANS]; -static int arlans_found; - -static int arlan_open(struct net_device *dev); -static netdev_tx_t arlan_tx(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t arlan_interrupt(int irq, void *dev_id); -static int arlan_close(struct net_device *dev); -static struct net_device_stats * - arlan_statistics (struct net_device *dev); -static void arlan_set_multicast (struct net_device *dev); -static int arlan_hw_tx (struct net_device* dev, char *buf, int length ); -static int arlan_hw_config (struct net_device * dev); -static void arlan_tx_done_interrupt (struct net_device * dev, int status); -static void arlan_rx_interrupt (struct net_device * dev, u_char rxStatus, u_short, u_short); -static void arlan_process_interrupt (struct net_device * dev); -static void arlan_tx_timeout (struct net_device *dev); - -static inline long us2ticks(int us) -{ - return us * (1000000 / HZ); -} - - -#ifdef ARLAN_ENTRY_EXIT_DEBUGGING -#define ARLAN_DEBUG_ENTRY(name) \ - {\ - struct timeval timev;\ - do_gettimeofday(&timev);\ - if (arlan_entry_debug || arlan_entry_and_exit_debug)\ - printk("--->>>" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec));\ - } -#define ARLAN_DEBUG_EXIT(name) \ - {\ - struct timeval timev;\ - do_gettimeofday(&timev);\ - if (arlan_exit_debug || arlan_entry_and_exit_debug)\ - printk("<<<---" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec) );\ - } -#else -#define ARLAN_DEBUG_ENTRY(name) -#define ARLAN_DEBUG_EXIT(name) -#endif - - -#define arlan_interrupt_ack(dev)\ - clearClearInterrupt(dev);\ - setClearInterrupt(dev); - -static inline int arlan_drop_tx(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - - dev->stats.tx_errors++; - if (priv->Conf->tx_delay_ms) - { - priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1; - } - else - { - priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; - TXHEAD(dev).offset = 0; - TXTAIL(dev).offset = 0; - priv->txLast = 0; - priv->bad = 0; - if (!priv->under_reset && !priv->under_config) - netif_wake_queue (dev); - } - return 1; -} - - -int arlan_command(struct net_device *dev, int command_p) -{ - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - struct arlan_conf_stru *conf = priv->Conf; - int udelayed = 0; - int i = 0; - unsigned long flags; - - ARLAN_DEBUG_ENTRY("arlan_command"); - - if (priv->card_polling_interval) - priv->card_polling_interval = 1; - - if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) - printk(KERN_DEBUG "arlan_command, %lx commandByte %x waiting %lx incoming %x \n", - jiffies, READSHMB(arlan->commandByte), - priv->waiting_command_mask, command_p); - - priv->waiting_command_mask |= command_p; - - if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) - if (time_after(jiffies, priv->lastReset + 5 * HZ)) - priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; - - if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ACK) - { - arlan_interrupt_ack(dev); - priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ACK; - } - if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ENABLE) - { - setInterruptEnable(dev); - priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ENABLE; - } - - /* Card access serializing lock */ - spin_lock_irqsave(&priv->lock, flags); - - /* Check cards status and waiting */ - - if (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) - { - while (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) - { - if (READSHMB(arlan->resetFlag) || - READSHMB(arlan->commandByte)) /* || - (readControlRegister(dev) & ARLAN_ACCESS)) - */ - udelay(40); - else - priv->waiting_command_mask &= ~(ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW); - - udelayed++; - - if (priv->waiting_command_mask & ARLAN_COMMAND_LONG_WAIT_NOW) - { - if (udelayed * 40 > 1000000) - { - printk(KERN_ERR "%s long wait too long \n", dev->name); - priv->waiting_command_mask |= ARLAN_COMMAND_RESET; - break; - } - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_WAIT_NOW) - { - if (udelayed * 40 > 1000) - { - printk(KERN_ERR "%s short wait too long \n", dev->name); - goto bad_end; - } - } - } - } - else - { - i = 0; - while ((READSHMB(arlan->resetFlag) || - READSHMB(arlan->commandByte)) && - conf->pre_Command_Wait > (i++) * 10) - udelay(10); - - - if ((READSHMB(arlan->resetFlag) || - READSHMB(arlan->commandByte)) && - !(priv->waiting_command_mask & ARLAN_COMMAND_RESET)) - { - goto card_busy_end; - } - } - if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) - priv->under_reset = 1; - if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) - priv->under_config = 1; - - /* Issuing command */ - arlan_lock_card_access(dev); - if (priv->waiting_command_mask & ARLAN_COMMAND_POWERUP) - { - // if (readControlRegister(dev) & (ARLAN_ACCESS && ARLAN_POWER)) - setPowerOn(dev); - arlan_interrupt_lancpu(dev); - priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERUP; - priv->waiting_command_mask |= ARLAN_COMMAND_RESET; - priv->card_polling_interval = HZ / 10; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_ACTIVATE) - { - WRITESHMB(arlan->commandByte, ARLAN_COM_ACTIVATE); - arlan_interrupt_lancpu(dev); - priv->waiting_command_mask &= ~ARLAN_COMMAND_ACTIVATE; - priv->card_polling_interval = HZ / 10; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_RX_ABORT) - { - if (priv->rx_command_given) - { - WRITESHMB(arlan->commandByte, ARLAN_COM_RX_ABORT); - arlan_interrupt_lancpu(dev); - priv->rx_command_given = 0; - } - priv->waiting_command_mask &= ~ARLAN_COMMAND_RX_ABORT; - priv->card_polling_interval = 1; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_TX_ABORT) - { - if (priv->tx_command_given) - { - WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ABORT); - arlan_interrupt_lancpu(dev); - priv->tx_command_given = 0; - } - priv->waiting_command_mask &= ~ARLAN_COMMAND_TX_ABORT; - priv->card_polling_interval = 1; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) - { - priv->under_reset=1; - netif_stop_queue (dev); - - arlan_drop_tx(dev); - if (priv->tx_command_given || priv->rx_command_given) - { - printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); - } - netif_stop_queue (dev); - if (arlan_debug & ARLAN_DEBUG_RESET) - printk(KERN_ERR "%s: Doing chip reset\n", dev->name); - priv->lastReset = jiffies; - WRITESHM(arlan->commandByte, 0, u_char); - /* hold card in reset state */ - setHardwareReset(dev); - /* set reset flag and then release reset */ - WRITESHM(arlan->resetFlag, 0xff, u_char); - clearChannelAttention(dev); - clearHardwareReset(dev); - priv->card_polling_interval = HZ / 4; - priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; - priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; -// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RENABLE; -// priv->waiting_command_mask |= ARLAN_COMMAND_RX; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RACK) - { - clearHardwareReset(dev); - clearClearInterrupt(dev); - setClearInterrupt(dev); - setInterruptEnable(dev); - priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RACK; - priv->waiting_command_mask |= ARLAN_COMMAND_CONF; - priv->under_config = 1; - priv->under_reset = 0; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RENABLE) - { - setInterruptEnable(dev); - priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RENABLE; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) - { - if (priv->tx_command_given || priv->rx_command_given) - { - printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); - } - arlan_drop_tx(dev); - setInterruptEnable(dev); - arlan_hw_config(dev); - arlan_interrupt_lancpu(dev); - priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF; - priv->card_polling_interval = HZ / 10; -// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; -// priv->waiting_command_mask |= ARLAN_COMMAND_INT_ENABLE; - priv->waiting_command_mask |= ARLAN_COMMAND_CONF_WAIT; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF_WAIT) - { - if (READSHMB(arlan->configuredStatusFlag) != 0 && - READSHMB(arlan->diagnosticInfo) == 0xff) - { - priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF_WAIT; - priv->waiting_command_mask |= ARLAN_COMMAND_RX; - priv->waiting_command_mask |= ARLAN_COMMAND_TBUSY_CLEAR; - priv->card_polling_interval = HZ / 10; - priv->tx_command_given = 0; - priv->under_config = 0; - } - else - { - priv->card_polling_interval = 1; - if (arlan_debug & ARLAN_DEBUG_TIMING) - printk(KERN_ERR "configure delayed \n"); - } - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_RX) - { - if (!registrationBad(dev)) - { - setInterruptEnable(dev); - memset_io(arlan->commandParameter, 0, 0xf); - WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_RX_ENABLE); - WRITESHMB(arlan->commandParameter[0], conf->rxParameter); - arlan_interrupt_lancpu(dev); - priv->rx_command_given = 0; // mnjah, bad - priv->waiting_command_mask &= ~ARLAN_COMMAND_RX; - priv->card_polling_interval = 1; - } - else - priv->card_polling_interval = 2; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_TBUSY_CLEAR) - { - if ( !registrationBad(dev) && - (netif_queue_stopped(dev) || !netif_running(dev)) ) - { - priv->waiting_command_mask &= ~ARLAN_COMMAND_TBUSY_CLEAR; - netif_wake_queue (dev); - } - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_TX) - { - if (!test_and_set_bit(0, (void *) &priv->tx_command_given)) - { - if (time_after(jiffies, - priv->tx_last_sent + us2ticks(conf->rx_tweak1)) - || time_before(jiffies, - priv->last_rx_int_ack_time + us2ticks(conf->rx_tweak2))) - { - setInterruptEnable(dev); - memset_io(arlan->commandParameter, 0, 0xf); - WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ENABLE | ARLAN_COM_INT); - memcpy_toio(arlan->commandParameter, &TXLAST(dev), 14); -// for ( i=1 ; i < 15 ; i++) printk("%02x:",READSHMB(arlan->commandParameter[i])); - priv->tx_last_sent = jiffies; - arlan_interrupt_lancpu(dev); - priv->tx_command_given = 1; - priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; - priv->card_polling_interval = 1; - } - else - { - priv->tx_command_given = 0; - priv->card_polling_interval = 1; - } - } - else if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) - printk(KERN_ERR "tx command when tx chain locked \n"); - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOPINT) - { - { - WRITESHMB(arlan->commandByte, ARLAN_COM_NOP | ARLAN_COM_INT); - } - arlan_interrupt_lancpu(dev); - priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOPINT; - priv->card_polling_interval = HZ / 3; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOP) - { - WRITESHMB(arlan->commandByte, ARLAN_COM_NOP); - arlan_interrupt_lancpu(dev); - priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOP; - priv->card_polling_interval = HZ / 3; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_SLOW_POLL) - { - WRITESHMB(arlan->commandByte, ARLAN_COM_GOTO_SLOW_POLL); - arlan_interrupt_lancpu(dev); - priv->waiting_command_mask &= ~ARLAN_COMMAND_SLOW_POLL; - priv->card_polling_interval = HZ / 3; - } - else if (priv->waiting_command_mask & ARLAN_COMMAND_POWERDOWN) - { - setPowerOff(dev); - if (arlan_debug & ARLAN_DEBUG_CARD_STATE) - printk(KERN_WARNING "%s: Arlan Going Standby\n", dev->name); - priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERDOWN; - priv->card_polling_interval = 3 * HZ; - } - arlan_unlock_card_access(dev); - for (i = 0; READSHMB(arlan->commandByte) && i < 20; i++) - udelay(10); - if (READSHMB(arlan->commandByte)) - if (arlan_debug & ARLAN_DEBUG_CARD_STATE) - printk(KERN_ERR "card busy leaving command %lx\n", priv->waiting_command_mask); - - spin_unlock_irqrestore(&priv->lock, flags); - ARLAN_DEBUG_EXIT("arlan_command"); - priv->last_command_buff_free_time = jiffies; - return 0; - -card_busy_end: - if (time_after(jiffies, priv->last_command_buff_free_time + HZ)) - priv->waiting_command_mask |= ARLAN_COMMAND_CLEAN_AND_RESET; - - if (arlan_debug & ARLAN_DEBUG_CARD_STATE) - printk(KERN_ERR "%s arlan_command card busy end \n", dev->name); - spin_unlock_irqrestore(&priv->lock, flags); - ARLAN_DEBUG_EXIT("arlan_command"); - return 1; - -bad_end: - printk(KERN_ERR "%s arlan_command bad end \n", dev->name); - - spin_unlock_irqrestore(&priv->lock, flags); - ARLAN_DEBUG_EXIT("arlan_command"); - - return -1; -} - -static inline void arlan_command_process(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - - int times = 0; - while (priv->waiting_command_mask && times < 8) - { - if (priv->waiting_command_mask) - { - if (arlan_command(dev, 0)) - break; - times++; - } - /* if long command, we won't repeat trying */ ; - if (priv->card_polling_interval > 1) - break; - times++; - } -} - - -static inline void arlan_retransmit_now(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - - - ARLAN_DEBUG_ENTRY("arlan_retransmit_now"); - if (TXLAST(dev).offset == 0) - { - if (TXHEAD(dev).offset) - { - priv->txLast = 0; - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to head \n"); - - } - else if (TXTAIL(dev).offset) - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to tail \n"); - priv->txLast = 1; - } - else - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "ReTransmit buff empty"); - netif_wake_queue (dev); - return; - - } - arlan_command(dev, ARLAN_COMMAND_TX); - - priv->Conf->driverRetransmissions++; - priv->retransmissions++; - - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("Retransmit %d bytes \n", TXLAST(dev).length); - - ARLAN_DEBUG_EXIT("arlan_retransmit_now"); -} - - - -static void arlan_registration_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *) data; - struct arlan_private *priv = netdev_priv(dev); - int bh_mark_needed = 0; - int next_tick = 1; - long lostTime = ((long)jiffies - (long)priv->registrationLastSeen) - * (1000/HZ); - - if (registrationBad(dev)) - { - priv->registrationLostCount++; - if (lostTime > 7000 && lostTime < 7200) - { - printk(KERN_NOTICE "%s registration Lost \n", dev->name); - } - if (lostTime / priv->reRegisterExp > 2000) - arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); - if (lostTime / (priv->reRegisterExp) > 3500) - arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); - if (priv->reRegisterExp < 400) - priv->reRegisterExp += 2; - if (lostTime > 7200) - { - next_tick = HZ; - arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); - } - } - else - { - if (priv->Conf->registrationMode && lostTime > 10000 && - priv->registrationLostCount) - { - printk(KERN_NOTICE "%s registration is back after %ld milliseconds\n", - dev->name, lostTime); - } - priv->registrationLastSeen = jiffies; - priv->registrationLostCount = 0; - priv->reRegisterExp = 1; - if (!netif_running(dev) ) - netif_wake_queue(dev); - if (time_after(priv->tx_last_sent,priv->tx_last_cleared) && - time_after(jiffies, priv->tx_last_sent * 5*HZ) ){ - arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); - priv->tx_last_cleared = jiffies; - } - } - - - if (!registrationBad(dev) && priv->ReTransmitRequested) - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk(KERN_ERR "Retransmit from timer \n"); - priv->ReTransmitRequested = 0; - arlan_retransmit_now(dev); - } - if (!registrationBad(dev) && - time_after(jiffies, priv->tx_done_delayed) && - priv->tx_done_delayed != 0) - { - TXLAST(dev).offset = 0; - if (priv->txLast) - priv->txLast = 0; - else if (TXTAIL(dev).offset) - priv->txLast = 1; - if (TXLAST(dev).offset) - { - arlan_retransmit_now(dev); - dev->trans_start = jiffies; - } - if (!(TXHEAD(dev).offset && TXTAIL(dev).offset)) - { - netif_wake_queue (dev); - } - priv->tx_done_delayed = 0; - bh_mark_needed = 1; - } - if (bh_mark_needed) - { - netif_wake_queue (dev); - } - arlan_process_interrupt(dev); - - if (next_tick < priv->card_polling_interval) - next_tick = priv->card_polling_interval; - - priv->timer.expires = jiffies + next_tick; - - add_timer(&priv->timer); -} - - -#ifdef ARLAN_DEBUGGING - -static void arlan_print_registers(struct net_device *dev, int line) -{ - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem *arlan = priv->card; - - u_char hostcpuLock, lancpuLock, controlRegister, cntrlRegImage, - txStatus, rxStatus, interruptInProgress, commandByte; - - - ARLAN_DEBUG_ENTRY("arlan_print_registers"); - READSHM(interruptInProgress, arlan->interruptInProgress, u_char); - READSHM(hostcpuLock, arlan->hostcpuLock, u_char); - READSHM(lancpuLock, arlan->lancpuLock, u_char); - READSHM(controlRegister, arlan->controlRegister, u_char); - READSHM(cntrlRegImage, arlan->cntrlRegImage, u_char); - READSHM(txStatus, arlan->txStatus, u_char); - READSHM(rxStatus, arlan->rxStatus, u_char); - READSHM(commandByte, arlan->commandByte, u_char); - - printk(KERN_WARNING "line %04d IP %02x HL %02x LL %02x CB %02x CR %02x CRI %02x TX %02x RX %02x\n", - line, interruptInProgress, hostcpuLock, lancpuLock, commandByte, - controlRegister, cntrlRegImage, txStatus, rxStatus); - - ARLAN_DEBUG_EXIT("arlan_print_registers"); -} -#endif - - -static int arlan_hw_tx(struct net_device *dev, char *buf, int length) -{ - int i; - - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - struct arlan_conf_stru *conf = priv->Conf; - - int tailStarts = 0x800; - int headEnds = 0x0; - - - ARLAN_DEBUG_ENTRY("arlan_hw_tx"); - if (TXHEAD(dev).offset) - headEnds = (((TXHEAD(dev).offset + TXHEAD(dev).length - offsetof(struct arlan_shmem, txBuffer)) / 64) + 1) * 64; - if (TXTAIL(dev).offset) - tailStarts = 0x800 - (((TXTAIL(dev).offset - offsetof(struct arlan_shmem, txBuffer)) / 64) + 2) * 64; - - - if (!TXHEAD(dev).offset && length < tailStarts) - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk(KERN_ERR "TXHEAD insert, tailStart %d\n", tailStarts); - - TXHEAD(dev).offset = - offsetof(struct arlan_shmem, txBuffer); - TXHEAD(dev).length = length - ARLAN_FAKE_HDR_LEN; - for (i = 0; i < 6; i++) - TXHEAD(dev).dest[i] = buf[i]; - TXHEAD(dev).clear = conf->txClear; - TXHEAD(dev).retries = conf->txRetries; /* 0 is use default */ - TXHEAD(dev).routing = conf->txRouting; - TXHEAD(dev).scrambled = conf->txScrambled; - memcpy_toio((char __iomem *)arlan + TXHEAD(dev).offset, buf + ARLAN_FAKE_HDR_LEN, TXHEAD(dev).length); - } - else if (!TXTAIL(dev).offset && length < (0x800 - headEnds)) - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk(KERN_ERR "TXTAIL insert, headEnd %d\n", headEnds); - - TXTAIL(dev).offset = - offsetof(struct arlan_shmem, txBuffer) + 0x800 - (length / 64 + 2) * 64; - TXTAIL(dev).length = length - ARLAN_FAKE_HDR_LEN; - for (i = 0; i < 6; i++) - TXTAIL(dev).dest[i] = buf[i]; - TXTAIL(dev).clear = conf->txClear; - TXTAIL(dev).retries = conf->txRetries; - TXTAIL(dev).routing = conf->txRouting; - TXTAIL(dev).scrambled = conf->txScrambled; - memcpy_toio(((char __iomem *)arlan + TXTAIL(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXTAIL(dev).length); - } - else - { - netif_stop_queue (dev); - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk(KERN_ERR "TX TAIL & HEAD full, return, tailStart %d headEnd %d\n", tailStarts, headEnds); - return -1; - } - priv->out_bytes += length; - priv->out_bytes10 += length; - if (conf->measure_rate < 1) - conf->measure_rate = 1; - if (time_after(jiffies, priv->out_time + conf->measure_rate * HZ)) - { - conf->out_speed = priv->out_bytes / conf->measure_rate; - priv->out_bytes = 0; - priv->out_time = jiffies; - } - if (time_after(jiffies, priv->out_time10 + conf->measure_rate * 10*HZ)) - { - conf->out_speed10 = priv->out_bytes10 / (10 * conf->measure_rate); - priv->out_bytes10 = 0; - priv->out_time10 = jiffies; - } - if (TXHEAD(dev).offset && TXTAIL(dev).offset) - { - netif_stop_queue (dev); - return 0; - } - else - netif_start_queue (dev); - - - IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) - printk(KERN_WARNING "%s Transmit t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, - (unsigned char) buf[0], (unsigned char) buf[1], (unsigned char) buf[2], (unsigned char) buf[3], - (unsigned char) buf[4], (unsigned char) buf[5], (unsigned char) buf[6], (unsigned char) buf[7], - (unsigned char) buf[8], (unsigned char) buf[9], (unsigned char) buf[10], (unsigned char) buf[11]); - - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "TX command prepare for buffer %d\n", priv->txLast); - - arlan_command(dev, ARLAN_COMMAND_TX); - - priv->tx_last_sent = jiffies; - - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("%s TX Qued %d bytes \n", dev->name, length); - - ARLAN_DEBUG_EXIT("arlan_hw_tx"); - - return 0; -} - - -static int arlan_hw_config(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - struct arlan_conf_stru *conf = priv->Conf; - - ARLAN_DEBUG_ENTRY("arlan_hw_config"); - - printk(KERN_NOTICE "%s arlan configure called \n", dev->name); - if (arlan_EEPROM_bad) - printk(KERN_NOTICE "arlan configure with eeprom bad option \n"); - - - WRITESHM(arlan->spreadingCode, conf->spreadingCode, u_char); - WRITESHM(arlan->channelSet, conf->channelSet, u_char); - - if (arlan_EEPROM_bad) - WRITESHM(arlan->defaultChannelSet, conf->channelSet, u_char); - - WRITESHM(arlan->channelNumber, conf->channelNumber, u_char); - - WRITESHM(arlan->scramblingDisable, conf->scramblingDisable, u_char); - WRITESHM(arlan->txAttenuation, conf->txAttenuation, u_char); - - WRITESHM(arlan->systemId, conf->systemId, u_int); - - WRITESHM(arlan->maxRetries, conf->maxRetries, u_char); - WRITESHM(arlan->receiveMode, conf->receiveMode, u_char); - WRITESHM(arlan->priority, conf->priority, u_char); - WRITESHM(arlan->rootOrRepeater, conf->rootOrRepeater, u_char); - WRITESHM(arlan->SID, conf->SID, u_int); - - WRITESHM(arlan->registrationMode, conf->registrationMode, u_char); - - WRITESHM(arlan->registrationFill, conf->registrationFill, u_char); - WRITESHM(arlan->localTalkAddress, conf->localTalkAddress, u_char); - WRITESHM(arlan->codeFormat, conf->codeFormat, u_char); - WRITESHM(arlan->numChannels, conf->numChannels, u_char); - WRITESHM(arlan->channel1, conf->channel1, u_char); - WRITESHM(arlan->channel2, conf->channel2, u_char); - WRITESHM(arlan->channel3, conf->channel3, u_char); - WRITESHM(arlan->channel4, conf->channel4, u_char); - WRITESHM(arlan->radioNodeId, conf->radioNodeId, u_short); - WRITESHM(arlan->SID, conf->SID, u_int); - WRITESHM(arlan->waitTime, conf->waitTime, u_short); - WRITESHM(arlan->lParameter, conf->lParameter, u_short); - memcpy_toio(&(arlan->_15), &(conf->_15), 3); - WRITESHM(arlan->_15, conf->_15, u_short); - WRITESHM(arlan->headerSize, conf->headerSize, u_short); - if (arlan_EEPROM_bad) - WRITESHM(arlan->hardwareType, conf->hardwareType, u_char); - WRITESHM(arlan->radioType, conf->radioType, u_char); - if (arlan_EEPROM_bad) - WRITESHM(arlan->radioModule, conf->radioType, u_char); - - memcpy_toio(arlan->encryptionKey + keyStart, encryptionKey, 8); - memcpy_toio(arlan->name, conf->siteName, 16); - - WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_CONF); /* do configure */ - memset_io(arlan->commandParameter, 0, 0xf); /* 0xf */ - memset_io(arlan->commandParameter + 1, 0, 2); - if (conf->writeEEPROM) - { - memset_io(arlan->commandParameter, conf->writeEEPROM, 1); -// conf->writeEEPROM=0; - } - if (conf->registrationMode && conf->registrationInterrupts) - memset_io(arlan->commandParameter + 3, 1, 1); - else - memset_io(arlan->commandParameter + 3, 0, 1); - - priv->irq_test_done = 0; - - if (conf->tx_queue_len) - dev->tx_queue_len = conf->tx_queue_len; - udelay(100); - - ARLAN_DEBUG_EXIT("arlan_hw_config"); - return 0; -} - - -static int arlan_read_card_configuration(struct net_device *dev) -{ - u_char tlx415; - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - struct arlan_conf_stru *conf = priv->Conf; - - ARLAN_DEBUG_ENTRY("arlan_read_card_configuration"); - - if (radioNodeId == radioNodeIdUNKNOWN) - { - READSHM(conf->radioNodeId, arlan->radioNodeId, u_short); - } - else - conf->radioNodeId = radioNodeId; - - if (SID == SIDUNKNOWN) - { - READSHM(conf->SID, arlan->SID, u_int); - } - else conf->SID = SID; - - if (spreadingCode == spreadingCodeUNKNOWN) - { - READSHM(conf->spreadingCode, arlan->spreadingCode, u_char); - } - else - conf->spreadingCode = spreadingCode; - - if (channelSet == channelSetUNKNOWN) - { - READSHM(conf->channelSet, arlan->channelSet, u_char); - } - else conf->channelSet = channelSet; - - if (channelNumber == channelNumberUNKNOWN) - { - READSHM(conf->channelNumber, arlan->channelNumber, u_char); - } - else conf->channelNumber = channelNumber; - - READSHM(conf->scramblingDisable, arlan->scramblingDisable, u_char); - READSHM(conf->txAttenuation, arlan->txAttenuation, u_char); - - if (systemId == systemIdUNKNOWN) - { - READSHM(conf->systemId, arlan->systemId, u_int); - } - else conf->systemId = systemId; - - READSHM(conf->maxDatagramSize, arlan->maxDatagramSize, u_short); - READSHM(conf->maxFrameSize, arlan->maxFrameSize, u_short); - READSHM(conf->maxRetries, arlan->maxRetries, u_char); - READSHM(conf->receiveMode, arlan->receiveMode, u_char); - READSHM(conf->priority, arlan->priority, u_char); - READSHM(conf->rootOrRepeater, arlan->rootOrRepeater, u_char); - - if (SID == SIDUNKNOWN) - { - READSHM(conf->SID, arlan->SID, u_int); - } - else conf->SID = SID; - - if (registrationMode == registrationModeUNKNOWN) - { - READSHM(conf->registrationMode, arlan->registrationMode, u_char); - } - else conf->registrationMode = registrationMode; - - READSHM(conf->registrationFill, arlan->registrationFill, u_char); - READSHM(conf->localTalkAddress, arlan->localTalkAddress, u_char); - READSHM(conf->codeFormat, arlan->codeFormat, u_char); - READSHM(conf->numChannels, arlan->numChannels, u_char); - READSHM(conf->channel1, arlan->channel1, u_char); - READSHM(conf->channel2, arlan->channel2, u_char); - READSHM(conf->channel3, arlan->channel3, u_char); - READSHM(conf->channel4, arlan->channel4, u_char); - READSHM(conf->waitTime, arlan->waitTime, u_short); - READSHM(conf->lParameter, arlan->lParameter, u_short); - READSHM(conf->_15, arlan->_15, u_short); - READSHM(conf->headerSize, arlan->headerSize, u_short); - READSHM(conf->hardwareType, arlan->hardwareType, u_char); - READSHM(conf->radioType, arlan->radioModule, u_char); - - if (conf->radioType == 0) - conf->radioType = 0xc; - - WRITESHM(arlan->configStatus, 0xA5, u_char); - READSHM(tlx415, arlan->configStatus, u_char); - - if (tlx415 != 0xA5) - printk(KERN_INFO "%s tlx415 chip \n", dev->name); - - conf->txClear = 0; - conf->txRetries = 1; - conf->txRouting = 1; - conf->txScrambled = 0; - conf->rxParameter = 1; - conf->txTimeoutMs = 4000; - conf->waitCardTimeout = 100000; - conf->receiveMode = ARLAN_RCV_CLEAN; - memcpy_fromio(conf->siteName, arlan->name, 16); - conf->siteName[16] = '\0'; - conf->retries = retries; - conf->tx_delay_ms = tx_delay_ms; - conf->ReTransmitPacketMaxSize = 200; - conf->waitReTransmitPacketMaxSize = 200; - conf->txAckTimeoutMs = 900; - conf->fastReTransCount = 3; - - ARLAN_DEBUG_EXIT("arlan_read_card_configuration"); - - return 0; -} - - -static int lastFoundAt = 0xbe000; - - -/* - * This is the real probe routine. Linux has a history of friendly device - * probes on the ISA bus. A good device probes avoids doing writes, and - * verifies that the correct device exists and functions. - */ -#define ARLAN_SHMEM_SIZE 0x2000 -static int __init arlan_check_fingerprint(unsigned long memaddr) -{ - static const char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; - volatile struct arlan_shmem __iomem *arlan = (struct arlan_shmem *) memaddr; - unsigned long paddr = virt_to_phys((void *) memaddr); - char tempBuf[49]; - - ARLAN_DEBUG_ENTRY("arlan_check_fingerprint"); - - if (!request_mem_region(paddr, ARLAN_SHMEM_SIZE, "arlan")) { - // printk(KERN_WARNING "arlan: memory region %lx excluded from probing \n",paddr); - return -ENODEV; - } - - memcpy_fromio(tempBuf, arlan->textRegion, 29); - tempBuf[30] = 0; - - /* check for card at this address */ - if (0 != strncmp(tempBuf, probeText, 29)){ - release_mem_region(paddr, ARLAN_SHMEM_SIZE); - return -ENODEV; - } - -// printk(KERN_INFO "arlan found at 0x%x \n",memaddr); - ARLAN_DEBUG_EXIT("arlan_check_fingerprint"); - - return 0; -} - -static int arlan_change_mtu(struct net_device *dev, int new_mtu) -{ - struct arlan_private *priv = netdev_priv(dev); - struct arlan_conf_stru *conf = priv->Conf; - - ARLAN_DEBUG_ENTRY("arlan_change_mtu"); - if (new_mtu > 2032) - return -EINVAL; - dev->mtu = new_mtu; - if (new_mtu < 256) - new_mtu = 256; /* cards book suggests 1600 */ - conf->maxDatagramSize = new_mtu; - conf->maxFrameSize = new_mtu + 48; - - arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); - printk(KERN_NOTICE "%s mtu changed to %d \n", dev->name, new_mtu); - - ARLAN_DEBUG_EXIT("arlan_change_mtu"); - - return 0; -} - -static int arlan_mac_addr(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - - - ARLAN_DEBUG_ENTRY("arlan_mac_addr"); - return -EINVAL; - - if (netif_running(dev)) - return -EBUSY; - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - - ARLAN_DEBUG_EXIT("arlan_mac_addr"); - return 0; -} - -static const struct net_device_ops arlan_netdev_ops = { - .ndo_open = arlan_open, - .ndo_stop = arlan_close, - .ndo_start_xmit = arlan_tx, - .ndo_get_stats = arlan_statistics, - .ndo_set_multicast_list = arlan_set_multicast, - .ndo_change_mtu = arlan_change_mtu, - .ndo_set_mac_address = arlan_mac_addr, - .ndo_tx_timeout = arlan_tx_timeout, - .ndo_validate_addr = eth_validate_addr, -}; - -static int __init arlan_setup_device(struct net_device *dev, int num) -{ - struct arlan_private *ap = netdev_priv(dev); - int err; - - ARLAN_DEBUG_ENTRY("arlan_setup_device"); - - ap->conf = (struct arlan_shmem *)(ap+1); - - dev->tx_queue_len = tx_queue_len; - dev->netdev_ops = &arlan_netdev_ops; - dev->watchdog_timeo = 3*HZ; - - ap->irq_test_done = 0; - ap->Conf = &arlan_conf[num]; - - ap->Conf->pre_Command_Wait = 40; - ap->Conf->rx_tweak1 = 30; - ap->Conf->rx_tweak2 = 0; - - - err = register_netdev(dev); - if (err) { - release_mem_region(virt_to_phys((void *) dev->mem_start), - ARLAN_SHMEM_SIZE); - free_netdev(dev); - return err; - } - arlan_device[num] = dev; - ARLAN_DEBUG_EXIT("arlan_setup_device"); - return 0; -} - -static int __init arlan_probe_here(struct net_device *dev, - unsigned long memaddr) -{ - struct arlan_private *ap = netdev_priv(dev); - - ARLAN_DEBUG_ENTRY("arlan_probe_here"); - - if (arlan_check_fingerprint(memaddr)) - return -ENODEV; - - printk(KERN_NOTICE "%s: Arlan found at %llx, \n ", dev->name, - (u64) virt_to_phys((void*)memaddr)); - - ap->card = (void *) memaddr; - dev->mem_start = memaddr; - dev->mem_end = memaddr + ARLAN_SHMEM_SIZE-1; - - if (dev->irq < 2) - { - READSHM(dev->irq, ap->card->irqLevel, u_char); - } else if (dev->irq == 2) - dev->irq = 9; - - arlan_read_card_configuration(dev); - - ARLAN_DEBUG_EXIT("arlan_probe_here"); - return 0; -} - - -static int arlan_open(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - int ret = 0; - - ARLAN_DEBUG_ENTRY("arlan_open"); - - ret = request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev); - if (ret) - { - printk(KERN_ERR "%s: unable to get IRQ %d .\n", - dev->name, dev->irq); - return ret; - } - - - priv->bad = 0; - priv->lastReset = 0; - priv->reset = 0; - memcpy_fromio(dev->dev_addr, arlan->lanCardNodeId, 6); - memset(dev->broadcast, 0xff, 6); - dev->tx_queue_len = tx_queue_len; - priv->interrupt_processing_active = 0; - spin_lock_init(&priv->lock); - - netif_start_queue (dev); - - priv->registrationLostCount = 0; - priv->registrationLastSeen = jiffies; - priv->txLast = 0; - priv->tx_command_given = 0; - priv->rx_command_given = 0; - - priv->reRegisterExp = 1; - priv->tx_last_sent = jiffies - 1; - priv->tx_last_cleared = jiffies; - priv->Conf->writeEEPROM = 0; - priv->Conf->registrationInterrupts = 1; - - init_timer(&priv->timer); - priv->timer.expires = jiffies + HZ / 10; - priv->timer.data = (unsigned long) dev; - priv->timer.function = &arlan_registration_timer; /* timer handler */ - - arlan_command(dev, ARLAN_COMMAND_POWERUP | ARLAN_COMMAND_LONG_WAIT_NOW); - mdelay(200); - add_timer(&priv->timer); - - ARLAN_DEBUG_EXIT("arlan_open"); - return 0; -} - - -static void arlan_tx_timeout (struct net_device *dev) -{ - printk(KERN_ERR "%s: arlan transmit timed out, kernel decided\n", dev->name); - /* Try to restart the adaptor. */ - arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); - // dev->trans_start = jiffies; - // netif_start_queue (dev); -} - - -static netdev_tx_t arlan_tx(struct sk_buff *skb, struct net_device *dev) -{ - short length; - unsigned char *buf; - - ARLAN_DEBUG_ENTRY("arlan_tx"); - - length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - buf = skb->data; - - if (length + 0x12 > 0x800) { - printk(KERN_ERR "TX RING overflow \n"); - netif_stop_queue (dev); - } - - if (arlan_hw_tx(dev, buf, length) == -1) - goto bad_end; - - dev->trans_start = jiffies; - - dev_kfree_skb(skb); - - arlan_process_interrupt(dev); - ARLAN_DEBUG_EXIT("arlan_tx"); - return NETDEV_TX_OK; - -bad_end: - arlan_process_interrupt(dev); - netif_stop_queue (dev); - ARLAN_DEBUG_EXIT("arlan_tx"); - return NETDEV_TX_BUSY; -} - - -static inline int DoNotReTransmitCrap(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - - if (TXLAST(dev).length < priv->Conf->ReTransmitPacketMaxSize) - return 1; - return 0; - -} - -static inline int DoNotWaitReTransmitCrap(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - - if (TXLAST(dev).length < priv->Conf->waitReTransmitPacketMaxSize) - return 1; - return 0; -} - -static inline void arlan_queue_retransmit(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - - ARLAN_DEBUG_ENTRY("arlan_queue_retransmit"); - - if (DoNotWaitReTransmitCrap(dev)) - { - arlan_drop_tx(dev); - } else - priv->ReTransmitRequested++; - - ARLAN_DEBUG_EXIT("arlan_queue_retransmit"); -} - -static inline void RetryOrFail(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - - ARLAN_DEBUG_ENTRY("RetryOrFail"); - - if (priv->retransmissions > priv->Conf->retries || - DoNotReTransmitCrap(dev)) - { - arlan_drop_tx(dev); - } - else if (priv->bad <= priv->Conf->fastReTransCount) - { - arlan_retransmit_now(dev); - } - else arlan_queue_retransmit(dev); - - ARLAN_DEBUG_EXIT("RetryOrFail"); -} - - -static void arlan_tx_done_interrupt(struct net_device *dev, int status) -{ - struct arlan_private *priv = netdev_priv(dev); - - ARLAN_DEBUG_ENTRY("arlan_tx_done_interrupt"); - - priv->tx_last_cleared = jiffies; - priv->tx_command_given = 0; - switch (status) - { - case 1: - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk("arlan intr: transmit OK\n"); - dev->stats.tx_packets++; - priv->bad = 0; - priv->reset = 0; - priv->retransmissions = 0; - if (priv->Conf->tx_delay_ms) - { - priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1; - } - else - { - TXLAST(dev).offset = 0; - if (priv->txLast) - priv->txLast = 0; - else if (TXTAIL(dev).offset) - priv->txLast = 1; - if (TXLAST(dev).offset) - { - arlan_retransmit_now(dev); - dev->trans_start = jiffies; - } - if (!TXHEAD(dev).offset || !TXTAIL(dev).offset) - { - netif_wake_queue (dev); - } - } - } - break; - - case 2: - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk("arlan intr: transmit timed out\n"); - priv->bad += 1; - //arlan_queue_retransmit(dev); - RetryOrFail(dev); - } - break; - - case 3: - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk("arlan intr: transmit max retries\n"); - priv->bad += 1; - priv->reset = 0; - //arlan_queue_retransmit(dev); - RetryOrFail(dev); - } - break; - - case 4: - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk("arlan intr: transmit aborted\n"); - priv->bad += 1; - arlan_queue_retransmit(dev); - //RetryOrFail(dev); - } - break; - - case 5: - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk("arlan intr: transmit not registered\n"); - priv->bad += 1; - //debug=101; - arlan_queue_retransmit(dev); - } - break; - - case 6: - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk("arlan intr: transmit destination full\n"); - priv->bad += 1; - priv->reset = 0; - //arlan_drop_tx(dev); - arlan_queue_retransmit(dev); - } - break; - - case 7: - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk("arlan intr: transmit unknown ack\n"); - priv->bad += 1; - priv->reset = 0; - arlan_queue_retransmit(dev); - } - break; - - case 8: - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk("arlan intr: transmit dest mail box full\n"); - priv->bad += 1; - priv->reset = 0; - //arlan_drop_tx(dev); - arlan_queue_retransmit(dev); - } - break; - - case 9: - { - IFDEBUG(ARLAN_DEBUG_TX_CHAIN) - printk("arlan intr: transmit root dest not reg.\n"); - priv->bad += 1; - priv->reset = 1; - //arlan_drop_tx(dev); - arlan_queue_retransmit(dev); - } - break; - - default: - { - printk(KERN_ERR "arlan intr: transmit status unknown\n"); - priv->bad += 1; - priv->reset = 1; - arlan_drop_tx(dev); - } - } - - ARLAN_DEBUG_EXIT("arlan_tx_done_interrupt"); -} - - -static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short rxOffset, u_short pkt_len) -{ - char *skbtmp; - int i = 0; - - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - struct arlan_conf_stru *conf = priv->Conf; - - - ARLAN_DEBUG_ENTRY("arlan_rx_interrupt"); - // by spec, not WRITESHMB(arlan->rxStatus,0x00); - // prohibited here arlan_command(dev, ARLAN_COMMAND_RX); - - if (pkt_len < 10 || pkt_len > 2048) - { - printk(KERN_WARNING "%s: got too short or long packet, len %d \n", dev->name, pkt_len); - return; - } - if (rxOffset + pkt_len > 0x2000) - { - printk("%s: got too long packet, len %d offset %x\n", dev->name, pkt_len, rxOffset); - return; - } - priv->in_bytes += pkt_len; - priv->in_bytes10 += pkt_len; - if (conf->measure_rate < 1) - conf->measure_rate = 1; - if (time_after(jiffies, priv->in_time + conf->measure_rate * HZ)) - { - conf->in_speed = priv->in_bytes / conf->measure_rate; - priv->in_bytes = 0; - priv->in_time = jiffies; - } - if (time_after(jiffies, priv->in_time10 + conf->measure_rate * 10*HZ)) - { - conf->in_speed10 = priv->in_bytes10 / (10 * conf->measure_rate); - priv->in_bytes10 = 0; - priv->in_time10 = jiffies; - } - DEBUGSHM(1, "arlan rcv pkt rxStatus= %d ", arlan->rxStatus, u_char); - switch (rxStatus) - { - case 1: - case 2: - case 3: - { - /* Malloc up new buffer. */ - struct sk_buff *skb; - - DEBUGSHM(50, "arlan recv pkt offs=%d\n", arlan->rxOffset, u_short); - DEBUGSHM(1, "arlan rxFrmType = %d \n", arlan->rxFrmType, u_char); - DEBUGSHM(1, KERN_INFO "arlan rx scrambled = %d \n", arlan->scrambled, u_char); - - /* here we do multicast filtering to avoid slow 8-bit memcopy */ -#ifdef ARLAN_MULTICAST - if (!(dev->flags & IFF_ALLMULTI) && - !(dev->flags & IFF_PROMISC) && - dev->mc_list) - { - char hw_dst_addr[6]; - struct dev_mc_list *dmi = dev->mc_list; - int i; - - memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6); - if (hw_dst_addr[0] == 0x01) - { - if (mdebug) - if (hw_dst_addr[1] == 0x00) - printk(KERN_ERR "%s mcast 0x0100 \n", dev->name); - else if (hw_dst_addr[1] == 0x40) - printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name); - while (dmi) - { - if (dmi->dmi_addrlen == 6) { - if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP) - printk(KERN_ERR "%s mcl %pM\n", - dev->name, dmi->dmi_addr); - for (i = 0; i < 6; i++) - if (dmi->dmi_addr[i] != hw_dst_addr[i]) - break; - if (i == 6) - break; - } else - printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name); - dmi = dmi->next; - } - /* we reach here if multicast filtering is on and packet - * is multicast and not for receive */ - goto end_of_interrupt; - } - } -#endif // ARLAN_MULTICAST - /* multicast filtering ends here */ - pkt_len += ARLAN_FAKE_HDR_LEN; - - skb = dev_alloc_skb(pkt_len + 4); - if (skb == NULL) - { - printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); - dev->stats.rx_dropped++; - break; - } - skb_reserve(skb, 2); - skbtmp = skb_put(skb, pkt_len); - - memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char __iomem *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN); - memcpy_fromio(skbtmp, arlan->ultimateDestAddress, 6); - memcpy_fromio(skbtmp + 6, arlan->rxSrc, 6); - WRITESHMB(arlan->rxStatus, 0x00); - arlan_command(dev, ARLAN_COMMAND_RX); - - IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) - { - char immedDestAddress[6]; - char immedSrcAddress[6]; - memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6); - memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6); - - printk(KERN_WARNING "%s t %pM f %pM imd %pM ims %pM\n", - dev->name, skbtmp, - &skbtmp[6], - immedDestAddress, - immedSrcAddress); - } - skb->protocol = eth_type_trans(skb, dev); - IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) - if (skb->protocol != 0x608 && skb->protocol != 0x8) - { - for (i = 0; i <= 22; i++) - printk("%02x:", (u_char) skbtmp[i + 12]); - printk(KERN_ERR "\n"); - printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol); - } - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } - break; - - default: - printk(KERN_ERR "arlan intr: received unknown status\n"); - dev->stats.rx_crc_errors++; - break; - } - ARLAN_DEBUG_EXIT("arlan_rx_interrupt"); -} - -static void arlan_process_interrupt(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - u_char rxStatus = READSHMB(arlan->rxStatus); - u_char txStatus = READSHMB(arlan->txStatus); - u_short rxOffset = READSHMS(arlan->rxOffset); - u_short pkt_len = READSHMS(arlan->rxLength); - int interrupt_count = 0; - - ARLAN_DEBUG_ENTRY("arlan_process_interrupt"); - - if (test_and_set_bit(0, (void *) &priv->interrupt_processing_active)) - { - if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) - printk(KERN_ERR "interrupt chain reentering \n"); - goto end_int_process; - } - while ((rxStatus || txStatus || priv->interrupt_ack_requested) - && (interrupt_count < 5)) - { - if (rxStatus) - priv->last_rx_int_ack_time = jiffies; - - arlan_command(dev, ARLAN_COMMAND_INT_ACK); - arlan_command(dev, ARLAN_COMMAND_INT_ENABLE); - - IFDEBUG(ARLAN_DEBUG_INTERRUPT) - printk(KERN_ERR "%s: got IRQ rx %x tx %x comm %x rxOff %x rxLen %x \n", - dev->name, rxStatus, txStatus, READSHMB(arlan->commandByte), - rxOffset, pkt_len); - - if (rxStatus == 0 && txStatus == 0) - { - if (priv->irq_test_done) - { - if (!registrationBad(dev)) - IFDEBUG(ARLAN_DEBUG_INTERRUPT) printk(KERN_ERR "%s unknown interrupt(nop? regLost ?) reason tx %d rx %d ", - dev->name, txStatus, rxStatus); - } else { - IFDEBUG(ARLAN_DEBUG_INTERRUPT) - printk(KERN_INFO "%s irq $%d test OK \n", dev->name, dev->irq); - - } - priv->interrupt_ack_requested = 0; - goto ends; - } - if (txStatus != 0) - { - WRITESHMB(arlan->txStatus, 0x00); - arlan_tx_done_interrupt(dev, txStatus); - goto ends; - } - if (rxStatus == 1 || rxStatus == 2) - { /* a packet waiting */ - arlan_rx_interrupt(dev, rxStatus, rxOffset, pkt_len); - goto ends; - } - if (rxStatus > 2 && rxStatus < 0xff) - { - WRITESHMB(arlan->rxStatus, 0x00); - printk(KERN_ERR "%s unknown rxStatus reason tx %d rx %d ", - dev->name, txStatus, rxStatus); - goto ends; - } - if (rxStatus == 0xff) - { - WRITESHMB(arlan->rxStatus, 0x00); - arlan_command(dev, ARLAN_COMMAND_RX); - if (registrationBad(dev)) - netif_device_detach(dev); - if (!registrationBad(dev)) - { - priv->registrationLastSeen = jiffies; - if (!netif_queue_stopped(dev) && !priv->under_reset && !priv->under_config) - netif_wake_queue (dev); - } - goto ends; - } -ends: - - arlan_command_process(dev); - - rxStatus = READSHMB(arlan->rxStatus); - txStatus = READSHMB(arlan->txStatus); - rxOffset = READSHMS(arlan->rxOffset); - pkt_len = READSHMS(arlan->rxLength); - - - priv->irq_test_done = 1; - - interrupt_count++; - } - priv->interrupt_processing_active = 0; - -end_int_process: - arlan_command_process(dev); - - ARLAN_DEBUG_EXIT("arlan_process_interrupt"); - return; -} - -static irqreturn_t arlan_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - u_char rxStatus = READSHMB(arlan->rxStatus); - u_char txStatus = READSHMB(arlan->txStatus); - - ARLAN_DEBUG_ENTRY("arlan_interrupt"); - - - if (!rxStatus && !txStatus) - priv->interrupt_ack_requested++; - - arlan_process_interrupt(dev); - - priv->irq_test_done = 1; - - ARLAN_DEBUG_EXIT("arlan_interrupt"); - return IRQ_HANDLED; - -} - - -static int arlan_close(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - - ARLAN_DEBUG_ENTRY("arlan_close"); - - del_timer_sync(&priv->timer); - - arlan_command(dev, ARLAN_COMMAND_POWERDOWN); - - IFDEBUG(ARLAN_DEBUG_STARTUP) - printk(KERN_NOTICE "%s: Closing device\n", dev->name); - - netif_stop_queue(dev); - free_irq(dev->irq, dev); - - ARLAN_DEBUG_EXIT("arlan_close"); - return 0; -} - -#ifdef ARLAN_DEBUGGING -static long alignLong(volatile u_char * ptr) -{ - long ret; - memcpy_fromio(&ret, (void *) ptr, 4); - return ret; -} -#endif - -/* - * Get the current statistics. - * This may be called with the card open or closed. - */ - -static struct net_device_stats *arlan_statistics(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - - - ARLAN_DEBUG_ENTRY("arlan_statistics"); - - /* Update the statistics from the device registers. */ - - READSHM(dev->stats.collisions, arlan->numReTransmissions, u_int); - READSHM(dev->stats.rx_crc_errors, arlan->numCRCErrors, u_int); - READSHM(dev->stats.rx_dropped, arlan->numFramesDiscarded, u_int); - READSHM(dev->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int); - READSHM(dev->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int); - READSHM(dev->stats.rx_over_errors, arlan->numRXOverruns, u_int); - READSHM(dev->stats.rx_packets, arlan->numDatagramsReceived, u_int); - READSHM(dev->stats.tx_aborted_errors, arlan->numAbortErrors, u_int); - READSHM(dev->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int); - READSHM(dev->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int); - READSHM(dev->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int); - READSHM(dev->stats.tx_packets, arlan->numDatagramsTransmitted, u_int); - READSHM(dev->stats.tx_window_errors, arlan->numHoldOffs, u_int); - - ARLAN_DEBUG_EXIT("arlan_statistics"); - - return &dev->stats; -} - - -static void arlan_set_multicast(struct net_device *dev) -{ - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - struct arlan_conf_stru *conf = priv->Conf; - int board_conf_needed = 0; - - - ARLAN_DEBUG_ENTRY("arlan_set_multicast"); - - if (dev->flags & IFF_PROMISC) - { - unsigned char recMode; - READSHM(recMode, arlan->receiveMode, u_char); - conf->receiveMode = (ARLAN_RCV_PROMISC | ARLAN_RCV_CONTROL); - if (conf->receiveMode != recMode) - board_conf_needed = 1; - } - else - { - /* turn off promiscuous mode */ - unsigned char recMode; - READSHM(recMode, arlan->receiveMode, u_char); - conf->receiveMode = ARLAN_RCV_CLEAN | ARLAN_RCV_CONTROL; - if (conf->receiveMode != recMode) - board_conf_needed = 1; - } - if (board_conf_needed) - arlan_command(dev, ARLAN_COMMAND_CONF); - - ARLAN_DEBUG_EXIT("arlan_set_multicast"); -} - - -struct net_device * __init arlan_probe(int unit) -{ - struct net_device *dev; - int err; - int m; - - ARLAN_DEBUG_ENTRY("arlan_probe"); - - if (arlans_found == MAX_ARLANS) - return ERR_PTR(-ENODEV); - - /* - * Reserve space for local data and a copy of the shared memory - * that is used by the /proc interface. - */ - dev = alloc_etherdev(sizeof(struct arlan_private) - + sizeof(struct arlan_shmem)); - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - if (dev->mem_start) { - if (arlan_probe_here(dev, dev->mem_start) == 0) - goto found; - goto not_found; - } - - } - - - for (m = (int)phys_to_virt(lastFoundAt) + ARLAN_SHMEM_SIZE; - m <= (int)phys_to_virt(0xDE000); - m += ARLAN_SHMEM_SIZE) - { - if (arlan_probe_here(dev, m) == 0) - { - lastFoundAt = (int)virt_to_phys((void*)m); - goto found; - } - } - - if (lastFoundAt == 0xbe000) - printk(KERN_ERR "arlan: No Arlan devices found \n"); - - not_found: - free_netdev(dev); - return ERR_PTR(-ENODEV); - - found: - err = arlan_setup_device(dev, arlans_found); - if (err) - dev = ERR_PTR(err); - else if (!arlans_found++) - printk(KERN_INFO "Arlan driver %s\n", arlan_version); - - return dev; -} - -#ifdef MODULE -int __init init_module(void) -{ - int i = 0; - - ARLAN_DEBUG_ENTRY("init_module"); - - if (channelSet != channelSetUNKNOWN || channelNumber != channelNumberUNKNOWN || systemId != systemIdUNKNOWN) - return -EINVAL; - - for (i = 0; i < MAX_ARLANS; i++) { - struct net_device *dev = arlan_probe(i); - - if (IS_ERR(dev)) - return PTR_ERR(dev); - } - init_arlan_proc(); - printk(KERN_INFO "Arlan driver %s\n", arlan_version); - ARLAN_DEBUG_EXIT("init_module"); - return 0; -} - - -void __exit cleanup_module(void) -{ - int i = 0; - struct net_device *dev; - - ARLAN_DEBUG_ENTRY("cleanup_module"); - - IFDEBUG(ARLAN_DEBUG_SHUTDOWN) - printk(KERN_INFO "arlan: unloading module\n"); - - cleanup_arlan_proc(); - - for (i = 0; i < MAX_ARLANS; i++) - { - dev = arlan_device[i]; - if (dev) { - arlan_command(dev, ARLAN_COMMAND_POWERDOWN ); - - unregister_netdev(dev); - release_mem_region(virt_to_phys((void *) dev->mem_start), - ARLAN_SHMEM_SIZE); - free_netdev(dev); - arlan_device[i] = NULL; - } - } - - ARLAN_DEBUG_EXIT("cleanup_module"); -} - - -#endif -MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/arlan-proc.c b/drivers/net/wireless/arlan-proc.c deleted file mode 100644 index a8b689635a3b..000000000000 --- a/drivers/net/wireless/arlan-proc.c +++ /dev/null @@ -1,1253 +0,0 @@ -#include "arlan.h" - -#include - -#ifdef CONFIG_PROC_FS - -/* void enableReceive(struct net_device* dev); -*/ - - - -#define ARLAN_STR_SIZE 0x2ff0 -#define DEV_ARLAN_INFO 1 -#define DEV_ARLAN 1 -#define SARLG(type,var) {\ - pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n", #var, READSHMB(priva->card->var)); \ - } - -#define SARLBN(type,var,nn) {\ - pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x",#var);\ - for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ - pos += sprintf(arlan_drive_info+pos, "\n"); \ - } - -#define SARLBNpln(type,var,nn) {\ - for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ - } - -#define SARLSTR(var,nn) {\ - char tmpStr[400];\ - int tmpLn = nn;\ - if (nn > 399 ) tmpLn = 399; \ - memcpy(tmpStr,(char *) priva->conf->var,tmpLn);\ - tmpStr[tmpLn] = 0; \ - pos += sprintf(arlan_drive_info+pos, "%s\t=\t%s \n",#var,priva->conf->var);\ - } - -#define SARLUC(var) SARLG(u_char, var) -#define SARLUCN(var,nn) SARLBN(u_char,var, nn) -#define SARLUS(var) SARLG(u_short, var) -#define SARLUSN(var,nn) SARLBN(u_short,var, nn) -#define SARLUI(var) SARLG(u_int, var) - -#define SARLUSA(var) {\ - u_short tmpVar;\ - memcpy(&tmpVar, (short *) priva->conf->var,2); \ - pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ -} - -#define SARLUIA(var) {\ - u_int tmpVar;\ - memcpy(&tmpVar, (int* )priva->conf->var,4); \ - pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ -} - - -static const char *arlan_diagnostic_info_string(struct net_device *dev) -{ - - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - u_char diagnosticInfo; - - READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); - - switch (diagnosticInfo) - { - case 0xFF: - return "Diagnostic info is OK"; - case 0xFE: - return "ERROR EPROM Checksum error "; - case 0xFD: - return "ERROR Local Ram Test Failed "; - case 0xFC: - return "ERROR SCC failure "; - case 0xFB: - return "ERROR BackBone failure "; - case 0xFA: - return "ERROR transceiver not found "; - case 0xF9: - return "ERROR no more address space "; - case 0xF8: - return "ERROR Checksum error "; - case 0xF7: - return "ERROR Missing SS Code"; - case 0xF6: - return "ERROR Invalid config format"; - case 0xF5: - return "ERROR Reserved errorcode F5"; - case 0xF4: - return "ERROR Invalid spreading code/channel number"; - case 0xF3: - return "ERROR Load Code Error"; - case 0xF2: - return "ERROR Reserver errorcode F2 "; - case 0xF1: - return "ERROR Invalid command receivec by LAN card "; - case 0xF0: - return "ERROR Invalid parameter found in command "; - case 0xEF: - return "ERROR On-chip timer failure "; - case 0xEE: - return "ERROR T410 timer failure "; - case 0xED: - return "ERROR Too Many TxEnable commands "; - case 0xEC: - return "ERROR EEPROM error on radio module "; - default: - return "ERROR unknown Diagnostic info reply code "; - } -} - -static const char *arlan_hardware_type_string(struct net_device *dev) -{ - u_char hardwareType; - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - - READSHM(hardwareType, arlan->hardwareType, u_char); - switch (hardwareType) - { - case 0x00: - return "type A450"; - case 0x01: - return "type A650 "; - case 0x04: - return "type TMA coproc"; - case 0x0D: - return "type A650E "; - case 0x18: - return "type TMA coproc Australian"; - case 0x19: - return "type A650A "; - case 0x26: - return "type TMA coproc European"; - case 0x2E: - return "type A655 "; - case 0x2F: - return "type A655A "; - case 0x30: - return "type A655E "; - case 0x0B: - return "type A670 "; - case 0x0C: - return "type A670E "; - case 0x2D: - return "type A670A "; - case 0x0F: - return "type A411T"; - case 0x16: - return "type A411TA"; - case 0x1B: - return "type A440T"; - case 0x1C: - return "type A412T"; - case 0x1E: - return "type A412TA"; - case 0x22: - return "type A411TE"; - case 0x24: - return "type A412TE"; - case 0x27: - return "type A671T "; - case 0x29: - return "type A671TA "; - case 0x2B: - return "type A671TE "; - case 0x31: - return "type A415T "; - case 0x33: - return "type A415TA "; - case 0x35: - return "type A415TE "; - case 0x37: - return "type A672"; - case 0x39: - return "type A672A "; - case 0x3B: - return "type A672T"; - case 0x6B: - return "type IC2200"; - default: - return "type A672T"; - } -} -#ifdef ARLAN_DEBUGGING -static void arlan_print_diagnostic_info(struct net_device *dev) -{ - int i; - u_char diagnosticInfo; - u_short diagnosticOffset; - u_char hardwareType; - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - - // ARLAN_DEBUG_ENTRY("arlan_print_diagnostic_info"); - - if (READSHMB(arlan->configuredStatusFlag) == 0) - printk("Arlan: Card NOT configured\n"); - else - printk("Arlan: Card is configured\n"); - - READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); - READSHM(diagnosticOffset, arlan->diagnosticOffset, u_short); - - printk(KERN_INFO "%s\n", arlan_diagnostic_info_string(dev)); - - if (diagnosticInfo != 0xff) - printk("%s arlan: Diagnostic Offset %d \n", dev->name, diagnosticOffset); - - printk("arlan: LAN CODE ID = "); - for (i = 0; i < 6; i++) - DEBUGSHM(1, "%03d:", arlan->lanCardNodeId[i], u_char); - printk("\n"); - - printk("arlan: Arlan BroadCast address = "); - for (i = 0; i < 6; i++) - DEBUGSHM(1, "%03d:", arlan->broadcastAddress[i], u_char); - printk("\n"); - - READSHM(hardwareType, arlan->hardwareType, u_char); - printk(KERN_INFO "%s\n", arlan_hardware_type_string(dev)); - - - DEBUGSHM(1, "arlan: channelNumber=%d\n", arlan->channelNumber, u_char); - DEBUGSHM(1, "arlan: channelSet=%d\n", arlan->channelSet, u_char); - DEBUGSHM(1, "arlan: spreadingCode=%d\n", arlan->spreadingCode, u_char); - DEBUGSHM(1, "arlan: radioNodeId=%d\n", arlan->radioNodeId, u_short); - DEBUGSHM(1, "arlan: SID =%d\n", arlan->SID, u_short); - DEBUGSHM(1, "arlan: rxOffset=%d\n", arlan->rxOffset, u_short); - - DEBUGSHM(1, "arlan: registration mode is %d\n", arlan->registrationMode, u_char); - - printk("arlan: name= "); - IFDEBUG(1) - - for (i = 0; i < 16; i++) - { - char c; - READSHM(c, arlan->name[i], char); - if (c) - printk("%c", c); - } - printk("\n"); - -// ARLAN_DEBUG_EXIT("arlan_print_diagnostic_info"); - -} - - -/****************************** TEST MEMORY **************/ - -static int arlan_hw_test_memory(struct net_device *dev) -{ - u_char *ptr; - int i; - int memlen = sizeof(struct arlan_shmem) - 0xF; /* avoid control register */ - volatile char *arlan_mem = (char *) (dev->mem_start); - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - char pattern; - - ptr = NULL; - - /* hold card in reset state */ - setHardwareReset(dev); - - /* test memory */ - pattern = 0; - for (i = 0; i < memlen; i++) - WRITESHM(arlan_mem[i], ((u_char) pattern++), u_char); - - pattern = 0; - for (i = 0; i < memlen; i++) - { - char res; - READSHM(res, arlan_mem[i], char); - if (res != pattern++) - { - printk(KERN_ERR "Arlan driver memory test 1 failed \n"); - return -1; - } - } - - pattern = 0; - for (i = 0; i < memlen; i++) - WRITESHM(arlan_mem[i], ~(pattern++), char); - - pattern = 0; - for (i = 0; i < memlen; i++) - { - char res; - READSHM(res, arlan_mem[i], char); - if (res != ~(pattern++)) - { - printk(KERN_ERR "Arlan driver memory test 2 failed \n"); - return -1; - } - } - - /* zero memory */ - for (i = 0; i < memlen; i++) - WRITESHM(arlan_mem[i], 0x00, char); - - IFDEBUG(1) printk(KERN_INFO "Arlan: memory tests ok\n"); - - /* set reset flag and then release reset */ - WRITESHM(arlan->resetFlag, 0xff, u_char); - - clearChannelAttention(dev); - clearHardwareReset(dev); - - /* wait for reset flag to become zero, we'll wait for two seconds */ - if (arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW)) - { - printk(KERN_ERR "%s arlan: failed to come back from memory test\n", dev->name); - return -1; - } - return 0; -} - -static int arlan_setup_card_by_book(struct net_device *dev) -{ - u_char irqLevel, configuredStatusFlag; - struct arlan_private *priv = netdev_priv(dev); - volatile struct arlan_shmem __iomem *arlan = priv->card; - -// ARLAN_DEBUG_ENTRY("arlan_setup_card"); - - READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); - - IFDEBUG(10) - if (configuredStatusFlag != 0) - IFDEBUG(10) printk("arlan: CARD IS CONFIGURED\n"); - else - IFDEBUG(10) printk("arlan: card is NOT configured\n"); - - if (testMemory || (READSHMB(arlan->diagnosticInfo) != 0xff)) - if (arlan_hw_test_memory(dev)) - return -1; - - DEBUGSHM(4, "arlan configuredStatus = %d \n", arlan->configuredStatusFlag, u_char); - DEBUGSHM(4, "arlan driver diagnostic: 0x%2x\n", arlan->diagnosticInfo, u_char); - - /* issue nop command - no interrupt */ - arlan_command(dev, ARLAN_COMMAND_NOOP); - if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) - return -1; - - IFDEBUG(50) printk("1st Noop successfully executed !!\n"); - - /* try to turn on the arlan interrupts */ - clearClearInterrupt(dev); - setClearInterrupt(dev); - setInterruptEnable(dev); - - /* issue nop command - with interrupt */ - - arlan_command(dev, ARLAN_COMMAND_NOOPINT); - if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) - return -1; - - - IFDEBUG(50) printk("2nd Noop successfully executed !!\n"); - - READSHM(irqLevel, arlan->irqLevel, u_char) - - if (irqLevel != dev->irq) - { - IFDEBUG(1) printk(KERN_WARNING "arlan dip switches set irq to %d\n", irqLevel); - printk(KERN_WARNING "device driver irq set to %d - does not match\n", dev->irq); - dev->irq = irqLevel; - } - else - IFDEBUG(2) printk("irq level is OK\n"); - - - IFDEBUG(3) arlan_print_diagnostic_info(dev); - - arlan_command(dev, ARLAN_COMMAND_CONF); - - READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); - if (configuredStatusFlag == 0) - { - printk(KERN_WARNING "arlan configure failed\n"); - return -1; - } - arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); - arlan_command(dev, ARLAN_COMMAND_RX); - arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); - printk(KERN_NOTICE "%s: arlan driver version %s loaded\n", - dev->name, arlan_version); - -// ARLAN_DEBUG_EXIT("arlan_setup_card"); - - return 0; /* no errors */ -} -#endif - -#ifdef ARLAN_PROC_INTERFACE -#ifdef ARLAN_PROC_SHM_DUMP - -static char arlan_drive_info[ARLAN_STR_SIZE] = "A655\n\0"; - -static int arlan_sysctl_info(ctl_table * ctl, int write, - void __user *buffer, size_t * lenp, loff_t *ppos) -{ - int i; - int retv, pos, devnum; - struct arlan_private *priva = NULL; - struct net_device *dev; - pos = 0; - if (write) - { - printk("wrirte: "); - for (i = 0; i < 100; i++) - printk("adi %x \n", arlan_drive_info[i]); - } - if (ctl->procname == NULL || arlan_drive_info == NULL) - { - printk(KERN_WARNING " procname is NULL in sysctl_table or arlan_drive_info is NULL \n at arlan module\n "); - return -1; - } - devnum = ctl->procname[5] - '0'; - if (devnum < 0 || devnum > MAX_ARLANS - 1) - { - printk(KERN_WARNING "too strange devnum in procfs parse\n "); - return -1; - } - else if (arlan_device[devnum] == NULL) - { - if (ctl->procname) - pos += sprintf(arlan_drive_info + pos, "\t%s\n\n", ctl->procname); - pos += sprintf(arlan_drive_info + pos, "No device found here \n"); - goto final; - } - else - priva = netdev_priv(arlan_device[devnum]); - - if (priva == NULL) - { - printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); - return -1; - } - dev = arlan_device[devnum]; - - memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); - - pos = sprintf(arlan_drive_info, "Arlan info \n"); - /* Header Signature */ - SARLSTR(textRegion, 48); - SARLUC(resetFlag); - pos += sprintf(arlan_drive_info + pos, "diagnosticInfo\t=\t%s \n", arlan_diagnostic_info_string(dev)); - SARLUC(diagnosticInfo); - SARLUS(diagnosticOffset); - SARLUCN(_1, 12); - SARLUCN(lanCardNodeId, 6); - SARLUCN(broadcastAddress, 6); - pos += sprintf(arlan_drive_info + pos, "hardwareType =\t %s \n", arlan_hardware_type_string(dev)); - SARLUC(hardwareType); - SARLUC(majorHardwareVersion); - SARLUC(minorHardwareVersion); - SARLUC(radioModule); - SARLUC(defaultChannelSet); - SARLUCN(_2, 47); - - /* Control/Status Block - 0x0080 */ - SARLUC(interruptInProgress); - SARLUC(cntrlRegImage); - - SARLUCN(_3, 14); - SARLUC(commandByte); - SARLUCN(commandParameter, 15); - - /* Receive Status - 0x00a0 */ - SARLUC(rxStatus); - SARLUC(rxFrmType); - SARLUS(rxOffset); - SARLUS(rxLength); - SARLUCN(rxSrc, 6); - SARLUC(rxBroadcastFlag); - SARLUC(rxQuality); - SARLUC(scrambled); - SARLUCN(_4, 1); - - /* Transmit Status - 0x00b0 */ - SARLUC(txStatus); - SARLUC(txAckQuality); - SARLUC(numRetries); - SARLUCN(_5, 14); - SARLUCN(registeredRouter, 6); - SARLUCN(backboneRouter, 6); - SARLUC(registrationStatus); - SARLUC(configuredStatusFlag); - SARLUCN(_6, 1); - SARLUCN(ultimateDestAddress, 6); - SARLUCN(immedDestAddress, 6); - SARLUCN(immedSrcAddress, 6); - SARLUS(rxSequenceNumber); - SARLUC(assignedLocaltalkAddress); - SARLUCN(_7, 27); - - /* System Parameter Block */ - - /* - Driver Parameters (Novell Specific) */ - - SARLUS(txTimeout); - SARLUS(transportTime); - SARLUCN(_8, 4); - - /* - Configuration Parameters */ - SARLUC(irqLevel); - SARLUC(spreadingCode); - SARLUC(channelSet); - SARLUC(channelNumber); - SARLUS(radioNodeId); - SARLUCN(_9, 2); - SARLUC(scramblingDisable); - SARLUC(radioType); - SARLUS(routerId); - SARLUCN(_10, 9); - SARLUC(txAttenuation); - SARLUIA(systemId); - SARLUS(globalChecksum); - SARLUCN(_11, 4); - SARLUS(maxDatagramSize); - SARLUS(maxFrameSize); - SARLUC(maxRetries); - SARLUC(receiveMode); - SARLUC(priority); - SARLUC(rootOrRepeater); - SARLUCN(specifiedRouter, 6); - SARLUS(fastPollPeriod); - SARLUC(pollDecay); - SARLUSA(fastPollDelay); - SARLUC(arlThreshold); - SARLUC(arlDecay); - SARLUCN(_12, 1); - SARLUS(specRouterTimeout); - SARLUCN(_13, 5); - - /* Scrambled Area */ - SARLUIA(SID); - SARLUCN(encryptionKey, 12); - SARLUIA(_14); - SARLUSA(waitTime); - SARLUSA(lParameter); - SARLUCN(_15, 3); - SARLUS(headerSize); - SARLUS(sectionChecksum); - - SARLUC(registrationMode); - SARLUC(registrationFill); - SARLUS(pollPeriod); - SARLUS(refreshPeriod); - SARLSTR(name, 16); - SARLUCN(NID, 6); - SARLUC(localTalkAddress); - SARLUC(codeFormat); - SARLUC(numChannels); - SARLUC(channel1); - SARLUC(channel2); - SARLUC(channel3); - SARLUC(channel4); - SARLUCN(SSCode, 59); - -/* SARLUCN( _16, 0x140); - */ - /* Statistics Block - 0x0300 */ - SARLUC(hostcpuLock); - SARLUC(lancpuLock); - SARLUCN(resetTime, 18); - SARLUIA(numDatagramsTransmitted); - SARLUIA(numReTransmissions); - SARLUIA(numFramesDiscarded); - SARLUIA(numDatagramsReceived); - SARLUIA(numDuplicateReceivedFrames); - SARLUIA(numDatagramsDiscarded); - SARLUS(maxNumReTransmitDatagram); - SARLUS(maxNumReTransmitFrames); - SARLUS(maxNumConsecutiveDuplicateFrames); - /* misaligned here so we have to go to characters */ - SARLUIA(numBytesTransmitted); - SARLUIA(numBytesReceived); - SARLUIA(numCRCErrors); - SARLUIA(numLengthErrors); - SARLUIA(numAbortErrors); - SARLUIA(numTXUnderruns); - SARLUIA(numRXOverruns); - SARLUIA(numHoldOffs); - SARLUIA(numFramesTransmitted); - SARLUIA(numFramesReceived); - SARLUIA(numReceiveFramesLost); - SARLUIA(numRXBufferOverflows); - SARLUIA(numFramesDiscardedAddrMismatch); - SARLUIA(numFramesDiscardedSIDMismatch); - SARLUIA(numPollsTransmistted); - SARLUIA(numPollAcknowledges); - SARLUIA(numStatusTimeouts); - SARLUIA(numNACKReceived); - SARLUS(auxCmd); - SARLUCN(dumpPtr, 4); - SARLUC(dumpVal); - SARLUC(wireTest); - - /* next 4 seems too long for procfs, over single page ? - SARLUCN( _17, 0x86); - SARLUCN( txBuffer, 0x800); - SARLUCN( rxBuffer, 0x800); - SARLUCN( _18, 0x0bff); - */ - - pos += sprintf(arlan_drive_info + pos, "rxRing\t=\t0x"); - for (i = 0; i < 0x50; i++) - pos += sprintf(arlan_drive_info + pos, "%02x", ((char *) priva->conf)[priva->conf->rxOffset + i]); - pos += sprintf(arlan_drive_info + pos, "\n"); - - SARLUC(configStatus); - SARLUC(_22); - SARLUC(progIOCtrl); - SARLUC(shareMBase); - SARLUC(controlRegister); - - pos += sprintf(arlan_drive_info + pos, " total %d chars\n", pos); - if (ctl) - if (ctl->procname) - pos += sprintf(arlan_drive_info + pos, " driver name : %s\n", ctl->procname); -final: - *lenp = pos; - - if (!write) - retv = proc_dostring(ctl, write, buffer, lenp, ppos); - else - { - *lenp = 0; - return -1; - } - return retv; -} - - -static int arlan_sysctl_info161719(ctl_table * ctl, int write, - void __user *buffer, size_t * lenp, loff_t *ppos) -{ - int i; - int retv, pos, devnum; - struct arlan_private *priva = NULL; - - pos = 0; - devnum = ctl->procname[5] - '0'; - if (arlan_device[devnum] == NULL) - { - pos += sprintf(arlan_drive_info + pos, "No device found here \n"); - goto final; - } - else - priva = netdev_priv(arlan_device[devnum]); - if (priva == NULL) - { - printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); - return -1; - } - memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); - SARLUCN(_16, 0xC0); - SARLUCN(_17, 0x6A); - SARLUCN(_18, 14); - SARLUCN(_19, 0x86); - SARLUCN(_21, 0x3fd); - -final: - *lenp = pos; - retv = proc_dostring(ctl, write, buffer, lenp, ppos); - return retv; -} - -static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, - void __user *buffer, size_t * lenp, loff_t *ppos) -{ - int i; - int retv, pos, devnum; - struct arlan_private *priva = NULL; - - pos = 0; - devnum = ctl->procname[5] - '0'; - if (arlan_device[devnum] == NULL) - { - pos += sprintf(arlan_drive_info + pos, "No device found here \n"); - goto final; - } - else - priva = netdev_priv(arlan_device[devnum]); - if (priva == NULL) - { - printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); - return -1; - } - memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); - SARLBNpln(u_char, txBuffer, 0x800); -final: - *lenp = pos; - retv = proc_dostring(ctl, write, buffer, lenp, ppos); - return retv; -} - -static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, - void __user *buffer, size_t * lenp, loff_t *ppos) -{ - int i; - int retv, pos, devnum; - struct arlan_private *priva = NULL; - - pos = 0; - devnum = ctl->procname[5] - '0'; - if (arlan_device[devnum] == NULL) - { - pos += sprintf(arlan_drive_info + pos, "No device found here \n"); - goto final; - } else - priva = netdev_priv(arlan_device[devnum]); - if (priva == NULL) - { - printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); - return -1; - } - memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); - SARLBNpln(u_char, rxBuffer, 0x800); -final: - *lenp = pos; - retv = proc_dostring(ctl, write, buffer, lenp, ppos); - return retv; -} - -static int arlan_sysctl_info18(ctl_table * ctl, int write, - void __user *buffer, size_t * lenp, loff_t *ppos) -{ - int i; - int retv, pos, devnum; - struct arlan_private *priva = NULL; - - pos = 0; - devnum = ctl->procname[5] - '0'; - if (arlan_device[devnum] == NULL) - { - pos += sprintf(arlan_drive_info + pos, "No device found here \n"); - goto final; - } - else - priva = netdev_priv(arlan_device[devnum]); - if (priva == NULL) - { - printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); - return -1; - } - memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); - SARLBNpln(u_char, _18, 0x800); - -final: - *lenp = pos; - retv = proc_dostring(ctl, write, buffer, lenp, ppos); - return retv; -} - - -#endif /* #ifdef ARLAN_PROC_SHM_DUMP */ - - -static char conf_reset_result[200]; - -static int arlan_configure(ctl_table * ctl, int write, - void __user *buffer, size_t * lenp, loff_t *ppos) -{ - int pos = 0; - int devnum = ctl->procname[6] - '0'; - struct arlan_private *priv; - - if (devnum < 0 || devnum > MAX_ARLANS - 1) - { - printk(KERN_WARNING "too strange devnum in procfs parse\n "); - return -1; - } - else if (arlan_device[devnum] != NULL) - { - priv = netdev_priv(arlan_device[devnum]); - - arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF); - } - else - return -1; - - *lenp = pos; - return proc_dostring(ctl, write, buffer, lenp, ppos); -} - -static int arlan_sysctl_reset(ctl_table * ctl, int write, - void __user *buffer, size_t * lenp, loff_t *ppos) -{ - int pos = 0; - int devnum = ctl->procname[5] - '0'; - struct arlan_private *priv; - - if (devnum < 0 || devnum > MAX_ARLANS - 1) - { - printk(KERN_WARNING "too strange devnum in procfs parse\n "); - return -1; - } - else if (arlan_device[devnum] != NULL) - { - priv = netdev_priv(arlan_device[devnum]); - arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET); - - } else - return -1; - *lenp = pos + 3; - return proc_dostring(ctl, write, buffer, lenp, ppos); -} - - -/* Place files in /proc/sys/dev/arlan */ -#define CTBLN(num,card,nam) \ - { .ctl_name = num,\ - .procname = #nam,\ - .data = &(arlan_conf[card].nam),\ - .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec} -#ifdef ARLAN_DEBUGGING - -#define ARLAN_PROC_DEBUG_ENTRIES \ - { .ctl_name = 48, .procname = "entry_exit_debug",\ - .data = &arlan_entry_and_exit_debug,\ - .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec},\ - { .ctl_name = 49, .procname = "debug", .data = &arlan_debug,\ - .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec}, -#else -#define ARLAN_PROC_DEBUG_ENTRIES -#endif - -#define ARLAN_SYSCTL_TABLE_TOTAL(cardNo)\ - CTBLN(1,cardNo,spreadingCode),\ - CTBLN(2,cardNo, channelNumber),\ - CTBLN(3,cardNo, scramblingDisable),\ - CTBLN(4,cardNo, txAttenuation),\ - CTBLN(5,cardNo, systemId), \ - CTBLN(6,cardNo, maxDatagramSize),\ - CTBLN(7,cardNo, maxFrameSize),\ - CTBLN(8,cardNo, maxRetries),\ - CTBLN(9,cardNo, receiveMode),\ - CTBLN(10,cardNo, priority),\ - CTBLN(11,cardNo, rootOrRepeater),\ - CTBLN(12,cardNo, SID),\ - CTBLN(13,cardNo, registrationMode),\ - CTBLN(14,cardNo, registrationFill),\ - CTBLN(15,cardNo, localTalkAddress),\ - CTBLN(16,cardNo, codeFormat),\ - CTBLN(17,cardNo, numChannels),\ - CTBLN(18,cardNo, channel1),\ - CTBLN(19,cardNo, channel2),\ - CTBLN(20,cardNo, channel3),\ - CTBLN(21,cardNo, channel4),\ - CTBLN(22,cardNo, txClear),\ - CTBLN(23,cardNo, txRetries),\ - CTBLN(24,cardNo, txRouting),\ - CTBLN(25,cardNo, txScrambled),\ - CTBLN(26,cardNo, rxParameter),\ - CTBLN(27,cardNo, txTimeoutMs),\ - CTBLN(28,cardNo, waitCardTimeout),\ - CTBLN(29,cardNo, channelSet), \ - {.ctl_name = 30, .procname = "name",\ - .data = arlan_conf[cardNo].siteName,\ - .maxlen = 16, .mode = 0600, .proc_handler = &proc_dostring},\ - CTBLN(31,cardNo,waitTime),\ - CTBLN(32,cardNo,lParameter),\ - CTBLN(33,cardNo,_15),\ - CTBLN(34,cardNo,headerSize),\ - CTBLN(36,cardNo,tx_delay_ms),\ - CTBLN(37,cardNo,retries),\ - CTBLN(38,cardNo,ReTransmitPacketMaxSize),\ - CTBLN(39,cardNo,waitReTransmitPacketMaxSize),\ - CTBLN(40,cardNo,fastReTransCount),\ - CTBLN(41,cardNo,driverRetransmissions),\ - CTBLN(42,cardNo,txAckTimeoutMs),\ - CTBLN(43,cardNo,registrationInterrupts),\ - CTBLN(44,cardNo,hardwareType),\ - CTBLN(45,cardNo,radioType),\ - CTBLN(46,cardNo,writeEEPROM),\ - CTBLN(47,cardNo,writeRadioType),\ - ARLAN_PROC_DEBUG_ENTRIES\ - CTBLN(50,cardNo,in_speed),\ - CTBLN(51,cardNo,out_speed),\ - CTBLN(52,cardNo,in_speed10),\ - CTBLN(53,cardNo,out_speed10),\ - CTBLN(54,cardNo,in_speed_max),\ - CTBLN(55,cardNo,out_speed_max),\ - CTBLN(56,cardNo,measure_rate),\ - CTBLN(57,cardNo,pre_Command_Wait),\ - CTBLN(58,cardNo,rx_tweak1),\ - CTBLN(59,cardNo,rx_tweak2),\ - CTBLN(60,cardNo,tx_queue_len),\ - - - -static ctl_table arlan_conf_table0[] = -{ - ARLAN_SYSCTL_TABLE_TOTAL(0) - -#ifdef ARLAN_PROC_SHM_DUMP - { - .ctl_name = 150, - .procname = "arlan0-txRing", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_infotxRing, - }, - { - .ctl_name = 151, - .procname = "arlan0-rxRing", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_inforxRing, - }, - { - .ctl_name = 152, - .procname = "arlan0-18", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info18, - }, - { - .ctl_name = 153, - .procname = "arlan0-ring", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info161719, - }, - { - .ctl_name = 154, - .procname = "arlan0-shm-cpy", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info, - }, -#endif - { - .ctl_name = 155, - .procname = "config0", - .data = &conf_reset_result, - .maxlen = 100, - .mode = 0400, - .proc_handler = &arlan_configure - }, - { - .ctl_name = 156, - .procname = "reset0", - .data = &conf_reset_result, - .maxlen = 100, - .mode = 0400, - .proc_handler = &arlan_sysctl_reset, - }, - { .ctl_name = 0 } -}; - -static ctl_table arlan_conf_table1[] = -{ - - ARLAN_SYSCTL_TABLE_TOTAL(1) - -#ifdef ARLAN_PROC_SHM_DUMP - { - .ctl_name = 150, - .procname = "arlan1-txRing", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_infotxRing, - }, - { - .ctl_name = 151, - .procname = "arlan1-rxRing", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_inforxRing, - }, - { - .ctl_name = 152, - .procname = "arlan1-18", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info18, - }, - { - .ctl_name = 153, - .procname = "arlan1-ring", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info161719, - }, - { - .ctl_name = 154, - .procname = "arlan1-shm-cpy", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info, - }, -#endif - { - .ctl_name = 155, - .procname = "config1", - .data = &conf_reset_result, - .maxlen = 100, - .mode = 0400, - .proc_handler = &arlan_configure, - }, - { - .ctl_name = 156, - .procname = "reset1", - .data = &conf_reset_result, - .maxlen = 100, - .mode = 0400, - .proc_handler = &arlan_sysctl_reset, - }, - { .ctl_name = 0 } -}; - -static ctl_table arlan_conf_table2[] = -{ - - ARLAN_SYSCTL_TABLE_TOTAL(2) - -#ifdef ARLAN_PROC_SHM_DUMP - { - .ctl_name = 150, - .procname = "arlan2-txRing", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_infotxRing, - }, - { - .ctl_name = 151, - .procname = "arlan2-rxRing", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_inforxRing, - }, - { - .ctl_name = 152, - .procname = "arlan2-18", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info18, - }, - { - .ctl_name = 153, - .procname = "arlan2-ring", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info161719, - }, - { - .ctl_name = 154, - .procname = "arlan2-shm-cpy", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info, - }, -#endif - { - .ctl_name = 155, - .procname = "config2", - .data = &conf_reset_result, - .maxlen = 100, - .mode = 0400, - .proc_handler = &arlan_configure, - }, - { - .ctl_name = 156, - .procname = "reset2", - .data = &conf_reset_result, - .maxlen = 100, - .mode = 0400, - .proc_handler = &arlan_sysctl_reset, - }, - { .ctl_name = 0 } -}; - -static ctl_table arlan_conf_table3[] = -{ - - ARLAN_SYSCTL_TABLE_TOTAL(3) - -#ifdef ARLAN_PROC_SHM_DUMP - { - .ctl_name = 150, - .procname = "arlan3-txRing", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_infotxRing, - }, - { - .ctl_name = 151, - .procname = "arlan3-rxRing", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_inforxRing, - }, - { - .ctl_name = 152, - .procname = "arlan3-18", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info18, - }, - { - .ctl_name = 153, - .procname = "arlan3-ring", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info161719, - }, - { - .ctl_name = 154, - .procname = "arlan3-shm-cpy", - .data = &arlan_drive_info, - .maxlen = ARLAN_STR_SIZE, - .mode = 0400, - .proc_handler = &arlan_sysctl_info, - }, -#endif - { - .ctl_name = 155, - .procname = "config3", - .data = &conf_reset_result, - .maxlen = 100, - .mode = 0400, - .proc_handler = &arlan_configure, - }, - { - .ctl_name = 156, - .procname = "reset3", - .data = &conf_reset_result, - .maxlen = 100, - .mode = 0400, - .proc_handler = &arlan_sysctl_reset, - }, - { .ctl_name = 0 } -}; - - - -static ctl_table arlan_table[] = -{ - { - .ctl_name = 0, - .procname = "arlan0", - .maxlen = 0, - .mode = 0600, - .child = arlan_conf_table0, - }, - { - .ctl_name = 0, - .procname = "arlan1", - .maxlen = 0, - .mode = 0600, - .child = arlan_conf_table1, - }, - { - .ctl_name = 0, - .procname = "arlan2", - .maxlen = 0, - .mode = 0600, - .child = arlan_conf_table2, - }, - { - .ctl_name = 0, - .procname = "arlan3", - .maxlen = 0, - .mode = 0600, - .child = arlan_conf_table3, - }, - { .ctl_name = 0 } -}; - -#else - -static ctl_table arlan_table[MAX_ARLANS + 1] = -{ - { .ctl_name = 0 } -}; -#endif - - -// static int mmtu = 1234; - -static ctl_table arlan_root_table[] = -{ - { - .ctl_name = CTL_ARLAN, - .procname = "arlan", - .maxlen = 0, - .mode = 0555, - .child = arlan_table, - }, - { .ctl_name = 0 } -}; - -/* Make sure that /proc/sys/dev is there */ -//static ctl_table arlan_device_root_table[] = -//{ -// {CTL_DEV, "dev", NULL, 0, 0555, arlan_root_table}, -// {0} -//}; - - -static struct ctl_table_header *arlan_device_sysctl_header; - -int __init init_arlan_proc(void) -{ - - int i = 0; - if (arlan_device_sysctl_header) - return 0; - for (i = 0; i < MAX_ARLANS && arlan_device[i]; i++) - arlan_table[i].ctl_name = i + 1; - arlan_device_sysctl_header = register_sysctl_table(arlan_root_table); - if (!arlan_device_sysctl_header) - return -1; - - return 0; - -} - -void __exit cleanup_arlan_proc(void) -{ - unregister_sysctl_table(arlan_device_sysctl_header); - arlan_device_sysctl_header = NULL; - -} -#endif diff --git a/drivers/net/wireless/arlan.h b/drivers/net/wireless/arlan.h deleted file mode 100644 index fb3ad51a1caf..000000000000 --- a/drivers/net/wireless/arlan.h +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Copyright (C) 1997 Cullen Jennings - * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500 - * GNU General Public License applies - */ - -#include -#include -#include -#include -#include /* For the statistics structure. */ -#include /* For ARPHRD_ETHER */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -//#define ARLAN_DEBUGGING 1 - -#define ARLAN_PROC_INTERFACE -#define MAX_ARLANS 4 /* not more than 4 ! */ -#define ARLAN_PROC_SHM_DUMP /* shows all card registers, makes driver way larger */ - -#define ARLAN_MAX_MULTICAST_ADDRS 16 -#define ARLAN_RCV_CLEAN 0 -#define ARLAN_RCV_PROMISC 1 -#define ARLAN_RCV_CONTROL 2 - -#ifdef CONFIG_PROC_FS -extern int init_arlan_proc(void); -extern void cleanup_arlan_proc(void); -#else -#define init_arlan_proc() ({ 0; }) -#define cleanup_arlan_proc() do { } while (0) -#endif - -extern struct net_device *arlan_device[MAX_ARLANS]; -extern int arlan_debug; -extern int arlan_entry_debug; -extern int arlan_exit_debug; -extern int testMemory; -extern int arlan_command(struct net_device * dev, int command); - -#define SIDUNKNOWN -1 -#define radioNodeIdUNKNOWN -1 -#define irqUNKNOWN 0 -#define debugUNKNOWN 0 -#define testMemoryUNKNOWN 1 -#define spreadingCodeUNKNOWN 0 -#define channelNumberUNKNOWN 0 -#define channelSetUNKNOWN 0 -#define systemIdUNKNOWN -1 -#define registrationModeUNKNOWN -1 - - -#define IFDEBUG( L ) if ( (L) & arlan_debug ) -#define ARLAN_FAKE_HDR_LEN 12 - -#ifdef ARLAN_DEBUGGING - #define DEBUG 1 - #define ARLAN_ENTRY_EXIT_DEBUGGING 1 - #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b) -#else - #define ARLAN_DEBUG(a,b) -#endif - -#define ARLAN_SHMEM_SIZE 0x2000 - -struct arlan_shmem -{ - /* Header Signature */ - volatile char textRegion[48]; - volatile u_char resetFlag; - volatile u_char diagnosticInfo; - volatile u_short diagnosticOffset; - volatile u_char _1[12]; - volatile u_char lanCardNodeId[6]; - volatile u_char broadcastAddress[6]; - volatile u_char hardwareType; - volatile u_char majorHardwareVersion; - volatile u_char minorHardwareVersion; - volatile u_char radioModule;// shows EEPROM, can be overridden at 0x111 - volatile u_char defaultChannelSet; // shows EEProm, can be overriiden at 0x10A - volatile u_char _2[47]; - - /* Control/Status Block - 0x0080 */ - volatile u_char interruptInProgress; /* not used by lancpu */ - volatile u_char cntrlRegImage; /* not used by lancpu */ - volatile u_char _3[13]; - volatile u_char dumpByte; - volatile u_char commandByte; /* non-zero = active */ - volatile u_char commandParameter[15]; - - /* Receive Status - 0x00a0 */ - volatile u_char rxStatus; /* 1- data, 2-control, 0xff - registr change */ - volatile u_char rxFrmType; - volatile u_short rxOffset; - volatile u_short rxLength; - volatile u_char rxSrc[6]; - volatile u_char rxBroadcastFlag; - volatile u_char rxQuality; - volatile u_char scrambled; - volatile u_char _4[1]; - - /* Transmit Status - 0x00b0 */ - volatile u_char txStatus; - volatile u_char txAckQuality; - volatile u_char numRetries; - volatile u_char _5[14]; - volatile u_char registeredRouter[6]; - volatile u_char backboneRouter[6]; - volatile u_char registrationStatus; - volatile u_char configuredStatusFlag; - volatile u_char _6[1]; - volatile u_char ultimateDestAddress[6]; - volatile u_char immedDestAddress[6]; - volatile u_char immedSrcAddress[6]; - volatile u_short rxSequenceNumber; - volatile u_char assignedLocaltalkAddress; - volatile u_char _7[27]; - - /* System Parameter Block */ - - /* - Driver Parameters (Novell Specific) */ - - volatile u_short txTimeout; - volatile u_short transportTime; - volatile u_char _8[4]; - - /* - Configuration Parameters */ - volatile u_char irqLevel; - volatile u_char spreadingCode; - volatile u_char channelSet; - volatile u_char channelNumber; - volatile u_short radioNodeId; - volatile u_char _9[2]; - volatile u_char scramblingDisable; - volatile u_char radioType; - volatile u_short routerId; - volatile u_char _10[9]; - volatile u_char txAttenuation; - volatile u_char systemId[4]; - volatile u_short globalChecksum; - volatile u_char _11[4]; - volatile u_short maxDatagramSize; - volatile u_short maxFrameSize; - volatile u_char maxRetries; - volatile u_char receiveMode; - volatile u_char priority; - volatile u_char rootOrRepeater; - volatile u_char specifiedRouter[6]; - volatile u_short fastPollPeriod; - volatile u_char pollDecay; - volatile u_char fastPollDelay[2]; - volatile u_char arlThreshold; - volatile u_char arlDecay; - volatile u_char _12[1]; - volatile u_short specRouterTimeout; - volatile u_char _13[5]; - - /* Scrambled Area */ - volatile u_char SID[4]; - volatile u_char encryptionKey[12]; - volatile u_char _14[2]; - volatile u_char waitTime[2]; - volatile u_char lParameter[2]; - volatile u_char _15[3]; - volatile u_short headerSize; - volatile u_short sectionChecksum; - - volatile u_char registrationMode; - volatile u_char registrationFill; - volatile u_short pollPeriod; - volatile u_short refreshPeriod; - volatile u_char name[16]; - volatile u_char NID[6]; - volatile u_char localTalkAddress; - volatile u_char codeFormat; - volatile u_char numChannels; - volatile u_char channel1; - volatile u_char channel2; - volatile u_char channel3; - volatile u_char channel4; - volatile u_char SSCode[59]; - - volatile u_char _16[0xC0]; - volatile u_short auxCmd; - volatile u_char dumpPtr[4]; - volatile u_char dumpVal; - volatile u_char _17[0x6A]; - volatile u_char wireTest; - volatile u_char _18[14]; - - /* Statistics Block - 0x0300 */ - volatile u_char hostcpuLock; - volatile u_char lancpuLock; - volatile u_char resetTime[18]; - - volatile u_char numDatagramsTransmitted[4]; - volatile u_char numReTransmissions[4]; - volatile u_char numFramesDiscarded[4]; - volatile u_char numDatagramsReceived[4]; - volatile u_char numDuplicateReceivedFrames[4]; - volatile u_char numDatagramsDiscarded[4]; - - volatile u_short maxNumReTransmitDatagram; - volatile u_short maxNumReTransmitFrames; - volatile u_short maxNumConsecutiveDuplicateFrames; - /* misaligned here so we have to go to characters */ - - volatile u_char numBytesTransmitted[4]; - volatile u_char numBytesReceived[4]; - volatile u_char numCRCErrors[4]; - volatile u_char numLengthErrors[4]; - volatile u_char numAbortErrors[4]; - volatile u_char numTXUnderruns[4]; - volatile u_char numRXOverruns[4]; - volatile u_char numHoldOffs[4]; - volatile u_char numFramesTransmitted[4]; - volatile u_char numFramesReceived[4]; - volatile u_char numReceiveFramesLost[4]; - volatile u_char numRXBufferOverflows[4]; - volatile u_char numFramesDiscardedAddrMismatch[4]; - volatile u_char numFramesDiscardedSIDMismatch[4]; - volatile u_char numPollsTransmistted[4]; - volatile u_char numPollAcknowledges[4]; - volatile u_char numStatusTimeouts[4]; - volatile u_char numNACKReceived[4]; - - volatile u_char _19[0x86]; - - volatile u_char txBuffer[0x800]; - volatile u_char rxBuffer[0x800]; - - volatile u_char _20[0x800]; - volatile u_char _21[0x3fb]; - volatile u_char configStatus; - volatile u_char _22; - volatile u_char progIOCtrl; - volatile u_char shareMBase; - volatile u_char controlRegister; -}; - -struct arlan_conf_stru { - int spreadingCode; - int channelSet; - int channelNumber; - int scramblingDisable; - int txAttenuation; - int systemId; - int maxDatagramSize; - int maxFrameSize; - int maxRetries; - int receiveMode; - int priority; - int rootOrRepeater; - int SID; - int radioNodeId; - int registrationMode; - int registrationFill; - int localTalkAddress; - int codeFormat; - int numChannels; - int channel1; - int channel2; - int channel3; - int channel4; - int txClear; - int txRetries; - int txRouting; - int txScrambled; - int rxParameter; - int txTimeoutMs; - int txAckTimeoutMs; - int waitCardTimeout; - int waitTime; - int lParameter; - int _15; - int headerSize; - int retries; - int tx_delay_ms; - int waitReTransmitPacketMaxSize; - int ReTransmitPacketMaxSize; - int fastReTransCount; - int driverRetransmissions; - int registrationInterrupts; - int hardwareType; - int radioType; - int writeRadioType; - int writeEEPROM; - char siteName[17]; - int measure_rate; - int in_speed; - int out_speed; - int in_speed10; - int out_speed10; - int in_speed_max; - int out_speed_max; - int pre_Command_Wait; - int rx_tweak1; - int rx_tweak2; - int tx_queue_len; -}; - -extern struct arlan_conf_stru arlan_conf[MAX_ARLANS]; - -struct TxParam -{ - volatile short offset; - volatile short length; - volatile u_char dest[6]; - volatile unsigned char clear; - volatile unsigned char retries; - volatile unsigned char routing; - volatile unsigned char scrambled; -}; - -#define TX_RING_SIZE 2 -/* Information that need to be kept for each board. */ -struct arlan_private { - struct arlan_shmem __iomem * card; - struct arlan_shmem * conf; - - struct arlan_conf_stru * Conf; - int bad; - int reset; - unsigned long lastReset; - struct timer_list timer; - struct timer_list tx_delay_timer; - struct timer_list tx_retry_timer; - struct timer_list rx_check_timer; - - int registrationLostCount; - int reRegisterExp; - int irq_test_done; - - struct TxParam txRing[TX_RING_SIZE]; - char reTransmitBuff[0x800]; - int txLast; - unsigned ReTransmitRequested; - unsigned long tx_done_delayed; - unsigned long registrationLastSeen; - - unsigned long tx_last_sent; - unsigned long tx_last_cleared; - unsigned long retransmissions; - unsigned long interrupt_ack_requested; - spinlock_t lock; - unsigned long waiting_command_mask; - unsigned long card_polling_interval; - unsigned long last_command_buff_free_time; - - int under_reset; - int under_config; - int rx_command_given; - int tx_command_given; - unsigned long interrupt_processing_active; - unsigned long last_rx_int_ack_time; - unsigned long in_bytes; - unsigned long out_bytes; - unsigned long in_time; - unsigned long out_time; - unsigned long in_time10; - unsigned long out_time10; - unsigned long in_bytes10; - unsigned long out_bytes10; - int init_etherdev_alloc; -}; - - - -#define ARLAN_CLEAR 0x00 -#define ARLAN_RESET 0x01 -#define ARLAN_CHANNEL_ATTENTION 0x02 -#define ARLAN_INTERRUPT_ENABLE 0x04 -#define ARLAN_CLEAR_INTERRUPT 0x08 -#define ARLAN_POWER 0x40 -#define ARLAN_ACCESS 0x80 - -#define ARLAN_COM_CONF 0x01 -#define ARLAN_COM_RX_ENABLE 0x03 -#define ARLAN_COM_RX_ABORT 0x04 -#define ARLAN_COM_TX_ENABLE 0x05 -#define ARLAN_COM_TX_ABORT 0x06 -#define ARLAN_COM_NOP 0x07 -#define ARLAN_COM_STANDBY 0x08 -#define ARLAN_COM_ACTIVATE 0x09 -#define ARLAN_COM_GOTO_SLOW_POLL 0x0a -#define ARLAN_COM_INT 0x80 - - -#define TXLAST(dev) (((struct arlan_private *)netdev_priv(dev))->txRing[((struct arlan_private *)netdev_priv(dev))->txLast]) -#define TXHEAD(dev) (((struct arlan_private *)netdev_priv(dev))->txRing[0]) -#define TXTAIL(dev) (((struct arlan_private *)netdev_priv(dev))->txRing[1]) - -#define TXBuffStart(dev) offsetof(struct arlan_shmem, txBuffer) -#define TXBuffEnd(dev) offsetof(struct arlan_shmem, xxBuffer) - -#define READSHM(to,from,atype) {\ - atype tmp;\ - memcpy_fromio(&(tmp),&(from),sizeof(atype));\ - to = tmp;\ - } - -#define READSHMEM(from,atype)\ - atype from; \ - READSHM(from, arlan->from, atype); - -#define WRITESHM(to,from,atype) \ - { atype tmpSHM = from;\ - memcpy_toio(&(to),&tmpSHM,sizeof(atype));\ - } - -#define DEBUGSHM(levelSHM,stringSHM,stuff,atype) \ - { atype tmpSHM; \ - memcpy_fromio(&tmpSHM,&(stuff),sizeof(atype));\ - IFDEBUG(levelSHM) printk(stringSHM,tmpSHM);\ - } - -#define WRITESHMB(to, val) \ - writeb(val,&(to)) -#define READSHMB(to) \ - readb(&(to)) -#define WRITESHMS(to, val) \ - writew(val,&(to)) -#define READSHMS(to) \ - readw(&(to)) -#define WRITESHMI(to, val) \ - writel(val,&(to)) -#define READSHMI(to) \ - readl(&(to)) - - - - - -#define registrationBad(dev)\ - ( ( READSHMB(((struct arlan_private *)netdev_priv(dev))->card->registrationMode) > 0) && \ - ( READSHMB(((struct arlan_private *)netdev_priv(dev))->card->registrationStatus) == 0) ) - - -#define readControlRegister(dev)\ - READSHMB(((struct arlan_private *)netdev_priv(dev))->card->cntrlRegImage) - -#define writeControlRegister(dev, v){\ - WRITESHMB(((struct arlan_private *)netdev_priv(dev))->card->cntrlRegImage ,((v) &0xF) );\ - WRITESHMB(((struct arlan_private *)netdev_priv(dev))->card->controlRegister ,(v) );} - - -#define arlan_interrupt_lancpu(dev) {\ - int cr; \ - \ - cr = readControlRegister(dev);\ - if (cr & ARLAN_CHANNEL_ATTENTION){ \ - writeControlRegister(dev, (cr & ~ARLAN_CHANNEL_ATTENTION));\ - }else \ - writeControlRegister(dev, (cr | ARLAN_CHANNEL_ATTENTION));\ -} - -#define clearChannelAttention(dev){ \ - writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CHANNEL_ATTENTION);} -#define setHardwareReset(dev) {\ - writeControlRegister(dev,readControlRegister(dev) | ARLAN_RESET);} -#define clearHardwareReset(dev) {\ - writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_RESET);} -#define setInterruptEnable(dev){\ - writeControlRegister(dev,readControlRegister(dev) | ARLAN_INTERRUPT_ENABLE) ;} -#define clearInterruptEnable(dev){\ - writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_INTERRUPT_ENABLE) ;} -#define setClearInterrupt(dev){\ - writeControlRegister(dev,readControlRegister(dev) | ARLAN_CLEAR_INTERRUPT) ;} -#define clearClearInterrupt(dev){\ - writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CLEAR_INTERRUPT);} -#define setPowerOff(dev){\ - writeControlRegister(dev,readControlRegister(dev) | (ARLAN_POWER && ARLAN_ACCESS));\ - writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} -#define setPowerOn(dev){\ - writeControlRegister(dev,readControlRegister(dev) & ~(ARLAN_POWER)); } -#define arlan_lock_card_access(dev){\ - writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} -#define arlan_unlock_card_access(dev){\ - writeControlRegister(dev,readControlRegister(dev) | ARLAN_ACCESS ); } - - - - -#define ARLAN_COMMAND_RX 0x000001 -#define ARLAN_COMMAND_NOOP 0x000002 -#define ARLAN_COMMAND_NOOPINT 0x000004 -#define ARLAN_COMMAND_TX 0x000008 -#define ARLAN_COMMAND_CONF 0x000010 -#define ARLAN_COMMAND_RESET 0x000020 -#define ARLAN_COMMAND_TX_ABORT 0x000040 -#define ARLAN_COMMAND_RX_ABORT 0x000080 -#define ARLAN_COMMAND_POWERDOWN 0x000100 -#define ARLAN_COMMAND_POWERUP 0x000200 -#define ARLAN_COMMAND_SLOW_POLL 0x000400 -#define ARLAN_COMMAND_ACTIVATE 0x000800 -#define ARLAN_COMMAND_INT_ACK 0x001000 -#define ARLAN_COMMAND_INT_ENABLE 0x002000 -#define ARLAN_COMMAND_WAIT_NOW 0x004000 -#define ARLAN_COMMAND_LONG_WAIT_NOW 0x008000 -#define ARLAN_COMMAND_STANDBY 0x010000 -#define ARLAN_COMMAND_INT_RACK 0x020000 -#define ARLAN_COMMAND_INT_RENABLE 0x040000 -#define ARLAN_COMMAND_CONF_WAIT 0x080000 -#define ARLAN_COMMAND_TBUSY_CLEAR 0x100000 -#define ARLAN_COMMAND_CLEAN_AND_CONF (ARLAN_COMMAND_TX_ABORT\ - | ARLAN_COMMAND_RX_ABORT\ - | ARLAN_COMMAND_CONF) -#define ARLAN_COMMAND_CLEAN_AND_RESET (ARLAN_COMMAND_TX_ABORT\ - | ARLAN_COMMAND_RX_ABORT\ - | ARLAN_COMMAND_RESET) - - - -#define ARLAN_DEBUG_CHAIN_LOCKS 0x00001 -#define ARLAN_DEBUG_RESET 0x00002 -#define ARLAN_DEBUG_TIMING 0x00004 -#define ARLAN_DEBUG_CARD_STATE 0x00008 -#define ARLAN_DEBUG_TX_CHAIN 0x00010 -#define ARLAN_DEBUG_MULTICAST 0x00020 -#define ARLAN_DEBUG_HEADER_DUMP 0x00040 -#define ARLAN_DEBUG_INTERRUPT 0x00080 -#define ARLAN_DEBUG_STARTUP 0x00100 -#define ARLAN_DEBUG_SHUTDOWN 0x00200 - diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 7ddc5c8d8956..ca946ca3823b 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -133,5 +133,7 @@ source "drivers/staging/cowloop/Kconfig" source "drivers/staging/strip/Kconfig" +source "drivers/staging/arlan/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 4386a620e9b2..ed92324178bd 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_COWLOOP) += cowloop/ obj-$(CONFIG_STRIP) += strip/ +obj-$(CONFIG_ARLAN) += arlan/ diff --git a/drivers/staging/arlan/Kconfig b/drivers/staging/arlan/Kconfig new file mode 100644 index 000000000000..0585ed8b4d3e --- /dev/null +++ b/drivers/staging/arlan/Kconfig @@ -0,0 +1,15 @@ +config ARLAN + tristate "Aironet Arlan 655 & IC2200 DS support" + depends on ISA && !64BIT + select WIRELESS_EXT + ---help--- + Aironet makes Arlan, a class of wireless LAN adapters. These use the + www.Telxon.com chip, which is also used on several similar cards. + This driver is tested on the 655 and IC2200 series cards. Look at + for the latest information. + + The driver is built as two modules, arlan and arlan-proc. The latter + is the /proc interface and is not needed most of time. + + On some computers the card ends up in non-valid state after some + time. Use a ping-reset script to clear it. diff --git a/drivers/staging/arlan/Makefile b/drivers/staging/arlan/Makefile new file mode 100644 index 000000000000..9e58e5fae7b9 --- /dev/null +++ b/drivers/staging/arlan/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_ARLAN) += arlan.o + +arlan-objs := arlan-main.o arlan-proc.o diff --git a/drivers/staging/arlan/arlan-main.c b/drivers/staging/arlan/arlan-main.c new file mode 100644 index 000000000000..921a082487a1 --- /dev/null +++ b/drivers/staging/arlan/arlan-main.c @@ -0,0 +1,1887 @@ +/* + * Copyright (C) 1997 Cullen Jennings + * Copyright (C) 1998 Elmer Joandiu, elmer@ylenurme.ee + * GNU General Public License applies + * This module provides support for the Arlan 655 card made by Aironet + */ + +#include "arlan.h" + +#if BITS_PER_LONG != 32 +# error FIXME: this driver requires a 32-bit platform +#endif + +static const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee Oct'98, http://www.ylenurme.ee/~elmer/655/"; + +struct net_device *arlan_device[MAX_ARLANS]; + +static int SID = SIDUNKNOWN; +static int radioNodeId = radioNodeIdUNKNOWN; +static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; +int arlan_debug = debugUNKNOWN; +static int spreadingCode = spreadingCodeUNKNOWN; +static int channelNumber = channelNumberUNKNOWN; +static int channelSet = channelSetUNKNOWN; +static int systemId = systemIdUNKNOWN; +static int registrationMode = registrationModeUNKNOWN; +static int keyStart; +static int tx_delay_ms; +static int retries = 5; +static int tx_queue_len = 1; +static int arlan_EEPROM_bad; + +#ifdef ARLAN_DEBUGGING + +static int testMemory = testMemoryUNKNOWN; +static int irq = irqUNKNOWN; +static int txScrambled = 1; +static int mdebug; + +module_param(irq, int, 0); +module_param(mdebug, int, 0); +module_param(testMemory, int, 0); +module_param(txScrambled, int, 0); +MODULE_PARM_DESC(irq, "(unused)"); +MODULE_PARM_DESC(testMemory, "(unused)"); +MODULE_PARM_DESC(mdebug, "Arlan multicast debugging (0-1)"); +#endif + +module_param_named(debug, arlan_debug, int, 0); +module_param(spreadingCode, int, 0); +module_param(channelNumber, int, 0); +module_param(channelSet, int, 0); +module_param(systemId, int, 0); +module_param(registrationMode, int, 0); +module_param(radioNodeId, int, 0); +module_param(SID, int, 0); +module_param(keyStart, int, 0); +module_param(tx_delay_ms, int, 0); +module_param(retries, int, 0); +module_param(tx_queue_len, int, 0); +module_param_named(EEPROM_bad, arlan_EEPROM_bad, int, 0); +MODULE_PARM_DESC(debug, "Arlan debug enable (0-1)"); +MODULE_PARM_DESC(retries, "Arlan maximum packet retransmisions"); +#ifdef ARLAN_ENTRY_EXIT_DEBUGGING +static int arlan_entry_debug; +static int arlan_exit_debug; +static int arlan_entry_and_exit_debug; +module_param_named(entry_debug, arlan_entry_debug, int, 0); +module_param_named(exit_debug, arlan_exit_debug, int, 0); +module_param_named(entry_and_exit_debug, arlan_entry_and_exit_debug, int, 0); +MODULE_PARM_DESC(entry_debug, "Arlan driver function entry debugging"); +MODULE_PARM_DESC(exit_debug, "Arlan driver function exit debugging"); +MODULE_PARM_DESC(entry_and_exit_debug, "Arlan driver function entry and exit debugging"); +#endif + +struct arlan_conf_stru arlan_conf[MAX_ARLANS]; +static int arlans_found; + +static int arlan_open(struct net_device *dev); +static netdev_tx_t arlan_tx(struct sk_buff *skb, struct net_device *dev); +static irqreturn_t arlan_interrupt(int irq, void *dev_id); +static int arlan_close(struct net_device *dev); +static struct net_device_stats * + arlan_statistics (struct net_device *dev); +static void arlan_set_multicast (struct net_device *dev); +static int arlan_hw_tx (struct net_device* dev, char *buf, int length ); +static int arlan_hw_config (struct net_device * dev); +static void arlan_tx_done_interrupt (struct net_device * dev, int status); +static void arlan_rx_interrupt (struct net_device * dev, u_char rxStatus, u_short, u_short); +static void arlan_process_interrupt (struct net_device * dev); +static void arlan_tx_timeout (struct net_device *dev); + +static inline long us2ticks(int us) +{ + return us * (1000000 / HZ); +} + + +#ifdef ARLAN_ENTRY_EXIT_DEBUGGING +#define ARLAN_DEBUG_ENTRY(name) \ + {\ + struct timeval timev;\ + do_gettimeofday(&timev);\ + if (arlan_entry_debug || arlan_entry_and_exit_debug)\ + printk("--->>>" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec));\ + } +#define ARLAN_DEBUG_EXIT(name) \ + {\ + struct timeval timev;\ + do_gettimeofday(&timev);\ + if (arlan_exit_debug || arlan_entry_and_exit_debug)\ + printk("<<<---" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec) );\ + } +#else +#define ARLAN_DEBUG_ENTRY(name) +#define ARLAN_DEBUG_EXIT(name) +#endif + + +#define arlan_interrupt_ack(dev)\ + clearClearInterrupt(dev);\ + setClearInterrupt(dev); + +static inline int arlan_drop_tx(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + + dev->stats.tx_errors++; + if (priv->Conf->tx_delay_ms) + { + priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1; + } + else + { + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; + TXHEAD(dev).offset = 0; + TXTAIL(dev).offset = 0; + priv->txLast = 0; + priv->bad = 0; + if (!priv->under_reset && !priv->under_config) + netif_wake_queue (dev); + } + return 1; +} + + +int arlan_command(struct net_device *dev, int command_p) +{ + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + int udelayed = 0; + int i = 0; + unsigned long flags; + + ARLAN_DEBUG_ENTRY("arlan_command"); + + if (priv->card_polling_interval) + priv->card_polling_interval = 1; + + if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_DEBUG "arlan_command, %lx commandByte %x waiting %lx incoming %x \n", + jiffies, READSHMB(arlan->commandByte), + priv->waiting_command_mask, command_p); + + priv->waiting_command_mask |= command_p; + + if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + if (time_after(jiffies, priv->lastReset + 5 * HZ)) + priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; + + if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ACK) + { + arlan_interrupt_ack(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ACK; + } + if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ENABLE) + { + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ENABLE; + } + + /* Card access serializing lock */ + spin_lock_irqsave(&priv->lock, flags); + + /* Check cards status and waiting */ + + if (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) + { + while (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) + { + if (READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) /* || + (readControlRegister(dev) & ARLAN_ACCESS)) + */ + udelay(40); + else + priv->waiting_command_mask &= ~(ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW); + + udelayed++; + + if (priv->waiting_command_mask & ARLAN_COMMAND_LONG_WAIT_NOW) + { + if (udelayed * 40 > 1000000) + { + printk(KERN_ERR "%s long wait too long \n", dev->name); + priv->waiting_command_mask |= ARLAN_COMMAND_RESET; + break; + } + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_WAIT_NOW) + { + if (udelayed * 40 > 1000) + { + printk(KERN_ERR "%s short wait too long \n", dev->name); + goto bad_end; + } + } + } + } + else + { + i = 0; + while ((READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) && + conf->pre_Command_Wait > (i++) * 10) + udelay(10); + + + if ((READSHMB(arlan->resetFlag) || + READSHMB(arlan->commandByte)) && + !(priv->waiting_command_mask & ARLAN_COMMAND_RESET)) + { + goto card_busy_end; + } + } + if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + priv->under_reset = 1; + if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) + priv->under_config = 1; + + /* Issuing command */ + arlan_lock_card_access(dev); + if (priv->waiting_command_mask & ARLAN_COMMAND_POWERUP) + { + // if (readControlRegister(dev) & (ARLAN_ACCESS && ARLAN_POWER)) + setPowerOn(dev); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERUP; + priv->waiting_command_mask |= ARLAN_COMMAND_RESET; + priv->card_polling_interval = HZ / 10; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_ACTIVATE) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_ACTIVATE); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_ACTIVATE; + priv->card_polling_interval = HZ / 10; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RX_ABORT) + { + if (priv->rx_command_given) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_RX_ABORT); + arlan_interrupt_lancpu(dev); + priv->rx_command_given = 0; + } + priv->waiting_command_mask &= ~ARLAN_COMMAND_RX_ABORT; + priv->card_polling_interval = 1; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_TX_ABORT) + { + if (priv->tx_command_given) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ABORT); + arlan_interrupt_lancpu(dev); + priv->tx_command_given = 0; + } + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX_ABORT; + priv->card_polling_interval = 1; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) + { + priv->under_reset=1; + netif_stop_queue (dev); + + arlan_drop_tx(dev); + if (priv->tx_command_given || priv->rx_command_given) + { + printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); + } + netif_stop_queue (dev); + if (arlan_debug & ARLAN_DEBUG_RESET) + printk(KERN_ERR "%s: Doing chip reset\n", dev->name); + priv->lastReset = jiffies; + WRITESHM(arlan->commandByte, 0, u_char); + /* hold card in reset state */ + setHardwareReset(dev); + /* set reset flag and then release reset */ + WRITESHM(arlan->resetFlag, 0xff, u_char); + clearChannelAttention(dev); + clearHardwareReset(dev); + priv->card_polling_interval = HZ / 4; + priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; + priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RENABLE; +// priv->waiting_command_mask |= ARLAN_COMMAND_RX; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RACK) + { + clearHardwareReset(dev); + clearClearInterrupt(dev); + setClearInterrupt(dev); + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RACK; + priv->waiting_command_mask |= ARLAN_COMMAND_CONF; + priv->under_config = 1; + priv->under_reset = 0; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RENABLE) + { + setInterruptEnable(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RENABLE; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) + { + if (priv->tx_command_given || priv->rx_command_given) + { + printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); + } + arlan_drop_tx(dev); + setInterruptEnable(dev); + arlan_hw_config(dev); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF; + priv->card_polling_interval = HZ / 10; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; +// priv->waiting_command_mask |= ARLAN_COMMAND_INT_ENABLE; + priv->waiting_command_mask |= ARLAN_COMMAND_CONF_WAIT; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF_WAIT) + { + if (READSHMB(arlan->configuredStatusFlag) != 0 && + READSHMB(arlan->diagnosticInfo) == 0xff) + { + priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF_WAIT; + priv->waiting_command_mask |= ARLAN_COMMAND_RX; + priv->waiting_command_mask |= ARLAN_COMMAND_TBUSY_CLEAR; + priv->card_polling_interval = HZ / 10; + priv->tx_command_given = 0; + priv->under_config = 0; + } + else + { + priv->card_polling_interval = 1; + if (arlan_debug & ARLAN_DEBUG_TIMING) + printk(KERN_ERR "configure delayed \n"); + } + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_RX) + { + if (!registrationBad(dev)) + { + setInterruptEnable(dev); + memset_io(arlan->commandParameter, 0, 0xf); + WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_RX_ENABLE); + WRITESHMB(arlan->commandParameter[0], conf->rxParameter); + arlan_interrupt_lancpu(dev); + priv->rx_command_given = 0; // mnjah, bad + priv->waiting_command_mask &= ~ARLAN_COMMAND_RX; + priv->card_polling_interval = 1; + } + else + priv->card_polling_interval = 2; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_TBUSY_CLEAR) + { + if ( !registrationBad(dev) && + (netif_queue_stopped(dev) || !netif_running(dev)) ) + { + priv->waiting_command_mask &= ~ARLAN_COMMAND_TBUSY_CLEAR; + netif_wake_queue (dev); + } + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_TX) + { + if (!test_and_set_bit(0, (void *) &priv->tx_command_given)) + { + if (time_after(jiffies, + priv->tx_last_sent + us2ticks(conf->rx_tweak1)) + || time_before(jiffies, + priv->last_rx_int_ack_time + us2ticks(conf->rx_tweak2))) + { + setInterruptEnable(dev); + memset_io(arlan->commandParameter, 0, 0xf); + WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ENABLE | ARLAN_COM_INT); + memcpy_toio(arlan->commandParameter, &TXLAST(dev), 14); +// for ( i=1 ; i < 15 ; i++) printk("%02x:",READSHMB(arlan->commandParameter[i])); + priv->tx_last_sent = jiffies; + arlan_interrupt_lancpu(dev); + priv->tx_command_given = 1; + priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; + priv->card_polling_interval = 1; + } + else + { + priv->tx_command_given = 0; + priv->card_polling_interval = 1; + } + } + else if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_ERR "tx command when tx chain locked \n"); + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOPINT) + { + { + WRITESHMB(arlan->commandByte, ARLAN_COM_NOP | ARLAN_COM_INT); + } + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOPINT; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOP) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_NOP); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOP; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_SLOW_POLL) + { + WRITESHMB(arlan->commandByte, ARLAN_COM_GOTO_SLOW_POLL); + arlan_interrupt_lancpu(dev); + priv->waiting_command_mask &= ~ARLAN_COMMAND_SLOW_POLL; + priv->card_polling_interval = HZ / 3; + } + else if (priv->waiting_command_mask & ARLAN_COMMAND_POWERDOWN) + { + setPowerOff(dev); + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_WARNING "%s: Arlan Going Standby\n", dev->name); + priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERDOWN; + priv->card_polling_interval = 3 * HZ; + } + arlan_unlock_card_access(dev); + for (i = 0; READSHMB(arlan->commandByte) && i < 20; i++) + udelay(10); + if (READSHMB(arlan->commandByte)) + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_ERR "card busy leaving command %lx\n", priv->waiting_command_mask); + + spin_unlock_irqrestore(&priv->lock, flags); + ARLAN_DEBUG_EXIT("arlan_command"); + priv->last_command_buff_free_time = jiffies; + return 0; + +card_busy_end: + if (time_after(jiffies, priv->last_command_buff_free_time + HZ)) + priv->waiting_command_mask |= ARLAN_COMMAND_CLEAN_AND_RESET; + + if (arlan_debug & ARLAN_DEBUG_CARD_STATE) + printk(KERN_ERR "%s arlan_command card busy end \n", dev->name); + spin_unlock_irqrestore(&priv->lock, flags); + ARLAN_DEBUG_EXIT("arlan_command"); + return 1; + +bad_end: + printk(KERN_ERR "%s arlan_command bad end \n", dev->name); + + spin_unlock_irqrestore(&priv->lock, flags); + ARLAN_DEBUG_EXIT("arlan_command"); + + return -1; +} + +static inline void arlan_command_process(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + + int times = 0; + while (priv->waiting_command_mask && times < 8) + { + if (priv->waiting_command_mask) + { + if (arlan_command(dev, 0)) + break; + times++; + } + /* if long command, we won't repeat trying */ ; + if (priv->card_polling_interval > 1) + break; + times++; + } +} + + +static inline void arlan_retransmit_now(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + + + ARLAN_DEBUG_ENTRY("arlan_retransmit_now"); + if (TXLAST(dev).offset == 0) + { + if (TXHEAD(dev).offset) + { + priv->txLast = 0; + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to head \n"); + + } + else if (TXTAIL(dev).offset) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_DEBUG "TX buff switch to tail \n"); + priv->txLast = 1; + } + else + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "ReTransmit buff empty"); + netif_wake_queue (dev); + return; + + } + arlan_command(dev, ARLAN_COMMAND_TX); + + priv->Conf->driverRetransmissions++; + priv->retransmissions++; + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("Retransmit %d bytes \n", TXLAST(dev).length); + + ARLAN_DEBUG_EXIT("arlan_retransmit_now"); +} + + + +static void arlan_registration_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct arlan_private *priv = netdev_priv(dev); + int bh_mark_needed = 0; + int next_tick = 1; + long lostTime = ((long)jiffies - (long)priv->registrationLastSeen) + * (1000/HZ); + + if (registrationBad(dev)) + { + priv->registrationLostCount++; + if (lostTime > 7000 && lostTime < 7200) + { + printk(KERN_NOTICE "%s registration Lost \n", dev->name); + } + if (lostTime / priv->reRegisterExp > 2000) + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); + if (lostTime / (priv->reRegisterExp) > 3500) + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + if (priv->reRegisterExp < 400) + priv->reRegisterExp += 2; + if (lostTime > 7200) + { + next_tick = HZ; + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + } + } + else + { + if (priv->Conf->registrationMode && lostTime > 10000 && + priv->registrationLostCount) + { + printk(KERN_NOTICE "%s registration is back after %ld milliseconds\n", + dev->name, lostTime); + } + priv->registrationLastSeen = jiffies; + priv->registrationLostCount = 0; + priv->reRegisterExp = 1; + if (!netif_running(dev) ) + netif_wake_queue(dev); + if (time_after(priv->tx_last_sent,priv->tx_last_cleared) && + time_after(jiffies, priv->tx_last_sent * 5*HZ) ){ + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + priv->tx_last_cleared = jiffies; + } + } + + + if (!registrationBad(dev) && priv->ReTransmitRequested) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "Retransmit from timer \n"); + priv->ReTransmitRequested = 0; + arlan_retransmit_now(dev); + } + if (!registrationBad(dev) && + time_after(jiffies, priv->tx_done_delayed) && + priv->tx_done_delayed != 0) + { + TXLAST(dev).offset = 0; + if (priv->txLast) + priv->txLast = 0; + else if (TXTAIL(dev).offset) + priv->txLast = 1; + if (TXLAST(dev).offset) + { + arlan_retransmit_now(dev); + dev->trans_start = jiffies; + } + if (!(TXHEAD(dev).offset && TXTAIL(dev).offset)) + { + netif_wake_queue (dev); + } + priv->tx_done_delayed = 0; + bh_mark_needed = 1; + } + if (bh_mark_needed) + { + netif_wake_queue (dev); + } + arlan_process_interrupt(dev); + + if (next_tick < priv->card_polling_interval) + next_tick = priv->card_polling_interval; + + priv->timer.expires = jiffies + next_tick; + + add_timer(&priv->timer); +} + + +#ifdef ARLAN_DEBUGGING + +static void arlan_print_registers(struct net_device *dev, int line) +{ + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem *arlan = priv->card; + + u_char hostcpuLock, lancpuLock, controlRegister, cntrlRegImage, + txStatus, rxStatus, interruptInProgress, commandByte; + + + ARLAN_DEBUG_ENTRY("arlan_print_registers"); + READSHM(interruptInProgress, arlan->interruptInProgress, u_char); + READSHM(hostcpuLock, arlan->hostcpuLock, u_char); + READSHM(lancpuLock, arlan->lancpuLock, u_char); + READSHM(controlRegister, arlan->controlRegister, u_char); + READSHM(cntrlRegImage, arlan->cntrlRegImage, u_char); + READSHM(txStatus, arlan->txStatus, u_char); + READSHM(rxStatus, arlan->rxStatus, u_char); + READSHM(commandByte, arlan->commandByte, u_char); + + printk(KERN_WARNING "line %04d IP %02x HL %02x LL %02x CB %02x CR %02x CRI %02x TX %02x RX %02x\n", + line, interruptInProgress, hostcpuLock, lancpuLock, commandByte, + controlRegister, cntrlRegImage, txStatus, rxStatus); + + ARLAN_DEBUG_EXIT("arlan_print_registers"); +} +#endif + + +static int arlan_hw_tx(struct net_device *dev, char *buf, int length) +{ + int i; + + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + + int tailStarts = 0x800; + int headEnds = 0x0; + + + ARLAN_DEBUG_ENTRY("arlan_hw_tx"); + if (TXHEAD(dev).offset) + headEnds = (((TXHEAD(dev).offset + TXHEAD(dev).length - offsetof(struct arlan_shmem, txBuffer)) / 64) + 1) * 64; + if (TXTAIL(dev).offset) + tailStarts = 0x800 - (((TXTAIL(dev).offset - offsetof(struct arlan_shmem, txBuffer)) / 64) + 2) * 64; + + + if (!TXHEAD(dev).offset && length < tailStarts) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TXHEAD insert, tailStart %d\n", tailStarts); + + TXHEAD(dev).offset = + offsetof(struct arlan_shmem, txBuffer); + TXHEAD(dev).length = length - ARLAN_FAKE_HDR_LEN; + for (i = 0; i < 6; i++) + TXHEAD(dev).dest[i] = buf[i]; + TXHEAD(dev).clear = conf->txClear; + TXHEAD(dev).retries = conf->txRetries; /* 0 is use default */ + TXHEAD(dev).routing = conf->txRouting; + TXHEAD(dev).scrambled = conf->txScrambled; + memcpy_toio((char __iomem *)arlan + TXHEAD(dev).offset, buf + ARLAN_FAKE_HDR_LEN, TXHEAD(dev).length); + } + else if (!TXTAIL(dev).offset && length < (0x800 - headEnds)) + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TXTAIL insert, headEnd %d\n", headEnds); + + TXTAIL(dev).offset = + offsetof(struct arlan_shmem, txBuffer) + 0x800 - (length / 64 + 2) * 64; + TXTAIL(dev).length = length - ARLAN_FAKE_HDR_LEN; + for (i = 0; i < 6; i++) + TXTAIL(dev).dest[i] = buf[i]; + TXTAIL(dev).clear = conf->txClear; + TXTAIL(dev).retries = conf->txRetries; + TXTAIL(dev).routing = conf->txRouting; + TXTAIL(dev).scrambled = conf->txScrambled; + memcpy_toio(((char __iomem *)arlan + TXTAIL(dev).offset), buf + ARLAN_FAKE_HDR_LEN, TXTAIL(dev).length); + } + else + { + netif_stop_queue (dev); + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk(KERN_ERR "TX TAIL & HEAD full, return, tailStart %d headEnd %d\n", tailStarts, headEnds); + return -1; + } + priv->out_bytes += length; + priv->out_bytes10 += length; + if (conf->measure_rate < 1) + conf->measure_rate = 1; + if (time_after(jiffies, priv->out_time + conf->measure_rate * HZ)) + { + conf->out_speed = priv->out_bytes / conf->measure_rate; + priv->out_bytes = 0; + priv->out_time = jiffies; + } + if (time_after(jiffies, priv->out_time10 + conf->measure_rate * 10*HZ)) + { + conf->out_speed10 = priv->out_bytes10 / (10 * conf->measure_rate); + priv->out_bytes10 = 0; + priv->out_time10 = jiffies; + } + if (TXHEAD(dev).offset && TXTAIL(dev).offset) + { + netif_stop_queue (dev); + return 0; + } + else + netif_start_queue (dev); + + + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + printk(KERN_WARNING "%s Transmit t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name, + (unsigned char) buf[0], (unsigned char) buf[1], (unsigned char) buf[2], (unsigned char) buf[3], + (unsigned char) buf[4], (unsigned char) buf[5], (unsigned char) buf[6], (unsigned char) buf[7], + (unsigned char) buf[8], (unsigned char) buf[9], (unsigned char) buf[10], (unsigned char) buf[11]); + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk(KERN_ERR "TX command prepare for buffer %d\n", priv->txLast); + + arlan_command(dev, ARLAN_COMMAND_TX); + + priv->tx_last_sent = jiffies; + + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) printk("%s TX Qued %d bytes \n", dev->name, length); + + ARLAN_DEBUG_EXIT("arlan_hw_tx"); + + return 0; +} + + +static int arlan_hw_config(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + + ARLAN_DEBUG_ENTRY("arlan_hw_config"); + + printk(KERN_NOTICE "%s arlan configure called \n", dev->name); + if (arlan_EEPROM_bad) + printk(KERN_NOTICE "arlan configure with eeprom bad option \n"); + + + WRITESHM(arlan->spreadingCode, conf->spreadingCode, u_char); + WRITESHM(arlan->channelSet, conf->channelSet, u_char); + + if (arlan_EEPROM_bad) + WRITESHM(arlan->defaultChannelSet, conf->channelSet, u_char); + + WRITESHM(arlan->channelNumber, conf->channelNumber, u_char); + + WRITESHM(arlan->scramblingDisable, conf->scramblingDisable, u_char); + WRITESHM(arlan->txAttenuation, conf->txAttenuation, u_char); + + WRITESHM(arlan->systemId, conf->systemId, u_int); + + WRITESHM(arlan->maxRetries, conf->maxRetries, u_char); + WRITESHM(arlan->receiveMode, conf->receiveMode, u_char); + WRITESHM(arlan->priority, conf->priority, u_char); + WRITESHM(arlan->rootOrRepeater, conf->rootOrRepeater, u_char); + WRITESHM(arlan->SID, conf->SID, u_int); + + WRITESHM(arlan->registrationMode, conf->registrationMode, u_char); + + WRITESHM(arlan->registrationFill, conf->registrationFill, u_char); + WRITESHM(arlan->localTalkAddress, conf->localTalkAddress, u_char); + WRITESHM(arlan->codeFormat, conf->codeFormat, u_char); + WRITESHM(arlan->numChannels, conf->numChannels, u_char); + WRITESHM(arlan->channel1, conf->channel1, u_char); + WRITESHM(arlan->channel2, conf->channel2, u_char); + WRITESHM(arlan->channel3, conf->channel3, u_char); + WRITESHM(arlan->channel4, conf->channel4, u_char); + WRITESHM(arlan->radioNodeId, conf->radioNodeId, u_short); + WRITESHM(arlan->SID, conf->SID, u_int); + WRITESHM(arlan->waitTime, conf->waitTime, u_short); + WRITESHM(arlan->lParameter, conf->lParameter, u_short); + memcpy_toio(&(arlan->_15), &(conf->_15), 3); + WRITESHM(arlan->_15, conf->_15, u_short); + WRITESHM(arlan->headerSize, conf->headerSize, u_short); + if (arlan_EEPROM_bad) + WRITESHM(arlan->hardwareType, conf->hardwareType, u_char); + WRITESHM(arlan->radioType, conf->radioType, u_char); + if (arlan_EEPROM_bad) + WRITESHM(arlan->radioModule, conf->radioType, u_char); + + memcpy_toio(arlan->encryptionKey + keyStart, encryptionKey, 8); + memcpy_toio(arlan->name, conf->siteName, 16); + + WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_CONF); /* do configure */ + memset_io(arlan->commandParameter, 0, 0xf); /* 0xf */ + memset_io(arlan->commandParameter + 1, 0, 2); + if (conf->writeEEPROM) + { + memset_io(arlan->commandParameter, conf->writeEEPROM, 1); +// conf->writeEEPROM=0; + } + if (conf->registrationMode && conf->registrationInterrupts) + memset_io(arlan->commandParameter + 3, 1, 1); + else + memset_io(arlan->commandParameter + 3, 0, 1); + + priv->irq_test_done = 0; + + if (conf->tx_queue_len) + dev->tx_queue_len = conf->tx_queue_len; + udelay(100); + + ARLAN_DEBUG_EXIT("arlan_hw_config"); + return 0; +} + + +static int arlan_read_card_configuration(struct net_device *dev) +{ + u_char tlx415; + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + + ARLAN_DEBUG_ENTRY("arlan_read_card_configuration"); + + if (radioNodeId == radioNodeIdUNKNOWN) + { + READSHM(conf->radioNodeId, arlan->radioNodeId, u_short); + } + else + conf->radioNodeId = radioNodeId; + + if (SID == SIDUNKNOWN) + { + READSHM(conf->SID, arlan->SID, u_int); + } + else conf->SID = SID; + + if (spreadingCode == spreadingCodeUNKNOWN) + { + READSHM(conf->spreadingCode, arlan->spreadingCode, u_char); + } + else + conf->spreadingCode = spreadingCode; + + if (channelSet == channelSetUNKNOWN) + { + READSHM(conf->channelSet, arlan->channelSet, u_char); + } + else conf->channelSet = channelSet; + + if (channelNumber == channelNumberUNKNOWN) + { + READSHM(conf->channelNumber, arlan->channelNumber, u_char); + } + else conf->channelNumber = channelNumber; + + READSHM(conf->scramblingDisable, arlan->scramblingDisable, u_char); + READSHM(conf->txAttenuation, arlan->txAttenuation, u_char); + + if (systemId == systemIdUNKNOWN) + { + READSHM(conf->systemId, arlan->systemId, u_int); + } + else conf->systemId = systemId; + + READSHM(conf->maxDatagramSize, arlan->maxDatagramSize, u_short); + READSHM(conf->maxFrameSize, arlan->maxFrameSize, u_short); + READSHM(conf->maxRetries, arlan->maxRetries, u_char); + READSHM(conf->receiveMode, arlan->receiveMode, u_char); + READSHM(conf->priority, arlan->priority, u_char); + READSHM(conf->rootOrRepeater, arlan->rootOrRepeater, u_char); + + if (SID == SIDUNKNOWN) + { + READSHM(conf->SID, arlan->SID, u_int); + } + else conf->SID = SID; + + if (registrationMode == registrationModeUNKNOWN) + { + READSHM(conf->registrationMode, arlan->registrationMode, u_char); + } + else conf->registrationMode = registrationMode; + + READSHM(conf->registrationFill, arlan->registrationFill, u_char); + READSHM(conf->localTalkAddress, arlan->localTalkAddress, u_char); + READSHM(conf->codeFormat, arlan->codeFormat, u_char); + READSHM(conf->numChannels, arlan->numChannels, u_char); + READSHM(conf->channel1, arlan->channel1, u_char); + READSHM(conf->channel2, arlan->channel2, u_char); + READSHM(conf->channel3, arlan->channel3, u_char); + READSHM(conf->channel4, arlan->channel4, u_char); + READSHM(conf->waitTime, arlan->waitTime, u_short); + READSHM(conf->lParameter, arlan->lParameter, u_short); + READSHM(conf->_15, arlan->_15, u_short); + READSHM(conf->headerSize, arlan->headerSize, u_short); + READSHM(conf->hardwareType, arlan->hardwareType, u_char); + READSHM(conf->radioType, arlan->radioModule, u_char); + + if (conf->radioType == 0) + conf->radioType = 0xc; + + WRITESHM(arlan->configStatus, 0xA5, u_char); + READSHM(tlx415, arlan->configStatus, u_char); + + if (tlx415 != 0xA5) + printk(KERN_INFO "%s tlx415 chip \n", dev->name); + + conf->txClear = 0; + conf->txRetries = 1; + conf->txRouting = 1; + conf->txScrambled = 0; + conf->rxParameter = 1; + conf->txTimeoutMs = 4000; + conf->waitCardTimeout = 100000; + conf->receiveMode = ARLAN_RCV_CLEAN; + memcpy_fromio(conf->siteName, arlan->name, 16); + conf->siteName[16] = '\0'; + conf->retries = retries; + conf->tx_delay_ms = tx_delay_ms; + conf->ReTransmitPacketMaxSize = 200; + conf->waitReTransmitPacketMaxSize = 200; + conf->txAckTimeoutMs = 900; + conf->fastReTransCount = 3; + + ARLAN_DEBUG_EXIT("arlan_read_card_configuration"); + + return 0; +} + + +static int lastFoundAt = 0xbe000; + + +/* + * This is the real probe routine. Linux has a history of friendly device + * probes on the ISA bus. A good device probes avoids doing writes, and + * verifies that the correct device exists and functions. + */ +#define ARLAN_SHMEM_SIZE 0x2000 +static int __init arlan_check_fingerprint(unsigned long memaddr) +{ + static const char probeText[] = "TELESYSTEM SLW INC. ARLAN \0"; + volatile struct arlan_shmem __iomem *arlan = (struct arlan_shmem *) memaddr; + unsigned long paddr = virt_to_phys((void *) memaddr); + char tempBuf[49]; + + ARLAN_DEBUG_ENTRY("arlan_check_fingerprint"); + + if (!request_mem_region(paddr, ARLAN_SHMEM_SIZE, "arlan")) { + // printk(KERN_WARNING "arlan: memory region %lx excluded from probing \n",paddr); + return -ENODEV; + } + + memcpy_fromio(tempBuf, arlan->textRegion, 29); + tempBuf[30] = 0; + + /* check for card at this address */ + if (0 != strncmp(tempBuf, probeText, 29)){ + release_mem_region(paddr, ARLAN_SHMEM_SIZE); + return -ENODEV; + } + +// printk(KERN_INFO "arlan found at 0x%x \n",memaddr); + ARLAN_DEBUG_EXIT("arlan_check_fingerprint"); + + return 0; +} + +static int arlan_change_mtu(struct net_device *dev, int new_mtu) +{ + struct arlan_private *priv = netdev_priv(dev); + struct arlan_conf_stru *conf = priv->Conf; + + ARLAN_DEBUG_ENTRY("arlan_change_mtu"); + if (new_mtu > 2032) + return -EINVAL; + dev->mtu = new_mtu; + if (new_mtu < 256) + new_mtu = 256; /* cards book suggests 1600 */ + conf->maxDatagramSize = new_mtu; + conf->maxFrameSize = new_mtu + 48; + + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_CONF); + printk(KERN_NOTICE "%s mtu changed to %d \n", dev->name, new_mtu); + + ARLAN_DEBUG_EXIT("arlan_change_mtu"); + + return 0; +} + +static int arlan_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + + ARLAN_DEBUG_ENTRY("arlan_mac_addr"); + return -EINVAL; + + if (netif_running(dev)) + return -EBUSY; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + ARLAN_DEBUG_EXIT("arlan_mac_addr"); + return 0; +} + +static const struct net_device_ops arlan_netdev_ops = { + .ndo_open = arlan_open, + .ndo_stop = arlan_close, + .ndo_start_xmit = arlan_tx, + .ndo_get_stats = arlan_statistics, + .ndo_set_multicast_list = arlan_set_multicast, + .ndo_change_mtu = arlan_change_mtu, + .ndo_set_mac_address = arlan_mac_addr, + .ndo_tx_timeout = arlan_tx_timeout, + .ndo_validate_addr = eth_validate_addr, +}; + +static int __init arlan_setup_device(struct net_device *dev, int num) +{ + struct arlan_private *ap = netdev_priv(dev); + int err; + + ARLAN_DEBUG_ENTRY("arlan_setup_device"); + + ap->conf = (struct arlan_shmem *)(ap+1); + + dev->tx_queue_len = tx_queue_len; + dev->netdev_ops = &arlan_netdev_ops; + dev->watchdog_timeo = 3*HZ; + + ap->irq_test_done = 0; + ap->Conf = &arlan_conf[num]; + + ap->Conf->pre_Command_Wait = 40; + ap->Conf->rx_tweak1 = 30; + ap->Conf->rx_tweak2 = 0; + + + err = register_netdev(dev); + if (err) { + release_mem_region(virt_to_phys((void *) dev->mem_start), + ARLAN_SHMEM_SIZE); + free_netdev(dev); + return err; + } + arlan_device[num] = dev; + ARLAN_DEBUG_EXIT("arlan_setup_device"); + return 0; +} + +static int __init arlan_probe_here(struct net_device *dev, + unsigned long memaddr) +{ + struct arlan_private *ap = netdev_priv(dev); + + ARLAN_DEBUG_ENTRY("arlan_probe_here"); + + if (arlan_check_fingerprint(memaddr)) + return -ENODEV; + + printk(KERN_NOTICE "%s: Arlan found at %llx, \n ", dev->name, + (u64) virt_to_phys((void*)memaddr)); + + ap->card = (void *) memaddr; + dev->mem_start = memaddr; + dev->mem_end = memaddr + ARLAN_SHMEM_SIZE-1; + + if (dev->irq < 2) + { + READSHM(dev->irq, ap->card->irqLevel, u_char); + } else if (dev->irq == 2) + dev->irq = 9; + + arlan_read_card_configuration(dev); + + ARLAN_DEBUG_EXIT("arlan_probe_here"); + return 0; +} + + +static int arlan_open(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + int ret = 0; + + ARLAN_DEBUG_ENTRY("arlan_open"); + + ret = request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev); + if (ret) + { + printk(KERN_ERR "%s: unable to get IRQ %d .\n", + dev->name, dev->irq); + return ret; + } + + + priv->bad = 0; + priv->lastReset = 0; + priv->reset = 0; + memcpy_fromio(dev->dev_addr, arlan->lanCardNodeId, 6); + memset(dev->broadcast, 0xff, 6); + dev->tx_queue_len = tx_queue_len; + priv->interrupt_processing_active = 0; + spin_lock_init(&priv->lock); + + netif_start_queue (dev); + + priv->registrationLostCount = 0; + priv->registrationLastSeen = jiffies; + priv->txLast = 0; + priv->tx_command_given = 0; + priv->rx_command_given = 0; + + priv->reRegisterExp = 1; + priv->tx_last_sent = jiffies - 1; + priv->tx_last_cleared = jiffies; + priv->Conf->writeEEPROM = 0; + priv->Conf->registrationInterrupts = 1; + + init_timer(&priv->timer); + priv->timer.expires = jiffies + HZ / 10; + priv->timer.data = (unsigned long) dev; + priv->timer.function = &arlan_registration_timer; /* timer handler */ + + arlan_command(dev, ARLAN_COMMAND_POWERUP | ARLAN_COMMAND_LONG_WAIT_NOW); + mdelay(200); + add_timer(&priv->timer); + + ARLAN_DEBUG_EXIT("arlan_open"); + return 0; +} + + +static void arlan_tx_timeout (struct net_device *dev) +{ + printk(KERN_ERR "%s: arlan transmit timed out, kernel decided\n", dev->name); + /* Try to restart the adaptor. */ + arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET); + // dev->trans_start = jiffies; + // netif_start_queue (dev); +} + + +static netdev_tx_t arlan_tx(struct sk_buff *skb, struct net_device *dev) +{ + short length; + unsigned char *buf; + + ARLAN_DEBUG_ENTRY("arlan_tx"); + + length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + buf = skb->data; + + if (length + 0x12 > 0x800) { + printk(KERN_ERR "TX RING overflow \n"); + netif_stop_queue (dev); + } + + if (arlan_hw_tx(dev, buf, length) == -1) + goto bad_end; + + dev->trans_start = jiffies; + + dev_kfree_skb(skb); + + arlan_process_interrupt(dev); + ARLAN_DEBUG_EXIT("arlan_tx"); + return NETDEV_TX_OK; + +bad_end: + arlan_process_interrupt(dev); + netif_stop_queue (dev); + ARLAN_DEBUG_EXIT("arlan_tx"); + return NETDEV_TX_BUSY; +} + + +static inline int DoNotReTransmitCrap(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + + if (TXLAST(dev).length < priv->Conf->ReTransmitPacketMaxSize) + return 1; + return 0; + +} + +static inline int DoNotWaitReTransmitCrap(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + + if (TXLAST(dev).length < priv->Conf->waitReTransmitPacketMaxSize) + return 1; + return 0; +} + +static inline void arlan_queue_retransmit(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + + ARLAN_DEBUG_ENTRY("arlan_queue_retransmit"); + + if (DoNotWaitReTransmitCrap(dev)) + { + arlan_drop_tx(dev); + } else + priv->ReTransmitRequested++; + + ARLAN_DEBUG_EXIT("arlan_queue_retransmit"); +} + +static inline void RetryOrFail(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + + ARLAN_DEBUG_ENTRY("RetryOrFail"); + + if (priv->retransmissions > priv->Conf->retries || + DoNotReTransmitCrap(dev)) + { + arlan_drop_tx(dev); + } + else if (priv->bad <= priv->Conf->fastReTransCount) + { + arlan_retransmit_now(dev); + } + else arlan_queue_retransmit(dev); + + ARLAN_DEBUG_EXIT("RetryOrFail"); +} + + +static void arlan_tx_done_interrupt(struct net_device *dev, int status) +{ + struct arlan_private *priv = netdev_priv(dev); + + ARLAN_DEBUG_ENTRY("arlan_tx_done_interrupt"); + + priv->tx_last_cleared = jiffies; + priv->tx_command_given = 0; + switch (status) + { + case 1: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit OK\n"); + dev->stats.tx_packets++; + priv->bad = 0; + priv->reset = 0; + priv->retransmissions = 0; + if (priv->Conf->tx_delay_ms) + { + priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1; + } + else + { + TXLAST(dev).offset = 0; + if (priv->txLast) + priv->txLast = 0; + else if (TXTAIL(dev).offset) + priv->txLast = 1; + if (TXLAST(dev).offset) + { + arlan_retransmit_now(dev); + dev->trans_start = jiffies; + } + if (!TXHEAD(dev).offset || !TXTAIL(dev).offset) + { + netif_wake_queue (dev); + } + } + } + break; + + case 2: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit timed out\n"); + priv->bad += 1; + //arlan_queue_retransmit(dev); + RetryOrFail(dev); + } + break; + + case 3: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit max retries\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_queue_retransmit(dev); + RetryOrFail(dev); + } + break; + + case 4: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit aborted\n"); + priv->bad += 1; + arlan_queue_retransmit(dev); + //RetryOrFail(dev); + } + break; + + case 5: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit not registered\n"); + priv->bad += 1; + //debug=101; + arlan_queue_retransmit(dev); + } + break; + + case 6: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit destination full\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + case 7: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit unknown ack\n"); + priv->bad += 1; + priv->reset = 0; + arlan_queue_retransmit(dev); + } + break; + + case 8: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit dest mail box full\n"); + priv->bad += 1; + priv->reset = 0; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + case 9: + { + IFDEBUG(ARLAN_DEBUG_TX_CHAIN) + printk("arlan intr: transmit root dest not reg.\n"); + priv->bad += 1; + priv->reset = 1; + //arlan_drop_tx(dev); + arlan_queue_retransmit(dev); + } + break; + + default: + { + printk(KERN_ERR "arlan intr: transmit status unknown\n"); + priv->bad += 1; + priv->reset = 1; + arlan_drop_tx(dev); + } + } + + ARLAN_DEBUG_EXIT("arlan_tx_done_interrupt"); +} + + +static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short rxOffset, u_short pkt_len) +{ + char *skbtmp; + int i = 0; + + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + + + ARLAN_DEBUG_ENTRY("arlan_rx_interrupt"); + // by spec, not WRITESHMB(arlan->rxStatus,0x00); + // prohibited here arlan_command(dev, ARLAN_COMMAND_RX); + + if (pkt_len < 10 || pkt_len > 2048) + { + printk(KERN_WARNING "%s: got too short or long packet, len %d \n", dev->name, pkt_len); + return; + } + if (rxOffset + pkt_len > 0x2000) + { + printk("%s: got too long packet, len %d offset %x\n", dev->name, pkt_len, rxOffset); + return; + } + priv->in_bytes += pkt_len; + priv->in_bytes10 += pkt_len; + if (conf->measure_rate < 1) + conf->measure_rate = 1; + if (time_after(jiffies, priv->in_time + conf->measure_rate * HZ)) + { + conf->in_speed = priv->in_bytes / conf->measure_rate; + priv->in_bytes = 0; + priv->in_time = jiffies; + } + if (time_after(jiffies, priv->in_time10 + conf->measure_rate * 10*HZ)) + { + conf->in_speed10 = priv->in_bytes10 / (10 * conf->measure_rate); + priv->in_bytes10 = 0; + priv->in_time10 = jiffies; + } + DEBUGSHM(1, "arlan rcv pkt rxStatus= %d ", arlan->rxStatus, u_char); + switch (rxStatus) + { + case 1: + case 2: + case 3: + { + /* Malloc up new buffer. */ + struct sk_buff *skb; + + DEBUGSHM(50, "arlan recv pkt offs=%d\n", arlan->rxOffset, u_short); + DEBUGSHM(1, "arlan rxFrmType = %d \n", arlan->rxFrmType, u_char); + DEBUGSHM(1, KERN_INFO "arlan rx scrambled = %d \n", arlan->scrambled, u_char); + + /* here we do multicast filtering to avoid slow 8-bit memcopy */ +#ifdef ARLAN_MULTICAST + if (!(dev->flags & IFF_ALLMULTI) && + !(dev->flags & IFF_PROMISC) && + dev->mc_list) + { + char hw_dst_addr[6]; + struct dev_mc_list *dmi = dev->mc_list; + int i; + + memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6); + if (hw_dst_addr[0] == 0x01) + { + if (mdebug) + if (hw_dst_addr[1] == 0x00) + printk(KERN_ERR "%s mcast 0x0100 \n", dev->name); + else if (hw_dst_addr[1] == 0x40) + printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name); + while (dmi) + { + if (dmi->dmi_addrlen == 6) { + if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP) + printk(KERN_ERR "%s mcl %pM\n", + dev->name, dmi->dmi_addr); + for (i = 0; i < 6; i++) + if (dmi->dmi_addr[i] != hw_dst_addr[i]) + break; + if (i == 6) + break; + } else + printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name); + dmi = dmi->next; + } + /* we reach here if multicast filtering is on and packet + * is multicast and not for receive */ + goto end_of_interrupt; + } + } +#endif // ARLAN_MULTICAST + /* multicast filtering ends here */ + pkt_len += ARLAN_FAKE_HDR_LEN; + + skb = dev_alloc_skb(pkt_len + 4); + if (skb == NULL) + { + printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); + dev->stats.rx_dropped++; + break; + } + skb_reserve(skb, 2); + skbtmp = skb_put(skb, pkt_len); + + memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char __iomem *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN); + memcpy_fromio(skbtmp, arlan->ultimateDestAddress, 6); + memcpy_fromio(skbtmp + 6, arlan->rxSrc, 6); + WRITESHMB(arlan->rxStatus, 0x00); + arlan_command(dev, ARLAN_COMMAND_RX); + + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + { + char immedDestAddress[6]; + char immedSrcAddress[6]; + memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6); + memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6); + + printk(KERN_WARNING "%s t %pM f %pM imd %pM ims %pM\n", + dev->name, skbtmp, + &skbtmp[6], + immedDestAddress, + immedSrcAddress); + } + skb->protocol = eth_type_trans(skb, dev); + IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) + if (skb->protocol != 0x608 && skb->protocol != 0x8) + { + for (i = 0; i <= 22; i++) + printk("%02x:", (u_char) skbtmp[i + 12]); + printk(KERN_ERR "\n"); + printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol); + } + netif_rx(skb); + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; + } + break; + + default: + printk(KERN_ERR "arlan intr: received unknown status\n"); + dev->stats.rx_crc_errors++; + break; + } + ARLAN_DEBUG_EXIT("arlan_rx_interrupt"); +} + +static void arlan_process_interrupt(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + u_char rxStatus = READSHMB(arlan->rxStatus); + u_char txStatus = READSHMB(arlan->txStatus); + u_short rxOffset = READSHMS(arlan->rxOffset); + u_short pkt_len = READSHMS(arlan->rxLength); + int interrupt_count = 0; + + ARLAN_DEBUG_ENTRY("arlan_process_interrupt"); + + if (test_and_set_bit(0, (void *) &priv->interrupt_processing_active)) + { + if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) + printk(KERN_ERR "interrupt chain reentering \n"); + goto end_int_process; + } + while ((rxStatus || txStatus || priv->interrupt_ack_requested) + && (interrupt_count < 5)) + { + if (rxStatus) + priv->last_rx_int_ack_time = jiffies; + + arlan_command(dev, ARLAN_COMMAND_INT_ACK); + arlan_command(dev, ARLAN_COMMAND_INT_ENABLE); + + IFDEBUG(ARLAN_DEBUG_INTERRUPT) + printk(KERN_ERR "%s: got IRQ rx %x tx %x comm %x rxOff %x rxLen %x \n", + dev->name, rxStatus, txStatus, READSHMB(arlan->commandByte), + rxOffset, pkt_len); + + if (rxStatus == 0 && txStatus == 0) + { + if (priv->irq_test_done) + { + if (!registrationBad(dev)) + IFDEBUG(ARLAN_DEBUG_INTERRUPT) printk(KERN_ERR "%s unknown interrupt(nop? regLost ?) reason tx %d rx %d ", + dev->name, txStatus, rxStatus); + } else { + IFDEBUG(ARLAN_DEBUG_INTERRUPT) + printk(KERN_INFO "%s irq $%d test OK \n", dev->name, dev->irq); + + } + priv->interrupt_ack_requested = 0; + goto ends; + } + if (txStatus != 0) + { + WRITESHMB(arlan->txStatus, 0x00); + arlan_tx_done_interrupt(dev, txStatus); + goto ends; + } + if (rxStatus == 1 || rxStatus == 2) + { /* a packet waiting */ + arlan_rx_interrupt(dev, rxStatus, rxOffset, pkt_len); + goto ends; + } + if (rxStatus > 2 && rxStatus < 0xff) + { + WRITESHMB(arlan->rxStatus, 0x00); + printk(KERN_ERR "%s unknown rxStatus reason tx %d rx %d ", + dev->name, txStatus, rxStatus); + goto ends; + } + if (rxStatus == 0xff) + { + WRITESHMB(arlan->rxStatus, 0x00); + arlan_command(dev, ARLAN_COMMAND_RX); + if (registrationBad(dev)) + netif_device_detach(dev); + if (!registrationBad(dev)) + { + priv->registrationLastSeen = jiffies; + if (!netif_queue_stopped(dev) && !priv->under_reset && !priv->under_config) + netif_wake_queue (dev); + } + goto ends; + } +ends: + + arlan_command_process(dev); + + rxStatus = READSHMB(arlan->rxStatus); + txStatus = READSHMB(arlan->txStatus); + rxOffset = READSHMS(arlan->rxOffset); + pkt_len = READSHMS(arlan->rxLength); + + + priv->irq_test_done = 1; + + interrupt_count++; + } + priv->interrupt_processing_active = 0; + +end_int_process: + arlan_command_process(dev); + + ARLAN_DEBUG_EXIT("arlan_process_interrupt"); + return; +} + +static irqreturn_t arlan_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + u_char rxStatus = READSHMB(arlan->rxStatus); + u_char txStatus = READSHMB(arlan->txStatus); + + ARLAN_DEBUG_ENTRY("arlan_interrupt"); + + + if (!rxStatus && !txStatus) + priv->interrupt_ack_requested++; + + arlan_process_interrupt(dev); + + priv->irq_test_done = 1; + + ARLAN_DEBUG_EXIT("arlan_interrupt"); + return IRQ_HANDLED; + +} + + +static int arlan_close(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + + ARLAN_DEBUG_ENTRY("arlan_close"); + + del_timer_sync(&priv->timer); + + arlan_command(dev, ARLAN_COMMAND_POWERDOWN); + + IFDEBUG(ARLAN_DEBUG_STARTUP) + printk(KERN_NOTICE "%s: Closing device\n", dev->name); + + netif_stop_queue(dev); + free_irq(dev->irq, dev); + + ARLAN_DEBUG_EXIT("arlan_close"); + return 0; +} + +#ifdef ARLAN_DEBUGGING +static long alignLong(volatile u_char * ptr) +{ + long ret; + memcpy_fromio(&ret, (void *) ptr, 4); + return ret; +} +#endif + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ + +static struct net_device_stats *arlan_statistics(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + + + ARLAN_DEBUG_ENTRY("arlan_statistics"); + + /* Update the statistics from the device registers. */ + + READSHM(dev->stats.collisions, arlan->numReTransmissions, u_int); + READSHM(dev->stats.rx_crc_errors, arlan->numCRCErrors, u_int); + READSHM(dev->stats.rx_dropped, arlan->numFramesDiscarded, u_int); + READSHM(dev->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int); + READSHM(dev->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int); + READSHM(dev->stats.rx_over_errors, arlan->numRXOverruns, u_int); + READSHM(dev->stats.rx_packets, arlan->numDatagramsReceived, u_int); + READSHM(dev->stats.tx_aborted_errors, arlan->numAbortErrors, u_int); + READSHM(dev->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int); + READSHM(dev->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int); + READSHM(dev->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int); + READSHM(dev->stats.tx_packets, arlan->numDatagramsTransmitted, u_int); + READSHM(dev->stats.tx_window_errors, arlan->numHoldOffs, u_int); + + ARLAN_DEBUG_EXIT("arlan_statistics"); + + return &dev->stats; +} + + +static void arlan_set_multicast(struct net_device *dev) +{ + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + struct arlan_conf_stru *conf = priv->Conf; + int board_conf_needed = 0; + + + ARLAN_DEBUG_ENTRY("arlan_set_multicast"); + + if (dev->flags & IFF_PROMISC) + { + unsigned char recMode; + READSHM(recMode, arlan->receiveMode, u_char); + conf->receiveMode = (ARLAN_RCV_PROMISC | ARLAN_RCV_CONTROL); + if (conf->receiveMode != recMode) + board_conf_needed = 1; + } + else + { + /* turn off promiscuous mode */ + unsigned char recMode; + READSHM(recMode, arlan->receiveMode, u_char); + conf->receiveMode = ARLAN_RCV_CLEAN | ARLAN_RCV_CONTROL; + if (conf->receiveMode != recMode) + board_conf_needed = 1; + } + if (board_conf_needed) + arlan_command(dev, ARLAN_COMMAND_CONF); + + ARLAN_DEBUG_EXIT("arlan_set_multicast"); +} + + +struct net_device * __init arlan_probe(int unit) +{ + struct net_device *dev; + int err; + int m; + + ARLAN_DEBUG_ENTRY("arlan_probe"); + + if (arlans_found == MAX_ARLANS) + return ERR_PTR(-ENODEV); + + /* + * Reserve space for local data and a copy of the shared memory + * that is used by the /proc interface. + */ + dev = alloc_etherdev(sizeof(struct arlan_private) + + sizeof(struct arlan_shmem)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + + if (dev->mem_start) { + if (arlan_probe_here(dev, dev->mem_start) == 0) + goto found; + goto not_found; + } + + } + + + for (m = (int)phys_to_virt(lastFoundAt) + ARLAN_SHMEM_SIZE; + m <= (int)phys_to_virt(0xDE000); + m += ARLAN_SHMEM_SIZE) + { + if (arlan_probe_here(dev, m) == 0) + { + lastFoundAt = (int)virt_to_phys((void*)m); + goto found; + } + } + + if (lastFoundAt == 0xbe000) + printk(KERN_ERR "arlan: No Arlan devices found \n"); + + not_found: + free_netdev(dev); + return ERR_PTR(-ENODEV); + + found: + err = arlan_setup_device(dev, arlans_found); + if (err) + dev = ERR_PTR(err); + else if (!arlans_found++) + printk(KERN_INFO "Arlan driver %s\n", arlan_version); + + return dev; +} + +#ifdef MODULE +int __init init_module(void) +{ + int i = 0; + + ARLAN_DEBUG_ENTRY("init_module"); + + if (channelSet != channelSetUNKNOWN || channelNumber != channelNumberUNKNOWN || systemId != systemIdUNKNOWN) + return -EINVAL; + + for (i = 0; i < MAX_ARLANS; i++) { + struct net_device *dev = arlan_probe(i); + + if (IS_ERR(dev)) + return PTR_ERR(dev); + } + init_arlan_proc(); + printk(KERN_INFO "Arlan driver %s\n", arlan_version); + ARLAN_DEBUG_EXIT("init_module"); + return 0; +} + + +void __exit cleanup_module(void) +{ + int i = 0; + struct net_device *dev; + + ARLAN_DEBUG_ENTRY("cleanup_module"); + + IFDEBUG(ARLAN_DEBUG_SHUTDOWN) + printk(KERN_INFO "arlan: unloading module\n"); + + cleanup_arlan_proc(); + + for (i = 0; i < MAX_ARLANS; i++) + { + dev = arlan_device[i]; + if (dev) { + arlan_command(dev, ARLAN_COMMAND_POWERDOWN ); + + unregister_netdev(dev); + release_mem_region(virt_to_phys((void *) dev->mem_start), + ARLAN_SHMEM_SIZE); + free_netdev(dev); + arlan_device[i] = NULL; + } + } + + ARLAN_DEBUG_EXIT("cleanup_module"); +} + + +#endif +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/arlan/arlan-proc.c b/drivers/staging/arlan/arlan-proc.c new file mode 100644 index 000000000000..a8b689635a3b --- /dev/null +++ b/drivers/staging/arlan/arlan-proc.c @@ -0,0 +1,1253 @@ +#include "arlan.h" + +#include + +#ifdef CONFIG_PROC_FS + +/* void enableReceive(struct net_device* dev); +*/ + + + +#define ARLAN_STR_SIZE 0x2ff0 +#define DEV_ARLAN_INFO 1 +#define DEV_ARLAN 1 +#define SARLG(type,var) {\ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n", #var, READSHMB(priva->card->var)); \ + } + +#define SARLBN(type,var,nn) {\ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x",#var);\ + for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ + pos += sprintf(arlan_drive_info+pos, "\n"); \ + } + +#define SARLBNpln(type,var,nn) {\ + for (i=0; i < nn; i++ ) pos += sprintf(arlan_drive_info+pos, "%02x",READSHMB(priva->card->var[i]));\ + } + +#define SARLSTR(var,nn) {\ + char tmpStr[400];\ + int tmpLn = nn;\ + if (nn > 399 ) tmpLn = 399; \ + memcpy(tmpStr,(char *) priva->conf->var,tmpLn);\ + tmpStr[tmpLn] = 0; \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t%s \n",#var,priva->conf->var);\ + } + +#define SARLUC(var) SARLG(u_char, var) +#define SARLUCN(var,nn) SARLBN(u_char,var, nn) +#define SARLUS(var) SARLG(u_short, var) +#define SARLUSN(var,nn) SARLBN(u_short,var, nn) +#define SARLUI(var) SARLG(u_int, var) + +#define SARLUSA(var) {\ + u_short tmpVar;\ + memcpy(&tmpVar, (short *) priva->conf->var,2); \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ +} + +#define SARLUIA(var) {\ + u_int tmpVar;\ + memcpy(&tmpVar, (int* )priva->conf->var,4); \ + pos += sprintf(arlan_drive_info+pos, "%s\t=\t0x%x\n",#var, tmpVar);\ +} + + +static const char *arlan_diagnostic_info_string(struct net_device *dev) +{ + + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + u_char diagnosticInfo; + + READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); + + switch (diagnosticInfo) + { + case 0xFF: + return "Diagnostic info is OK"; + case 0xFE: + return "ERROR EPROM Checksum error "; + case 0xFD: + return "ERROR Local Ram Test Failed "; + case 0xFC: + return "ERROR SCC failure "; + case 0xFB: + return "ERROR BackBone failure "; + case 0xFA: + return "ERROR transceiver not found "; + case 0xF9: + return "ERROR no more address space "; + case 0xF8: + return "ERROR Checksum error "; + case 0xF7: + return "ERROR Missing SS Code"; + case 0xF6: + return "ERROR Invalid config format"; + case 0xF5: + return "ERROR Reserved errorcode F5"; + case 0xF4: + return "ERROR Invalid spreading code/channel number"; + case 0xF3: + return "ERROR Load Code Error"; + case 0xF2: + return "ERROR Reserver errorcode F2 "; + case 0xF1: + return "ERROR Invalid command receivec by LAN card "; + case 0xF0: + return "ERROR Invalid parameter found in command "; + case 0xEF: + return "ERROR On-chip timer failure "; + case 0xEE: + return "ERROR T410 timer failure "; + case 0xED: + return "ERROR Too Many TxEnable commands "; + case 0xEC: + return "ERROR EEPROM error on radio module "; + default: + return "ERROR unknown Diagnostic info reply code "; + } +} + +static const char *arlan_hardware_type_string(struct net_device *dev) +{ + u_char hardwareType; + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + + READSHM(hardwareType, arlan->hardwareType, u_char); + switch (hardwareType) + { + case 0x00: + return "type A450"; + case 0x01: + return "type A650 "; + case 0x04: + return "type TMA coproc"; + case 0x0D: + return "type A650E "; + case 0x18: + return "type TMA coproc Australian"; + case 0x19: + return "type A650A "; + case 0x26: + return "type TMA coproc European"; + case 0x2E: + return "type A655 "; + case 0x2F: + return "type A655A "; + case 0x30: + return "type A655E "; + case 0x0B: + return "type A670 "; + case 0x0C: + return "type A670E "; + case 0x2D: + return "type A670A "; + case 0x0F: + return "type A411T"; + case 0x16: + return "type A411TA"; + case 0x1B: + return "type A440T"; + case 0x1C: + return "type A412T"; + case 0x1E: + return "type A412TA"; + case 0x22: + return "type A411TE"; + case 0x24: + return "type A412TE"; + case 0x27: + return "type A671T "; + case 0x29: + return "type A671TA "; + case 0x2B: + return "type A671TE "; + case 0x31: + return "type A415T "; + case 0x33: + return "type A415TA "; + case 0x35: + return "type A415TE "; + case 0x37: + return "type A672"; + case 0x39: + return "type A672A "; + case 0x3B: + return "type A672T"; + case 0x6B: + return "type IC2200"; + default: + return "type A672T"; + } +} +#ifdef ARLAN_DEBUGGING +static void arlan_print_diagnostic_info(struct net_device *dev) +{ + int i; + u_char diagnosticInfo; + u_short diagnosticOffset; + u_char hardwareType; + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + + // ARLAN_DEBUG_ENTRY("arlan_print_diagnostic_info"); + + if (READSHMB(arlan->configuredStatusFlag) == 0) + printk("Arlan: Card NOT configured\n"); + else + printk("Arlan: Card is configured\n"); + + READSHM(diagnosticInfo, arlan->diagnosticInfo, u_char); + READSHM(diagnosticOffset, arlan->diagnosticOffset, u_short); + + printk(KERN_INFO "%s\n", arlan_diagnostic_info_string(dev)); + + if (diagnosticInfo != 0xff) + printk("%s arlan: Diagnostic Offset %d \n", dev->name, diagnosticOffset); + + printk("arlan: LAN CODE ID = "); + for (i = 0; i < 6; i++) + DEBUGSHM(1, "%03d:", arlan->lanCardNodeId[i], u_char); + printk("\n"); + + printk("arlan: Arlan BroadCast address = "); + for (i = 0; i < 6; i++) + DEBUGSHM(1, "%03d:", arlan->broadcastAddress[i], u_char); + printk("\n"); + + READSHM(hardwareType, arlan->hardwareType, u_char); + printk(KERN_INFO "%s\n", arlan_hardware_type_string(dev)); + + + DEBUGSHM(1, "arlan: channelNumber=%d\n", arlan->channelNumber, u_char); + DEBUGSHM(1, "arlan: channelSet=%d\n", arlan->channelSet, u_char); + DEBUGSHM(1, "arlan: spreadingCode=%d\n", arlan->spreadingCode, u_char); + DEBUGSHM(1, "arlan: radioNodeId=%d\n", arlan->radioNodeId, u_short); + DEBUGSHM(1, "arlan: SID =%d\n", arlan->SID, u_short); + DEBUGSHM(1, "arlan: rxOffset=%d\n", arlan->rxOffset, u_short); + + DEBUGSHM(1, "arlan: registration mode is %d\n", arlan->registrationMode, u_char); + + printk("arlan: name= "); + IFDEBUG(1) + + for (i = 0; i < 16; i++) + { + char c; + READSHM(c, arlan->name[i], char); + if (c) + printk("%c", c); + } + printk("\n"); + +// ARLAN_DEBUG_EXIT("arlan_print_diagnostic_info"); + +} + + +/****************************** TEST MEMORY **************/ + +static int arlan_hw_test_memory(struct net_device *dev) +{ + u_char *ptr; + int i; + int memlen = sizeof(struct arlan_shmem) - 0xF; /* avoid control register */ + volatile char *arlan_mem = (char *) (dev->mem_start); + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + char pattern; + + ptr = NULL; + + /* hold card in reset state */ + setHardwareReset(dev); + + /* test memory */ + pattern = 0; + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], ((u_char) pattern++), u_char); + + pattern = 0; + for (i = 0; i < memlen; i++) + { + char res; + READSHM(res, arlan_mem[i], char); + if (res != pattern++) + { + printk(KERN_ERR "Arlan driver memory test 1 failed \n"); + return -1; + } + } + + pattern = 0; + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], ~(pattern++), char); + + pattern = 0; + for (i = 0; i < memlen; i++) + { + char res; + READSHM(res, arlan_mem[i], char); + if (res != ~(pattern++)) + { + printk(KERN_ERR "Arlan driver memory test 2 failed \n"); + return -1; + } + } + + /* zero memory */ + for (i = 0; i < memlen; i++) + WRITESHM(arlan_mem[i], 0x00, char); + + IFDEBUG(1) printk(KERN_INFO "Arlan: memory tests ok\n"); + + /* set reset flag and then release reset */ + WRITESHM(arlan->resetFlag, 0xff, u_char); + + clearChannelAttention(dev); + clearHardwareReset(dev); + + /* wait for reset flag to become zero, we'll wait for two seconds */ + if (arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW)) + { + printk(KERN_ERR "%s arlan: failed to come back from memory test\n", dev->name); + return -1; + } + return 0; +} + +static int arlan_setup_card_by_book(struct net_device *dev) +{ + u_char irqLevel, configuredStatusFlag; + struct arlan_private *priv = netdev_priv(dev); + volatile struct arlan_shmem __iomem *arlan = priv->card; + +// ARLAN_DEBUG_ENTRY("arlan_setup_card"); + + READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); + + IFDEBUG(10) + if (configuredStatusFlag != 0) + IFDEBUG(10) printk("arlan: CARD IS CONFIGURED\n"); + else + IFDEBUG(10) printk("arlan: card is NOT configured\n"); + + if (testMemory || (READSHMB(arlan->diagnosticInfo) != 0xff)) + if (arlan_hw_test_memory(dev)) + return -1; + + DEBUGSHM(4, "arlan configuredStatus = %d \n", arlan->configuredStatusFlag, u_char); + DEBUGSHM(4, "arlan driver diagnostic: 0x%2x\n", arlan->diagnosticInfo, u_char); + + /* issue nop command - no interrupt */ + arlan_command(dev, ARLAN_COMMAND_NOOP); + if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) + return -1; + + IFDEBUG(50) printk("1st Noop successfully executed !!\n"); + + /* try to turn on the arlan interrupts */ + clearClearInterrupt(dev); + setClearInterrupt(dev); + setInterruptEnable(dev); + + /* issue nop command - with interrupt */ + + arlan_command(dev, ARLAN_COMMAND_NOOPINT); + if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) + return -1; + + + IFDEBUG(50) printk("2nd Noop successfully executed !!\n"); + + READSHM(irqLevel, arlan->irqLevel, u_char) + + if (irqLevel != dev->irq) + { + IFDEBUG(1) printk(KERN_WARNING "arlan dip switches set irq to %d\n", irqLevel); + printk(KERN_WARNING "device driver irq set to %d - does not match\n", dev->irq); + dev->irq = irqLevel; + } + else + IFDEBUG(2) printk("irq level is OK\n"); + + + IFDEBUG(3) arlan_print_diagnostic_info(dev); + + arlan_command(dev, ARLAN_COMMAND_CONF); + + READSHM(configuredStatusFlag, arlan->configuredStatusFlag, u_char); + if (configuredStatusFlag == 0) + { + printk(KERN_WARNING "arlan configure failed\n"); + return -1; + } + arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); + arlan_command(dev, ARLAN_COMMAND_RX); + arlan_command(dev, ARLAN_COMMAND_LONG_WAIT_NOW); + printk(KERN_NOTICE "%s: arlan driver version %s loaded\n", + dev->name, arlan_version); + +// ARLAN_DEBUG_EXIT("arlan_setup_card"); + + return 0; /* no errors */ +} +#endif + +#ifdef ARLAN_PROC_INTERFACE +#ifdef ARLAN_PROC_SHM_DUMP + +static char arlan_drive_info[ARLAN_STR_SIZE] = "A655\n\0"; + +static int arlan_sysctl_info(ctl_table * ctl, int write, + void __user *buffer, size_t * lenp, loff_t *ppos) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + struct net_device *dev; + pos = 0; + if (write) + { + printk("wrirte: "); + for (i = 0; i < 100; i++) + printk("adi %x \n", arlan_drive_info[i]); + } + if (ctl->procname == NULL || arlan_drive_info == NULL) + { + printk(KERN_WARNING " procname is NULL in sysctl_table or arlan_drive_info is NULL \n at arlan module\n "); + return -1; + } + devnum = ctl->procname[5] - '0'; + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] == NULL) + { + if (ctl->procname) + pos += sprintf(arlan_drive_info + pos, "\t%s\n\n", ctl->procname); + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = netdev_priv(arlan_device[devnum]); + + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + dev = arlan_device[devnum]; + + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + + pos = sprintf(arlan_drive_info, "Arlan info \n"); + /* Header Signature */ + SARLSTR(textRegion, 48); + SARLUC(resetFlag); + pos += sprintf(arlan_drive_info + pos, "diagnosticInfo\t=\t%s \n", arlan_diagnostic_info_string(dev)); + SARLUC(diagnosticInfo); + SARLUS(diagnosticOffset); + SARLUCN(_1, 12); + SARLUCN(lanCardNodeId, 6); + SARLUCN(broadcastAddress, 6); + pos += sprintf(arlan_drive_info + pos, "hardwareType =\t %s \n", arlan_hardware_type_string(dev)); + SARLUC(hardwareType); + SARLUC(majorHardwareVersion); + SARLUC(minorHardwareVersion); + SARLUC(radioModule); + SARLUC(defaultChannelSet); + SARLUCN(_2, 47); + + /* Control/Status Block - 0x0080 */ + SARLUC(interruptInProgress); + SARLUC(cntrlRegImage); + + SARLUCN(_3, 14); + SARLUC(commandByte); + SARLUCN(commandParameter, 15); + + /* Receive Status - 0x00a0 */ + SARLUC(rxStatus); + SARLUC(rxFrmType); + SARLUS(rxOffset); + SARLUS(rxLength); + SARLUCN(rxSrc, 6); + SARLUC(rxBroadcastFlag); + SARLUC(rxQuality); + SARLUC(scrambled); + SARLUCN(_4, 1); + + /* Transmit Status - 0x00b0 */ + SARLUC(txStatus); + SARLUC(txAckQuality); + SARLUC(numRetries); + SARLUCN(_5, 14); + SARLUCN(registeredRouter, 6); + SARLUCN(backboneRouter, 6); + SARLUC(registrationStatus); + SARLUC(configuredStatusFlag); + SARLUCN(_6, 1); + SARLUCN(ultimateDestAddress, 6); + SARLUCN(immedDestAddress, 6); + SARLUCN(immedSrcAddress, 6); + SARLUS(rxSequenceNumber); + SARLUC(assignedLocaltalkAddress); + SARLUCN(_7, 27); + + /* System Parameter Block */ + + /* - Driver Parameters (Novell Specific) */ + + SARLUS(txTimeout); + SARLUS(transportTime); + SARLUCN(_8, 4); + + /* - Configuration Parameters */ + SARLUC(irqLevel); + SARLUC(spreadingCode); + SARLUC(channelSet); + SARLUC(channelNumber); + SARLUS(radioNodeId); + SARLUCN(_9, 2); + SARLUC(scramblingDisable); + SARLUC(radioType); + SARLUS(routerId); + SARLUCN(_10, 9); + SARLUC(txAttenuation); + SARLUIA(systemId); + SARLUS(globalChecksum); + SARLUCN(_11, 4); + SARLUS(maxDatagramSize); + SARLUS(maxFrameSize); + SARLUC(maxRetries); + SARLUC(receiveMode); + SARLUC(priority); + SARLUC(rootOrRepeater); + SARLUCN(specifiedRouter, 6); + SARLUS(fastPollPeriod); + SARLUC(pollDecay); + SARLUSA(fastPollDelay); + SARLUC(arlThreshold); + SARLUC(arlDecay); + SARLUCN(_12, 1); + SARLUS(specRouterTimeout); + SARLUCN(_13, 5); + + /* Scrambled Area */ + SARLUIA(SID); + SARLUCN(encryptionKey, 12); + SARLUIA(_14); + SARLUSA(waitTime); + SARLUSA(lParameter); + SARLUCN(_15, 3); + SARLUS(headerSize); + SARLUS(sectionChecksum); + + SARLUC(registrationMode); + SARLUC(registrationFill); + SARLUS(pollPeriod); + SARLUS(refreshPeriod); + SARLSTR(name, 16); + SARLUCN(NID, 6); + SARLUC(localTalkAddress); + SARLUC(codeFormat); + SARLUC(numChannels); + SARLUC(channel1); + SARLUC(channel2); + SARLUC(channel3); + SARLUC(channel4); + SARLUCN(SSCode, 59); + +/* SARLUCN( _16, 0x140); + */ + /* Statistics Block - 0x0300 */ + SARLUC(hostcpuLock); + SARLUC(lancpuLock); + SARLUCN(resetTime, 18); + SARLUIA(numDatagramsTransmitted); + SARLUIA(numReTransmissions); + SARLUIA(numFramesDiscarded); + SARLUIA(numDatagramsReceived); + SARLUIA(numDuplicateReceivedFrames); + SARLUIA(numDatagramsDiscarded); + SARLUS(maxNumReTransmitDatagram); + SARLUS(maxNumReTransmitFrames); + SARLUS(maxNumConsecutiveDuplicateFrames); + /* misaligned here so we have to go to characters */ + SARLUIA(numBytesTransmitted); + SARLUIA(numBytesReceived); + SARLUIA(numCRCErrors); + SARLUIA(numLengthErrors); + SARLUIA(numAbortErrors); + SARLUIA(numTXUnderruns); + SARLUIA(numRXOverruns); + SARLUIA(numHoldOffs); + SARLUIA(numFramesTransmitted); + SARLUIA(numFramesReceived); + SARLUIA(numReceiveFramesLost); + SARLUIA(numRXBufferOverflows); + SARLUIA(numFramesDiscardedAddrMismatch); + SARLUIA(numFramesDiscardedSIDMismatch); + SARLUIA(numPollsTransmistted); + SARLUIA(numPollAcknowledges); + SARLUIA(numStatusTimeouts); + SARLUIA(numNACKReceived); + SARLUS(auxCmd); + SARLUCN(dumpPtr, 4); + SARLUC(dumpVal); + SARLUC(wireTest); + + /* next 4 seems too long for procfs, over single page ? + SARLUCN( _17, 0x86); + SARLUCN( txBuffer, 0x800); + SARLUCN( rxBuffer, 0x800); + SARLUCN( _18, 0x0bff); + */ + + pos += sprintf(arlan_drive_info + pos, "rxRing\t=\t0x"); + for (i = 0; i < 0x50; i++) + pos += sprintf(arlan_drive_info + pos, "%02x", ((char *) priva->conf)[priva->conf->rxOffset + i]); + pos += sprintf(arlan_drive_info + pos, "\n"); + + SARLUC(configStatus); + SARLUC(_22); + SARLUC(progIOCtrl); + SARLUC(shareMBase); + SARLUC(controlRegister); + + pos += sprintf(arlan_drive_info + pos, " total %d chars\n", pos); + if (ctl) + if (ctl->procname) + pos += sprintf(arlan_drive_info + pos, " driver name : %s\n", ctl->procname); +final: + *lenp = pos; + + if (!write) + retv = proc_dostring(ctl, write, buffer, lenp, ppos); + else + { + *lenp = 0; + return -1; + } + return retv; +} + + +static int arlan_sysctl_info161719(ctl_table * ctl, int write, + void __user *buffer, size_t * lenp, loff_t *ppos) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = netdev_priv(arlan_device[devnum]); + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLUCN(_16, 0xC0); + SARLUCN(_17, 0x6A); + SARLUCN(_18, 14); + SARLUCN(_19, 0x86); + SARLUCN(_21, 0x3fd); + +final: + *lenp = pos; + retv = proc_dostring(ctl, write, buffer, lenp, ppos); + return retv; +} + +static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, + void __user *buffer, size_t * lenp, loff_t *ppos) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = netdev_priv(arlan_device[devnum]); + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, txBuffer, 0x800); +final: + *lenp = pos; + retv = proc_dostring(ctl, write, buffer, lenp, ppos); + return retv; +} + +static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, + void __user *buffer, size_t * lenp, loff_t *ppos) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } else + priva = netdev_priv(arlan_device[devnum]); + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, rxBuffer, 0x800); +final: + *lenp = pos; + retv = proc_dostring(ctl, write, buffer, lenp, ppos); + return retv; +} + +static int arlan_sysctl_info18(ctl_table * ctl, int write, + void __user *buffer, size_t * lenp, loff_t *ppos) +{ + int i; + int retv, pos, devnum; + struct arlan_private *priva = NULL; + + pos = 0; + devnum = ctl->procname[5] - '0'; + if (arlan_device[devnum] == NULL) + { + pos += sprintf(arlan_drive_info + pos, "No device found here \n"); + goto final; + } + else + priva = netdev_priv(arlan_device[devnum]); + if (priva == NULL) + { + printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n "); + return -1; + } + memcpy_fromio(priva->conf, priva->card, sizeof(struct arlan_shmem)); + SARLBNpln(u_char, _18, 0x800); + +final: + *lenp = pos; + retv = proc_dostring(ctl, write, buffer, lenp, ppos); + return retv; +} + + +#endif /* #ifdef ARLAN_PROC_SHM_DUMP */ + + +static char conf_reset_result[200]; + +static int arlan_configure(ctl_table * ctl, int write, + void __user *buffer, size_t * lenp, loff_t *ppos) +{ + int pos = 0; + int devnum = ctl->procname[6] - '0'; + struct arlan_private *priv; + + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] != NULL) + { + priv = netdev_priv(arlan_device[devnum]); + + arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF); + } + else + return -1; + + *lenp = pos; + return proc_dostring(ctl, write, buffer, lenp, ppos); +} + +static int arlan_sysctl_reset(ctl_table * ctl, int write, + void __user *buffer, size_t * lenp, loff_t *ppos) +{ + int pos = 0; + int devnum = ctl->procname[5] - '0'; + struct arlan_private *priv; + + if (devnum < 0 || devnum > MAX_ARLANS - 1) + { + printk(KERN_WARNING "too strange devnum in procfs parse\n "); + return -1; + } + else if (arlan_device[devnum] != NULL) + { + priv = netdev_priv(arlan_device[devnum]); + arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET); + + } else + return -1; + *lenp = pos + 3; + return proc_dostring(ctl, write, buffer, lenp, ppos); +} + + +/* Place files in /proc/sys/dev/arlan */ +#define CTBLN(num,card,nam) \ + { .ctl_name = num,\ + .procname = #nam,\ + .data = &(arlan_conf[card].nam),\ + .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec} +#ifdef ARLAN_DEBUGGING + +#define ARLAN_PROC_DEBUG_ENTRIES \ + { .ctl_name = 48, .procname = "entry_exit_debug",\ + .data = &arlan_entry_and_exit_debug,\ + .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec},\ + { .ctl_name = 49, .procname = "debug", .data = &arlan_debug,\ + .maxlen = sizeof(int), .mode = 0600, .proc_handler = &proc_dointvec}, +#else +#define ARLAN_PROC_DEBUG_ENTRIES +#endif + +#define ARLAN_SYSCTL_TABLE_TOTAL(cardNo)\ + CTBLN(1,cardNo,spreadingCode),\ + CTBLN(2,cardNo, channelNumber),\ + CTBLN(3,cardNo, scramblingDisable),\ + CTBLN(4,cardNo, txAttenuation),\ + CTBLN(5,cardNo, systemId), \ + CTBLN(6,cardNo, maxDatagramSize),\ + CTBLN(7,cardNo, maxFrameSize),\ + CTBLN(8,cardNo, maxRetries),\ + CTBLN(9,cardNo, receiveMode),\ + CTBLN(10,cardNo, priority),\ + CTBLN(11,cardNo, rootOrRepeater),\ + CTBLN(12,cardNo, SID),\ + CTBLN(13,cardNo, registrationMode),\ + CTBLN(14,cardNo, registrationFill),\ + CTBLN(15,cardNo, localTalkAddress),\ + CTBLN(16,cardNo, codeFormat),\ + CTBLN(17,cardNo, numChannels),\ + CTBLN(18,cardNo, channel1),\ + CTBLN(19,cardNo, channel2),\ + CTBLN(20,cardNo, channel3),\ + CTBLN(21,cardNo, channel4),\ + CTBLN(22,cardNo, txClear),\ + CTBLN(23,cardNo, txRetries),\ + CTBLN(24,cardNo, txRouting),\ + CTBLN(25,cardNo, txScrambled),\ + CTBLN(26,cardNo, rxParameter),\ + CTBLN(27,cardNo, txTimeoutMs),\ + CTBLN(28,cardNo, waitCardTimeout),\ + CTBLN(29,cardNo, channelSet), \ + {.ctl_name = 30, .procname = "name",\ + .data = arlan_conf[cardNo].siteName,\ + .maxlen = 16, .mode = 0600, .proc_handler = &proc_dostring},\ + CTBLN(31,cardNo,waitTime),\ + CTBLN(32,cardNo,lParameter),\ + CTBLN(33,cardNo,_15),\ + CTBLN(34,cardNo,headerSize),\ + CTBLN(36,cardNo,tx_delay_ms),\ + CTBLN(37,cardNo,retries),\ + CTBLN(38,cardNo,ReTransmitPacketMaxSize),\ + CTBLN(39,cardNo,waitReTransmitPacketMaxSize),\ + CTBLN(40,cardNo,fastReTransCount),\ + CTBLN(41,cardNo,driverRetransmissions),\ + CTBLN(42,cardNo,txAckTimeoutMs),\ + CTBLN(43,cardNo,registrationInterrupts),\ + CTBLN(44,cardNo,hardwareType),\ + CTBLN(45,cardNo,radioType),\ + CTBLN(46,cardNo,writeEEPROM),\ + CTBLN(47,cardNo,writeRadioType),\ + ARLAN_PROC_DEBUG_ENTRIES\ + CTBLN(50,cardNo,in_speed),\ + CTBLN(51,cardNo,out_speed),\ + CTBLN(52,cardNo,in_speed10),\ + CTBLN(53,cardNo,out_speed10),\ + CTBLN(54,cardNo,in_speed_max),\ + CTBLN(55,cardNo,out_speed_max),\ + CTBLN(56,cardNo,measure_rate),\ + CTBLN(57,cardNo,pre_Command_Wait),\ + CTBLN(58,cardNo,rx_tweak1),\ + CTBLN(59,cardNo,rx_tweak2),\ + CTBLN(60,cardNo,tx_queue_len),\ + + + +static ctl_table arlan_conf_table0[] = +{ + ARLAN_SYSCTL_TABLE_TOTAL(0) + +#ifdef ARLAN_PROC_SHM_DUMP + { + .ctl_name = 150, + .procname = "arlan0-txRing", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_infotxRing, + }, + { + .ctl_name = 151, + .procname = "arlan0-rxRing", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_inforxRing, + }, + { + .ctl_name = 152, + .procname = "arlan0-18", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info18, + }, + { + .ctl_name = 153, + .procname = "arlan0-ring", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info161719, + }, + { + .ctl_name = 154, + .procname = "arlan0-shm-cpy", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info, + }, +#endif + { + .ctl_name = 155, + .procname = "config0", + .data = &conf_reset_result, + .maxlen = 100, + .mode = 0400, + .proc_handler = &arlan_configure + }, + { + .ctl_name = 156, + .procname = "reset0", + .data = &conf_reset_result, + .maxlen = 100, + .mode = 0400, + .proc_handler = &arlan_sysctl_reset, + }, + { .ctl_name = 0 } +}; + +static ctl_table arlan_conf_table1[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(1) + +#ifdef ARLAN_PROC_SHM_DUMP + { + .ctl_name = 150, + .procname = "arlan1-txRing", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_infotxRing, + }, + { + .ctl_name = 151, + .procname = "arlan1-rxRing", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_inforxRing, + }, + { + .ctl_name = 152, + .procname = "arlan1-18", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info18, + }, + { + .ctl_name = 153, + .procname = "arlan1-ring", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info161719, + }, + { + .ctl_name = 154, + .procname = "arlan1-shm-cpy", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info, + }, +#endif + { + .ctl_name = 155, + .procname = "config1", + .data = &conf_reset_result, + .maxlen = 100, + .mode = 0400, + .proc_handler = &arlan_configure, + }, + { + .ctl_name = 156, + .procname = "reset1", + .data = &conf_reset_result, + .maxlen = 100, + .mode = 0400, + .proc_handler = &arlan_sysctl_reset, + }, + { .ctl_name = 0 } +}; + +static ctl_table arlan_conf_table2[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(2) + +#ifdef ARLAN_PROC_SHM_DUMP + { + .ctl_name = 150, + .procname = "arlan2-txRing", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_infotxRing, + }, + { + .ctl_name = 151, + .procname = "arlan2-rxRing", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_inforxRing, + }, + { + .ctl_name = 152, + .procname = "arlan2-18", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info18, + }, + { + .ctl_name = 153, + .procname = "arlan2-ring", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info161719, + }, + { + .ctl_name = 154, + .procname = "arlan2-shm-cpy", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info, + }, +#endif + { + .ctl_name = 155, + .procname = "config2", + .data = &conf_reset_result, + .maxlen = 100, + .mode = 0400, + .proc_handler = &arlan_configure, + }, + { + .ctl_name = 156, + .procname = "reset2", + .data = &conf_reset_result, + .maxlen = 100, + .mode = 0400, + .proc_handler = &arlan_sysctl_reset, + }, + { .ctl_name = 0 } +}; + +static ctl_table arlan_conf_table3[] = +{ + + ARLAN_SYSCTL_TABLE_TOTAL(3) + +#ifdef ARLAN_PROC_SHM_DUMP + { + .ctl_name = 150, + .procname = "arlan3-txRing", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_infotxRing, + }, + { + .ctl_name = 151, + .procname = "arlan3-rxRing", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_inforxRing, + }, + { + .ctl_name = 152, + .procname = "arlan3-18", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info18, + }, + { + .ctl_name = 153, + .procname = "arlan3-ring", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info161719, + }, + { + .ctl_name = 154, + .procname = "arlan3-shm-cpy", + .data = &arlan_drive_info, + .maxlen = ARLAN_STR_SIZE, + .mode = 0400, + .proc_handler = &arlan_sysctl_info, + }, +#endif + { + .ctl_name = 155, + .procname = "config3", + .data = &conf_reset_result, + .maxlen = 100, + .mode = 0400, + .proc_handler = &arlan_configure, + }, + { + .ctl_name = 156, + .procname = "reset3", + .data = &conf_reset_result, + .maxlen = 100, + .mode = 0400, + .proc_handler = &arlan_sysctl_reset, + }, + { .ctl_name = 0 } +}; + + + +static ctl_table arlan_table[] = +{ + { + .ctl_name = 0, + .procname = "arlan0", + .maxlen = 0, + .mode = 0600, + .child = arlan_conf_table0, + }, + { + .ctl_name = 0, + .procname = "arlan1", + .maxlen = 0, + .mode = 0600, + .child = arlan_conf_table1, + }, + { + .ctl_name = 0, + .procname = "arlan2", + .maxlen = 0, + .mode = 0600, + .child = arlan_conf_table2, + }, + { + .ctl_name = 0, + .procname = "arlan3", + .maxlen = 0, + .mode = 0600, + .child = arlan_conf_table3, + }, + { .ctl_name = 0 } +}; + +#else + +static ctl_table arlan_table[MAX_ARLANS + 1] = +{ + { .ctl_name = 0 } +}; +#endif + + +// static int mmtu = 1234; + +static ctl_table arlan_root_table[] = +{ + { + .ctl_name = CTL_ARLAN, + .procname = "arlan", + .maxlen = 0, + .mode = 0555, + .child = arlan_table, + }, + { .ctl_name = 0 } +}; + +/* Make sure that /proc/sys/dev is there */ +//static ctl_table arlan_device_root_table[] = +//{ +// {CTL_DEV, "dev", NULL, 0, 0555, arlan_root_table}, +// {0} +//}; + + +static struct ctl_table_header *arlan_device_sysctl_header; + +int __init init_arlan_proc(void) +{ + + int i = 0; + if (arlan_device_sysctl_header) + return 0; + for (i = 0; i < MAX_ARLANS && arlan_device[i]; i++) + arlan_table[i].ctl_name = i + 1; + arlan_device_sysctl_header = register_sysctl_table(arlan_root_table); + if (!arlan_device_sysctl_header) + return -1; + + return 0; + +} + +void __exit cleanup_arlan_proc(void) +{ + unregister_sysctl_table(arlan_device_sysctl_header); + arlan_device_sysctl_header = NULL; + +} +#endif diff --git a/drivers/staging/arlan/arlan.h b/drivers/staging/arlan/arlan.h new file mode 100644 index 000000000000..fb3ad51a1caf --- /dev/null +++ b/drivers/staging/arlan/arlan.h @@ -0,0 +1,539 @@ +/* + * Copyright (C) 1997 Cullen Jennings + * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500 + * GNU General Public License applies + */ + +#include +#include +#include +#include +#include /* For the statistics structure. */ +#include /* For ARPHRD_ETHER */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +//#define ARLAN_DEBUGGING 1 + +#define ARLAN_PROC_INTERFACE +#define MAX_ARLANS 4 /* not more than 4 ! */ +#define ARLAN_PROC_SHM_DUMP /* shows all card registers, makes driver way larger */ + +#define ARLAN_MAX_MULTICAST_ADDRS 16 +#define ARLAN_RCV_CLEAN 0 +#define ARLAN_RCV_PROMISC 1 +#define ARLAN_RCV_CONTROL 2 + +#ifdef CONFIG_PROC_FS +extern int init_arlan_proc(void); +extern void cleanup_arlan_proc(void); +#else +#define init_arlan_proc() ({ 0; }) +#define cleanup_arlan_proc() do { } while (0) +#endif + +extern struct net_device *arlan_device[MAX_ARLANS]; +extern int arlan_debug; +extern int arlan_entry_debug; +extern int arlan_exit_debug; +extern int testMemory; +extern int arlan_command(struct net_device * dev, int command); + +#define SIDUNKNOWN -1 +#define radioNodeIdUNKNOWN -1 +#define irqUNKNOWN 0 +#define debugUNKNOWN 0 +#define testMemoryUNKNOWN 1 +#define spreadingCodeUNKNOWN 0 +#define channelNumberUNKNOWN 0 +#define channelSetUNKNOWN 0 +#define systemIdUNKNOWN -1 +#define registrationModeUNKNOWN -1 + + +#define IFDEBUG( L ) if ( (L) & arlan_debug ) +#define ARLAN_FAKE_HDR_LEN 12 + +#ifdef ARLAN_DEBUGGING + #define DEBUG 1 + #define ARLAN_ENTRY_EXIT_DEBUGGING 1 + #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b) +#else + #define ARLAN_DEBUG(a,b) +#endif + +#define ARLAN_SHMEM_SIZE 0x2000 + +struct arlan_shmem +{ + /* Header Signature */ + volatile char textRegion[48]; + volatile u_char resetFlag; + volatile u_char diagnosticInfo; + volatile u_short diagnosticOffset; + volatile u_char _1[12]; + volatile u_char lanCardNodeId[6]; + volatile u_char broadcastAddress[6]; + volatile u_char hardwareType; + volatile u_char majorHardwareVersion; + volatile u_char minorHardwareVersion; + volatile u_char radioModule;// shows EEPROM, can be overridden at 0x111 + volatile u_char defaultChannelSet; // shows EEProm, can be overriiden at 0x10A + volatile u_char _2[47]; + + /* Control/Status Block - 0x0080 */ + volatile u_char interruptInProgress; /* not used by lancpu */ + volatile u_char cntrlRegImage; /* not used by lancpu */ + volatile u_char _3[13]; + volatile u_char dumpByte; + volatile u_char commandByte; /* non-zero = active */ + volatile u_char commandParameter[15]; + + /* Receive Status - 0x00a0 */ + volatile u_char rxStatus; /* 1- data, 2-control, 0xff - registr change */ + volatile u_char rxFrmType; + volatile u_short rxOffset; + volatile u_short rxLength; + volatile u_char rxSrc[6]; + volatile u_char rxBroadcastFlag; + volatile u_char rxQuality; + volatile u_char scrambled; + volatile u_char _4[1]; + + /* Transmit Status - 0x00b0 */ + volatile u_char txStatus; + volatile u_char txAckQuality; + volatile u_char numRetries; + volatile u_char _5[14]; + volatile u_char registeredRouter[6]; + volatile u_char backboneRouter[6]; + volatile u_char registrationStatus; + volatile u_char configuredStatusFlag; + volatile u_char _6[1]; + volatile u_char ultimateDestAddress[6]; + volatile u_char immedDestAddress[6]; + volatile u_char immedSrcAddress[6]; + volatile u_short rxSequenceNumber; + volatile u_char assignedLocaltalkAddress; + volatile u_char _7[27]; + + /* System Parameter Block */ + + /* - Driver Parameters (Novell Specific) */ + + volatile u_short txTimeout; + volatile u_short transportTime; + volatile u_char _8[4]; + + /* - Configuration Parameters */ + volatile u_char irqLevel; + volatile u_char spreadingCode; + volatile u_char channelSet; + volatile u_char channelNumber; + volatile u_short radioNodeId; + volatile u_char _9[2]; + volatile u_char scramblingDisable; + volatile u_char radioType; + volatile u_short routerId; + volatile u_char _10[9]; + volatile u_char txAttenuation; + volatile u_char systemId[4]; + volatile u_short globalChecksum; + volatile u_char _11[4]; + volatile u_short maxDatagramSize; + volatile u_short maxFrameSize; + volatile u_char maxRetries; + volatile u_char receiveMode; + volatile u_char priority; + volatile u_char rootOrRepeater; + volatile u_char specifiedRouter[6]; + volatile u_short fastPollPeriod; + volatile u_char pollDecay; + volatile u_char fastPollDelay[2]; + volatile u_char arlThreshold; + volatile u_char arlDecay; + volatile u_char _12[1]; + volatile u_short specRouterTimeout; + volatile u_char _13[5]; + + /* Scrambled Area */ + volatile u_char SID[4]; + volatile u_char encryptionKey[12]; + volatile u_char _14[2]; + volatile u_char waitTime[2]; + volatile u_char lParameter[2]; + volatile u_char _15[3]; + volatile u_short headerSize; + volatile u_short sectionChecksum; + + volatile u_char registrationMode; + volatile u_char registrationFill; + volatile u_short pollPeriod; + volatile u_short refreshPeriod; + volatile u_char name[16]; + volatile u_char NID[6]; + volatile u_char localTalkAddress; + volatile u_char codeFormat; + volatile u_char numChannels; + volatile u_char channel1; + volatile u_char channel2; + volatile u_char channel3; + volatile u_char channel4; + volatile u_char SSCode[59]; + + volatile u_char _16[0xC0]; + volatile u_short auxCmd; + volatile u_char dumpPtr[4]; + volatile u_char dumpVal; + volatile u_char _17[0x6A]; + volatile u_char wireTest; + volatile u_char _18[14]; + + /* Statistics Block - 0x0300 */ + volatile u_char hostcpuLock; + volatile u_char lancpuLock; + volatile u_char resetTime[18]; + + volatile u_char numDatagramsTransmitted[4]; + volatile u_char numReTransmissions[4]; + volatile u_char numFramesDiscarded[4]; + volatile u_char numDatagramsReceived[4]; + volatile u_char numDuplicateReceivedFrames[4]; + volatile u_char numDatagramsDiscarded[4]; + + volatile u_short maxNumReTransmitDatagram; + volatile u_short maxNumReTransmitFrames; + volatile u_short maxNumConsecutiveDuplicateFrames; + /* misaligned here so we have to go to characters */ + + volatile u_char numBytesTransmitted[4]; + volatile u_char numBytesReceived[4]; + volatile u_char numCRCErrors[4]; + volatile u_char numLengthErrors[4]; + volatile u_char numAbortErrors[4]; + volatile u_char numTXUnderruns[4]; + volatile u_char numRXOverruns[4]; + volatile u_char numHoldOffs[4]; + volatile u_char numFramesTransmitted[4]; + volatile u_char numFramesReceived[4]; + volatile u_char numReceiveFramesLost[4]; + volatile u_char numRXBufferOverflows[4]; + volatile u_char numFramesDiscardedAddrMismatch[4]; + volatile u_char numFramesDiscardedSIDMismatch[4]; + volatile u_char numPollsTransmistted[4]; + volatile u_char numPollAcknowledges[4]; + volatile u_char numStatusTimeouts[4]; + volatile u_char numNACKReceived[4]; + + volatile u_char _19[0x86]; + + volatile u_char txBuffer[0x800]; + volatile u_char rxBuffer[0x800]; + + volatile u_char _20[0x800]; + volatile u_char _21[0x3fb]; + volatile u_char configStatus; + volatile u_char _22; + volatile u_char progIOCtrl; + volatile u_char shareMBase; + volatile u_char controlRegister; +}; + +struct arlan_conf_stru { + int spreadingCode; + int channelSet; + int channelNumber; + int scramblingDisable; + int txAttenuation; + int systemId; + int maxDatagramSize; + int maxFrameSize; + int maxRetries; + int receiveMode; + int priority; + int rootOrRepeater; + int SID; + int radioNodeId; + int registrationMode; + int registrationFill; + int localTalkAddress; + int codeFormat; + int numChannels; + int channel1; + int channel2; + int channel3; + int channel4; + int txClear; + int txRetries; + int txRouting; + int txScrambled; + int rxParameter; + int txTimeoutMs; + int txAckTimeoutMs; + int waitCardTimeout; + int waitTime; + int lParameter; + int _15; + int headerSize; + int retries; + int tx_delay_ms; + int waitReTransmitPacketMaxSize; + int ReTransmitPacketMaxSize; + int fastReTransCount; + int driverRetransmissions; + int registrationInterrupts; + int hardwareType; + int radioType; + int writeRadioType; + int writeEEPROM; + char siteName[17]; + int measure_rate; + int in_speed; + int out_speed; + int in_speed10; + int out_speed10; + int in_speed_max; + int out_speed_max; + int pre_Command_Wait; + int rx_tweak1; + int rx_tweak2; + int tx_queue_len; +}; + +extern struct arlan_conf_stru arlan_conf[MAX_ARLANS]; + +struct TxParam +{ + volatile short offset; + volatile short length; + volatile u_char dest[6]; + volatile unsigned char clear; + volatile unsigned char retries; + volatile unsigned char routing; + volatile unsigned char scrambled; +}; + +#define TX_RING_SIZE 2 +/* Information that need to be kept for each board. */ +struct arlan_private { + struct arlan_shmem __iomem * card; + struct arlan_shmem * conf; + + struct arlan_conf_stru * Conf; + int bad; + int reset; + unsigned long lastReset; + struct timer_list timer; + struct timer_list tx_delay_timer; + struct timer_list tx_retry_timer; + struct timer_list rx_check_timer; + + int registrationLostCount; + int reRegisterExp; + int irq_test_done; + + struct TxParam txRing[TX_RING_SIZE]; + char reTransmitBuff[0x800]; + int txLast; + unsigned ReTransmitRequested; + unsigned long tx_done_delayed; + unsigned long registrationLastSeen; + + unsigned long tx_last_sent; + unsigned long tx_last_cleared; + unsigned long retransmissions; + unsigned long interrupt_ack_requested; + spinlock_t lock; + unsigned long waiting_command_mask; + unsigned long card_polling_interval; + unsigned long last_command_buff_free_time; + + int under_reset; + int under_config; + int rx_command_given; + int tx_command_given; + unsigned long interrupt_processing_active; + unsigned long last_rx_int_ack_time; + unsigned long in_bytes; + unsigned long out_bytes; + unsigned long in_time; + unsigned long out_time; + unsigned long in_time10; + unsigned long out_time10; + unsigned long in_bytes10; + unsigned long out_bytes10; + int init_etherdev_alloc; +}; + + + +#define ARLAN_CLEAR 0x00 +#define ARLAN_RESET 0x01 +#define ARLAN_CHANNEL_ATTENTION 0x02 +#define ARLAN_INTERRUPT_ENABLE 0x04 +#define ARLAN_CLEAR_INTERRUPT 0x08 +#define ARLAN_POWER 0x40 +#define ARLAN_ACCESS 0x80 + +#define ARLAN_COM_CONF 0x01 +#define ARLAN_COM_RX_ENABLE 0x03 +#define ARLAN_COM_RX_ABORT 0x04 +#define ARLAN_COM_TX_ENABLE 0x05 +#define ARLAN_COM_TX_ABORT 0x06 +#define ARLAN_COM_NOP 0x07 +#define ARLAN_COM_STANDBY 0x08 +#define ARLAN_COM_ACTIVATE 0x09 +#define ARLAN_COM_GOTO_SLOW_POLL 0x0a +#define ARLAN_COM_INT 0x80 + + +#define TXLAST(dev) (((struct arlan_private *)netdev_priv(dev))->txRing[((struct arlan_private *)netdev_priv(dev))->txLast]) +#define TXHEAD(dev) (((struct arlan_private *)netdev_priv(dev))->txRing[0]) +#define TXTAIL(dev) (((struct arlan_private *)netdev_priv(dev))->txRing[1]) + +#define TXBuffStart(dev) offsetof(struct arlan_shmem, txBuffer) +#define TXBuffEnd(dev) offsetof(struct arlan_shmem, xxBuffer) + +#define READSHM(to,from,atype) {\ + atype tmp;\ + memcpy_fromio(&(tmp),&(from),sizeof(atype));\ + to = tmp;\ + } + +#define READSHMEM(from,atype)\ + atype from; \ + READSHM(from, arlan->from, atype); + +#define WRITESHM(to,from,atype) \ + { atype tmpSHM = from;\ + memcpy_toio(&(to),&tmpSHM,sizeof(atype));\ + } + +#define DEBUGSHM(levelSHM,stringSHM,stuff,atype) \ + { atype tmpSHM; \ + memcpy_fromio(&tmpSHM,&(stuff),sizeof(atype));\ + IFDEBUG(levelSHM) printk(stringSHM,tmpSHM);\ + } + +#define WRITESHMB(to, val) \ + writeb(val,&(to)) +#define READSHMB(to) \ + readb(&(to)) +#define WRITESHMS(to, val) \ + writew(val,&(to)) +#define READSHMS(to) \ + readw(&(to)) +#define WRITESHMI(to, val) \ + writel(val,&(to)) +#define READSHMI(to) \ + readl(&(to)) + + + + + +#define registrationBad(dev)\ + ( ( READSHMB(((struct arlan_private *)netdev_priv(dev))->card->registrationMode) > 0) && \ + ( READSHMB(((struct arlan_private *)netdev_priv(dev))->card->registrationStatus) == 0) ) + + +#define readControlRegister(dev)\ + READSHMB(((struct arlan_private *)netdev_priv(dev))->card->cntrlRegImage) + +#define writeControlRegister(dev, v){\ + WRITESHMB(((struct arlan_private *)netdev_priv(dev))->card->cntrlRegImage ,((v) &0xF) );\ + WRITESHMB(((struct arlan_private *)netdev_priv(dev))->card->controlRegister ,(v) );} + + +#define arlan_interrupt_lancpu(dev) {\ + int cr; \ + \ + cr = readControlRegister(dev);\ + if (cr & ARLAN_CHANNEL_ATTENTION){ \ + writeControlRegister(dev, (cr & ~ARLAN_CHANNEL_ATTENTION));\ + }else \ + writeControlRegister(dev, (cr | ARLAN_CHANNEL_ATTENTION));\ +} + +#define clearChannelAttention(dev){ \ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CHANNEL_ATTENTION);} +#define setHardwareReset(dev) {\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_RESET);} +#define clearHardwareReset(dev) {\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_RESET);} +#define setInterruptEnable(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_INTERRUPT_ENABLE) ;} +#define clearInterruptEnable(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_INTERRUPT_ENABLE) ;} +#define setClearInterrupt(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_CLEAR_INTERRUPT) ;} +#define clearClearInterrupt(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_CLEAR_INTERRUPT);} +#define setPowerOff(dev){\ + writeControlRegister(dev,readControlRegister(dev) | (ARLAN_POWER && ARLAN_ACCESS));\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} +#define setPowerOn(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~(ARLAN_POWER)); } +#define arlan_lock_card_access(dev){\ + writeControlRegister(dev,readControlRegister(dev) & ~ARLAN_ACCESS);} +#define arlan_unlock_card_access(dev){\ + writeControlRegister(dev,readControlRegister(dev) | ARLAN_ACCESS ); } + + + + +#define ARLAN_COMMAND_RX 0x000001 +#define ARLAN_COMMAND_NOOP 0x000002 +#define ARLAN_COMMAND_NOOPINT 0x000004 +#define ARLAN_COMMAND_TX 0x000008 +#define ARLAN_COMMAND_CONF 0x000010 +#define ARLAN_COMMAND_RESET 0x000020 +#define ARLAN_COMMAND_TX_ABORT 0x000040 +#define ARLAN_COMMAND_RX_ABORT 0x000080 +#define ARLAN_COMMAND_POWERDOWN 0x000100 +#define ARLAN_COMMAND_POWERUP 0x000200 +#define ARLAN_COMMAND_SLOW_POLL 0x000400 +#define ARLAN_COMMAND_ACTIVATE 0x000800 +#define ARLAN_COMMAND_INT_ACK 0x001000 +#define ARLAN_COMMAND_INT_ENABLE 0x002000 +#define ARLAN_COMMAND_WAIT_NOW 0x004000 +#define ARLAN_COMMAND_LONG_WAIT_NOW 0x008000 +#define ARLAN_COMMAND_STANDBY 0x010000 +#define ARLAN_COMMAND_INT_RACK 0x020000 +#define ARLAN_COMMAND_INT_RENABLE 0x040000 +#define ARLAN_COMMAND_CONF_WAIT 0x080000 +#define ARLAN_COMMAND_TBUSY_CLEAR 0x100000 +#define ARLAN_COMMAND_CLEAN_AND_CONF (ARLAN_COMMAND_TX_ABORT\ + | ARLAN_COMMAND_RX_ABORT\ + | ARLAN_COMMAND_CONF) +#define ARLAN_COMMAND_CLEAN_AND_RESET (ARLAN_COMMAND_TX_ABORT\ + | ARLAN_COMMAND_RX_ABORT\ + | ARLAN_COMMAND_RESET) + + + +#define ARLAN_DEBUG_CHAIN_LOCKS 0x00001 +#define ARLAN_DEBUG_RESET 0x00002 +#define ARLAN_DEBUG_TIMING 0x00004 +#define ARLAN_DEBUG_CARD_STATE 0x00008 +#define ARLAN_DEBUG_TX_CHAIN 0x00010 +#define ARLAN_DEBUG_MULTICAST 0x00020 +#define ARLAN_DEBUG_HEADER_DUMP 0x00040 +#define ARLAN_DEBUG_INTERRUPT 0x00080 +#define ARLAN_DEBUG_STARTUP 0x00100 +#define ARLAN_DEBUG_SHUTDOWN 0x00200 + -- cgit v1.2.3 From 0234f84ebb00d36c48062befa5436eef36b71ccd Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 28 Oct 2009 16:06:56 -0400 Subject: wavelan: move driver to staging Move the wavelan driver to drivers/staging. This is another pre-802.11 driver that has seen virtually no non-API-fixup activity in years, and for which no active hardware is likely to still exist. This driver represents unnecessary ongoing maintenance for no clear benefit. This patch brought to you by the "hacking" session at the 2009 Kernel Summit in Tokyo, Japan... Acked-by: Greg Kroah-Hartman Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 39 - drivers/net/wireless/Makefile | 2 - drivers/net/wireless/i82586.h | 413 --- drivers/net/wireless/i82593.h | 229 -- drivers/net/wireless/wavelan.c | 4383 ------------------------------ drivers/net/wireless/wavelan.h | 370 --- drivers/net/wireless/wavelan.p.h | 696 ----- drivers/net/wireless/wavelan_cs.c | 4635 -------------------------------- drivers/net/wireless/wavelan_cs.h | 386 --- drivers/net/wireless/wavelan_cs.p.h | 766 ------ drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 2 + drivers/staging/wavelan/Kconfig | 38 + drivers/staging/wavelan/Makefile | 2 + drivers/staging/wavelan/i82586.h | 413 +++ drivers/staging/wavelan/i82593.h | 229 ++ drivers/staging/wavelan/wavelan.c | 4383 ++++++++++++++++++++++++++++++ drivers/staging/wavelan/wavelan.h | 370 +++ drivers/staging/wavelan/wavelan.p.h | 696 +++++ drivers/staging/wavelan/wavelan_cs.c | 4635 ++++++++++++++++++++++++++++++++ drivers/staging/wavelan/wavelan_cs.h | 386 +++ drivers/staging/wavelan/wavelan_cs.p.h | 766 ++++++ 22 files changed, 11922 insertions(+), 11919 deletions(-) delete mode 100644 drivers/net/wireless/i82586.h delete mode 100644 drivers/net/wireless/i82593.h delete mode 100644 drivers/net/wireless/wavelan.c delete mode 100644 drivers/net/wireless/wavelan.h delete mode 100644 drivers/net/wireless/wavelan.p.h delete mode 100644 drivers/net/wireless/wavelan_cs.c delete mode 100644 drivers/net/wireless/wavelan_cs.h delete mode 100644 drivers/net/wireless/wavelan_cs.p.h create mode 100644 drivers/staging/wavelan/Kconfig create mode 100644 drivers/staging/wavelan/Makefile create mode 100644 drivers/staging/wavelan/i82586.h create mode 100644 drivers/staging/wavelan/i82593.h create mode 100644 drivers/staging/wavelan/wavelan.c create mode 100644 drivers/staging/wavelan/wavelan.h create mode 100644 drivers/staging/wavelan/wavelan.p.h create mode 100644 drivers/staging/wavelan/wavelan_cs.c create mode 100644 drivers/staging/wavelan/wavelan_cs.h create mode 100644 drivers/staging/wavelan/wavelan_cs.p.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index d50b3bee9a9b..f94188f05a02 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -25,45 +25,6 @@ menuconfig WLAN_PRE80211 This option does not affect the kernel build, it only lets you choose drivers. -config WAVELAN - tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support" - depends on ISA && WLAN_PRE80211 - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - ---help--- - The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is - a Radio LAN (wireless Ethernet-like Local Area Network) using the - radio frequencies 900 MHz and 2.4 GHz. - - If you want to use an ISA WaveLAN card under Linux, say Y and read - the Ethernet-HOWTO, available from - . Some more specific - information is contained in - and in the source code - . - - You will also need the wireless tools package available from - . - Please read the man pages contained therein. - - To compile this driver as a module, choose M here: the module will be - called wavelan. - -config PCMCIA_WAVELAN - tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support" - depends on PCMCIA && WLAN_PRE80211 - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - help - Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA - (PC-card) wireless Ethernet networking card to your computer. This - driver is for the non-IEEE-802.11 Wavelan cards. - - To compile this driver as a module, choose M here: the module will be - called wavelan_cs. If unsure, say N. - config PCMCIA_NETWAVE tristate "Xircom Netwave AirSurfer Pcmcia wireless support" depends on PCMCIA && WLAN_PRE80211 diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index b56c70f4ca75..f4a7c8ae27ea 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -6,9 +6,7 @@ obj-$(CONFIG_IPW2100) += ipw2x00/ obj-$(CONFIG_IPW2200) += ipw2x00/ # Obsolete cards -obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o -obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o obj-$(CONFIG_HERMES) += orinoco/ diff --git a/drivers/net/wireless/i82586.h b/drivers/net/wireless/i82586.h deleted file mode 100644 index 5f65b250646f..000000000000 --- a/drivers/net/wireless/i82586.h +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Intel 82586 IEEE 802.3 Ethernet LAN Coprocessor. - * - * See: - * Intel Microcommunications 1991 - * p1-1 to p1-37 - * Intel order No. 231658 - * ISBN 1-55512-119-5 - * - * Unfortunately, the above chapter mentions neither - * the System Configuration Pointer (SCP) nor the - * Intermediate System Configuration Pointer (ISCP), - * so we probably need to look elsewhere for the - * whole story -- some recommend the "Intel LAN - * Components manual" but I have neither a copy - * nor a full reference. But "elsewhere" may be - * in the same publication... - * The description of a later device, the - * "82596CA High-Performance 32-Bit Local Area Network - * Coprocessor", (ibid. p1-38 to p1-109) does mention - * the SCP and ISCP and also has an i82586 compatibility - * mode. Even more useful is "AP-235 An 82586 Data Link - * Driver" (ibid. p1-337 to p1-417). - */ - -#define I82586_MEMZ (64 * 1024) - -#define I82586_SCP_ADDR (I82586_MEMZ - sizeof(scp_t)) - -#define ADDR_LEN 6 -#define I82586NULL 0xFFFF - -#define toff(t,p,f) (unsigned short)((void *)(&((t *)((void *)0 + (p)))->f) - (void *)0) - -/* - * System Configuration Pointer (SCP). - */ -typedef struct scp_t scp_t; -struct scp_t -{ - unsigned short scp_sysbus; /* 82586 bus width: */ -#define SCP_SY_16BBUS (0x0 << 0) /* 16 bits */ -#define SCP_SY_8BBUS (0x1 << 0) /* 8 bits. */ - unsigned short scp_junk[2]; /* Unused */ - unsigned short scp_iscpl; /* lower 16 bits of ISCP_ADDR */ - unsigned short scp_iscph; /* upper 16 bits of ISCP_ADDR */ -}; - -/* - * Intermediate System Configuration Pointer (ISCP). - */ -typedef struct iscp_t iscp_t; -struct iscp_t -{ - unsigned short iscp_busy; /* set by CPU before first CA, */ - /* cleared by 82586 after read. */ - unsigned short iscp_offset; /* offset of SCB */ - unsigned short iscp_basel; /* base of SCB */ - unsigned short iscp_baseh; /* " */ -}; - -/* - * System Control Block (SCB). - * The 82586 writes its status to scb_status and then - * raises an interrupt to alert the CPU. - * The CPU writes a command to scb_command and - * then issues a Channel Attention (CA) to alert the 82586. - */ -typedef struct scb_t scb_t; -struct scb_t -{ - unsigned short scb_status; /* Status of 82586 */ -#define SCB_ST_INT (0xF << 12) /* Some of: */ -#define SCB_ST_CX (0x1 << 15) /* Cmd completed */ -#define SCB_ST_FR (0x1 << 14) /* Frame received */ -#define SCB_ST_CNA (0x1 << 13) /* Cmd unit not active */ -#define SCB_ST_RNR (0x1 << 12) /* Rcv unit not ready */ -#define SCB_ST_JUNK0 (0x1 << 11) /* 0 */ -#define SCB_ST_CUS (0x7 << 8) /* Cmd unit status */ -#define SCB_ST_CUS_IDLE (0 << 8) /* Idle */ -#define SCB_ST_CUS_SUSP (1 << 8) /* Suspended */ -#define SCB_ST_CUS_ACTV (2 << 8) /* Active */ -#define SCB_ST_JUNK1 (0x1 << 7) /* 0 */ -#define SCB_ST_RUS (0x7 << 4) /* Rcv unit status */ -#define SCB_ST_RUS_IDLE (0 << 4) /* Idle */ -#define SCB_ST_RUS_SUSP (1 << 4) /* Suspended */ -#define SCB_ST_RUS_NRES (2 << 4) /* No resources */ -#define SCB_ST_RUS_RDY (4 << 4) /* Ready */ - unsigned short scb_command; /* Next command */ -#define SCB_CMD_ACK_CX (0x1 << 15) /* Ack cmd completion */ -#define SCB_CMD_ACK_FR (0x1 << 14) /* Ack frame received */ -#define SCB_CMD_ACK_CNA (0x1 << 13) /* Ack CU not active */ -#define SCB_CMD_ACK_RNR (0x1 << 12) /* Ack RU not ready */ -#define SCB_CMD_JUNKX (0x1 << 11) /* Unused */ -#define SCB_CMD_CUC (0x7 << 8) /* Command Unit command */ -#define SCB_CMD_CUC_NOP (0 << 8) /* Nop */ -#define SCB_CMD_CUC_GO (1 << 8) /* Start cbl_offset */ -#define SCB_CMD_CUC_RES (2 << 8) /* Resume execution */ -#define SCB_CMD_CUC_SUS (3 << 8) /* Suspend " */ -#define SCB_CMD_CUC_ABT (4 << 8) /* Abort " */ -#define SCB_CMD_RESET (0x1 << 7) /* Reset chip (hardware) */ -#define SCB_CMD_RUC (0x7 << 4) /* Receive Unit command */ -#define SCB_CMD_RUC_NOP (0 << 4) /* Nop */ -#define SCB_CMD_RUC_GO (1 << 4) /* Start rfa_offset */ -#define SCB_CMD_RUC_RES (2 << 4) /* Resume reception */ -#define SCB_CMD_RUC_SUS (3 << 4) /* Suspend " */ -#define SCB_CMD_RUC_ABT (4 << 4) /* Abort " */ - unsigned short scb_cbl_offset; /* Offset of first command unit */ - /* Action Command */ - unsigned short scb_rfa_offset; /* Offset of first Receive */ - /* Frame Descriptor in the */ - /* Receive Frame Area */ - unsigned short scb_crcerrs; /* Properly aligned frames */ - /* received with a CRC error */ - unsigned short scb_alnerrs; /* Misaligned frames received */ - /* with a CRC error */ - unsigned short scb_rscerrs; /* Frames lost due to no space */ - unsigned short scb_ovrnerrs; /* Frames lost due to slow bus */ -}; - -#define scboff(p,f) toff(scb_t, p, f) - -/* - * The eight Action Commands. - */ -typedef enum acmd_e acmd_e; -enum acmd_e -{ - acmd_nop = 0, /* Do nothing */ - acmd_ia_setup = 1, /* Load an (ethernet) address into the */ - /* 82586 */ - acmd_configure = 2, /* Update the 82586 operating parameters */ - acmd_mc_setup = 3, /* Load a list of (ethernet) multicast */ - /* addresses into the 82586 */ - acmd_transmit = 4, /* Transmit a frame */ - acmd_tdr = 5, /* Perform a Time Domain Reflectometer */ - /* test on the serial link */ - acmd_dump = 6, /* Copy 82586 registers to memory */ - acmd_diagnose = 7, /* Run an internal self test */ -}; - -/* - * Generic Action Command header. - */ -typedef struct ach_t ach_t; -struct ach_t -{ - unsigned short ac_status; /* Command status: */ -#define AC_SFLD_C (0x1 << 15) /* Command completed */ -#define AC_SFLD_B (0x1 << 14) /* Busy executing */ -#define AC_SFLD_OK (0x1 << 13) /* Completed error free */ -#define AC_SFLD_A (0x1 << 12) /* Command aborted */ -#define AC_SFLD_FAIL (0x1 << 11) /* Selftest failed */ -#define AC_SFLD_S10 (0x1 << 10) /* No carrier sense */ - /* during transmission */ -#define AC_SFLD_S9 (0x1 << 9) /* Tx unsuccessful: */ - /* (stopped) lost CTS */ -#define AC_SFLD_S8 (0x1 << 8) /* Tx unsuccessful: */ - /* (stopped) slow DMA */ -#define AC_SFLD_S7 (0x1 << 7) /* Tx deferred: */ - /* other link traffic */ -#define AC_SFLD_S6 (0x1 << 6) /* Heart Beat: collision */ - /* detect after last tx */ -#define AC_SFLD_S5 (0x1 << 5) /* Tx stopped: */ - /* excessive collisions */ -#define AC_SFLD_MAXCOL (0xF << 0) /* Collision count */ - unsigned short ac_command; /* Command specifier: */ -#define AC_CFLD_EL (0x1 << 15) /* End of command list */ -#define AC_CFLD_S (0x1 << 14) /* Suspend on completion */ -#define AC_CFLD_I (0x1 << 13) /* Interrupt on completion */ -#define AC_CFLD_CMD (0x7 << 0) /* acmd_e */ - unsigned short ac_link; /* Next Action Command */ -}; - -#define acoff(p,f) toff(ach_t, p, f) - -/* - * The Nop Action Command. - */ -typedef struct ac_nop_t ac_nop_t; -struct ac_nop_t -{ - ach_t nop_h; -}; - -/* - * The IA-Setup Action Command. - */ -typedef struct ac_ias_t ac_ias_t; -struct ac_ias_t -{ - ach_t ias_h; - unsigned char ias_addr[ADDR_LEN]; /* The (ethernet) address */ -}; - -/* - * The Configure Action Command. - */ -typedef struct ac_cfg_t ac_cfg_t; -struct ac_cfg_t -{ - ach_t cfg_h; - unsigned char cfg_byte_cnt; /* Size foll data: 4-12 */ -#define AC_CFG_BYTE_CNT(v) (((v) & 0xF) << 0) - unsigned char cfg_fifolim; /* FIFO threshold */ -#define AC_CFG_FIFOLIM(v) (((v) & 0xF) << 0) - unsigned char cfg_byte8; -#define AC_CFG_SAV_BF(v) (((v) & 0x1) << 7) /* Save rxd bad frames */ -#define AC_CFG_SRDY(v) (((v) & 0x1) << 6) /* SRDY/ARDY pin means */ - /* external sync. */ - unsigned char cfg_byte9; -#define AC_CFG_ELPBCK(v) (((v) & 0x1) << 7) /* External loopback */ -#define AC_CFG_ILPBCK(v) (((v) & 0x1) << 6) /* Internal loopback */ -#define AC_CFG_PRELEN(v) (((v) & 0x3) << 4) /* Preamble length */ -#define AC_CFG_PLEN_2 0 /* 2 bytes */ -#define AC_CFG_PLEN_4 1 /* 4 bytes */ -#define AC_CFG_PLEN_8 2 /* 8 bytes */ -#define AC_CFG_PLEN_16 3 /* 16 bytes */ -#define AC_CFG_ALOC(v) (((v) & 0x1) << 3) /* Addr/len data is */ - /* explicit in buffers */ -#define AC_CFG_ADDRLEN(v) (((v) & 0x7) << 0) /* Bytes per address */ - unsigned char cfg_byte10; -#define AC_CFG_BOFMET(v) (((v) & 0x1) << 7) /* Use alternate expo. */ - /* backoff method */ -#define AC_CFG_ACR(v) (((v) & 0x7) << 4) /* Accelerated cont. res. */ -#define AC_CFG_LINPRIO(v) (((v) & 0x7) << 0) /* Linear priority */ - unsigned char cfg_ifs; /* Interframe spacing */ - unsigned char cfg_slotl; /* Slot time (low byte) */ - unsigned char cfg_byte13; -#define AC_CFG_RETRYNUM(v) (((v) & 0xF) << 4) /* Max. collision retry */ -#define AC_CFG_SLTTMHI(v) (((v) & 0x7) << 0) /* Slot time (high bits) */ - unsigned char cfg_byte14; -#define AC_CFG_FLGPAD(v) (((v) & 0x1) << 7) /* Pad with HDLC flags */ -#define AC_CFG_BTSTF(v) (((v) & 0x1) << 6) /* Do HDLC bitstuffing */ -#define AC_CFG_CRC16(v) (((v) & 0x1) << 5) /* 16 bit CCITT CRC */ -#define AC_CFG_NCRC(v) (((v) & 0x1) << 4) /* Insert no CRC */ -#define AC_CFG_TNCRS(v) (((v) & 0x1) << 3) /* Tx even if no carrier */ -#define AC_CFG_MANCH(v) (((v) & 0x1) << 2) /* Manchester coding */ -#define AC_CFG_BCDIS(v) (((v) & 0x1) << 1) /* Disable broadcast */ -#define AC_CFG_PRM(v) (((v) & 0x1) << 0) /* Promiscuous mode */ - unsigned char cfg_byte15; -#define AC_CFG_ICDS(v) (((v) & 0x1) << 7) /* Internal collision */ - /* detect source */ -#define AC_CFG_CDTF(v) (((v) & 0x7) << 4) /* Collision detect */ - /* filter in bit times */ -#define AC_CFG_ICSS(v) (((v) & 0x1) << 3) /* Internal carrier */ - /* sense source */ -#define AC_CFG_CSTF(v) (((v) & 0x7) << 0) /* Carrier sense */ - /* filter in bit times */ - unsigned short cfg_min_frm_len; -#define AC_CFG_MNFRM(v) (((v) & 0xFF) << 0) /* Min. bytes/frame (<= 255) */ -}; - -/* - * The MC-Setup Action Command. - */ -typedef struct ac_mcs_t ac_mcs_t; -struct ac_mcs_t -{ - ach_t mcs_h; - unsigned short mcs_cnt; /* No. of bytes of MC addresses */ -#if 0 - unsigned char mcs_data[ADDR_LEN]; /* The first MC address .. */ - ... -#endif -}; - -#define I82586_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ - -/* - * The Transmit Action Command. - */ -typedef struct ac_tx_t ac_tx_t; -struct ac_tx_t -{ - ach_t tx_h; - unsigned short tx_tbd_offset; /* Address of list of buffers. */ -#if 0 -Linux packets are passed down with the destination MAC address -and length/type field already prepended to the data, -so we do not need to insert it. Consistent with this -we must also set the AC_CFG_ALOC(..) flag during the -ac_cfg_t action command. - unsigned char tx_addr[ADDR_LEN]; /* The frame dest. address */ - unsigned short tx_length; /* The frame length */ -#endif /* 0 */ -}; - -/* - * The Time Domain Reflectometer Action Command. - */ -typedef struct ac_tdr_t ac_tdr_t; -struct ac_tdr_t -{ - ach_t tdr_h; - unsigned short tdr_result; /* Result. */ -#define AC_TDR_LNK_OK (0x1 << 15) /* No link problem */ -#define AC_TDR_XCVR_PRB (0x1 << 14) /* Txcvr cable problem */ -#define AC_TDR_ET_OPN (0x1 << 13) /* Open on the link */ -#define AC_TDR_ET_SRT (0x1 << 12) /* Short on the link */ -#define AC_TDR_TIME (0x7FF << 0) /* Distance to problem */ - /* site in transmit */ - /* clock cycles */ -}; - -/* - * The Dump Action Command. - */ -typedef struct ac_dmp_t ac_dmp_t; -struct ac_dmp_t -{ - ach_t dmp_h; - unsigned short dmp_offset; /* Result. */ -}; - -/* - * Size of the result of the dump command. - */ -#define DUMPBYTES 170 - -/* - * The Diagnose Action Command. - */ -typedef struct ac_dgn_t ac_dgn_t; -struct ac_dgn_t -{ - ach_t dgn_h; -}; - -/* - * Transmit Buffer Descriptor (TBD). - */ -typedef struct tbd_t tbd_t; -struct tbd_t -{ - unsigned short tbd_status; /* Written by the CPU */ -#define TBD_STATUS_EOF (0x1 << 15) /* This TBD is the */ - /* last for this frame */ -#define TBD_STATUS_ACNT (0x3FFF << 0) /* Actual count of data */ - /* bytes in this buffer */ - unsigned short tbd_next_bd_offset; /* Next in list */ - unsigned short tbd_bufl; /* Buffer address (low) */ - unsigned short tbd_bufh; /* " " (high) */ -}; - -/* - * Receive Buffer Descriptor (RBD). - */ -typedef struct rbd_t rbd_t; -struct rbd_t -{ - unsigned short rbd_status; /* Written by the 82586 */ -#define RBD_STATUS_EOF (0x1 << 15) /* This RBD is the */ - /* last for this frame */ -#define RBD_STATUS_F (0x1 << 14) /* ACNT field is valid */ -#define RBD_STATUS_ACNT (0x3FFF << 0) /* Actual no. of data */ - /* bytes in this buffer */ - unsigned short rbd_next_rbd_offset; /* Next rbd in list */ - unsigned short rbd_bufl; /* Data pointer (low) */ - unsigned short rbd_bufh; /* " " (high) */ - unsigned short rbd_el_size; /* EL+Data buf. size */ -#define RBD_EL (0x1 << 15) /* This BD is the */ - /* last in the list */ -#define RBD_SIZE (0x3FFF << 0) /* No. of bytes the */ - /* buffer can hold */ -}; - -#define rbdoff(p,f) toff(rbd_t, p, f) - -/* - * Frame Descriptor (FD). - */ -typedef struct fd_t fd_t; -struct fd_t -{ - unsigned short fd_status; /* Written by the 82586 */ -#define FD_STATUS_C (0x1 << 15) /* Completed storing frame */ -#define FD_STATUS_B (0x1 << 14) /* FD was consumed by RU */ -#define FD_STATUS_OK (0x1 << 13) /* Frame rxd successfully */ -#define FD_STATUS_S11 (0x1 << 11) /* CRC error */ -#define FD_STATUS_S10 (0x1 << 10) /* Alignment error */ -#define FD_STATUS_S9 (0x1 << 9) /* Ran out of resources */ -#define FD_STATUS_S8 (0x1 << 8) /* Rx DMA overrun */ -#define FD_STATUS_S7 (0x1 << 7) /* Frame too short */ -#define FD_STATUS_S6 (0x1 << 6) /* No EOF flag */ - unsigned short fd_command; /* Command */ -#define FD_COMMAND_EL (0x1 << 15) /* Last FD in list */ -#define FD_COMMAND_S (0x1 << 14) /* Suspend RU after rx */ - unsigned short fd_link_offset; /* Next FD */ - unsigned short fd_rbd_offset; /* First RBD (data) */ - /* Prepared by CPU, */ - /* updated by 82586 */ -#if 0 -I think the rest is unused since we -have set AC_CFG_ALOC(..). However, just -in case, we leave the space. -#endif /* 0 */ - unsigned char fd_dest[ADDR_LEN]; /* Destination address */ - /* Written by 82586 */ - unsigned char fd_src[ADDR_LEN]; /* Source address */ - /* Written by 82586 */ - unsigned short fd_length; /* Frame length or type */ - /* Written by 82586 */ -}; - -#define fdoff(p,f) toff(fd_t, p, f) - -/* - * This software may only be used and distributed - * according to the terms of the GNU General Public License. - * - * For more details, see wavelan.c. - */ diff --git a/drivers/net/wireless/i82593.h b/drivers/net/wireless/i82593.h deleted file mode 100644 index afac5c7a323d..000000000000 --- a/drivers/net/wireless/i82593.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Definitions for Intel 82593 CSMA/CD Core LAN Controller - * The definitions are taken from the 1992 users manual with Intel - * order number 297125-001. - * - * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp - * - * Copyright 1994, Anders Klemets - * - * HISTORY - * i82593.h,v - * Revision 1.4 2005/11/4 09:15:00 baroniunas - * Modified copyright with permission of author as follows: - * - * "If I82539.H is the only file with my copyright statement - * that is included in the Source Forge project, then you have - * my approval to change the copyright statement to be a GPL - * license, in the way you proposed on October 10." - * - * Revision 1.1 1996/07/17 15:23:12 root - * Initial revision - * - * Revision 1.3 1995/04/05 15:13:58 adj - * Initial alpha release - * - * Revision 1.2 1994/06/16 23:57:31 klemets - * Mirrored all the fields in the configuration block. - * - * Revision 1.1 1994/06/02 20:25:34 klemets - * Initial revision - * - * - */ -#ifndef _I82593_H -#define _I82593_H - -/* Intel 82593 CSMA/CD Core LAN Controller */ - -/* Port 0 Command Register definitions */ - -/* Execution operations */ -#define OP0_NOP 0 /* CHNL = 0 */ -#define OP0_SWIT_TO_PORT_1 0 /* CHNL = 1 */ -#define OP0_IA_SETUP 1 -#define OP0_CONFIGURE 2 -#define OP0_MC_SETUP 3 -#define OP0_TRANSMIT 4 -#define OP0_TDR 5 -#define OP0_DUMP 6 -#define OP0_DIAGNOSE 7 -#define OP0_TRANSMIT_NO_CRC 9 -#define OP0_RETRANSMIT 12 -#define OP0_ABORT 13 -/* Reception operations */ -#define OP0_RCV_ENABLE 8 -#define OP0_RCV_DISABLE 10 -#define OP0_STOP_RCV 11 -/* Status pointer control operations */ -#define OP0_FIX_PTR 15 /* CHNL = 1 */ -#define OP0_RLS_PTR 15 /* CHNL = 0 */ -#define OP0_RESET 14 - -#define CR0_CHNL (1 << 4) /* 0=Channel 0, 1=Channel 1 */ -#define CR0_STATUS_0 0x00 -#define CR0_STATUS_1 0x20 -#define CR0_STATUS_2 0x40 -#define CR0_STATUS_3 0x60 -#define CR0_INT_ACK (1 << 7) /* 0=No ack, 1=acknowledge */ - -/* Port 0 Status Register definitions */ - -#define SR0_NO_RESULT 0 /* dummy */ -#define SR0_EVENT_MASK 0x0f -#define SR0_IA_SETUP_DONE 1 -#define SR0_CONFIGURE_DONE 2 -#define SR0_MC_SETUP_DONE 3 -#define SR0_TRANSMIT_DONE 4 -#define SR0_TDR_DONE 5 -#define SR0_DUMP_DONE 6 -#define SR0_DIAGNOSE_PASSED 7 -#define SR0_TRANSMIT_NO_CRC_DONE 9 -#define SR0_RETRANSMIT_DONE 12 -#define SR0_EXECUTION_ABORTED 13 -#define SR0_END_OF_FRAME 8 -#define SR0_RECEPTION_ABORTED 10 -#define SR0_DIAGNOSE_FAILED 15 -#define SR0_STOP_REG_HIT 11 - -#define SR0_CHNL (1 << 4) -#define SR0_EXECUTION (1 << 5) -#define SR0_RECEPTION (1 << 6) -#define SR0_INTERRUPT (1 << 7) -#define SR0_BOTH_RX_TX (SR0_EXECUTION | SR0_RECEPTION) - -#define SR3_EXEC_STATE_MASK 0x03 -#define SR3_EXEC_IDLE 0 -#define SR3_TX_ABORT_IN_PROGRESS 1 -#define SR3_EXEC_ACTIVE 2 -#define SR3_ABORT_IN_PROGRESS 3 -#define SR3_EXEC_CHNL (1 << 2) -#define SR3_STP_ON_NO_RSRC (1 << 3) -#define SR3_RCVING_NO_RSRC (1 << 4) -#define SR3_RCV_STATE_MASK 0x60 -#define SR3_RCV_IDLE 0x00 -#define SR3_RCV_READY 0x20 -#define SR3_RCV_ACTIVE 0x40 -#define SR3_RCV_STOP_IN_PROG 0x60 -#define SR3_RCV_CHNL (1 << 7) - -/* Port 1 Command Register definitions */ - -#define OP1_NOP 0 -#define OP1_SWIT_TO_PORT_0 1 -#define OP1_INT_DISABLE 2 -#define OP1_INT_ENABLE 3 -#define OP1_SET_TS 5 -#define OP1_RST_TS 7 -#define OP1_POWER_DOWN 8 -#define OP1_RESET_RING_MNGMT 11 -#define OP1_RESET 14 -#define OP1_SEL_RST 15 - -#define CR1_STATUS_4 0x00 -#define CR1_STATUS_5 0x20 -#define CR1_STATUS_6 0x40 -#define CR1_STOP_REG_UPDATE (1 << 7) - -/* Receive frame status bits */ - -#define RX_RCLD (1 << 0) -#define RX_IA_MATCH (1 << 1) -#define RX_NO_AD_MATCH (1 << 2) -#define RX_NO_SFD (1 << 3) -#define RX_SRT_FRM (1 << 7) -#define RX_OVRRUN (1 << 8) -#define RX_ALG_ERR (1 << 10) -#define RX_CRC_ERR (1 << 11) -#define RX_LEN_ERR (1 << 12) -#define RX_RCV_OK (1 << 13) -#define RX_TYP_LEN (1 << 15) - -/* Transmit status bits */ - -#define TX_NCOL_MASK 0x0f -#define TX_FRTL (1 << 4) -#define TX_MAX_COL (1 << 5) -#define TX_HRT_BEAT (1 << 6) -#define TX_DEFER (1 << 7) -#define TX_UND_RUN (1 << 8) -#define TX_LOST_CTS (1 << 9) -#define TX_LOST_CRS (1 << 10) -#define TX_LTCOL (1 << 11) -#define TX_OK (1 << 13) -#define TX_COLL (1 << 15) - -struct i82593_conf_block { - u_char fifo_limit : 4, - forgnesi : 1, - fifo_32 : 1, - d6mod : 1, - throttle_enb : 1; - u_char throttle : 6, - cntrxint : 1, - contin : 1; - u_char addr_len : 3, - acloc : 1, - preamb_len : 2, - loopback : 2; - u_char lin_prio : 3, - tbofstop : 1, - exp_prio : 3, - bof_met : 1; - u_char : 4, - ifrm_spc : 4; - u_char : 5, - slottim_low : 3; - u_char slottim_hi : 3, - : 1, - max_retr : 4; - u_char prmisc : 1, - bc_dis : 1, - : 1, - crs_1 : 1, - nocrc_ins : 1, - crc_1632 : 1, - : 1, - crs_cdt : 1; - u_char cs_filter : 3, - crs_src : 1, - cd_filter : 3, - : 1; - u_char : 2, - min_fr_len : 6; - u_char lng_typ : 1, - lng_fld : 1, - rxcrc_xf : 1, - artx : 1, - sarec : 1, - tx_jabber : 1, /* why is this called max_len in the manual? */ - hash_1 : 1, - lbpkpol : 1; - u_char : 6, - fdx : 1, - : 1; - u_char dummy_6 : 6, /* supposed to be ones */ - mult_ia : 1, - dis_bof : 1; - u_char dummy_1 : 1, /* supposed to be one */ - tx_ifs_retrig : 2, - mc_all : 1, - rcv_mon : 2, - frag_acpt : 1, - tstrttrs : 1; - u_char fretx : 1, - runt_eop : 1, - hw_sw_pin : 1, - big_endn : 1, - syncrqs : 1, - sttlen : 1, - tx_eop : 1, - rx_eop : 1; - u_char rbuf_size : 5, - rcvstop : 1, - : 2; -}; - -#define I82593_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ - -#endif /* _I82593_H */ diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c deleted file mode 100644 index d634b2da3b84..000000000000 --- a/drivers/net/wireless/wavelan.c +++ /dev/null @@ -1,4383 +0,0 @@ -/* - * WaveLAN ISA driver - * - * Jean II - HPLB '96 - * - * Reorganisation and extension of the driver. - * Original copyright follows (also see the end of this file). - * See wavelan.p.h for details. - * - * - * - * AT&T GIS (nee NCR) WaveLAN card: - * An Ethernet-like radio transceiver - * controlled by an Intel 82586 coprocessor. - */ - -#include "wavelan.p.h" /* Private header */ - -/************************* MISC SUBROUTINES **************************/ -/* - * Subroutines which won't fit in one of the following category - * (WaveLAN modem or i82586) - */ - -/*------------------------------------------------------------------*/ -/* - * Translate irq number to PSA irq parameter - */ -static u8 wv_irq_to_psa(int irq) -{ - if (irq < 0 || irq >= ARRAY_SIZE(irqvals)) - return 0; - - return irqvals[irq]; -} - -/*------------------------------------------------------------------*/ -/* - * Translate PSA irq parameter to irq number - */ -static int __init wv_psa_to_irq(u8 irqval) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(irqvals); i++) - if (irqvals[i] == irqval) - return i; - - return -1; -} - -/********************* HOST ADAPTER SUBROUTINES *********************/ -/* - * Useful subroutines to manage the WaveLAN ISA interface - * - * One major difference with the PCMCIA hardware (except the port mapping) - * is that we have to keep the state of the Host Control Register - * because of the interrupt enable & bus size flags. - */ - -/*------------------------------------------------------------------*/ -/* - * Read from card's Host Adaptor Status Register. - */ -static inline u16 hasr_read(unsigned long ioaddr) -{ - return (inw(HASR(ioaddr))); -} /* hasr_read */ - -/*------------------------------------------------------------------*/ -/* - * Write to card's Host Adapter Command Register. - */ -static inline void hacr_write(unsigned long ioaddr, u16 hacr) -{ - outw(hacr, HACR(ioaddr)); -} /* hacr_write */ - -/*------------------------------------------------------------------*/ -/* - * Write to card's Host Adapter Command Register. Include a delay for - * those times when it is needed. - */ -static void hacr_write_slow(unsigned long ioaddr, u16 hacr) -{ - hacr_write(ioaddr, hacr); - /* delay might only be needed sometimes */ - mdelay(1); -} /* hacr_write_slow */ - -/*------------------------------------------------------------------*/ -/* - * Set the channel attention bit. - */ -static inline void set_chan_attn(unsigned long ioaddr, u16 hacr) -{ - hacr_write(ioaddr, hacr | HACR_CA); -} /* set_chan_attn */ - -/*------------------------------------------------------------------*/ -/* - * Reset, and then set host adaptor into default mode. - */ -static inline void wv_hacr_reset(unsigned long ioaddr) -{ - hacr_write_slow(ioaddr, HACR_RESET); - hacr_write(ioaddr, HACR_DEFAULT); -} /* wv_hacr_reset */ - -/*------------------------------------------------------------------*/ -/* - * Set the I/O transfer over the ISA bus to 8-bit mode - */ -static inline void wv_16_off(unsigned long ioaddr, u16 hacr) -{ - hacr &= ~HACR_16BITS; - hacr_write(ioaddr, hacr); -} /* wv_16_off */ - -/*------------------------------------------------------------------*/ -/* - * Set the I/O transfer over the ISA bus to 8-bit mode - */ -static inline void wv_16_on(unsigned long ioaddr, u16 hacr) -{ - hacr |= HACR_16BITS; - hacr_write(ioaddr, hacr); -} /* wv_16_on */ - -/*------------------------------------------------------------------*/ -/* - * Disable interrupts on the WaveLAN hardware. - * (called by wv_82586_stop()) - */ -static inline void wv_ints_off(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - - lp->hacr &= ~HACR_INTRON; - hacr_write(ioaddr, lp->hacr); -} /* wv_ints_off */ - -/*------------------------------------------------------------------*/ -/* - * Enable interrupts on the WaveLAN hardware. - * (called by wv_hw_reset()) - */ -static inline void wv_ints_on(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - - lp->hacr |= HACR_INTRON; - hacr_write(ioaddr, lp->hacr); -} /* wv_ints_on */ - -/******************* MODEM MANAGEMENT SUBROUTINES *******************/ -/* - * Useful subroutines to manage the modem of the WaveLAN - */ - -/*------------------------------------------------------------------*/ -/* - * Read the Parameter Storage Area from the WaveLAN card's memory - */ -/* - * Read bytes from the PSA. - */ -static void psa_read(unsigned long ioaddr, u16 hacr, int o, /* offset in PSA */ - u8 * b, /* buffer to fill */ - int n) -{ /* size to read */ - wv_16_off(ioaddr, hacr); - - while (n-- > 0) { - outw(o, PIOR2(ioaddr)); - o++; - *b++ = inb(PIOP2(ioaddr)); - } - - wv_16_on(ioaddr, hacr); -} /* psa_read */ - -/*------------------------------------------------------------------*/ -/* - * Write the Parameter Storage Area to the WaveLAN card's memory. - */ -static void psa_write(unsigned long ioaddr, u16 hacr, int o, /* Offset in PSA */ - u8 * b, /* Buffer in memory */ - int n) -{ /* Length of buffer */ - int count = 0; - - wv_16_off(ioaddr, hacr); - - while (n-- > 0) { - outw(o, PIOR2(ioaddr)); - o++; - - outb(*b, PIOP2(ioaddr)); - b++; - - /* Wait for the memory to finish its write cycle */ - count = 0; - while ((count++ < 100) && - (hasr_read(ioaddr) & HASR_PSA_BUSY)) mdelay(1); - } - - wv_16_on(ioaddr, hacr); -} /* psa_write */ - -#ifdef SET_PSA_CRC -/*------------------------------------------------------------------*/ -/* - * Calculate the PSA CRC - * Thanks to Valster, Nico for the code - * NOTE: By specifying a length including the CRC position the - * returned value should be zero. (i.e. a correct checksum in the PSA) - * - * The Windows drivers don't use the CRC, but the AP and the PtP tool - * depend on it. - */ -static u16 psa_crc(u8 * psa, /* The PSA */ - int size) -{ /* Number of short for CRC */ - int byte_cnt; /* Loop on the PSA */ - u16 crc_bytes = 0; /* Data in the PSA */ - int bit_cnt; /* Loop on the bits of the short */ - - for (byte_cnt = 0; byte_cnt < size; byte_cnt++) { - crc_bytes ^= psa[byte_cnt]; /* Its an xor */ - - for (bit_cnt = 1; bit_cnt < 9; bit_cnt++) { - if (crc_bytes & 0x0001) - crc_bytes = (crc_bytes >> 1) ^ 0xA001; - else - crc_bytes >>= 1; - } - } - - return crc_bytes; -} /* psa_crc */ -#endif /* SET_PSA_CRC */ - -/*------------------------------------------------------------------*/ -/* - * update the checksum field in the Wavelan's PSA - */ -static void update_psa_checksum(struct net_device * dev, unsigned long ioaddr, u16 hacr) -{ -#ifdef SET_PSA_CRC - psa_t psa; - u16 crc; - - /* read the parameter storage area */ - psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa)); - - /* update the checksum */ - crc = psa_crc((unsigned char *) &psa, - sizeof(psa) - sizeof(psa.psa_crc[0]) - - sizeof(psa.psa_crc[1]) - - sizeof(psa.psa_crc_status)); - - psa.psa_crc[0] = crc & 0xFF; - psa.psa_crc[1] = (crc & 0xFF00) >> 8; - - /* Write it ! */ - psa_write(ioaddr, hacr, (char *) &psa.psa_crc - (char *) &psa, - (unsigned char *) &psa.psa_crc, 2); - -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", - dev->name, psa.psa_crc[0], psa.psa_crc[1]); - - /* Check again (luxury !) */ - crc = psa_crc((unsigned char *) &psa, - sizeof(psa) - sizeof(psa.psa_crc_status)); - - if (crc != 0) - printk(KERN_WARNING - "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", - dev->name); -#endif /* DEBUG_IOCTL_INFO */ -#endif /* SET_PSA_CRC */ -} /* update_psa_checksum */ - -/*------------------------------------------------------------------*/ -/* - * Write 1 byte to the MMC. - */ -static void mmc_out(unsigned long ioaddr, u16 o, u8 d) -{ - int count = 0; - - /* Wait for MMC to go idle */ - while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) - udelay(10); - - outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr)); -} - -/*------------------------------------------------------------------*/ -/* - * Routine to write bytes to the Modem Management Controller. - * We start at the end because it is the way it should be! - */ -static void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n) -{ - o += n; - b += n; - - while (n-- > 0) - mmc_out(ioaddr, --o, *(--b)); -} /* mmc_write */ - -/*------------------------------------------------------------------*/ -/* - * Read a byte from the MMC. - * Optimised version for 1 byte, avoid using memory. - */ -static u8 mmc_in(unsigned long ioaddr, u16 o) -{ - int count = 0; - - while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) - udelay(10); - outw(o << 1, MMCR(ioaddr)); - - while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) - udelay(10); - return (u8) (inw(MMCR(ioaddr)) >> 8); -} - -/*------------------------------------------------------------------*/ -/* - * Routine to read bytes from the Modem Management Controller. - * The implementation is complicated by a lack of address lines, - * which prevents decoding of the low-order bit. - * (code has just been moved in the above function) - * We start at the end because it is the way it should be! - */ -static inline void mmc_read(unsigned long ioaddr, u8 o, u8 * b, int n) -{ - o += n; - b += n; - - while (n-- > 0) - *(--b) = mmc_in(ioaddr, --o); -} /* mmc_read */ - -/*------------------------------------------------------------------*/ -/* - * Get the type of encryption available. - */ -static inline int mmc_encr(unsigned long ioaddr) -{ /* I/O port of the card */ - int temp; - - temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail)); - if ((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) - return 0; - else - return temp; -} - -/*------------------------------------------------------------------*/ -/* - * Wait for the frequency EEPROM to complete a command. - * I hope this one will be optimally inlined. - */ -static inline void fee_wait(unsigned long ioaddr, /* I/O port of the card */ - int delay, /* Base delay to wait for */ - int number) -{ /* Number of time to wait */ - int count = 0; /* Wait only a limited time */ - - while ((count++ < number) && - (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - MMR_FEE_STATUS_BUSY)) udelay(delay); -} - -/*------------------------------------------------------------------*/ -/* - * Read bytes from the Frequency EEPROM (frequency select cards). - */ -static void fee_read(unsigned long ioaddr, /* I/O port of the card */ - u16 o, /* destination offset */ - u16 * b, /* data buffer */ - int n) -{ /* number of registers */ - b += n; /* Position at the end of the area */ - - /* Write the address */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); - - /* Loop on all buffer */ - while (n-- > 0) { - /* Write the read command */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), - MMW_FEE_CTRL_READ); - - /* Wait until EEPROM is ready (should be quick). */ - fee_wait(ioaddr, 10, 100); - - /* Read the value. */ - *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) | - mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); - } -} - - -/*------------------------------------------------------------------*/ -/* - * Write bytes from the Frequency EEPROM (frequency select cards). - * This is a bit complicated, because the frequency EEPROM has to - * be unprotected and the write enabled. - * Jean II - */ -static void fee_write(unsigned long ioaddr, /* I/O port of the card */ - u16 o, /* destination offset */ - u16 * b, /* data buffer */ - int n) -{ /* number of registers */ - b += n; /* Position at the end of the area. */ - -#ifdef EEPROM_IS_PROTECTED /* disabled */ -#ifdef DOESNT_SEEM_TO_WORK /* disabled */ - /* Ask to read the protected register */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); - - fee_wait(ioaddr, 10, 100); - - /* Read the protected register. */ - printk("Protected 2: %02X-%02X\n", - mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)), - mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); -#endif /* DOESNT_SEEM_TO_WORK */ - - /* Enable protected register. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); - - fee_wait(ioaddr, 10, 100); - - /* Unprotect area. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); -#ifdef DOESNT_SEEM_TO_WORK /* disabled */ - /* or use: */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); -#endif /* DOESNT_SEEM_TO_WORK */ - - fee_wait(ioaddr, 10, 100); -#endif /* EEPROM_IS_PROTECTED */ - - /* Write enable. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); - - fee_wait(ioaddr, 10, 100); - - /* Write the EEPROM address. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); - - /* Loop on all buffer */ - while (n-- > 0) { - /* Write the value. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); - mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF); - - /* Write the write command. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), - MMW_FEE_CTRL_WRITE); - - /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */ - mdelay(10); - fee_wait(ioaddr, 10, 100); - } - - /* Write disable. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); - - fee_wait(ioaddr, 10, 100); - -#ifdef EEPROM_IS_PROTECTED /* disabled */ - /* Reprotect EEPROM. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); - - fee_wait(ioaddr, 10, 100); -#endif /* EEPROM_IS_PROTECTED */ -} - -/************************ I82586 SUBROUTINES *************************/ -/* - * Useful subroutines to manage the Ethernet controller - */ - -/*------------------------------------------------------------------*/ -/* - * Read bytes from the on-board RAM. - * Why does inlining this function make it fail? - */ -static /*inline */ void obram_read(unsigned long ioaddr, - u16 o, u8 * b, int n) -{ - outw(o, PIOR1(ioaddr)); - insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); -} - -/*------------------------------------------------------------------*/ -/* - * Write bytes to the on-board RAM. - */ -static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n) -{ - outw(o, PIOR1(ioaddr)); - outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); -} - -/*------------------------------------------------------------------*/ -/* - * Acknowledge the reading of the status issued by the i82586. - */ -static void wv_ack(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - u16 scb_cs; - int i; - - obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - scb_cs &= SCB_ST_INT; - - if (scb_cs == 0) - return; - - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - - set_chan_attn(ioaddr, lp->hacr); - - for (i = 1000; i > 0; i--) { - obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - if (scb_cs == 0) - break; - - udelay(10); - } - udelay(100); - -#ifdef DEBUG_CONFIG_ERROR - if (i <= 0) - printk(KERN_INFO - "%s: wv_ack(): board not accepting command.\n", - dev->name); -#endif -} - -/*------------------------------------------------------------------*/ -/* - * Set channel attention bit and busy wait until command has - * completed, then acknowledge completion of the command. - */ -static int wv_synchronous_cmd(struct net_device * dev, const char *str) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - u16 scb_cmd; - ach_t cb; - int i; - - scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO; - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cmd, sizeof(scb_cmd)); - - set_chan_attn(ioaddr, lp->hacr); - - for (i = 1000; i > 0; i--) { - obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, - sizeof(cb)); - if (cb.ac_status & AC_SFLD_C) - break; - - udelay(10); - } - udelay(100); - - if (i <= 0 || !(cb.ac_status & AC_SFLD_OK)) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO "%s: %s failed; status = 0x%x\n", - dev->name, str, cb.ac_status); -#endif -#ifdef DEBUG_I82586_SHOW - wv_scb_show(ioaddr); -#endif - return -1; - } - - /* Ack the status */ - wv_ack(dev); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Configuration commands completion interrupt. - * Check if done, and if OK. - */ -static int -wv_config_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) -{ - unsigned short mcs_addr; - unsigned short status; - int ret; - -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name); -#endif - - mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t) - + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t); - - /* Read the status of the last command (set mc list). */ - obram_read(ioaddr, acoff(mcs_addr, ac_status), - (unsigned char *) &status, sizeof(status)); - - /* If not completed -> exit */ - if ((status & AC_SFLD_C) == 0) - ret = 0; /* Not ready to be scrapped */ - else { -#ifdef DEBUG_CONFIG_ERROR - unsigned short cfg_addr; - unsigned short ias_addr; - - /* Check mc_config command */ - if ((status & AC_SFLD_OK) != AC_SFLD_OK) - printk(KERN_INFO - "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n", - dev->name, status); - - /* check ia-config command */ - ias_addr = mcs_addr - sizeof(ac_ias_t); - obram_read(ioaddr, acoff(ias_addr, ac_status), - (unsigned char *) &status, sizeof(status)); - if ((status & AC_SFLD_OK) != AC_SFLD_OK) - printk(KERN_INFO - "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n", - dev->name, status); - - /* Check config command. */ - cfg_addr = ias_addr - sizeof(ac_cfg_t); - obram_read(ioaddr, acoff(cfg_addr, ac_status), - (unsigned char *) &status, sizeof(status)); - if ((status & AC_SFLD_OK) != AC_SFLD_OK) - printk(KERN_INFO - "%s: wv_config_complete(): configure failed; status = 0x%x\n", - dev->name, status); -#endif /* DEBUG_CONFIG_ERROR */ - - ret = 1; /* Ready to be scrapped */ - } - -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, - ret); -#endif - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Command completion interrupt. - * Reclaim as many freed tx buffers as we can. - * (called in wavelan_interrupt()). - * Note : the spinlock is already grabbed for us. - */ -static int wv_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) -{ - int nreaped = 0; - -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name); -#endif - - /* Loop on all the transmit buffers */ - while (lp->tx_first_in_use != I82586NULL) { - unsigned short tx_status; - - /* Read the first transmit buffer */ - obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), - (unsigned char *) &tx_status, - sizeof(tx_status)); - - /* If not completed -> exit */ - if ((tx_status & AC_SFLD_C) == 0) - break; - - /* Hack for reconfiguration */ - if (tx_status == 0xFFFF) - if (!wv_config_complete(dev, ioaddr, lp)) - break; /* Not completed */ - - /* We now remove this buffer */ - nreaped++; - --lp->tx_n_in_use; - -/* -if (lp->tx_n_in_use > 0) - printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]); -*/ - - /* Was it the last one? */ - if (lp->tx_n_in_use <= 0) - lp->tx_first_in_use = I82586NULL; - else { - /* Next one in the chain */ - lp->tx_first_in_use += TXBLOCKZ; - if (lp->tx_first_in_use >= - OFFSET_CU + - NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -= - NTXBLOCKS * TXBLOCKZ; - } - - /* Hack for reconfiguration */ - if (tx_status == 0xFFFF) - continue; - - /* Now, check status of the finished command */ - if (tx_status & AC_SFLD_OK) { - int ncollisions; - - dev->stats.tx_packets++; - ncollisions = tx_status & AC_SFLD_MAXCOL; - dev->stats.collisions += ncollisions; -#ifdef DEBUG_TX_INFO - if (ncollisions > 0) - printk(KERN_DEBUG - "%s: wv_complete(): tx completed after %d collisions.\n", - dev->name, ncollisions); -#endif - } else { - dev->stats.tx_errors++; - if (tx_status & AC_SFLD_S10) { - dev->stats.tx_carrier_errors++; -#ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG - "%s: wv_complete(): tx error: no CS.\n", - dev->name); -#endif - } - if (tx_status & AC_SFLD_S9) { - dev->stats.tx_carrier_errors++; -#ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG - "%s: wv_complete(): tx error: lost CTS.\n", - dev->name); -#endif - } - if (tx_status & AC_SFLD_S8) { - dev->stats.tx_fifo_errors++; -#ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG - "%s: wv_complete(): tx error: slow DMA.\n", - dev->name); -#endif - } - if (tx_status & AC_SFLD_S6) { - dev->stats.tx_heartbeat_errors++; -#ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG - "%s: wv_complete(): tx error: heart beat.\n", - dev->name); -#endif - } - if (tx_status & AC_SFLD_S5) { - dev->stats.tx_aborted_errors++; -#ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG - "%s: wv_complete(): tx error: too many collisions.\n", - dev->name); -#endif - } - } - -#ifdef DEBUG_TX_INFO - printk(KERN_DEBUG - "%s: wv_complete(): tx completed, tx_status 0x%04x\n", - dev->name, tx_status); -#endif - } - -#ifdef DEBUG_INTERRUPT_INFO - if (nreaped > 1) - printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", - dev->name, nreaped); -#endif - - /* - * Inform upper layers. - */ - if (lp->tx_n_in_use < NTXBLOCKS - 1) { - netif_wake_queue(dev); - } -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name); -#endif - return nreaped; -} - -/*------------------------------------------------------------------*/ -/* - * Reconfigure the i82586, or at least ask for it. - * Because wv_82586_config uses a transmission buffer, we must do it - * when we are sure that there is one left, so we do it now - * or in wavelan_packet_xmit() (I can't find any better place, - * wavelan_interrupt is not an option), so you may experience - * delays sometimes. - */ -static void wv_82586_reconfig(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long flags; - - /* Arm the flag, will be cleard in wv_82586_config() */ - lp->reconfig_82586 = 1; - - /* Check if we can do it now ! */ - if((netif_running(dev)) && !(netif_queue_stopped(dev))) { - spin_lock_irqsave(&lp->spinlock, flags); - /* May fail */ - wv_82586_config(dev); - spin_unlock_irqrestore(&lp->spinlock, flags); - } - else { -#ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG - "%s: wv_82586_reconfig(): delayed (state = %lX)\n", - dev->name, dev->state); -#endif - } -} - -/********************* DEBUG & INFO SUBROUTINES *********************/ -/* - * This routine is used in the code to show information for debugging. - * Most of the time, it dumps the contents of hardware structures. - */ - -#ifdef DEBUG_PSA_SHOW -/*------------------------------------------------------------------*/ -/* - * Print the formatted contents of the Parameter Storage Area. - */ -static void wv_psa_show(psa_t * p) -{ - printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); - printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", - p->psa_io_base_addr_1, - p->psa_io_base_addr_2, - p->psa_io_base_addr_3, p->psa_io_base_addr_4); - printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", - p->psa_rem_boot_addr_1, - p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3); - printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); - printk("psa_int_req_no: %d\n", p->psa_int_req_no); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); - printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); - printk(KERN_DEBUG "psa_univ_local_sel: %d, ", - p->psa_univ_local_sel); - printk("psa_comp_number: %d, ", p->psa_comp_number); - printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); - printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", - p->psa_feature_select); - printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); - printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); - printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); - printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], - p->psa_nwid[1]); - printk("psa_nwid_select: %d\n", p->psa_nwid_select); - printk(KERN_DEBUG "psa_encryption_select: %d, ", - p->psa_encryption_select); - printk - ("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_encryption_key[0], p->psa_encryption_key[1], - p->psa_encryption_key[2], p->psa_encryption_key[3], - p->psa_encryption_key[4], p->psa_encryption_key[5], - p->psa_encryption_key[6], p->psa_encryption_key[7]); - printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); - printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", - p->psa_call_code[0]); - printk - ("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - p->psa_call_code[0], p->psa_call_code[1], p->psa_call_code[2], - p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5], - p->psa_call_code[6], p->psa_call_code[7]); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_reserved[]: %02X:%02X\n", - p->psa_reserved[0], - p->psa_reserved[1]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); - printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); - printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); -} /* wv_psa_show */ -#endif /* DEBUG_PSA_SHOW */ - -#ifdef DEBUG_MMC_SHOW -/*------------------------------------------------------------------*/ -/* - * Print the formatted status of the Modem Management Controller. - * This function needs to be completed. - */ -static void wv_mmc_show(struct net_device * dev) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); - mmr_t m; - - /* Basic check */ - if (hasr_read(ioaddr) & HASR_NO_CLK) { - printk(KERN_WARNING - "%s: wv_mmc_show: modem not connected\n", - dev->name); - return; - } - - /* Read the mmc */ - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); - mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m)); - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); - - /* Don't forget to update statistics */ - lp->wstats.discard.nwid += - (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; - - printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n"); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG - "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - m.mmr_unused0[0], m.mmr_unused0[1], m.mmr_unused0[2], - m.mmr_unused0[3], m.mmr_unused0[4], m.mmr_unused0[5], - m.mmr_unused0[6], m.mmr_unused0[7]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n", - m.mmr_des_avail, m.mmr_des_status); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", - m.mmr_unused1[0], - m.mmr_unused1[1], - m.mmr_unused1[2], m.mmr_unused1[3], m.mmr_unused1[4]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", - m.mmr_dce_status, - (m. - mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? - "energy detected," : "", - (m. - mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? - "loop test indicated," : "", - (m. - mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? - "transmitter on," : "", - (m. - mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? - "jabber timer expired," : ""); - printk(KERN_DEBUG "Dsp ID: %02X\n", m.mmr_dsp_id); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", - m.mmr_unused2[0], m.mmr_unused2[1]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", - (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, - (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); - printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", - m.mmr_thr_pre_set & MMR_THR_PRE_SET, - (m. - mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : - "below"); - printk(KERN_DEBUG "signal_lvl: %d [%s], ", - m.mmr_signal_lvl & MMR_SIGNAL_LVL, - (m. - mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : - "no new msg"); - printk("silence_lvl: %d [%s], ", - m.mmr_silence_lvl & MMR_SILENCE_LVL, - (m. - mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : - "no new update"); - printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, - (m. - mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : - "Antenna 0"); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); -#endif /* DEBUG_SHOW_UNUSED */ -} /* wv_mmc_show */ -#endif /* DEBUG_MMC_SHOW */ - -#ifdef DEBUG_I82586_SHOW -/*------------------------------------------------------------------*/ -/* - * Print the last block of the i82586 memory. - */ -static void wv_scb_show(unsigned long ioaddr) -{ - scb_t scb; - - obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, - sizeof(scb)); - - printk(KERN_DEBUG "##### WaveLAN system control block: #####\n"); - - printk(KERN_DEBUG "status: "); - printk("stat 0x%x[%s%s%s%s] ", - (scb. - scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | - SCB_ST_RNR)) >> 12, - (scb. - scb_status & SCB_ST_CX) ? "command completion interrupt," : - "", (scb.scb_status & SCB_ST_FR) ? "frame received," : "", - (scb. - scb_status & SCB_ST_CNA) ? "command unit not active," : "", - (scb. - scb_status & SCB_ST_RNR) ? "receiving unit not ready," : - ""); - printk("cus 0x%x[%s%s%s] ", (scb.scb_status & SCB_ST_CUS) >> 8, - ((scb.scb_status & SCB_ST_CUS) == - SCB_ST_CUS_IDLE) ? "idle" : "", - ((scb.scb_status & SCB_ST_CUS) == - SCB_ST_CUS_SUSP) ? "suspended" : "", - ((scb.scb_status & SCB_ST_CUS) == - SCB_ST_CUS_ACTV) ? "active" : ""); - printk("rus 0x%x[%s%s%s%s]\n", (scb.scb_status & SCB_ST_RUS) >> 4, - ((scb.scb_status & SCB_ST_RUS) == - SCB_ST_RUS_IDLE) ? "idle" : "", - ((scb.scb_status & SCB_ST_RUS) == - SCB_ST_RUS_SUSP) ? "suspended" : "", - ((scb.scb_status & SCB_ST_RUS) == - SCB_ST_RUS_NRES) ? "no resources" : "", - ((scb.scb_status & SCB_ST_RUS) == - SCB_ST_RUS_RDY) ? "ready" : ""); - - printk(KERN_DEBUG "command: "); - printk("ack 0x%x[%s%s%s%s] ", - (scb. - scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR | - SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12, - (scb. - scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "", - (scb. - scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "", - (scb. - scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "", - (scb. - scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : ""); - printk("cuc 0x%x[%s%s%s%s%s] ", - (scb.scb_command & SCB_CMD_CUC) >> 8, - ((scb.scb_command & SCB_CMD_CUC) == - SCB_CMD_CUC_NOP) ? "nop" : "", - ((scb.scb_command & SCB_CMD_CUC) == - SCB_CMD_CUC_GO) ? "start cbl_offset" : "", - ((scb.scb_command & SCB_CMD_CUC) == - SCB_CMD_CUC_RES) ? "resume execution" : "", - ((scb.scb_command & SCB_CMD_CUC) == - SCB_CMD_CUC_SUS) ? "suspend execution" : "", - ((scb.scb_command & SCB_CMD_CUC) == - SCB_CMD_CUC_ABT) ? "abort execution" : ""); - printk("ruc 0x%x[%s%s%s%s%s]\n", - (scb.scb_command & SCB_CMD_RUC) >> 4, - ((scb.scb_command & SCB_CMD_RUC) == - SCB_CMD_RUC_NOP) ? "nop" : "", - ((scb.scb_command & SCB_CMD_RUC) == - SCB_CMD_RUC_GO) ? "start rfa_offset" : "", - ((scb.scb_command & SCB_CMD_RUC) == - SCB_CMD_RUC_RES) ? "resume reception" : "", - ((scb.scb_command & SCB_CMD_RUC) == - SCB_CMD_RUC_SUS) ? "suspend reception" : "", - ((scb.scb_command & SCB_CMD_RUC) == - SCB_CMD_RUC_ABT) ? "abort reception" : ""); - - printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset); - printk("rfa_offset 0x%x\n", scb.scb_rfa_offset); - - printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs); - printk("alnerrs %d ", scb.scb_alnerrs); - printk("rscerrs %d ", scb.scb_rscerrs); - printk("ovrnerrs %d\n", scb.scb_ovrnerrs); -} - -/*------------------------------------------------------------------*/ -/* - * Print the formatted status of the i82586's receive unit. - */ -static void wv_ru_show(struct net_device * dev) -{ - printk(KERN_DEBUG - "##### WaveLAN i82586 receiver unit status: #####\n"); - printk(KERN_DEBUG "ru:"); - /* - * Not implemented yet - */ - printk("\n"); -} /* wv_ru_show */ - -/*------------------------------------------------------------------*/ -/* - * Display info about one control block of the i82586 memory. - */ -static void wv_cu_show_one(struct net_device * dev, net_local * lp, int i, u16 p) -{ - unsigned long ioaddr; - ac_tx_t actx; - - ioaddr = dev->base_addr; - - printk("%d: 0x%x:", i, p); - - obram_read(ioaddr, p, (unsigned char *) &actx, sizeof(actx)); - printk(" status=0x%x,", actx.tx_h.ac_status); - printk(" command=0x%x,", actx.tx_h.ac_command); - - /* - { - tbd_t tbd; - - obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd)); - printk(" tbd_status=0x%x,", tbd.tbd_status); - } - */ - - printk("|"); -} - -/*------------------------------------------------------------------*/ -/* - * Print status of the command unit of the i82586. - */ -static void wv_cu_show(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned int i; - u16 p; - - printk(KERN_DEBUG - "##### WaveLAN i82586 command unit status: #####\n"); - - printk(KERN_DEBUG); - for (i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) { - wv_cu_show_one(dev, lp, i, p); - - p += TXBLOCKZ; - if (p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) - p -= NTXBLOCKS * TXBLOCKZ; - } - printk("\n"); -} -#endif /* DEBUG_I82586_SHOW */ - -#ifdef DEBUG_DEVICE_SHOW -/*------------------------------------------------------------------*/ -/* - * Print the formatted status of the WaveLAN PCMCIA device driver. - */ -static void wv_dev_show(struct net_device * dev) -{ - printk(KERN_DEBUG "dev:"); - printk(" state=%lX,", dev->state); - printk(" trans_start=%ld,", dev->trans_start); - printk(" flags=0x%x,", dev->flags); - printk("\n"); -} /* wv_dev_show */ - -/*------------------------------------------------------------------*/ -/* - * Print the formatted status of the WaveLAN PCMCIA device driver's - * private information. - */ -static void wv_local_show(struct net_device * dev) -{ - net_local *lp; - - lp = netdev_priv(dev); - - printk(KERN_DEBUG "local:"); - printk(" tx_n_in_use=%d,", lp->tx_n_in_use); - printk(" hacr=0x%x,", lp->hacr); - printk(" rx_head=0x%x,", lp->rx_head); - printk(" rx_last=0x%x,", lp->rx_last); - printk(" tx_first_free=0x%x,", lp->tx_first_free); - printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use); - printk("\n"); -} /* wv_local_show */ -#endif /* DEBUG_DEVICE_SHOW */ - -#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) -/*------------------------------------------------------------------*/ -/* - * Dump packet header (and content if necessary) on the screen - */ -static inline void wv_packet_info(u8 * p, /* Packet to dump */ - int length, /* Length of the packet */ - char *msg1, /* Name of the device */ - char *msg2) -{ /* Name of the function */ - int i; - int maxi; - - printk(KERN_DEBUG - "%s: %s(): dest %pM, length %d\n", - msg1, msg2, p, length); - printk(KERN_DEBUG - "%s: %s(): src %pM, type 0x%02X%02X\n", - msg1, msg2, &p[6], p[12], p[13]); - -#ifdef DEBUG_PACKET_DUMP - - printk(KERN_DEBUG "data=\""); - - if ((maxi = length) > DEBUG_PACKET_DUMP) - maxi = DEBUG_PACKET_DUMP; - for (i = 14; i < maxi; i++) - if (p[i] >= ' ' && p[i] <= '~') - printk(" %c", p[i]); - else - printk("%02X", p[i]); - if (maxi < length) - printk(".."); - printk("\"\n"); - printk(KERN_DEBUG "\n"); -#endif /* DEBUG_PACKET_DUMP */ -} -#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ - -/*------------------------------------------------------------------*/ -/* - * This is the information which is displayed by the driver at startup. - * There are lots of flags for configuring it to your liking. - */ -static void wv_init_info(struct net_device * dev) -{ - short ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); - psa_t psa; - - /* Read the parameter storage area */ - psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); - -#ifdef DEBUG_PSA_SHOW - wv_psa_show(&psa); -#endif -#ifdef DEBUG_MMC_SHOW - wv_mmc_show(dev); -#endif -#ifdef DEBUG_I82586_SHOW - wv_cu_show(dev); -#endif - -#ifdef DEBUG_BASIC_SHOW - /* Now, let's go for the basic stuff. */ - printk(KERN_NOTICE "%s: WaveLAN at %#x, %pM, IRQ %d", - dev->name, ioaddr, dev->dev_addr, dev->irq); - - /* Print current network ID. */ - if (psa.psa_nwid_select) - printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], - psa.psa_nwid[1]); - else - printk(", nwid off"); - - /* If 2.00 card */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - unsigned short freq; - - /* Ask the EEPROM to read the frequency from the first area. */ - fee_read(ioaddr, 0x00, &freq, 1); - - /* Print frequency */ - printk(", 2.00, %ld", (freq >> 6) + 2400L); - - /* Hack! */ - if (freq & 0x20) - printk(".5"); - } else { - printk(", PC"); - switch (psa.psa_comp_number) { - case PSA_COMP_PC_AT_915: - case PSA_COMP_PC_AT_2400: - printk("-AT"); - break; - case PSA_COMP_PC_MC_915: - case PSA_COMP_PC_MC_2400: - printk("-MC"); - break; - case PSA_COMP_PCMCIA_915: - printk("MCIA"); - break; - default: - printk("?"); - } - printk(", "); - switch (psa.psa_subband) { - case PSA_SUBBAND_915: - printk("915"); - break; - case PSA_SUBBAND_2425: - printk("2425"); - break; - case PSA_SUBBAND_2460: - printk("2460"); - break; - case PSA_SUBBAND_2484: - printk("2484"); - break; - case PSA_SUBBAND_2430_5: - printk("2430.5"); - break; - default: - printk("?"); - } - } - - printk(" MHz\n"); -#endif /* DEBUG_BASIC_SHOW */ - -#ifdef DEBUG_VERSION_SHOW - /* Print version information */ - printk(KERN_NOTICE "%s", version); -#endif -} /* wv_init_info */ - -/********************* IOCTL, STATS & RECONFIG *********************/ -/* - * We found here routines that are called by Linux on different - * occasions after the configuration and not for transmitting data - * These may be called when the user use ifconfig, /proc/net/dev - * or wireless extensions - */ - - -/*------------------------------------------------------------------*/ -/* - * Set or clear the multicast filter for this adaptor. - * num_addrs == -1 Promiscuous mode, receive all packets - * num_addrs == 0 Normal mode, clear multicast list - * num_addrs > 0 Multicast mode, receive normal and MC packets, - * and do best-effort filtering. - */ -static void wavelan_set_multicast_list(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", - dev->name); -#endif - -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG - "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", - dev->name, dev->flags, dev->mc_count); -#endif - - /* Are we asking for promiscuous mode, - * or all multicast addresses (we don't have that!) - * or too many multicast addresses for the hardware filter? */ - if ((dev->flags & IFF_PROMISC) || - (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) { - /* - * Enable promiscuous mode: receive all packets. - */ - if (!lp->promiscuous) { - lp->promiscuous = 1; - lp->mc_count = 0; - - wv_82586_reconfig(dev); - } - } else - /* Are there multicast addresses to send? */ - if (dev->mc_list != (struct dev_mc_list *) NULL) { - /* - * Disable promiscuous mode, but receive all packets - * in multicast list - */ -#ifdef MULTICAST_AVOID - if (lp->promiscuous || (dev->mc_count != lp->mc_count)) -#endif - { - lp->promiscuous = 0; - lp->mc_count = dev->mc_count; - - wv_82586_reconfig(dev); - } - } else { - /* - * Switch to normal mode: disable promiscuous mode and - * clear the multicast list. - */ - if (lp->promiscuous || lp->mc_count == 0) { - lp->promiscuous = 0; - lp->mc_count = 0; - - wv_82586_reconfig(dev); - } - } -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", - dev->name); -#endif -} - -/*------------------------------------------------------------------*/ -/* - * This function doesn't exist. - * (Note : it was a nice way to test the reconfigure stuff...) - */ -#ifdef SET_MAC_ADDRESS -static int wavelan_set_mac_address(struct net_device * dev, void *addr) -{ - struct sockaddr *mac = addr; - - /* Copy the address. */ - memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); - - /* Reconfigure the beast. */ - wv_82586_reconfig(dev); - - return 0; -} -#endif /* SET_MAC_ADDRESS */ - - -/*------------------------------------------------------------------*/ -/* - * Frequency setting (for hardware capable of it) - * It's a bit complicated and you don't really want to look into it. - * (called in wavelan_ioctl) - */ -static int wv_set_frequency(unsigned long ioaddr, /* I/O port of the card */ - iw_freq * frequency) -{ - const int BAND_NUM = 10; /* Number of bands */ - long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ -#ifdef DEBUG_IOCTL_INFO - int i; -#endif - - /* Setting by frequency */ - /* Theoretically, you may set any frequency between - * the two limits with a 0.5 MHz precision. In practice, - * I don't want you to have trouble with local regulations. - */ - if ((frequency->e == 1) && - (frequency->m >= (int) 2.412e8) - && (frequency->m <= (int) 2.487e8)) { - freq = ((frequency->m / 10000) - 24000L) / 5; - } - - /* Setting by channel (same as wfreqsel) */ - /* Warning: each channel is 22 MHz wide, so some of the channels - * will interfere. */ - if ((frequency->e == 0) && (frequency->m < BAND_NUM)) { - /* Get frequency offset. */ - freq = channel_bands[frequency->m] >> 1; - } - - /* Verify that the frequency is allowed. */ - if (freq != 0L) { - u16 table[10]; /* Authorized frequency table */ - - /* Read the frequency table. */ - fee_read(ioaddr, 0x71, table, 10); - -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "Frequency table: "); - for (i = 0; i < 10; i++) { - printk(" %04X", table[i]); - } - printk("\n"); -#endif - - /* Look in the table to see whether the frequency is allowed. */ - if (!(table[9 - ((freq - 24) / 16)] & - (1 << ((freq - 24) % 16)))) return -EINVAL; /* not allowed */ - } else - return -EINVAL; - - /* if we get a usable frequency */ - if (freq != 0L) { - unsigned short area[16]; - unsigned short dac[2]; - unsigned short area_verify[16]; - unsigned short dac_verify[2]; - /* Corresponding gain (in the power adjust value table) - * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8 - * and WCIN062D.DOC, page 6.2.9. */ - unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; - int power_band = 0; /* Selected band */ - unsigned short power_adjust; /* Correct value */ - - /* Search for the gain. */ - power_band = 0; - while ((freq > power_limit[power_band]) && - (power_limit[++power_band] != 0)); - - /* Read the first area. */ - fee_read(ioaddr, 0x00, area, 16); - - /* Read the DAC. */ - fee_read(ioaddr, 0x60, dac, 2); - - /* Read the new power adjust value. */ - fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, - 1); - if (power_band & 0x1) - power_adjust >>= 8; - else - power_adjust &= 0xFF; - -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); - for (i = 0; i < 16; i++) { - printk(" %04X", area[i]); - } - printk("\n"); - - printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", - dac[0], dac[1]); -#endif - - /* Frequency offset (for info only) */ - area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); - - /* Receiver Principle main divider coefficient */ - area[3] = (freq >> 1) + 2400L - 352L; - area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); - - /* Transmitter Main divider coefficient */ - area[13] = (freq >> 1) + 2400L; - area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); - - /* Other parts of the area are flags, bit streams or unused. */ - - /* Set the value in the DAC. */ - dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); - dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); - - /* Write the first area. */ - fee_write(ioaddr, 0x00, area, 16); - - /* Write the DAC. */ - fee_write(ioaddr, 0x60, dac, 2); - - /* We now should verify here that the writing of the EEPROM went OK. */ - - /* Reread the first area. */ - fee_read(ioaddr, 0x00, area_verify, 16); - - /* Reread the DAC. */ - fee_read(ioaddr, 0x60, dac_verify, 2); - - /* Compare. */ - if (memcmp(area, area_verify, 16 * 2) || - memcmp(dac, dac_verify, 2 * 2)) { -#ifdef DEBUG_IOCTL_ERROR - printk(KERN_INFO - "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n"); -#endif - return -EOPNOTSUPP; - } - - /* We must download the frequency parameters to the - * synthesizers (from the EEPROM - area 1) - * Note: as the EEPROM is automatically decremented, we set the end - * if the area... */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), - MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); - - /* Wait until the download is finished. */ - fee_wait(ioaddr, 100, 100); - - /* We must now download the power adjust value (gain) to - * the synthesizers (from the EEPROM - area 7 - DAC). */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), - MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); - - /* Wait for the download to finish. */ - fee_wait(ioaddr, 100, 100); - -#ifdef DEBUG_IOCTL_INFO - /* Verification of what we have done */ - - printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); - for (i = 0; i < 16; i++) { - printk(" %04X", area_verify[i]); - } - printk("\n"); - - printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", - dac_verify[0], dac_verify[1]); -#endif - - return 0; - } else - return -EINVAL; /* Bah, never get there... */ -} - -/*------------------------------------------------------------------*/ -/* - * Give the list of available frequencies. - */ -static int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */ - iw_freq * list, /* List of frequencies to fill */ - int max) -{ /* Maximum number of frequencies */ - u16 table[10]; /* Authorized frequency table */ - long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ - int i; /* index in the table */ - int c = 0; /* Channel number */ - - /* Read the frequency table. */ - fee_read(ioaddr, 0x71 /* frequency table */ , table, 10); - - /* Check all frequencies. */ - i = 0; - for (freq = 0; freq < 150; freq++) - /* Look in the table if the frequency is allowed */ - if (table[9 - (freq / 16)] & (1 << (freq % 16))) { - /* Compute approximate channel number */ - while ((c < ARRAY_SIZE(channel_bands)) && - (((channel_bands[c] >> 1) - 24) < freq)) - c++; - list[i].i = c; /* Set the list index */ - - /* put in the list */ - list[i].m = (((freq + 24) * 5) + 24000L) * 10000; - list[i++].e = 1; - - /* Check number. */ - if (i >= max) - return (i); - } - - return (i); -} - -#ifdef IW_WIRELESS_SPY -/*------------------------------------------------------------------*/ -/* - * Gather wireless spy statistics: for each packet, compare the source - * address with our list, and if they match, get the statistics. - * Sorry, but this function really needs the wireless extensions. - */ -static inline void wl_spy_gather(struct net_device * dev, - u8 * mac, /* MAC address */ - u8 * stats) /* Statistics to gather */ -{ - struct iw_quality wstats; - - wstats.qual = stats[2] & MMR_SGNL_QUAL; - wstats.level = stats[0] & MMR_SIGNAL_LVL; - wstats.noise = stats[1] & MMR_SILENCE_LVL; - wstats.updated = 0x7; - - /* Update spy records */ - wireless_spy_update(dev, mac, &wstats); -} -#endif /* IW_WIRELESS_SPY */ - -#ifdef HISTOGRAM -/*------------------------------------------------------------------*/ -/* - * This function calculates a histogram of the signal level. - * As the noise is quite constant, it's like doing it on the SNR. - * We have defined a set of interval (lp->his_range), and each time - * the level goes in that interval, we increment the count (lp->his_sum). - * With this histogram you may detect if one WaveLAN is really weak, - * or you may also calculate the mean and standard deviation of the level. - */ -static inline void wl_his_gather(struct net_device * dev, u8 * stats) -{ /* Statistics to gather */ - net_local *lp = netdev_priv(dev); - u8 level = stats[0] & MMR_SIGNAL_LVL; - int i; - - /* Find the correct interval. */ - i = 0; - while ((i < (lp->his_number - 1)) - && (level >= lp->his_range[i++])); - - /* Increment interval counter. */ - (lp->his_sum[i])++; -} -#endif /* HISTOGRAM */ - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get protocol name - */ -static int wavelan_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - strcpy(wrqu->name, "WaveLAN"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set NWID - */ -static int wavelan_set_nwid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); /* lp is not unused */ - psa_t psa; - mm_t m; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Set NWID in WaveLAN. */ - if (!wrqu->nwid.disabled) { - /* Set NWID in psa */ - psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; - psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; - psa.psa_nwid_select = 0x01; - psa_write(ioaddr, lp->hacr, - (char *) psa.psa_nwid - (char *) &psa, - (unsigned char *) psa.psa_nwid, 3); - - /* Set NWID in mmc. */ - m.w.mmw_netw_id_l = psa.psa_nwid[1]; - m.w.mmw_netw_id_h = psa.psa_nwid[0]; - mmc_write(ioaddr, - (char *) &m.w.mmw_netw_id_l - - (char *) &m, - (unsigned char *) &m.w.mmw_netw_id_l, 2); - mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); - } else { - /* Disable NWID in the psa. */ - psa.psa_nwid_select = 0x00; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_nwid_select - - (char *) &psa, - (unsigned char *) &psa.psa_nwid_select, - 1); - - /* Disable NWID in the mmc (no filtering). */ - mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), - MMW_LOOPT_SEL_DIS_NWID); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get NWID - */ -static int wavelan_get_nwid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); /* lp is not unused */ - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Read the NWID. */ - psa_read(ioaddr, lp->hacr, - (char *) psa.psa_nwid - (char *) &psa, - (unsigned char *) psa.psa_nwid, 3); - wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrqu->nwid.disabled = !(psa.psa_nwid_select); - wrqu->nwid.fixed = 1; /* Superfluous */ - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set frequency - */ -static int wavelan_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); /* lp is not unused */ - unsigned long flags; - int ret; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - ret = wv_set_frequency(ioaddr, &(wrqu->freq)); - else - ret = -EOPNOTSUPP; - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get frequency - */ -static int wavelan_get_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); /* lp is not unused */ - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). - * Does it work for everybody, especially old cards? */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - unsigned short freq; - - /* Ask the EEPROM to read the frequency from the first area. */ - fee_read(ioaddr, 0x00, &freq, 1); - wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; - wrqu->freq.e = 1; - } else { - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_subband - (char *) &psa, - (unsigned char *) &psa.psa_subband, 1); - - if (psa.psa_subband <= 4) { - wrqu->freq.m = fixed_bands[psa.psa_subband]; - wrqu->freq.e = (psa.psa_subband != 0); - } else - ret = -EOPNOTSUPP; - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set level threshold - */ -static int wavelan_set_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); /* lp is not unused */ - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Set the level threshold. */ - /* We should complain loudly if wrqu->sens.fixed = 0, because we - * can't set auto mode... */ - psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_thr_pre_set - (char *) &psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), - psa.psa_thr_pre_set); - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get level threshold - */ -static int wavelan_get_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); /* lp is not unused */ - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Read the level threshold. */ - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_thr_pre_set - (char *) &psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; - wrqu->sens.fixed = 1; - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set encryption key - */ -static int wavelan_set_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); /* lp is not unused */ - unsigned long flags; - psa_t psa; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Check if capable of encryption */ - if (!mmc_encr(ioaddr)) { - ret = -EOPNOTSUPP; - } - - /* Check the size of the key */ - if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { - ret = -EINVAL; - } - - if(!ret) { - /* Basic checking... */ - if (wrqu->encoding.length == 8) { - /* Copy the key in the driver */ - memcpy(psa.psa_encryption_key, extra, - wrqu->encoding.length); - psa.psa_encryption_select = 1; - - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_encryption_select - - (char *) &psa, - (unsigned char *) &psa. - psa_encryption_select, 8 + 1); - - mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), - MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); - mmc_write(ioaddr, mmwoff(0, mmw_encr_key), - (unsigned char *) &psa. - psa_encryption_key, 8); - } - - /* disable encryption */ - if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { - psa.psa_encryption_select = 0; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_encryption_select - - (char *) &psa, - (unsigned char *) &psa. - psa_encryption_select, 1); - - mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get encryption key - */ -static int wavelan_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); /* lp is not unused */ - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Check if encryption is available */ - if (!mmc_encr(ioaddr)) { - ret = -EOPNOTSUPP; - } else { - /* Read the encryption key */ - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_encryption_select - - (char *) &psa, - (unsigned char *) &psa. - psa_encryption_select, 1 + 8); - - /* encryption is enabled ? */ - if (psa.psa_encryption_select) - wrqu->encoding.flags = IW_ENCODE_ENABLED; - else - wrqu->encoding.flags = IW_ENCODE_DISABLED; - wrqu->encoding.flags |= mmc_encr(ioaddr); - - /* Copy the key to the user buffer */ - wrqu->encoding.length = 8; - memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get range info - */ -static int wavelan_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); /* lp is not unused */ - struct iw_range *range = (struct iw_range *) extra; - unsigned long flags; - int ret = 0; - - /* Set the length (very important for backward compatibility) */ - wrqu->data.length = sizeof(struct iw_range); - - /* Set all the info we don't care or don't know about to zero */ - memset(range, 0, sizeof(struct iw_range)); - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 9; - - /* Set information in the range struct. */ - range->throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ - range->min_nwid = 0x0000; - range->max_nwid = 0xFFFF; - - range->sensitivity = 0x3F; - range->max_qual.qual = MMR_SGNL_QUAL; - range->max_qual.level = MMR_SIGNAL_LVL; - range->max_qual.noise = MMR_SILENCE_LVL; - range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ - /* Need to get better values for those two */ - range->avg_qual.level = 30; - range->avg_qual.noise = 8; - - range->num_bitrates = 1; - range->bitrate[0] = 2000000; /* 2 Mb/s */ - - /* Event capability (kernel + driver) */ - range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) | - IW_EVENT_CAPA_MASK(0x8B04)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - range->num_channels = 10; - range->num_frequency = wv_frequency_list(ioaddr, range->freq, - IW_MAX_FREQUENCIES); - } else - range->num_channels = range->num_frequency = 0; - - /* Encryption supported ? */ - if (mmc_encr(ioaddr)) { - range->encoding_size[0] = 8; /* DES = 64 bits key */ - range->num_encoding_sizes = 1; - range->max_encoding_tokens = 1; /* Only one key possible */ - } else { - range->num_encoding_sizes = 0; - range->max_encoding_tokens = 0; - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : set quality threshold - */ -static int wavelan_set_qthr(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); /* lp is not unused */ - psa_t psa; - unsigned long flags; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - psa.psa_quality_thr = *(extra) & 0x0F; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_quality_thr - (char *) &psa, - (unsigned char *) &psa.psa_quality_thr, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), - psa.psa_quality_thr); - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get quality threshold - */ -static int wavelan_get_qthr(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); /* lp is not unused */ - psa_t psa; - unsigned long flags; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_quality_thr - (char *) &psa, - (unsigned char *) &psa.psa_quality_thr, 1); - *(extra) = psa.psa_quality_thr & 0x0F; - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return 0; -} - -#ifdef HISTOGRAM -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : set histogram - */ -static int wavelan_set_histo(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = netdev_priv(dev); /* lp is not unused */ - - /* Check the number of intervals. */ - if (wrqu->data.length > 16) { - return(-E2BIG); - } - - /* Disable histo while we copy the addresses. - * As we don't disable interrupts, we need to do this */ - lp->his_number = 0; - - /* Are there ranges to copy? */ - if (wrqu->data.length > 0) { - /* Copy interval ranges to the driver */ - memcpy(lp->his_range, extra, wrqu->data.length); - - { - int i; - printk(KERN_DEBUG "Histo :"); - for(i = 0; i < wrqu->data.length; i++) - printk(" %d", lp->his_range[i]); - printk("\n"); - } - - /* Reset result structure. */ - memset(lp->his_sum, 0x00, sizeof(long) * 16); - } - - /* Now we can set the number of ranges */ - lp->his_number = wrqu->data.length; - - return(0); -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get histogram - */ -static int wavelan_get_histo(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = netdev_priv(dev); /* lp is not unused */ - - /* Set the number of intervals. */ - wrqu->data.length = lp->his_number; - - /* Give back the distribution statistics */ - if(lp->his_number > 0) - memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); - - return(0); -} -#endif /* HISTOGRAM */ - -/*------------------------------------------------------------------*/ -/* - * Structures to export the Wireless Handlers - */ - -static const iw_handler wavelan_handler[] = -{ - NULL, /* SIOCSIWNAME */ - wavelan_get_name, /* SIOCGIWNAME */ - wavelan_set_nwid, /* SIOCSIWNWID */ - wavelan_get_nwid, /* SIOCGIWNWID */ - wavelan_set_freq, /* SIOCSIWFREQ */ - wavelan_get_freq, /* SIOCGIWFREQ */ - NULL, /* SIOCSIWMODE */ - NULL, /* SIOCGIWMODE */ - wavelan_set_sens, /* SIOCSIWSENS */ - wavelan_get_sens, /* SIOCGIWSENS */ - NULL, /* SIOCSIWRANGE */ - wavelan_get_range, /* SIOCGIWRANGE */ - NULL, /* SIOCSIWPRIV */ - NULL, /* SIOCGIWPRIV */ - NULL, /* SIOCSIWSTATS */ - NULL, /* SIOCGIWSTATS */ - iw_handler_set_spy, /* SIOCSIWSPY */ - iw_handler_get_spy, /* SIOCGIWSPY */ - iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ - iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ - NULL, /* SIOCSIWAP */ - NULL, /* SIOCGIWAP */ - NULL, /* -- hole -- */ - NULL, /* SIOCGIWAPLIST */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - NULL, /* SIOCSIWESSID */ - NULL, /* SIOCGIWESSID */ - NULL, /* SIOCSIWNICKN */ - NULL, /* SIOCGIWNICKN */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - NULL, /* SIOCSIWRATE */ - NULL, /* SIOCGIWRATE */ - NULL, /* SIOCSIWRTS */ - NULL, /* SIOCGIWRTS */ - NULL, /* SIOCSIWFRAG */ - NULL, /* SIOCGIWFRAG */ - NULL, /* SIOCSIWTXPOW */ - NULL, /* SIOCGIWTXPOW */ - NULL, /* SIOCSIWRETRY */ - NULL, /* SIOCGIWRETRY */ - /* Bummer ! Why those are only at the end ??? */ - wavelan_set_encode, /* SIOCSIWENCODE */ - wavelan_get_encode, /* SIOCGIWENCODE */ -}; - -static const iw_handler wavelan_private_handler[] = -{ - wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ - wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ -#ifdef HISTOGRAM - wavelan_set_histo, /* SIOCIWFIRSTPRIV + 2 */ - wavelan_get_histo, /* SIOCIWFIRSTPRIV + 3 */ -#endif /* HISTOGRAM */ -}; - -static const struct iw_priv_args wavelan_private_args[] = { -/*{ cmd, set_args, get_args, name } */ - { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, - { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, - { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, - { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, -}; - -static const struct iw_handler_def wavelan_handler_def = -{ - .num_standard = ARRAY_SIZE(wavelan_handler), - .num_private = ARRAY_SIZE(wavelan_private_handler), - .num_private_args = ARRAY_SIZE(wavelan_private_args), - .standard = wavelan_handler, - .private = wavelan_private_handler, - .private_args = wavelan_private_args, - .get_wireless_stats = wavelan_get_wireless_stats, -}; - -/*------------------------------------------------------------------*/ -/* - * Get wireless statistics. - * Called by /proc/net/wireless - */ -static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); - mmr_t m; - iw_stats *wstats; - unsigned long flags; - -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", - dev->name); -#endif - - /* Check */ - if (lp == (net_local *) NULL) - return (iw_stats *) NULL; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - wstats = &lp->wstats; - - /* Get data from the mmc. */ - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); - - mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); - mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, - 2); - mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, - 4); - - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); - - /* Copy data to wireless stuff. */ - wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; - wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; - wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; - wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; - wstats->qual.updated = (((m. mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) - | ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) - | ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); - wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; - wstats->discard.code = 0L; - wstats->discard.misc = 0L; - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", - dev->name); -#endif - return &lp->wstats; -} - -/************************* PACKET RECEPTION *************************/ -/* - * This part deals with receiving the packets. - * The interrupt handler gets an interrupt when a packet has been - * successfully received and calls this part. - */ - -/*------------------------------------------------------------------*/ -/* - * This routine does the actual copying of data (including the Ethernet - * header structure) from the WaveLAN card to an sk_buff chain that - * will be passed up to the network interface layer. NOTE: we - * currently don't handle trailer protocols (neither does the rest of - * the network interface), so if that is needed, it will (at least in - * part) be added here. The contents of the receive ring buffer are - * copied to a message chain that is then passed to the kernel. - * - * Note: if any errors occur, the packet is "dropped on the floor". - * (called by wv_packet_rcv()) - */ -static void -wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - struct sk_buff *skb; - -#ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", - dev->name, buf_off, sksize); -#endif - - /* Allocate buffer for the data */ - if ((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) { -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO - "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n", - dev->name, sksize); -#endif - dev->stats.rx_dropped++; - return; - } - - /* Copy the packet to the buffer. */ - obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize); - skb->protocol = eth_type_trans(skb, dev); - -#ifdef DEBUG_RX_INFO - wv_packet_info(skb_mac_header(skb), sksize, dev->name, - "wv_packet_read"); -#endif /* DEBUG_RX_INFO */ - - /* Statistics-gathering and associated stuff. - * It seem a bit messy with all the define, but it's really - * simple... */ - if ( -#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ - (lp->spy_data.spy_number > 0) || -#endif /* IW_WIRELESS_SPY */ -#ifdef HISTOGRAM - (lp->his_number > 0) || -#endif /* HISTOGRAM */ - 0) { - u8 stats[3]; /* signal level, noise level, signal quality */ - - /* Read signal level, silence level and signal quality bytes */ - /* Note: in the PCMCIA hardware, these are part of the frame. - * It seems that for the ISA hardware, it's nowhere to be - * found in the frame, so I'm obliged to do this (it has a - * side effect on /proc/net/wireless). - * Any ideas? - */ - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); - mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3); - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); - -#ifdef DEBUG_RX_INFO - printk(KERN_DEBUG - "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", - dev->name, stats[0] & 0x3F, stats[1] & 0x3F, - stats[2] & 0x0F); -#endif - - /* Spying stuff */ -#ifdef IW_WIRELESS_SPY - wl_spy_gather(dev, skb_mac_header(skb) + WAVELAN_ADDR_SIZE, - stats); -#endif /* IW_WIRELESS_SPY */ -#ifdef HISTOGRAM - wl_his_gather(dev, stats); -#endif /* HISTOGRAM */ - } - - /* - * Hand the packet to the network module. - */ - netif_rx(skb); - - /* Keep statistics up to date */ - dev->stats.rx_packets++; - dev->stats.rx_bytes += sksize; - -#ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); -#endif -} - -/*------------------------------------------------------------------*/ -/* - * Transfer as many packets as we can - * from the device RAM. - * (called in wavelan_interrupt()). - * Note : the spinlock is already grabbed for us. - */ -static void wv_receive(struct net_device * dev) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); - fd_t fd; - rbd_t rbd; - int nreaped = 0; - -#ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name); -#endif - - /* Loop on each received packet. */ - for (;;) { - obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, - sizeof(fd)); - - /* Note about the status : - * It start up to be 0 (the value we set). Then, when the RU - * grab the buffer to prepare for reception, it sets the - * FD_STATUS_B flag. When the RU has finished receiving the - * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate - * completion and set the other flags to indicate the eventual - * errors. FD_STATUS_OK indicates that the reception was OK. - */ - - /* If the current frame is not complete, we have reached the end. */ - if ((fd.fd_status & FD_STATUS_C) != FD_STATUS_C) - break; /* This is how we exit the loop. */ - - nreaped++; - - /* Check whether frame was correctly received. */ - if ((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) { - /* Does the frame contain a pointer to the data? Let's check. */ - if (fd.fd_rbd_offset != I82586NULL) { - /* Read the receive buffer descriptor */ - obram_read(ioaddr, fd.fd_rbd_offset, - (unsigned char *) &rbd, - sizeof(rbd)); - -#ifdef DEBUG_RX_ERROR - if ((rbd.rbd_status & RBD_STATUS_EOF) != - RBD_STATUS_EOF) printk(KERN_INFO - "%s: wv_receive(): missing EOF flag.\n", - dev->name); - - if ((rbd.rbd_status & RBD_STATUS_F) != - RBD_STATUS_F) printk(KERN_INFO - "%s: wv_receive(): missing F flag.\n", - dev->name); -#endif /* DEBUG_RX_ERROR */ - - /* Read the packet and transmit to Linux */ - wv_packet_read(dev, rbd.rbd_bufl, - rbd. - rbd_status & - RBD_STATUS_ACNT); - } -#ifdef DEBUG_RX_ERROR - else /* if frame has no data */ - printk(KERN_INFO - "%s: wv_receive(): frame has no data.\n", - dev->name); -#endif - } else { /* If reception was no successful */ - - dev->stats.rx_errors++; - -#ifdef DEBUG_RX_INFO - printk(KERN_DEBUG - "%s: wv_receive(): frame not received successfully (%X).\n", - dev->name, fd.fd_status); -#endif - -#ifdef DEBUG_RX_ERROR - if ((fd.fd_status & FD_STATUS_S6) != 0) - printk(KERN_INFO - "%s: wv_receive(): no EOF flag.\n", - dev->name); -#endif - - if ((fd.fd_status & FD_STATUS_S7) != 0) { - dev->stats.rx_length_errors++; -#ifdef DEBUG_RX_FAIL - printk(KERN_DEBUG - "%s: wv_receive(): frame too short.\n", - dev->name); -#endif - } - - if ((fd.fd_status & FD_STATUS_S8) != 0) { - dev->stats.rx_over_errors++; -#ifdef DEBUG_RX_FAIL - printk(KERN_DEBUG - "%s: wv_receive(): rx DMA overrun.\n", - dev->name); -#endif - } - - if ((fd.fd_status & FD_STATUS_S9) != 0) { - dev->stats.rx_fifo_errors++; -#ifdef DEBUG_RX_FAIL - printk(KERN_DEBUG - "%s: wv_receive(): ran out of resources.\n", - dev->name); -#endif - } - - if ((fd.fd_status & FD_STATUS_S10) != 0) { - dev->stats.rx_frame_errors++; -#ifdef DEBUG_RX_FAIL - printk(KERN_DEBUG - "%s: wv_receive(): alignment error.\n", - dev->name); -#endif - } - - if ((fd.fd_status & FD_STATUS_S11) != 0) { - dev->stats.rx_crc_errors++; -#ifdef DEBUG_RX_FAIL - printk(KERN_DEBUG - "%s: wv_receive(): CRC error.\n", - dev->name); -#endif - } - } - - fd.fd_status = 0; - obram_write(ioaddr, fdoff(lp->rx_head, fd_status), - (unsigned char *) &fd.fd_status, - sizeof(fd.fd_status)); - - fd.fd_command = FD_COMMAND_EL; - obram_write(ioaddr, fdoff(lp->rx_head, fd_command), - (unsigned char *) &fd.fd_command, - sizeof(fd.fd_command)); - - fd.fd_command = 0; - obram_write(ioaddr, fdoff(lp->rx_last, fd_command), - (unsigned char *) &fd.fd_command, - sizeof(fd.fd_command)); - - lp->rx_last = lp->rx_head; - lp->rx_head = fd.fd_link_offset; - } /* for(;;) -> loop on all frames */ - -#ifdef DEBUG_RX_INFO - if (nreaped > 1) - printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n", - dev->name, nreaped); -#endif -#ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name); -#endif -} - -/*********************** PACKET TRANSMISSION ***********************/ -/* - * This part deals with sending packets through the WaveLAN. - * - */ - -/*------------------------------------------------------------------*/ -/* - * This routine fills in the appropriate registers and memory - * locations on the WaveLAN card and starts the card off on - * the transmit. - * - * The principle: - * Each block contains a transmit command, a NOP command, - * a transmit block descriptor and a buffer. - * The CU read the transmit block which point to the tbd, - * read the tbd and the content of the buffer. - * When it has finish with it, it goes to the next command - * which in our case is the NOP. The NOP points on itself, - * so the CU stop here. - * When we add the next block, we modify the previous nop - * to make it point on the new tx command. - * Simple, isn't it ? - * - * (called in wavelan_packet_xmit()) - */ -static int wv_packet_write(struct net_device * dev, void *buf, short length) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - unsigned short txblock; - unsigned short txpred; - unsigned short tx_addr; - unsigned short nop_addr; - unsigned short tbd_addr; - unsigned short buf_addr; - ac_tx_t tx; - ac_nop_t nop; - tbd_t tbd; - int clen = length; - unsigned long flags; - -#ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, - length); -#endif - - spin_lock_irqsave(&lp->spinlock, flags); - - /* Check nothing bad has happened */ - if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { -#ifdef DEBUG_TX_ERROR - printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", - dev->name); -#endif - spin_unlock_irqrestore(&lp->spinlock, flags); - return 1; - } - - /* Calculate addresses of next block and previous block. */ - txblock = lp->tx_first_free; - txpred = txblock - TXBLOCKZ; - if (txpred < OFFSET_CU) - txpred += NTXBLOCKS * TXBLOCKZ; - lp->tx_first_free += TXBLOCKZ; - if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) - lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; - - lp->tx_n_in_use++; - - /* Calculate addresses of the different parts of the block. */ - tx_addr = txblock; - nop_addr = tx_addr + sizeof(tx); - tbd_addr = nop_addr + sizeof(nop); - buf_addr = tbd_addr + sizeof(tbd); - - /* - * Transmit command - */ - tx.tx_h.ac_status = 0; - obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), - (unsigned char *) &tx.tx_h.ac_status, - sizeof(tx.tx_h.ac_status)); - - /* - * NOP command - */ - nop.nop_h.ac_status = 0; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), - (unsigned char *) &nop.nop_h.ac_status, - sizeof(nop.nop_h.ac_status)); - nop.nop_h.ac_link = nop_addr; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), - (unsigned char *) &nop.nop_h.ac_link, - sizeof(nop.nop_h.ac_link)); - - /* - * Transmit buffer descriptor - */ - tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen); - tbd.tbd_next_bd_offset = I82586NULL; - tbd.tbd_bufl = buf_addr; - tbd.tbd_bufh = 0; - obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd)); - - /* - * Data - */ - obram_write(ioaddr, buf_addr, buf, length); - - /* - * Overwrite the predecessor NOP link - * so that it points to this txblock. - */ - nop_addr = txpred + sizeof(tx); - nop.nop_h.ac_status = 0; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), - (unsigned char *) &nop.nop_h.ac_status, - sizeof(nop.nop_h.ac_status)); - nop.nop_h.ac_link = txblock; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), - (unsigned char *) &nop.nop_h.ac_link, - sizeof(nop.nop_h.ac_link)); - - /* Make sure the watchdog will keep quiet for a while */ - dev->trans_start = jiffies; - - /* Keep stats up to date. */ - dev->stats.tx_bytes += length; - - if (lp->tx_first_in_use == I82586NULL) - lp->tx_first_in_use = txblock; - - if (lp->tx_n_in_use < NTXBLOCKS - 1) - netif_wake_queue(dev); - - spin_unlock_irqrestore(&lp->spinlock, flags); - -#ifdef DEBUG_TX_INFO - wv_packet_info((u8 *) buf, length, dev->name, - "wv_packet_write"); -#endif /* DEBUG_TX_INFO */ - -#ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); -#endif - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * This routine is called when we want to send a packet (NET3 callback) - * In this routine, we check if the harware is ready to accept - * the packet. We also prevent reentrance. Then we call the function - * to send the packet. - */ -static netdev_tx_t wavelan_packet_xmit(struct sk_buff *skb, - struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long flags; - char data[ETH_ZLEN]; - -#ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, - (unsigned) skb); -#endif - - /* - * Block a timer-based transmit from overlapping. - * In other words, prevent reentering this routine. - */ - netif_stop_queue(dev); - - /* If somebody has asked to reconfigure the controller, - * we can do it now. - */ - if (lp->reconfig_82586) { - spin_lock_irqsave(&lp->spinlock, flags); - wv_82586_config(dev); - spin_unlock_irqrestore(&lp->spinlock, flags); - /* Check that we can continue */ - if (lp->tx_n_in_use == (NTXBLOCKS - 1)) - return NETDEV_TX_BUSY; - } - - /* Do we need some padding? */ - /* Note : on wireless the propagation time is in the order of 1us, - * and we don't have the Ethernet specific requirement of beeing - * able to detect collisions, therefore in theory we don't really - * need to pad. Jean II */ - if (skb->len < ETH_ZLEN) { - memset(data, 0, ETH_ZLEN); - skb_copy_from_linear_data(skb, data, skb->len); - /* Write packet on the card */ - if(wv_packet_write(dev, data, ETH_ZLEN)) - return NETDEV_TX_BUSY; /* We failed */ - } - else if(wv_packet_write(dev, skb->data, skb->len)) - return NETDEV_TX_BUSY; /* We failed */ - - - dev_kfree_skb(skb); - -#ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); -#endif - return NETDEV_TX_OK; -} - -/*********************** HARDWARE CONFIGURATION ***********************/ -/* - * This part does the real job of starting and configuring the hardware. - */ - -/*--------------------------------------------------------------------*/ -/* - * Routine to initialize the Modem Management Controller. - * (called by wv_hw_reset()) - */ -static int wv_mmc_init(struct net_device * dev) -{ - unsigned long ioaddr = dev->base_addr; - net_local *lp = netdev_priv(dev); - psa_t psa; - mmw_t m; - int configured; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); -#endif - - /* Read the parameter storage area. */ - psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); - -#ifdef USE_PSA_CONFIG - configured = psa.psa_conf_status & 1; -#else - configured = 0; -#endif - - /* Is the PSA is not configured */ - if (!configured) { - /* User will be able to configure NWID later (with iwconfig). */ - psa.psa_nwid[0] = 0; - psa.psa_nwid[1] = 0; - - /* no NWID checking since NWID is not set */ - psa.psa_nwid_select = 0; - - /* Disable encryption */ - psa.psa_encryption_select = 0; - - /* Set to standard values: - * 0x04 for AT, - * 0x01 for MCA, - * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) - */ - if (psa.psa_comp_number & 1) - psa.psa_thr_pre_set = 0x01; - else - psa.psa_thr_pre_set = 0x04; - psa.psa_quality_thr = 0x03; - - /* It is configured */ - psa.psa_conf_status |= 1; - -#ifdef USE_PSA_CONFIG - /* Write the psa. */ - psa_write(ioaddr, lp->hacr, - (char *) psa.psa_nwid - (char *) &psa, - (unsigned char *) psa.psa_nwid, 4); - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_thr_pre_set - (char *) &psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_quality_thr - (char *) &psa, - (unsigned char *) &psa.psa_quality_thr, 1); - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_conf_status - (char *) &psa, - (unsigned char *) &psa.psa_conf_status, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); -#endif - } - - /* Zero the mmc structure. */ - memset(&m, 0x00, sizeof(m)); - - /* Copy PSA info to the mmc. */ - m.mmw_netw_id_l = psa.psa_nwid[1]; - m.mmw_netw_id_h = psa.psa_nwid[0]; - - if (psa.psa_nwid_select & 1) - m.mmw_loopt_sel = 0x00; - else - m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; - - memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, - sizeof(m.mmw_encr_key)); - - if (psa.psa_encryption_select) - m.mmw_encr_enable = - MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; - else - m.mmw_encr_enable = 0; - - m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; - m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; - - /* - * Set default modem control parameters. - * See NCR document 407-0024326 Rev. A. - */ - m.mmw_jabber_enable = 0x01; - m.mmw_freeze = 0; - m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; - m.mmw_ifs = 0x20; - m.mmw_mod_delay = 0x04; - m.mmw_jam_time = 0x38; - - m.mmw_des_io_invert = 0; - m.mmw_decay_prm = 0; - m.mmw_decay_updat_prm = 0; - - /* Write all info to MMC. */ - mmc_write(ioaddr, 0, (u8 *) & m, sizeof(m)); - - /* The following code starts the modem of the 2.00 frequency - * selectable cards at power on. It's not strictly needed for the - * following boots. - * The original patch was by Joe Finney for the PCMCIA driver, but - * I've cleaned it up a bit and added documentation. - * Thanks to Loeke Brederveld from Lucent for the info. - */ - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * Does it work for everybody, especially old cards? */ - /* Note: WFREQSEL verifies that it is able to read a sensible - * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID - * is 0xA (Xilinx version) or 0xB (Ariadne version). - * My test is more crude but does work. */ - if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - /* We must download the frequency parameters to the - * synthesizers (from the EEPROM - area 1) - * Note: as the EEPROM is automatically decremented, we set the end - * if the area... */ - m.mmw_fee_addr = 0x0F; - m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; - mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, - (unsigned char *) &m.mmw_fee_ctrl, 2); - - /* Wait until the download is finished. */ - fee_wait(ioaddr, 100, 100); - -#ifdef DEBUG_CONFIG_INFO - /* The frequency was in the last word downloaded. */ - mmc_read(ioaddr, (char *) &m.mmw_fee_data_l - (char *) &m, - (unsigned char *) &m.mmw_fee_data_l, 2); - - /* Print some info for the user. */ - printk(KERN_DEBUG - "%s: WaveLAN 2.00 recognised (frequency select). Current frequency = %ld\n", - dev->name, - ((m. - mmw_fee_data_h << 4) | (m.mmw_fee_data_l >> 4)) * - 5 / 2 + 24000L); -#endif - - /* We must now download the power adjust value (gain) to - * the synthesizers (from the EEPROM - area 7 - DAC). */ - m.mmw_fee_addr = 0x61; - m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; - mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, - (unsigned char *) &m.mmw_fee_ctrl, 2); - - /* Wait until the download is finished. */ - } - /* if 2.00 card */ -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); -#endif - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Construct the fd and rbd structures. - * Start the receive unit. - * (called by wv_hw_reset()) - */ -static int wv_ru_start(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - u16 scb_cs; - fd_t fd; - rbd_t rbd; - u16 rx; - u16 rx_next; - int i; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); -#endif - - obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - if ((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY) - return 0; - - lp->rx_head = OFFSET_RU; - - for (i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) { - rx_next = - (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ; - - fd.fd_status = 0; - fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0; - fd.fd_link_offset = rx_next; - fd.fd_rbd_offset = rx + sizeof(fd); - obram_write(ioaddr, rx, (unsigned char *) &fd, sizeof(fd)); - - rbd.rbd_status = 0; - rbd.rbd_next_rbd_offset = I82586NULL; - rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd); - rbd.rbd_bufh = 0; - rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ); - obram_write(ioaddr, rx + sizeof(fd), - (unsigned char *) &rbd, sizeof(rbd)); - - lp->rx_last = rx; - } - - obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset), - (unsigned char *) &lp->rx_head, sizeof(lp->rx_head)); - - scb_cs = SCB_CMD_RUC_GO; - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - - set_chan_attn(ioaddr, lp->hacr); - - for (i = 1000; i > 0; i--) { - obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - if (scb_cs == 0) - break; - - udelay(10); - } - - if (i <= 0) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO - "%s: wavelan_ru_start(): board not accepting command.\n", - dev->name); -#endif - return -1; - } -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); -#endif - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Initialise the transmit blocks. - * Start the command unit executing the NOP - * self-loop of the first transmit block. - * - * Here we create the list of send buffers used to transmit packets - * between the PC and the command unit. For each buffer, we create a - * buffer descriptor (pointing on the buffer), a transmit command - * (pointing to the buffer descriptor) and a NOP command. - * The transmit command is linked to the NOP, and the NOP to itself. - * When we will have finished executing the transmit command, we will - * then loop on the NOP. By releasing the NOP link to a new command, - * we may send another buffer. - * - * (called by wv_hw_reset()) - */ -static int wv_cu_start(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - int i; - u16 txblock; - u16 first_nop; - u16 scb_cs; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name); -#endif - - lp->tx_first_free = OFFSET_CU; - lp->tx_first_in_use = I82586NULL; - - for (i = 0, txblock = OFFSET_CU; - i < NTXBLOCKS; i++, txblock += TXBLOCKZ) { - ac_tx_t tx; - ac_nop_t nop; - tbd_t tbd; - unsigned short tx_addr; - unsigned short nop_addr; - unsigned short tbd_addr; - unsigned short buf_addr; - - tx_addr = txblock; - nop_addr = tx_addr + sizeof(tx); - tbd_addr = nop_addr + sizeof(nop); - buf_addr = tbd_addr + sizeof(tbd); - - tx.tx_h.ac_status = 0; - tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I; - tx.tx_h.ac_link = nop_addr; - tx.tx_tbd_offset = tbd_addr; - obram_write(ioaddr, tx_addr, (unsigned char *) &tx, - sizeof(tx)); - - nop.nop_h.ac_status = 0; - nop.nop_h.ac_command = acmd_nop; - nop.nop_h.ac_link = nop_addr; - obram_write(ioaddr, nop_addr, (unsigned char *) &nop, - sizeof(nop)); - - tbd.tbd_status = TBD_STATUS_EOF; - tbd.tbd_next_bd_offset = I82586NULL; - tbd.tbd_bufl = buf_addr; - tbd.tbd_bufh = 0; - obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, - sizeof(tbd)); - } - - first_nop = - OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t); - obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset), - (unsigned char *) &first_nop, sizeof(first_nop)); - - scb_cs = SCB_CMD_CUC_GO; - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - - set_chan_attn(ioaddr, lp->hacr); - - for (i = 1000; i > 0; i--) { - obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - if (scb_cs == 0) - break; - - udelay(10); - } - - if (i <= 0) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO - "%s: wavelan_cu_start(): board not accepting command.\n", - dev->name); -#endif - return -1; - } - - lp->tx_n_in_use = 0; - netif_start_queue(dev); -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name); -#endif - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * This routine does a standard configuration of the WaveLAN - * controller (i82586). - * - * It initialises the scp, iscp and scb structure - * The first two are just pointers to the next. - * The last one is used for basic configuration and for basic - * communication (interrupt status). - * - * (called by wv_hw_reset()) - */ -static int wv_82586_start(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - scp_t scp; /* system configuration pointer */ - iscp_t iscp; /* intermediate scp */ - scb_t scb; /* system control block */ - ach_t cb; /* Action command header */ - u8 zeroes[512]; - int i; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name); -#endif - - /* - * Clear the onboard RAM. - */ - memset(&zeroes[0], 0x00, sizeof(zeroes)); - for (i = 0; i < I82586_MEMZ; i += sizeof(zeroes)) - obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes)); - - /* - * Construct the command unit structures: - * scp, iscp, scb, cb. - */ - memset(&scp, 0x00, sizeof(scp)); - scp.scp_sysbus = SCP_SY_16BBUS; - scp.scp_iscpl = OFFSET_ISCP; - obram_write(ioaddr, OFFSET_SCP, (unsigned char *) &scp, - sizeof(scp)); - - memset(&iscp, 0x00, sizeof(iscp)); - iscp.iscp_busy = 1; - iscp.iscp_offset = OFFSET_SCB; - obram_write(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, - sizeof(iscp)); - - /* Our first command is to reset the i82586. */ - memset(&scb, 0x00, sizeof(scb)); - scb.scb_command = SCB_CMD_RESET; - scb.scb_cbl_offset = OFFSET_CU; - scb.scb_rfa_offset = OFFSET_RU; - obram_write(ioaddr, OFFSET_SCB, (unsigned char *) &scb, - sizeof(scb)); - - set_chan_attn(ioaddr, lp->hacr); - - /* Wait for command to finish. */ - for (i = 1000; i > 0; i--) { - obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, - sizeof(iscp)); - - if (iscp.iscp_busy == (unsigned short) 0) - break; - - udelay(10); - } - - if (i <= 0) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO - "%s: wv_82586_start(): iscp_busy timeout.\n", - dev->name); -#endif - return -1; - } - - /* Check command completion. */ - for (i = 15; i > 0; i--) { - obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, - sizeof(scb)); - - if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA)) - break; - - udelay(10); - } - - if (i <= 0) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO - "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n", - dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status); -#endif - return -1; - } - - wv_ack(dev); - - /* Set the action command header. */ - memset(&cb, 0x00, sizeof(cb)); - cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose); - cb.ac_link = OFFSET_CU; - obram_write(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); - - if (wv_synchronous_cmd(dev, "diag()") == -1) - return -1; - - obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); - if (cb.ac_status & AC_SFLD_FAIL) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO - "%s: wv_82586_start(): i82586 Self Test failed.\n", - dev->name); -#endif - return -1; - } -#ifdef DEBUG_I82586_SHOW - wv_scb_show(ioaddr); -#endif - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name); -#endif - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * This routine does a standard configuration of the WaveLAN - * controller (i82586). - * - * This routine is a violent hack. We use the first free transmit block - * to make our configuration. In the buffer area, we create the three - * configuration commands (linked). We make the previous NOP point to - * the beginning of the buffer instead of the tx command. After, we go - * as usual to the NOP command. - * Note that only the last command (mc_set) will generate an interrupt. - * - * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit()) - */ -static void wv_82586_config(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - unsigned short txblock; - unsigned short txpred; - unsigned short tx_addr; - unsigned short nop_addr; - unsigned short tbd_addr; - unsigned short cfg_addr; - unsigned short ias_addr; - unsigned short mcs_addr; - ac_tx_t tx; - ac_nop_t nop; - ac_cfg_t cfg; /* Configure action */ - ac_ias_t ias; /* IA-setup action */ - ac_mcs_t mcs; /* Multicast setup */ - struct dev_mc_list *dmi; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name); -#endif - - /* Check nothing bad has happened */ - if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO "%s: wv_82586_config(): Tx queue full.\n", - dev->name); -#endif - return; - } - - /* Calculate addresses of next block and previous block. */ - txblock = lp->tx_first_free; - txpred = txblock - TXBLOCKZ; - if (txpred < OFFSET_CU) - txpred += NTXBLOCKS * TXBLOCKZ; - lp->tx_first_free += TXBLOCKZ; - if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) - lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; - - lp->tx_n_in_use++; - - /* Calculate addresses of the different parts of the block. */ - tx_addr = txblock; - nop_addr = tx_addr + sizeof(tx); - tbd_addr = nop_addr + sizeof(nop); - cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */ - ias_addr = cfg_addr + sizeof(cfg); - mcs_addr = ias_addr + sizeof(ias); - - /* - * Transmit command - */ - tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */ - obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), - (unsigned char *) &tx.tx_h.ac_status, - sizeof(tx.tx_h.ac_status)); - - /* - * NOP command - */ - nop.nop_h.ac_status = 0; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), - (unsigned char *) &nop.nop_h.ac_status, - sizeof(nop.nop_h.ac_status)); - nop.nop_h.ac_link = nop_addr; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), - (unsigned char *) &nop.nop_h.ac_link, - sizeof(nop.nop_h.ac_link)); - - /* Create a configure action. */ - memset(&cfg, 0x00, sizeof(cfg)); - - /* - * For Linux we invert AC_CFG_ALOC() so as to conform - * to the way that net packets reach us from above. - * (See also ac_tx_t.) - * - * Updated from Wavelan Manual WCIN085B - */ - cfg.cfg_byte_cnt = - AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t)); - cfg.cfg_fifolim = AC_CFG_FIFOLIM(4); - cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0); - cfg.cfg_byte9 = AC_CFG_ELPBCK(0) | - AC_CFG_ILPBCK(0) | - AC_CFG_PRELEN(AC_CFG_PLEN_2) | - AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE); - cfg.cfg_byte10 = AC_CFG_BOFMET(1) | - AC_CFG_ACR(6) | AC_CFG_LINPRIO(0); - cfg.cfg_ifs = 0x20; - cfg.cfg_slotl = 0x0C; - cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | AC_CFG_SLTTMHI(0); - cfg.cfg_byte14 = AC_CFG_FLGPAD(0) | - AC_CFG_BTSTF(0) | - AC_CFG_CRC16(0) | - AC_CFG_NCRC(0) | - AC_CFG_TNCRS(1) | - AC_CFG_MANCH(0) | - AC_CFG_BCDIS(0) | AC_CFG_PRM(lp->promiscuous); - cfg.cfg_byte15 = AC_CFG_ICDS(0) | - AC_CFG_CDTF(0) | AC_CFG_ICSS(0) | AC_CFG_CSTF(0); -/* - cfg.cfg_min_frm_len = AC_CFG_MNFRM(64); -*/ - cfg.cfg_min_frm_len = AC_CFG_MNFRM(8); - - cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure); - cfg.cfg_h.ac_link = ias_addr; - obram_write(ioaddr, cfg_addr, (unsigned char *) &cfg, sizeof(cfg)); - - /* Set up the MAC address */ - memset(&ias, 0x00, sizeof(ias)); - ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup); - ias.ias_h.ac_link = mcs_addr; - memcpy(&ias.ias_addr[0], (unsigned char *) &dev->dev_addr[0], - sizeof(ias.ias_addr)); - obram_write(ioaddr, ias_addr, (unsigned char *) &ias, sizeof(ias)); - - /* Initialize adapter's Ethernet multicast addresses */ - memset(&mcs, 0x00, sizeof(mcs)); - mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup); - mcs.mcs_h.ac_link = nop_addr; - mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count; - obram_write(ioaddr, mcs_addr, (unsigned char *) &mcs, sizeof(mcs)); - - /* Any address to set? */ - if (lp->mc_count) { - for (dmi = dev->mc_list; dmi; dmi = dmi->next) - outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr, - WAVELAN_ADDR_SIZE >> 1); - -#ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG - "%s: wv_82586_config(): set %d multicast addresses:\n", - dev->name, lp->mc_count); - for (dmi = dev->mc_list; dmi; dmi = dmi->next) - printk(KERN_DEBUG " %pM\n", dmi->dmi_addr); -#endif - } - - /* - * Overwrite the predecessor NOP link - * so that it points to the configure action. - */ - nop_addr = txpred + sizeof(tx); - nop.nop_h.ac_status = 0; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), - (unsigned char *) &nop.nop_h.ac_status, - sizeof(nop.nop_h.ac_status)); - nop.nop_h.ac_link = cfg_addr; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), - (unsigned char *) &nop.nop_h.ac_link, - sizeof(nop.nop_h.ac_link)); - - /* Job done, clear the flag */ - lp->reconfig_82586 = 0; - - if (lp->tx_first_in_use == I82586NULL) - lp->tx_first_in_use = txblock; - - if (lp->tx_n_in_use == (NTXBLOCKS - 1)) - netif_stop_queue(dev); - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name); -#endif -} - -/*------------------------------------------------------------------*/ -/* - * This routine, called by wavelan_close(), gracefully stops the - * WaveLAN controller (i82586). - * (called by wavelan_close()) - */ -static void wv_82586_stop(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - u16 scb_cmd; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name); -#endif - - /* Suspend both command unit and receive unit. */ - scb_cmd = - (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & - SCB_CMD_RUC_SUS); - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cmd, sizeof(scb_cmd)); - set_chan_attn(ioaddr, lp->hacr); - - /* No more interrupts */ - wv_ints_off(dev); - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name); -#endif -} - -/*------------------------------------------------------------------*/ -/* - * Totally reset the WaveLAN and restart it. - * Performs the following actions: - * 1. A power reset (reset DMA) - * 2. Initialize the radio modem (using wv_mmc_init) - * 3. Reset & Configure LAN controller (using wv_82586_start) - * 4. Start the LAN controller's command unit - * 5. Start the LAN controller's receive unit - * (called by wavelan_interrupt(), wavelan_watchdog() & wavelan_open()) - */ -static int wv_hw_reset(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long ioaddr = dev->base_addr; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name, - (unsigned int) dev); -#endif - - /* Increase the number of resets done. */ - lp->nresets++; - - wv_hacr_reset(ioaddr); - lp->hacr = HACR_DEFAULT; - - if ((wv_mmc_init(dev) < 0) || (wv_82586_start(dev) < 0)) - return -1; - - /* Enable the card to send interrupts. */ - wv_ints_on(dev); - - /* Start card functions */ - if (wv_cu_start(dev) < 0) - return -1; - - /* Setup the controller and parameters */ - wv_82586_config(dev); - - /* Finish configuration with the receive unit */ - if (wv_ru_start(dev) < 0) - return -1; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); -#endif - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Check if there is a WaveLAN at the specific base address. - * As a side effect, this reads the MAC address. - * (called in wavelan_probe() and init_module()) - */ -static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac) -{ - int i; /* Loop counter */ - - /* Check if the base address if available. */ - if (!request_region(ioaddr, sizeof(ha_t), "wavelan probe")) - return -EBUSY; /* ioaddr already used */ - - /* Reset host interface */ - wv_hacr_reset(ioaddr); - - /* Read the MAC address from the parameter storage area. */ - psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr), - mac, 6); - - release_region(ioaddr, sizeof(ha_t)); - - /* - * Check the first three octets of the address for the manufacturer's code. - * Note: if this can't find your WaveLAN card, you've got a - * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on - * how to configure your card. - */ - for (i = 0; i < ARRAY_SIZE(MAC_ADDRESSES); i++) - if ((mac[0] == MAC_ADDRESSES[i][0]) && - (mac[1] == MAC_ADDRESSES[i][1]) && - (mac[2] == MAC_ADDRESSES[i][2])) - return 0; - -#ifdef DEBUG_CONFIG_INFO - printk(KERN_WARNING - "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n", - ioaddr, mac[0], mac[1], mac[2]); -#endif - return -ENODEV; -} - -/************************ INTERRUPT HANDLING ************************/ - -/* - * This function is the interrupt handler for the WaveLAN card. This - * routine will be called whenever: - */ -static irqreturn_t wavelan_interrupt(int irq, void *dev_id) -{ - struct net_device *dev; - unsigned long ioaddr; - net_local *lp; - u16 hasr; - u16 status; - u16 ack_cmd; - - dev = dev_id; - -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); -#endif - - lp = netdev_priv(dev); - ioaddr = dev->base_addr; - -#ifdef DEBUG_INTERRUPT_INFO - /* Check state of our spinlock */ - if(spin_is_locked(&lp->spinlock)) - printk(KERN_DEBUG - "%s: wavelan_interrupt(): spinlock is already locked !!!\n", - dev->name); -#endif - - /* Prevent reentrancy. We need to do that because we may have - * multiple interrupt handler running concurrently. - * It is safe because interrupts are disabled before acquiring - * the spinlock. */ - spin_lock(&lp->spinlock); - - /* We always had spurious interrupts at startup, but lately I - * saw them comming *between* the request_irq() and the - * spin_lock_irqsave() in wavelan_open(), so the spinlock - * protection is no enough. - * So, we also check lp->hacr that will tell us is we enabled - * irqs or not (see wv_ints_on()). - * We can't use netif_running(dev) because we depend on the - * proper processing of the irq generated during the config. */ - - /* Which interrupt it is ? */ - hasr = hasr_read(ioaddr); - -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_INFO - "%s: wavelan_interrupt(): hasr 0x%04x; hacr 0x%04x.\n", - dev->name, hasr, lp->hacr); -#endif - - /* Check modem interrupt */ - if ((hasr & HASR_MMC_INTR) && (lp->hacr & HACR_MMC_INT_ENABLE)) { - u8 dce_status; - - /* - * Interrupt from the modem management controller. - * This will clear it -- ignored for now. - */ - mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, - sizeof(dce_status)); - -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO - "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", - dev->name, dce_status); -#endif - } - - /* Check if not controller interrupt */ - if (((hasr & HASR_82586_INTR) == 0) || - ((lp->hacr & HACR_82586_INT_ENABLE) == 0)) { -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO - "%s: wavelan_interrupt(): interrupt not coming from i82586 - hasr 0x%04x.\n", - dev->name, hasr); -#endif - spin_unlock (&lp->spinlock); - return IRQ_NONE; - } - - /* Read interrupt data. */ - obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), - (unsigned char *) &status, sizeof(status)); - - /* - * Acknowledge the interrupt(s). - */ - ack_cmd = status & SCB_ST_INT; - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &ack_cmd, sizeof(ack_cmd)); - set_chan_attn(ioaddr, lp->hacr); - -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n", - dev->name, status); -#endif - - /* Command completed. */ - if ((status & SCB_ST_CX) == SCB_ST_CX) { -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG - "%s: wavelan_interrupt(): command completed.\n", - dev->name); -#endif - wv_complete(dev, ioaddr, lp); - } - - /* Frame received. */ - if ((status & SCB_ST_FR) == SCB_ST_FR) { -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG - "%s: wavelan_interrupt(): received packet.\n", - dev->name); -#endif - wv_receive(dev); - } - - /* Check the state of the command unit. */ - if (((status & SCB_ST_CNA) == SCB_ST_CNA) || - (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && - (netif_running(dev)))) { -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO - "%s: wavelan_interrupt(): CU inactive -- restarting\n", - dev->name); -#endif - wv_hw_reset(dev); - } - - /* Check the state of the command unit. */ - if (((status & SCB_ST_RNR) == SCB_ST_RNR) || - (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && - (netif_running(dev)))) { -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO - "%s: wavelan_interrupt(): RU not ready -- restarting\n", - dev->name); -#endif - wv_hw_reset(dev); - } - - /* Release spinlock */ - spin_unlock (&lp->spinlock); - -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); -#endif - return IRQ_HANDLED; -} - -/*------------------------------------------------------------------*/ -/* - * Watchdog: when we start a transmission, a timer is set for us in the - * kernel. If the transmission completes, this timer is disabled. If - * the timer expires, we are called and we try to unlock the hardware. - */ -static void wavelan_watchdog(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - u_long ioaddr = dev->base_addr; - unsigned long flags; - unsigned int nreaped; - -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); -#endif - -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", - dev->name); -#endif - - /* Check that we came here for something */ - if (lp->tx_n_in_use <= 0) { - return; - } - - spin_lock_irqsave(&lp->spinlock, flags); - - /* Try to see if some buffers are not free (in case we missed - * an interrupt */ - nreaped = wv_complete(dev, ioaddr, lp); - -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG - "%s: wavelan_watchdog(): %d reaped, %d remain.\n", - dev->name, nreaped, lp->tx_n_in_use); -#endif - -#ifdef DEBUG_PSA_SHOW - { - psa_t psa; - psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); - wv_psa_show(&psa); - } -#endif -#ifdef DEBUG_MMC_SHOW - wv_mmc_show(dev); -#endif -#ifdef DEBUG_I82586_SHOW - wv_cu_show(dev); -#endif - - /* If no buffer has been freed */ - if (nreaped == 0) { -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO - "%s: wavelan_watchdog(): cleanup failed, trying reset\n", - dev->name); -#endif - wv_hw_reset(dev); - } - - /* At this point, we should have some free Tx buffer ;-) */ - if (lp->tx_n_in_use < NTXBLOCKS - 1) - netif_wake_queue(dev); - - spin_unlock_irqrestore(&lp->spinlock, flags); - -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); -#endif -} - -/********************* CONFIGURATION CALLBACKS *********************/ -/* - * Here are the functions called by the Linux networking code (NET3) - * for initialization, configuration and deinstallations of the - * WaveLAN ISA hardware. - */ - -/*------------------------------------------------------------------*/ -/* - * Configure and start up the WaveLAN PCMCIA adaptor. - * Called by NET3 when it "opens" the device. - */ -static int wavelan_open(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long flags; - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, - (unsigned int) dev); -#endif - - /* Check irq */ - if (dev->irq == 0) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", - dev->name); -#endif - return -ENXIO; - } - - if (request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0) - { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", - dev->name); -#endif - return -EAGAIN; - } - - spin_lock_irqsave(&lp->spinlock, flags); - - if (wv_hw_reset(dev) != -1) { - netif_start_queue(dev); - } else { - free_irq(dev->irq, dev); -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO - "%s: wavelan_open(): impossible to start the card\n", - dev->name); -#endif - spin_unlock_irqrestore(&lp->spinlock, flags); - return -EAGAIN; - } - spin_unlock_irqrestore(&lp->spinlock, flags); - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); -#endif - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Shut down the WaveLAN ISA card. - * Called by NET3 when it "closes" the device. - */ -static int wavelan_close(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - unsigned long flags; - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, - (unsigned int) dev); -#endif - - netif_stop_queue(dev); - - /* - * Flush the Tx and disable Rx. - */ - spin_lock_irqsave(&lp->spinlock, flags); - wv_82586_stop(dev); - spin_unlock_irqrestore(&lp->spinlock, flags); - - free_irq(dev->irq, dev); - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); -#endif - return 0; -} - -static const struct net_device_ops wavelan_netdev_ops = { - .ndo_open = wavelan_open, - .ndo_stop = wavelan_close, - .ndo_start_xmit = wavelan_packet_xmit, - .ndo_set_multicast_list = wavelan_set_multicast_list, - .ndo_tx_timeout = wavelan_watchdog, - .ndo_change_mtu = eth_change_mtu, - .ndo_validate_addr = eth_validate_addr, -#ifdef SET_MAC_ADDRESS - .ndo_set_mac_address = wavelan_set_mac_address -#else - .ndo_set_mac_address = eth_mac_addr, -#endif -}; - - -/*------------------------------------------------------------------*/ -/* - * Probe an I/O address, and if the WaveLAN is there configure the - * device structure - * (called by wavelan_probe() and via init_module()). - */ -static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) -{ - u8 irq_mask; - int irq; - net_local *lp; - mac_addr mac; - int err; - - if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) - return -EADDRINUSE; - - err = wv_check_ioaddr(ioaddr, mac); - if (err) - goto out; - - memcpy(dev->dev_addr, mac, 6); - - dev->base_addr = ioaddr; - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n", - dev->name, (unsigned int) dev, ioaddr); -#endif - - /* Check IRQ argument on command line. */ - if (dev->irq != 0) { - irq_mask = wv_irq_to_psa(dev->irq); - - if (irq_mask == 0) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_WARNING - "%s: wavelan_config(): invalid IRQ %d ignored.\n", - dev->name, dev->irq); -#endif - dev->irq = 0; - } else { -#ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG - "%s: wavelan_config(): changing IRQ to %d\n", - dev->name, dev->irq); -#endif - psa_write(ioaddr, HACR_DEFAULT, - psaoff(0, psa_int_req_no), &irq_mask, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, HACR_DEFAULT); - wv_hacr_reset(ioaddr); - } - } - - psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), - &irq_mask, 1); - if ((irq = wv_psa_to_irq(irq_mask)) == -1) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO - "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", - dev->name, irq_mask); -#endif - err = -EAGAIN; - goto out; - } - - dev->irq = irq; - - dev->mem_start = 0x0000; - dev->mem_end = 0x0000; - dev->if_port = 0; - - /* Initialize device structures */ - memset(netdev_priv(dev), 0, sizeof(net_local)); - lp = netdev_priv(dev); - - /* Back link to the device structure. */ - lp->dev = dev; - /* Add the device at the beginning of the linked list. */ - lp->next = wavelan_list; - wavelan_list = lp; - - lp->hacr = HACR_DEFAULT; - - /* Multicast stuff */ - lp->promiscuous = 0; - lp->mc_count = 0; - - /* Init spinlock */ - spin_lock_init(&lp->spinlock); - - dev->netdev_ops = &wavelan_netdev_ops; - dev->watchdog_timeo = WATCHDOG_JIFFIES; - dev->wireless_handlers = &wavelan_handler_def; - lp->wireless_data.spy_data = &lp->spy_data; - dev->wireless_data = &lp->wireless_data; - - dev->mtu = WAVELAN_MTU; - - /* Display nice information. */ - wv_init_info(dev); - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); -#endif - return 0; -out: - release_region(ioaddr, sizeof(ha_t)); - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Check for a network adaptor of this type. Return '0' iff one - * exists. There seem to be different interpretations of - * the initial value of dev->base_addr. - * We follow the example in drivers/net/ne.c. - * (called in "Space.c") - */ -struct net_device * __init wavelan_probe(int unit) -{ - struct net_device *dev; - short base_addr; - int def_irq; - int i; - int r = 0; - - /* compile-time check the sizes of structures */ - BUILD_BUG_ON(sizeof(psa_t) != PSA_SIZE); - BUILD_BUG_ON(sizeof(mmw_t) != MMW_SIZE); - BUILD_BUG_ON(sizeof(mmr_t) != MMR_SIZE); - BUILD_BUG_ON(sizeof(ha_t) != HA_SIZE); - - dev = alloc_etherdev(sizeof(net_local)); - if (!dev) - return ERR_PTR(-ENOMEM); - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - base_addr = dev->base_addr; - def_irq = dev->irq; - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG - "%s: ->wavelan_probe(dev=%p (base_addr=0x%x))\n", - dev->name, dev, (unsigned int) dev->base_addr); -#endif - - /* Don't probe at all. */ - if (base_addr < 0) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_WARNING - "%s: wavelan_probe(): invalid base address\n", - dev->name); -#endif - r = -ENXIO; - } else if (base_addr > 0x100) { /* Check a single specified location. */ - r = wavelan_config(dev, base_addr); -#ifdef DEBUG_CONFIG_INFO - if (r != 0) - printk(KERN_DEBUG - "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n", - dev->name, base_addr); -#endif - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); -#endif - } else { /* Scan all possible addresses of the WaveLAN hardware. */ - for (i = 0; i < ARRAY_SIZE(iobase); i++) { - dev->irq = def_irq; - if (wavelan_config(dev, iobase[i]) == 0) { -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG - "%s: <-wavelan_probe()\n", - dev->name); -#endif - break; - } - } - if (i == ARRAY_SIZE(iobase)) - r = -ENODEV; - } - if (r) - goto out; - r = register_netdev(dev); - if (r) - goto out1; - return dev; -out1: - release_region(dev->base_addr, sizeof(ha_t)); - wavelan_list = wavelan_list->next; -out: - free_netdev(dev); - return ERR_PTR(r); -} - -/****************************** MODULE ******************************/ -/* - * Module entry point: insertion and removal - */ - -#ifdef MODULE -/*------------------------------------------------------------------*/ -/* - * Insertion of the module - * I'm now quite proud of the multi-device support. - */ -int __init init_module(void) -{ - int ret = -EIO; /* Return error if no cards found */ - int i; - -#ifdef DEBUG_MODULE_TRACE - printk(KERN_DEBUG "-> init_module()\n"); -#endif - - /* If probing is asked */ - if (io[0] == 0) { -#ifdef DEBUG_CONFIG_ERROR - printk(KERN_WARNING - "WaveLAN init_module(): doing device probing (bad !)\n"); - printk(KERN_WARNING - "Specify base addresses while loading module to correct the problem\n"); -#endif - - /* Copy the basic set of address to be probed. */ - for (i = 0; i < ARRAY_SIZE(iobase); i++) - io[i] = iobase[i]; - } - - - /* Loop on all possible base addresses. */ - for (i = 0; i < ARRAY_SIZE(io) && io[i] != 0; i++) { - struct net_device *dev = alloc_etherdev(sizeof(net_local)); - if (!dev) - break; - if (name[i]) - strcpy(dev->name, name[i]); /* Copy name */ - dev->base_addr = io[i]; - dev->irq = irq[i]; - - /* Check if there is something at this base address. */ - if (wavelan_config(dev, io[i]) == 0) { - if (register_netdev(dev) != 0) { - release_region(dev->base_addr, sizeof(ha_t)); - wavelan_list = wavelan_list->next; - } else { - ret = 0; - continue; - } - } - free_netdev(dev); - } - -#ifdef DEBUG_CONFIG_ERROR - if (!wavelan_list) - printk(KERN_WARNING - "WaveLAN init_module(): no device found\n"); -#endif - -#ifdef DEBUG_MODULE_TRACE - printk(KERN_DEBUG "<- init_module()\n"); -#endif - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Removal of the module - */ -void cleanup_module(void) -{ -#ifdef DEBUG_MODULE_TRACE - printk(KERN_DEBUG "-> cleanup_module()\n"); -#endif - - /* Loop on all devices and release them. */ - while (wavelan_list) { - struct net_device *dev = wavelan_list->dev; - -#ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG - "%s: cleanup_module(): removing device at 0x%x\n", - dev->name, (unsigned int) dev); -#endif - unregister_netdev(dev); - - release_region(dev->base_addr, sizeof(ha_t)); - wavelan_list = wavelan_list->next; - - free_netdev(dev); - } - -#ifdef DEBUG_MODULE_TRACE - printk(KERN_DEBUG "<- cleanup_module()\n"); -#endif -} -#endif /* MODULE */ -MODULE_LICENSE("GPL"); - -/* - * This software may only be used and distributed - * according to the terms of the GNU General Public License. - * - * This software was developed as a component of the - * Linux operating system. - * It is based on other device drivers and information - * either written or supplied by: - * Ajay Bakre (bakre@paul.rutgers.edu), - * Donald Becker (becker@scyld.com), - * Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com), - * Anders Klemets (klemets@it.kth.se), - * Vladimir V. Kolpakov (w@stier.koenig.ru), - * Marc Meertens (Marc.Meertens@Utrecht.NCR.com), - * Pauline Middelink (middelin@polyware.iaf.nl), - * Robert Morris (rtm@das.harvard.edu), - * Jean Tourrilhes (jt@hplb.hpl.hp.com), - * Girish Welling (welling@paul.rutgers.edu), - * - * Thanks go also to: - * James Ashton (jaa101@syseng.anu.edu.au), - * Alan Cox (alan@lxorguk.ukuu.org.uk), - * Allan Creighton (allanc@cs.usyd.edu.au), - * Matthew Geier (matthew@cs.usyd.edu.au), - * Remo di Giovanni (remo@cs.usyd.edu.au), - * Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de), - * Vipul Gupta (vgupta@cs.binghamton.edu), - * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), - * Tim Nicholson (tim@cs.usyd.edu.au), - * Ian Parkin (ian@cs.usyd.edu.au), - * John Rosenberg (johnr@cs.usyd.edu.au), - * George Rossi (george@phm.gov.au), - * Arthur Scott (arthur@cs.usyd.edu.au), - * Peter Storey, - * for their assistance and advice. - * - * Please send bug reports, updates, comments to: - * - * Bruce Janson Email: bruce@cs.usyd.edu.au - * Basser Department of Computer Science Phone: +61-2-9351-3423 - * University of Sydney, N.S.W., 2006, AUSTRALIA Fax: +61-2-9351-3838 - */ diff --git a/drivers/net/wireless/wavelan.h b/drivers/net/wireless/wavelan.h deleted file mode 100644 index 9ab360558ffd..000000000000 --- a/drivers/net/wireless/wavelan.h +++ /dev/null @@ -1,370 +0,0 @@ -/* - * WaveLAN ISA driver - * - * Jean II - HPLB '96 - * - * Reorganisation and extension of the driver. - * Original copyright follows. See wavelan.p.h for details. - * - * This file contains the declarations for the WaveLAN hardware. Note that - * the WaveLAN ISA includes a i82586 controller (see definitions in - * file i82586.h). - * - * The main difference between the ISA hardware and the PCMCIA one is - * the Ethernet controller (i82586 instead of i82593). - * The i82586 allows multiple transmit buffers. The PSA needs to be accessed - * through the host interface. - */ - -#ifndef _WAVELAN_H -#define _WAVELAN_H - -/************************** MAGIC NUMBERS ***************************/ - -/* Detection of the WaveLAN card is done by reading the MAC - * address from the card and checking it. If you have a non-AT&T - * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson), - * you might need to modify this part to accommodate your hardware. - */ -static const char MAC_ADDRESSES[][3] = -{ - { 0x08, 0x00, 0x0E }, /* AT&T WaveLAN (standard) & DEC RoamAbout */ - { 0x08, 0x00, 0x6A }, /* AT&T WaveLAN (alternate) */ - { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ - { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ - /* Add your card here and send me the patch! */ -}; - -#define WAVELAN_ADDR_SIZE 6 /* Size of a MAC address */ - -#define WAVELAN_MTU 1500 /* Maximum size of WaveLAN packet */ - -#define MAXDATAZ (WAVELAN_ADDR_SIZE + WAVELAN_ADDR_SIZE + 2 + WAVELAN_MTU) - -/* - * Constants used to convert channels to frequencies - */ - -/* Frequency available in the 2.0 modem, in units of 250 kHz - * (as read in the offset register of the dac area). - * Used to map channel numbers used by `wfreqsel' to frequencies - */ -static const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, - 0xD0, 0xF0, 0xF8, 0x150 }; - -/* Frequencies of the 1.0 modem (fixed frequencies). - * Use to map the PSA `subband' to a frequency - * Note : all frequencies apart from the first one need to be multiplied by 10 - */ -static const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; - - - -/*************************** PC INTERFACE ****************************/ - -/* - * Host Adaptor structure. - * (base is board port address). - */ -typedef union hacs_u hacs_u; -union hacs_u -{ - unsigned short hu_command; /* Command register */ -#define HACR_RESET 0x0001 /* Reset board */ -#define HACR_CA 0x0002 /* Set Channel Attention for 82586 */ -#define HACR_16BITS 0x0004 /* 16-bit operation (0 => 8bits) */ -#define HACR_OUT0 0x0008 /* General purpose output pin 0 */ - /* not used - must be 1 */ -#define HACR_OUT1 0x0010 /* General purpose output pin 1 */ - /* not used - must be 1 */ -#define HACR_82586_INT_ENABLE 0x0020 /* Enable 82586 interrupts */ -#define HACR_MMC_INT_ENABLE 0x0040 /* Enable MMC interrupts */ -#define HACR_INTR_CLR_ENABLE 0x0080 /* Enable interrupt status read/clear */ - unsigned short hu_status; /* Status Register */ -#define HASR_82586_INTR 0x0001 /* Interrupt request from 82586 */ -#define HASR_MMC_INTR 0x0002 /* Interrupt request from MMC */ -#define HASR_MMC_BUSY 0x0004 /* MMC busy indication */ -#define HASR_PSA_BUSY 0x0008 /* LAN parameter storage area busy */ -} __attribute__ ((packed)); - -typedef struct ha_t ha_t; -struct ha_t -{ - hacs_u ha_cs; /* Command and status registers */ -#define ha_command ha_cs.hu_command -#define ha_status ha_cs.hu_status - unsigned short ha_mmcr; /* Modem Management Ctrl Register */ - unsigned short ha_pior0; /* Program I/O Address Register Port 0 */ - unsigned short ha_piop0; /* Program I/O Port 0 */ - unsigned short ha_pior1; /* Program I/O Address Register Port 1 */ - unsigned short ha_piop1; /* Program I/O Port 1 */ - unsigned short ha_pior2; /* Program I/O Address Register Port 2 */ - unsigned short ha_piop2; /* Program I/O Port 2 */ -}; - -#define HA_SIZE 16 - -#define hoff(p,f) (unsigned short)((void *)(&((ha_t *)((void *)0 + (p)))->f) - (void *)0) -#define HACR(p) hoff(p, ha_command) -#define HASR(p) hoff(p, ha_status) -#define MMCR(p) hoff(p, ha_mmcr) -#define PIOR0(p) hoff(p, ha_pior0) -#define PIOP0(p) hoff(p, ha_piop0) -#define PIOR1(p) hoff(p, ha_pior1) -#define PIOP1(p) hoff(p, ha_piop1) -#define PIOR2(p) hoff(p, ha_pior2) -#define PIOP2(p) hoff(p, ha_piop2) - -/* - * Program I/O Mode Register values. - */ -#define STATIC_PIO 0 /* Mode 1: static mode */ - /* RAM access ??? */ -#define AUTOINCR_PIO 1 /* Mode 2: auto increment mode */ - /* RAM access ??? */ -#define AUTODECR_PIO 2 /* Mode 3: auto decrement mode */ - /* RAM access ??? */ -#define PARAM_ACCESS_PIO 3 /* Mode 4: LAN parameter access mode */ - /* Parameter access. */ -#define PIO_MASK 3 /* register mask */ -#define PIOM(cmd,piono) ((u_short)cmd << 10 << (piono * 2)) - -#define HACR_DEFAULT (HACR_OUT0 | HACR_OUT1 | HACR_16BITS | PIOM(STATIC_PIO, 0) | PIOM(AUTOINCR_PIO, 1) | PIOM(PARAM_ACCESS_PIO, 2)) -#define HACR_INTRON (HACR_82586_INT_ENABLE | HACR_MMC_INT_ENABLE | HACR_INTR_CLR_ENABLE) - -/************************** MEMORY LAYOUT **************************/ - -/* - * Onboard 64 k RAM layout. - * (Offsets from 0x0000.) - */ -#define OFFSET_RU 0x0000 /* 75% memory */ -#define OFFSET_CU 0xC000 /* 25% memory */ -#define OFFSET_SCB (OFFSET_ISCP - sizeof(scb_t)) -#define OFFSET_ISCP (OFFSET_SCP - sizeof(iscp_t)) -#define OFFSET_SCP I82586_SCP_ADDR - -#define RXBLOCKZ (sizeof(fd_t) + sizeof(rbd_t) + MAXDATAZ) -#define TXBLOCKZ (sizeof(ac_tx_t) + sizeof(ac_nop_t) + sizeof(tbd_t) + MAXDATAZ) - -#define NRXBLOCKS ((OFFSET_CU - OFFSET_RU) / RXBLOCKZ) -#define NTXBLOCKS ((OFFSET_SCB - OFFSET_CU) / TXBLOCKZ) - -/********************** PARAMETER STORAGE AREA **********************/ - -/* - * Parameter Storage Area (PSA). - */ -typedef struct psa_t psa_t; -struct psa_t -{ - unsigned char psa_io_base_addr_1; /* [0x00] Base address 1 ??? */ - unsigned char psa_io_base_addr_2; /* [0x01] Base address 2 */ - unsigned char psa_io_base_addr_3; /* [0x02] Base address 3 */ - unsigned char psa_io_base_addr_4; /* [0x03] Base address 4 */ - unsigned char psa_rem_boot_addr_1; /* [0x04] Remote Boot Address 1 */ - unsigned char psa_rem_boot_addr_2; /* [0x05] Remote Boot Address 2 */ - unsigned char psa_rem_boot_addr_3; /* [0x06] Remote Boot Address 3 */ - unsigned char psa_holi_params; /* [0x07] HOst Lan Interface (HOLI) Parameters */ - unsigned char psa_int_req_no; /* [0x08] Interrupt Request Line */ - unsigned char psa_unused0[7]; /* [0x09-0x0F] unused */ - - unsigned char psa_univ_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x10-0x15] Universal (factory) MAC Address */ - unsigned char psa_local_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x16-1B] Local MAC Address */ - unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */ -#define PSA_UNIVERSAL 0 /* Universal (factory) */ -#define PSA_LOCAL 1 /* Local */ - unsigned char psa_comp_number; /* [0x1D] Compatibility Number: */ -#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ -#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ -#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ -#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ -#define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */ - unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ - unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */ -#define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */ - unsigned char psa_subband; /* [0x20] Subband */ -#define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */ -#define PSA_SUBBAND_2425 1 /* 2425 MHz */ -#define PSA_SUBBAND_2460 2 /* 2460 MHz */ -#define PSA_SUBBAND_2484 3 /* 2484 MHz */ -#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ - unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */ - unsigned char psa_mod_delay; /* [0x22] Modem Delay (?) (reserved) */ - unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */ - unsigned char psa_nwid_select; /* [0x25] Network ID Select On/Off */ - unsigned char psa_encryption_select; /* [0x26] Encryption On/Off */ - unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ - unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */ - unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ - unsigned char psa_nwid_prefix[2]; /* [0x38-0x39] Roaming domain */ - unsigned char psa_reserved[2]; /* [0x3A-0x3B] Reserved - fixed 00 */ - unsigned char psa_conf_status; /* [0x3C] Conf Status, bit 0=1:config*/ - unsigned char psa_crc[2]; /* [0x3D] CRC-16 over PSA */ - unsigned char psa_crc_status; /* [0x3F] CRC Valid Flag */ -}; - -#define PSA_SIZE 64 - -/* Calculate offset of a field in the above structure. - * Warning: only even addresses are used. */ -#define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL)) - -/******************** MODEM MANAGEMENT INTERFACE ********************/ - -/* - * Modem Management Controller (MMC) write structure. - */ -typedef struct mmw_t mmw_t; -struct mmw_t -{ - unsigned char mmw_encr_key[8]; /* encryption key */ - unsigned char mmw_encr_enable; /* Enable or disable encryption. */ -#define MMW_ENCR_ENABLE_MODE 0x02 /* mode of security option */ -#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option. */ - unsigned char mmw_unused0[1]; /* unused */ - unsigned char mmw_des_io_invert; /* encryption option */ -#define MMW_DES_IO_INVERT_RES 0x0F /* reserved */ -#define MMW_DES_IO_INVERT_CTRL 0xF0 /* control (?) (set to 0) */ - unsigned char mmw_unused1[5]; /* unused */ - unsigned char mmw_loopt_sel; /* looptest selection */ -#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* Disable NWID filtering. */ -#define MMW_LOOPT_SEL_INT 0x20 /* Activate Attention Request. */ -#define MMW_LOOPT_SEL_LS 0x10 /* looptest, no collision avoidance */ -#define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */ -#define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */ -#define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */ -#define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */ - unsigned char mmw_jabber_enable; /* jabber timer enable */ - /* Abort transmissions > 200 ms */ - unsigned char mmw_freeze; /* freeze or unfreeze signal level */ - /* 0 : signal level & qual updated for every new message, 1 : frozen */ - unsigned char mmw_anten_sel; /* antenna selection */ -#define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */ -#define MMW_ANTEN_SEL_ALG_EN 0x02 /* antenna selection algo. enable */ - unsigned char mmw_ifs; /* inter frame spacing */ - /* min time between transmission in bit periods (.5 us) - bit 0 ignored */ - unsigned char mmw_mod_delay; /* modem delay (synchro) */ - unsigned char mmw_jam_time; /* jamming time (after collision) */ - unsigned char mmw_unused2[1]; /* unused */ - unsigned char mmw_thr_pre_set; /* level threshold preset */ - /* Discard all packet with signal < this value (4) */ - unsigned char mmw_decay_prm; /* decay parameters */ - unsigned char mmw_decay_updat_prm; /* decay update parameters */ - unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ - /* Discard all packet with quality < this value (3) */ - unsigned char mmw_netw_id_l; /* NWID low order byte */ - unsigned char mmw_netw_id_h; /* NWID high order byte */ - /* Network ID or Domain : create virtual net on the air */ - - /* 2.0 Hardware extension - frequency selection support */ - unsigned char mmw_mode_select; /* for analog tests (set to 0) */ - unsigned char mmw_unused3[1]; /* unused */ - unsigned char mmw_fee_ctrl; /* frequency EEPROM control */ -#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions. */ -#define MMW_FEE_CTRL_DWLD 0x08 /* Download EEPROM to mmc. */ -#define MMW_FEE_CTRL_CMD 0x07 /* EEPROM commands: */ -#define MMW_FEE_CTRL_READ 0x06 /* Read */ -#define MMW_FEE_CTRL_WREN 0x04 /* Write enable */ -#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address. */ -#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses. */ -#define MMW_FEE_CTRL_WDS 0x04 /* Write disable */ -#define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */ -#define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */ -#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers. */ -#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write address in protect register */ -#define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */ - /* Never issue the PRDS command: it's irreversible! */ - - unsigned char mmw_fee_addr; /* EEPROM address */ -#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel. */ -#define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */ -#define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */ -#define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */ -#define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */ -#define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */ - - unsigned char mmw_fee_data_l; /* Write data to EEPROM. */ - unsigned char mmw_fee_data_h; /* high octet */ - unsigned char mmw_ext_ant; /* Setting for external antenna */ -#define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */ -#define MMW_EXT_ANT_POL 0x02 /* Polarity of the antenna */ -#define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ -#define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ -#define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ -} __attribute__ ((packed)); - -#define MMW_SIZE 37 - -#define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) - -/* - * Modem Management Controller (MMC) read structure. - */ -typedef struct mmr_t mmr_t; -struct mmr_t -{ - unsigned char mmr_unused0[8]; /* unused */ - unsigned char mmr_des_status; /* encryption status */ - unsigned char mmr_des_avail; /* encryption available (0x55 read) */ -#define MMR_DES_AVAIL_DES 0x55 /* DES available */ -#define MMR_DES_AVAIL_AES 0x33 /* AES (AT&T) available */ - unsigned char mmr_des_io_invert; /* des I/O invert register */ - unsigned char mmr_unused1[5]; /* unused */ - unsigned char mmr_dce_status; /* DCE status */ -#define MMR_DCE_STATUS_RX_BUSY 0x01 /* receiver busy */ -#define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ -#define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ -#define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ -#define MMR_DCE_STATUS 0x0F /* mask to get the bits */ - unsigned char mmr_dsp_id; /* DSP ID (AA = Daedalus rev A) */ - unsigned char mmr_unused2[2]; /* unused */ - unsigned char mmr_correct_nwid_l; /* # of correct NWIDs rxd (low) */ - unsigned char mmr_correct_nwid_h; /* # of correct NWIDs rxd (high) */ - /* Warning: read high-order octet first! */ - unsigned char mmr_wrong_nwid_l; /* # of wrong NWIDs rxd (low) */ - unsigned char mmr_wrong_nwid_h; /* # of wrong NWIDs rxd (high) */ - unsigned char mmr_thr_pre_set; /* level threshold preset */ -#define MMR_THR_PRE_SET 0x3F /* level threshold preset */ -#define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */ - unsigned char mmr_signal_lvl; /* signal level */ -#define MMR_SIGNAL_LVL 0x3F /* signal level */ -#define MMR_SIGNAL_LVL_VALID 0x80 /* Updated since last read */ - unsigned char mmr_silence_lvl; /* silence level (noise) */ -#define MMR_SILENCE_LVL 0x3F /* silence level */ -#define MMR_SILENCE_LVL_VALID 0x80 /* Updated since last read */ - unsigned char mmr_sgnl_qual; /* signal quality */ -#define MMR_SGNL_QUAL 0x0F /* signal quality */ -#define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */ - unsigned char mmr_netw_id_l; /* NWID low order byte (?) */ - unsigned char mmr_unused3[3]; /* unused */ - - /* 2.0 Hardware extension - frequency selection support */ - unsigned char mmr_fee_status; /* Status of frequency EEPROM */ -#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision ID */ -#define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */ -#define MMR_FEE_STATUS_BUSY 0x04 /* EEPROM busy */ - unsigned char mmr_unused4[1]; /* unused */ - unsigned char mmr_fee_data_l; /* Read data from EEPROM (low) */ - unsigned char mmr_fee_data_h; /* Read data from EEPROM (high) */ -} __attribute__ ((packed)); - -#define MMR_SIZE 36 - -#define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) - -/* Make the two above structures one */ -typedef union mm_t -{ - struct mmw_t w; /* Write to the mmc */ - struct mmr_t r; /* Read from the mmc */ -} mm_t; - -#endif /* _WAVELAN_H */ - -/* - * This software may only be used and distributed - * according to the terms of the GNU General Public License. - * - * For more details, see wavelan.c. - */ diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h deleted file mode 100644 index dbe8de6e5f52..000000000000 --- a/drivers/net/wireless/wavelan.p.h +++ /dev/null @@ -1,696 +0,0 @@ -/* - * WaveLAN ISA driver - * - * Jean II - HPLB '96 - * - * Reorganisation and extension of the driver. - * - * This file contains all definitions and declarations necessary for the - * WaveLAN ISA driver. This file is a private header, so it should - * be included only in wavelan.c! - */ - -#ifndef WAVELAN_P_H -#define WAVELAN_P_H - -/************************** DOCUMENTATION ***************************/ -/* - * This driver provides a Linux interface to the WaveLAN ISA hardware. - * The WaveLAN is a product of Lucent (http://www.wavelan.com/). - * This division was formerly part of NCR and then AT&T. - * WaveLANs are also distributed by DEC (RoamAbout DS) and Digital Ocean. - * - * To learn how to use this driver, read the NET3 HOWTO. - * If you want to exploit the many other functionalities, read the comments - * in the code. - * - * This driver is the result of the effort of many people (see below). - */ - -/* ------------------------ SPECIFIC NOTES ------------------------ */ -/* - * Web page - * -------- - * I try to maintain a web page with the Wireless LAN Howto at : - * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html - * - * SMP - * --- - * We now are SMP compliant (I eventually fixed the remaining bugs). - * The driver has been tested on a dual P6-150 and survived my usual - * set of torture tests. - * Anyway, I spent enough time chasing interrupt re-entrancy during - * errors or reconfigure, and I designed the locked/unlocked sections - * of the driver with great care, and with the recent addition of - * the spinlock (thanks to the new API), we should be quite close to - * the truth. - * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), - * but better safe than sorry (especially at 2 Mb/s ;-). - * - * I have also looked into disabling only our interrupt on the card - * (via HACR) instead of all interrupts in the processor (via cli), - * so that other driver are not impacted, and it look like it's - * possible, but it's very tricky to do right (full of races). As - * the gain would be mostly for SMP systems, it can wait... - * - * Debugging and options - * --------------------- - * You will find below a set of '#define" allowing a very fine control - * on the driver behaviour and the debug messages printed. - * The main options are : - * o SET_PSA_CRC, to have your card correctly recognised by - * an access point and the Point-to-Point diagnostic tool. - * o USE_PSA_CONFIG, to read configuration from the PSA (EEprom) - * (otherwise we always start afresh with some defaults) - * - * wavelan.o is too darned big - * --------------------------- - * That's true! There is a very simple way to reduce the driver - * object by 33%! Comment out the following line: - * #include - * Other compile options can also reduce the size of it... - * - * MAC address and hardware detection: - * ----------------------------------- - * The detection code for the WaveLAN checks that the first three - * octets of the MAC address fit the company code. This type of - * detection works well for AT&T cards (because the AT&T code is - * hardcoded in wavelan.h), but of course will fail for other - * manufacturers. - * - * If you are sure that your card is derived from the WaveLAN, - * here is the way to configure it: - * 1) Get your MAC address - * a) With your card utilities (wfreqsel, instconf, etc.) - * b) With the driver: - * o compile the kernel with DEBUG_CONFIG_INFO enabled - * o Boot and look the card messages - * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h) - * 3) Compile and verify - * 4) Send me the MAC code. I will include it in the next version. - * - */ - -/* --------------------- WIRELESS EXTENSIONS --------------------- */ -/* - * This driver is the first to support "wireless extensions". - * This set of extensions provides a standard way to control the wireless - * characteristics of the hardware. Applications such as mobile IP may - * take advantage of it. - * - * It might be a good idea as well to fetch the wireless tools to - * configure the device and play a bit. - */ - -/* ---------------------------- FILES ---------------------------- */ -/* - * wavelan.c: actual code for the driver: C functions - * - * wavelan.p.h: private header: local types and variables for driver - * - * wavelan.h: description of the hardware interface and structs - * - * i82586.h: description of the Ethernet controller - */ - -/* --------------------------- HISTORY --------------------------- */ -/* - * This is based on information in the drivers' headers. It may not be - * accurate, and I guarantee only my best effort. - * - * The history of the WaveLAN drivers is as complicated as the history of - * the WaveLAN itself (NCR -> AT&T -> Lucent). - * - * It all started with Anders Klemets - * writing a WaveLAN ISA driver for the Mach microkernel. Girish - * Welling had also worked on it. - * Keith Moore modified this for the PCMCIA hardware. - * - * Robert Morris ported these two drivers to BSDI - * and added specific PCMCIA support (there is currently no equivalent - * of the PCMCIA package under BSD). - * - * Jim Binkley ported both BSDI drivers to FreeBSD. - * - * Bruce Janson ported the BSDI ISA driver to Linux. - * - * Anthony D. Joseph started to modify Bruce's driver - * (with help of the BSDI PCMCIA driver) for PCMCIA. - * Yunzhou Li finished this work. - * Joe Finney patched the driver to start - * 2.00 cards correctly (2.4 GHz with frequency selection). - * David Hinds integrated the whole in his - * PCMCIA package (and bug corrections). - * - * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some - * patches to the PCMCIA driver. Later, I added code in the ISA driver - * for Wireless Extensions and full support of frequency selection - * cards. Then, I did the same to the PCMCIA driver, and did some - * reorganisation. Finally, I came back to the ISA driver to - * upgrade it at the same level as the PCMCIA one and reorganise - * the code. - * Loeke Brederveld from Lucent has given me - * much needed information on the WaveLAN hardware. - */ - -/* The original copyrights and literature mention others' names and - * credits. I don't know what their part in this development was. - */ - -/* By the way, for the copyright and legal stuff: - * almost everybody wrote code under the GNU or BSD license (or similar), - * and want their original copyright to remain somewhere in the - * code (for myself, I go with the GPL). - * Nobody wants to take responsibility for anything, except the fame. - */ - -/* --------------------------- CREDITS --------------------------- */ -/* - * This software was developed as a component of the - * Linux operating system. - * It is based on other device drivers and information - * either written or supplied by: - * Ajay Bakre , - * Donald Becker , - * Loeke Brederveld , - * Brent Elphick , - * Anders Klemets , - * Vladimir V. Kolpakov , - * Marc Meertens , - * Pauline Middelink , - * Robert Morris , - * Jean Tourrilhes , - * Girish Welling , - * Clark Woodworth - * Yongguang Zhang - * - * Thanks go also to: - * James Ashton , - * Alan Cox , - * Allan Creighton , - * Matthew Geier , - * Remo di Giovanni , - * Eckhard Grah , - * Vipul Gupta , - * Mark Hagan , - * Tim Nicholson , - * Ian Parkin , - * John Rosenberg , - * George Rossi , - * Arthur Scott , - * Stanislav Sinyagin - * and Peter Storey for their assistance and advice. - * - * Additional Credits: - * - * My development has been done initially under Debian 1.1 (Linux 2.0.x) - * and now under Debian 2.2, initially with an HP Vectra XP/60, and now - * an HP Vectra XP/90. - * - */ - -/* ------------------------- IMPROVEMENTS ------------------------- */ -/* - * I proudly present: - * - * Changes made in first pre-release: - * ---------------------------------- - * - reorganisation of the code, function name change - * - creation of private header (wavelan.p.h) - * - reorganised debug messages - * - more comments, history, etc. - * - mmc_init: configure the PSA if not done - * - mmc_init: correct default value of level threshold for PCMCIA - * - mmc_init: 2.00 detection better code for 2.00 initialization - * - better info at startup - * - IRQ setting (note: this setting is permanent) - * - watchdog: change strategy (and solve module removal problems) - * - add wireless extensions (ioctl and get_wireless_stats) - * get/set nwid/frequency on fly, info for /proc/net/wireless - * - more wireless extensions: SETSPY and GETSPY - * - make wireless extensions optional - * - private ioctl to set/get quality and level threshold, histogram - * - remove /proc/net/wavelan - * - suppress useless stuff from lp (net_local) - * - kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) - * - add message level (debug stuff in /var/adm/debug and errors not - * displayed at console and still in /var/adm/messages) - * - multi device support - * - start fixing the probe (init code) - * - more inlines - * - man page - * - many other minor details and cleanups - * - * Changes made in second pre-release: - * ----------------------------------- - * - clean up init code (probe and module init) - * - better multiple device support (module) - * - name assignment (module) - * - * Changes made in third pre-release: - * ---------------------------------- - * - be more conservative on timers - * - preliminary support for multicast (I still lack some details) - * - * Changes made in fourth pre-release: - * ----------------------------------- - * - multicast (revisited and finished) - * - avoid reset in set_multicast_list (a really big hack) - * if somebody could apply this code for other i82586 based drivers - * - share onboard memory 75% RU and 25% CU (instead of 50/50) - * - * Changes made for release in 2.1.15: - * ----------------------------------- - * - change the detection code for multi manufacturer code support - * - * Changes made for release in 2.1.17: - * ----------------------------------- - * - update to wireless extensions changes - * - silly bug in card initial configuration (psa_conf_status) - * - * Changes made for release in 2.1.27 & 2.0.30: - * -------------------------------------------- - * - small bug in debug code (probably not the last one...) - * - remove extern keyword for wavelan_probe() - * - level threshold is now a standard wireless extension (version 4 !) - * - modules parameters types (new module interface) - * - * Changes made for release in 2.1.36: - * ----------------------------------- - * - byte count stats (courtesy of David Hinds) - * - remove dev_tint stuff (courtesy of David Hinds) - * - encryption setting from Brent Elphick (thanks a lot!) - * - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) - * - * Other changes (not by me) : - * ------------------------- - * - Spelling and gramar "rectification". - * - * Changes made for release in 2.0.37 & 2.2.2 : - * ------------------------------------------ - * - Correct status in /proc/net/wireless - * - Set PSA CRC to make PtP diagnostic tool happy (Bob Gray) - * - Module init code don't fail if we found at least one card in - * the address list (Karlis Peisenieks) - * - Missing parenthesis (Christopher Peterson) - * - Correct i82586 configuration parameters - * - Encryption initialisation bug (Robert McCormack) - * - New mac addresses detected in the probe - * - Increase watchdog for busy environments - * - * Changes made for release in 2.0.38 & 2.2.7 : - * ------------------------------------------ - * - Correct the reception logic to better report errors and avoid - * sending bogus packet up the stack - * - Delay RU config to avoid corrupting first received packet - * - Change config completion code (to actually check something) - * - Avoid reading out of bound in skbuf to transmit - * - Rectify a lot of (useless) debugging code - * - Change the way to `#ifdef SET_PSA_CRC' - * - * Changes made for release in 2.2.11 & 2.3.13 : - * ------------------------------------------- - * - Change e-mail and web page addresses - * - Watchdog timer is now correctly expressed in HZ, not in jiffies - * - Add channel number to the list of frequencies in range - * - Add the (short) list of bit-rates in range - * - Developp a new sensitivity... (sens.value & sens.fixed) - * - * Changes made for release in 2.2.14 & 2.3.23 : - * ------------------------------------------- - * - Fix check for root permission (break instead of exit) - * - New nwid & encoding setting (Wireless Extension 9) - * - * Changes made for release in 2.3.49 : - * ---------------------------------- - * - Indentation reformating (Alan) - * - Update to new network API (softnet - 2.3.43) : - * o replace dev->tbusy (Alan) - * o replace dev->tstart (Alan) - * o remove dev->interrupt (Alan) - * o add SMP locking via spinlock in splxx (me) - * o add spinlock in interrupt handler (me) - * o use kernel watchdog instead of ours (me) - * o increase watchdog timeout (kernel is more sensitive) (me) - * o verify that all the changes make sense and work (me) - * - Fixup a potential gotcha when reconfiguring and thighten a bit - * the interactions with Tx queue. - * - * Changes made for release in 2.4.0 : - * --------------------------------- - * - Fix spinlock stupid bugs that I left in. The driver is now SMP - * compliant and doesn't lockup at startup. - * - * Changes made for release in 2.5.2 : - * --------------------------------- - * - Use new driver API for Wireless Extensions : - * o got rid of wavelan_ioctl() - * o use a bunch of iw_handler instead - * - * Changes made for release in 2.5.35 : - * ---------------------------------- - * - Set dev->trans_start to avoid filling the logs - * - Handle better spurious/bogus interrupt - * - Avoid deadlocks in mmc_out()/mmc_in() - * - * Wishes & dreams: - * ---------------- - * - roaming (see Pcmcia driver) - */ - -/***************************** INCLUDES *****************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include /* Wireless extensions */ -#include /* Wireless handlers */ - -/* WaveLAN declarations */ -#include "i82586.h" -#include "wavelan.h" - -/************************** DRIVER OPTIONS **************************/ -/* - * `#define' or `#undef' the following constant to change the behaviour - * of the driver... - */ -#undef SET_PSA_CRC /* Calculate and set the CRC on PSA (slower) */ -#define USE_PSA_CONFIG /* Use info from the PSA. */ -#undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */ -#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ -#undef SET_MAC_ADDRESS /* Experimental */ - -/* Warning: this stuff will slow down the driver. */ -#define WIRELESS_SPY /* Enable spying addresses. */ -#undef HISTOGRAM /* Enable histogram of signal level. */ - -/****************************** DEBUG ******************************/ - -#undef DEBUG_MODULE_TRACE /* module insertion/removal */ -#undef DEBUG_CALLBACK_TRACE /* calls made by Linux */ -#undef DEBUG_INTERRUPT_TRACE /* calls to handler */ -#undef DEBUG_INTERRUPT_INFO /* type of interrupt and so on */ -#define DEBUG_INTERRUPT_ERROR /* problems */ -#undef DEBUG_CONFIG_TRACE /* Trace the config functions. */ -#undef DEBUG_CONFIG_INFO /* what's going on */ -#define DEBUG_CONFIG_ERROR /* errors on configuration */ -#undef DEBUG_TX_TRACE /* transmission calls */ -#undef DEBUG_TX_INFO /* header of the transmitted packet */ -#undef DEBUG_TX_FAIL /* Normal failure conditions */ -#define DEBUG_TX_ERROR /* Unexpected conditions */ -#undef DEBUG_RX_TRACE /* transmission calls */ -#undef DEBUG_RX_INFO /* header of the received packet */ -#undef DEBUG_RX_FAIL /* Normal failure conditions */ -#define DEBUG_RX_ERROR /* Unexpected conditions */ - -#undef DEBUG_PACKET_DUMP /* Dump packet on the screen if defined to 32. */ -#undef DEBUG_IOCTL_TRACE /* misc. call by Linux */ -#undef DEBUG_IOCTL_INFO /* various debugging info */ -#define DEBUG_IOCTL_ERROR /* what's going wrong */ -#define DEBUG_BASIC_SHOW /* Show basic startup info. */ -#undef DEBUG_VERSION_SHOW /* Print version info. */ -#undef DEBUG_PSA_SHOW /* Dump PSA to screen. */ -#undef DEBUG_MMC_SHOW /* Dump mmc to screen. */ -#undef DEBUG_SHOW_UNUSED /* Show unused fields too. */ -#undef DEBUG_I82586_SHOW /* Show i82586 status. */ -#undef DEBUG_DEVICE_SHOW /* Show device parameters. */ - -/************************ CONSTANTS & MACROS ************************/ - -#ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v24 (SMP + wireless extensions) 11/12/01\n"; -#endif - -/* Watchdog temporisation */ -#define WATCHDOG_JIFFIES (512*HZ/100) - -/* ------------------------ PRIVATE IOCTL ------------------------ */ - -#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ -#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ - -#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 2 /* Set histogram ranges */ -#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 3 /* Get histogram values */ - -/****************************** TYPES ******************************/ - -/* Shortcuts */ -typedef struct iw_statistics iw_stats; -typedef struct iw_quality iw_qual; -typedef struct iw_freq iw_freq;typedef struct net_local net_local; -typedef struct timer_list timer_list; - -/* Basic types */ -typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ - -/* - * Static specific data for the interface. - * - * For each network interface, Linux keeps data in two structures: "device" - * keeps the generic data (same format for everybody) and "net_local" keeps - * additional specific data. - */ -struct net_local -{ - net_local * next; /* linked list of the devices */ - struct net_device * dev; /* reverse link */ - spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ - int nresets; /* number of hardware resets */ - u_char reconfig_82586; /* We need to reconfigure the controller. */ - u_char promiscuous; /* promiscuous mode */ - int mc_count; /* number of multicast addresses */ - u_short hacr; /* current host interface state */ - - int tx_n_in_use; - u_short rx_head; - u_short rx_last; - u_short tx_first_free; - u_short tx_first_in_use; - - iw_stats wstats; /* Wireless-specific statistics */ - - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; - -#ifdef HISTOGRAM - int his_number; /* number of intervals */ - u_char his_range[16]; /* boundaries of interval ]n-1; n] */ - u_long his_sum[16]; /* sum in interval */ -#endif /* HISTOGRAM */ -}; - -/**************************** PROTOTYPES ****************************/ - -/* ----------------------- MISC. SUBROUTINES ------------------------ */ -static u_char - wv_irq_to_psa(int); -static int - wv_psa_to_irq(u_char); -/* ------------------- HOST ADAPTER SUBROUTINES ------------------- */ -static inline u_short /* data */ - hasr_read(u_long); /* Read the host interface: base address */ -static inline void - hacr_write(u_long, /* Write to host interface: base address */ - u_short), /* data */ - hacr_write_slow(u_long, - u_short), - set_chan_attn(u_long, /* ioaddr */ - u_short), /* hacr */ - wv_hacr_reset(u_long), /* ioaddr */ - wv_16_off(u_long, /* ioaddr */ - u_short), /* hacr */ - wv_16_on(u_long, /* ioaddr */ - u_short), /* hacr */ - wv_ints_off(struct net_device *), - wv_ints_on(struct net_device *); -/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ -static void - psa_read(u_long, /* Read the Parameter Storage Area. */ - u_short, /* hacr */ - int, /* offset in PSA */ - u_char *, /* buffer to fill */ - int), /* size to read */ - psa_write(u_long, /* Write to the PSA. */ - u_short, /* hacr */ - int, /* offset in PSA */ - u_char *, /* buffer in memory */ - int); /* length of buffer */ -static inline void - mmc_out(u_long, /* Write 1 byte to the Modem Manag Control. */ - u_short, - u_char), - mmc_write(u_long, /* Write n bytes to the MMC. */ - u_char, - u_char *, - int); -static inline u_char /* Read 1 byte from the MMC. */ - mmc_in(u_long, - u_short); -static inline void - mmc_read(u_long, /* Read n bytes from the MMC. */ - u_char, - u_char *, - int), - fee_wait(u_long, /* Wait for frequency EEPROM: base address */ - int, /* base delay to wait for */ - int); /* time to wait */ -static void - fee_read(u_long, /* Read the frequency EEPROM: base address */ - u_short, /* destination offset */ - u_short *, /* data buffer */ - int); /* number of registers */ -/* ---------------------- I82586 SUBROUTINES ----------------------- */ -static /*inline*/ void - obram_read(u_long, /* ioaddr */ - u_short, /* o */ - u_char *, /* b */ - int); /* n */ -static inline void - obram_write(u_long, /* ioaddr */ - u_short, /* o */ - u_char *, /* b */ - int); /* n */ -static void - wv_ack(struct net_device *); -static inline int - wv_synchronous_cmd(struct net_device *, - const char *), - wv_config_complete(struct net_device *, - u_long, - net_local *); -static int - wv_complete(struct net_device *, - u_long, - net_local *); -static inline void - wv_82586_reconfig(struct net_device *); -/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ -#ifdef DEBUG_I82586_SHOW -static void - wv_scb_show(unsigned short); -#endif -static inline void - wv_init_info(struct net_device *); /* display startup info */ -/* ------------------- IOCTL, STATS & RECONFIG ------------------- */ -static iw_stats * - wavelan_get_wireless_stats(struct net_device *); -static void - wavelan_set_multicast_list(struct net_device *); -/* ----------------------- PACKET RECEPTION ----------------------- */ -static inline void - wv_packet_read(struct net_device *, /* Read a packet from a frame. */ - u_short, - int), - wv_receive(struct net_device *); /* Read all packets waiting. */ -/* --------------------- PACKET TRANSMISSION --------------------- */ -static inline int - wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer. */ - void *, - short); -static netdev_tx_t - wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */ - struct net_device *); -/* -------------------- HARDWARE CONFIGURATION -------------------- */ -static inline int - wv_mmc_init(struct net_device *), /* Initialize the modem. */ - wv_ru_start(struct net_device *), /* Start the i82586 receiver unit. */ - wv_cu_start(struct net_device *), /* Start the i82586 command unit. */ - wv_82586_start(struct net_device *); /* Start the i82586. */ -static void - wv_82586_config(struct net_device *); /* Configure the i82586. */ -static inline void - wv_82586_stop(struct net_device *); -static int - wv_hw_reset(struct net_device *), /* Reset the WaveLAN hardware. */ - wv_check_ioaddr(u_long, /* ioaddr */ - u_char *); /* mac address (read) */ -/* ---------------------- INTERRUPT HANDLING ---------------------- */ -static irqreturn_t - wavelan_interrupt(int, /* interrupt handler */ - void *); -static void - wavelan_watchdog(struct net_device *); /* transmission watchdog */ -/* ------------------- CONFIGURATION CALLBACKS ------------------- */ -static int - wavelan_open(struct net_device *), /* Open the device. */ - wavelan_close(struct net_device *), /* Close the device. */ - wavelan_config(struct net_device *, unsigned short);/* Configure one device. */ -extern struct net_device *wavelan_probe(int unit); /* See Space.c. */ - -/**************************** VARIABLES ****************************/ - -/* - * This is the root of the linked list of WaveLAN drivers - * It is use to verify that we don't reuse the same base address - * for two different drivers and to clean up when removing the module. - */ -static net_local * wavelan_list = (net_local *) NULL; - -/* - * This table is used to translate the PSA value to IRQ number - * and vice versa. - */ -static u_char irqvals[] = -{ - 0, 0, 0, 0x01, - 0x02, 0x04, 0, 0x08, - 0, 0, 0x10, 0x20, - 0x40, 0, 0, 0x80, -}; - -/* - * Table of the available I/O addresses (base addresses) for WaveLAN - */ -static unsigned short iobase[] = -{ -#if 0 - /* Leave out 0x3C0 for now -- seems to clash with some video - * controllers. - * Leave out the others too -- we will always use 0x390 and leave - * 0x300 for the Ethernet device. - * Jean II: 0x3E0 is fine as well. - */ - 0x300, 0x390, 0x3E0, 0x3C0 -#endif /* 0 */ - 0x390, 0x3E0 -}; - -#ifdef MODULE -/* Parameters set by insmod */ -static int io[4]; -static int irq[4]; -static char *name[4]; -module_param_array(io, int, NULL, 0); -module_param_array(irq, int, NULL, 0); -module_param_array(name, charp, NULL, 0); - -MODULE_PARM_DESC(io, "WaveLAN I/O base address(es),required"); -MODULE_PARM_DESC(irq, "WaveLAN IRQ number(s)"); -MODULE_PARM_DESC(name, "WaveLAN interface neme(s)"); -#endif /* MODULE */ - -#endif /* WAVELAN_P_H */ diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c deleted file mode 100644 index 431a20ec6db6..000000000000 --- a/drivers/net/wireless/wavelan_cs.c +++ /dev/null @@ -1,4635 +0,0 @@ -/* - * Wavelan Pcmcia driver - * - * Jean II - HPLB '96 - * - * Reorganisation and extension of the driver. - * Original copyright follow. See wavelan_cs.p.h for details. - * - * This code is derived from Anthony D. Joseph's code and all the changes here - * are also under the original copyright below. - * - * This code supports version 2.00 of WaveLAN/PCMCIA cards (2.4GHz), and - * can work on Linux 2.0.36 with support of David Hinds' PCMCIA Card Services - * - * Joe Finney (joe@comp.lancs.ac.uk) at Lancaster University in UK added - * critical code in the routine to initialize the Modem Management Controller. - * - * Thanks to Alan Cox and Bruce Janson for their advice. - * - * -- Yunzhou Li (scip4166@nus.sg) - * -#ifdef WAVELAN_ROAMING - * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu) - * based on patch by Joe Finney from Lancaster University. -#endif - * - * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An - * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor. - * - * A non-shared memory PCMCIA ethernet driver for linux - * - * ISA version modified to support PCMCIA by Anthony Joseph (adj@lcs.mit.edu) - * - * - * Joseph O'Sullivan & John Langford (josullvn@cs.cmu.edu & jcl@cs.cmu.edu) - * - * Apr 2 '98 made changes to bring the i82593 control/int handling in line - * with offical specs... - * - **************************************************************************** - * Copyright 1995 - * Anthony D. Joseph - * Massachusetts Institute of Technology - * - * Permission to use, copy, modify, and distribute this program - * for any purpose and without fee is hereby granted, provided - * that this copyright and permission notice appear on all copies - * and supporting documentation, the name of M.I.T. not be used - * in advertising or publicity pertaining to distribution of the - * program without specific prior permission, and notice be given - * in supporting documentation that copying and distribution is - * by permission of M.I.T. M.I.T. makes no representations about - * the suitability of this software for any purpose. It is pro- - * vided "as is" without express or implied warranty. - **************************************************************************** - * - */ - -/* Do *NOT* add other headers here, you are guaranteed to be wrong - Jean II */ -#include "wavelan_cs.p.h" /* Private header */ - -#ifdef WAVELAN_ROAMING -static void wl_cell_expiry(unsigned long data); -static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp); -static void wv_nwid_filter(unsigned char mode, net_local *lp); -#endif /* WAVELAN_ROAMING */ - -/************************* MISC SUBROUTINES **************************/ -/* - * Subroutines which won't fit in one of the following category - * (wavelan modem or i82593) - */ - -/******************* MODEM MANAGEMENT SUBROUTINES *******************/ -/* - * Useful subroutines to manage the modem of the wavelan - */ - -/*------------------------------------------------------------------*/ -/* - * Read from card's Host Adaptor Status Register. - */ -static inline u_char -hasr_read(u_long base) -{ - return(inb(HASR(base))); -} /* hasr_read */ - -/*------------------------------------------------------------------*/ -/* - * Write to card's Host Adapter Command Register. - */ -static inline void -hacr_write(u_long base, - u_char hacr) -{ - outb(hacr, HACR(base)); -} /* hacr_write */ - -/*------------------------------------------------------------------*/ -/* - * Write to card's Host Adapter Command Register. Include a delay for - * those times when it is needed. - */ -static void -hacr_write_slow(u_long base, - u_char hacr) -{ - hacr_write(base, hacr); - /* delay might only be needed sometimes */ - mdelay(1); -} /* hacr_write_slow */ - -/*------------------------------------------------------------------*/ -/* - * Read the Parameter Storage Area from the WaveLAN card's memory - */ -static void -psa_read(struct net_device * dev, - int o, /* offset in PSA */ - u_char * b, /* buffer to fill */ - int n) /* size to read */ -{ - net_local *lp = netdev_priv(dev); - u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1); - - while(n-- > 0) - { - *b++ = readb(ptr); - /* Due to a lack of address decode pins, the WaveLAN PCMCIA card - * only supports reading even memory addresses. That means the - * increment here MUST be two. - * Because of that, we can't use memcpy_fromio()... - */ - ptr += 2; - } -} /* psa_read */ - -/*------------------------------------------------------------------*/ -/* - * Write the Parameter Storage Area to the WaveLAN card's memory - */ -static void -psa_write(struct net_device * dev, - int o, /* Offset in psa */ - u_char * b, /* Buffer in memory */ - int n) /* Length of buffer */ -{ - net_local *lp = netdev_priv(dev); - u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1); - int count = 0; - unsigned int base = dev->base_addr; - /* As there seem to have no flag PSA_BUSY as in the ISA model, we are - * oblige to verify this address to know when the PSA is ready... */ - volatile u_char __iomem *verify = lp->mem + PSA_ADDR + - (psaoff(0, psa_comp_number) << 1); - - /* Authorize writing to PSA */ - hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN); - - while(n-- > 0) - { - /* write to PSA */ - writeb(*b++, ptr); - ptr += 2; - - /* I don't have the spec, so I don't know what the correct - * sequence to write is. This hack seem to work for me... */ - count = 0; - while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100)) - mdelay(1); - } - - /* Put the host interface back in standard state */ - hacr_write(base, HACR_DEFAULT); -} /* psa_write */ - -#ifdef SET_PSA_CRC -/*------------------------------------------------------------------*/ -/* - * Calculate the PSA CRC - * Thanks to Valster, Nico for the code - * NOTE: By specifying a length including the CRC position the - * returned value should be zero. (i.e. a correct checksum in the PSA) - * - * The Windows drivers don't use the CRC, but the AP and the PtP tool - * depend on it. - */ -static u_short -psa_crc(unsigned char * psa, /* The PSA */ - int size) /* Number of short for CRC */ -{ - int byte_cnt; /* Loop on the PSA */ - u_short crc_bytes = 0; /* Data in the PSA */ - int bit_cnt; /* Loop on the bits of the short */ - - for(byte_cnt = 0; byte_cnt < size; byte_cnt++ ) - { - crc_bytes ^= psa[byte_cnt]; /* Its an xor */ - - for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ ) - { - if(crc_bytes & 0x0001) - crc_bytes = (crc_bytes >> 1) ^ 0xA001; - else - crc_bytes >>= 1 ; - } - } - - return crc_bytes; -} /* psa_crc */ -#endif /* SET_PSA_CRC */ - -/*------------------------------------------------------------------*/ -/* - * update the checksum field in the Wavelan's PSA - */ -static void -update_psa_checksum(struct net_device * dev) -{ -#ifdef SET_PSA_CRC - psa_t psa; - u_short crc; - - /* read the parameter storage area */ - psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); - - /* update the checksum */ - crc = psa_crc((unsigned char *) &psa, - sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1]) - - sizeof(psa.psa_crc_status)); - - psa.psa_crc[0] = crc & 0xFF; - psa.psa_crc[1] = (crc & 0xFF00) >> 8; - - /* Write it ! */ - psa_write(dev, (char *)&psa.psa_crc - (char *)&psa, - (unsigned char *)&psa.psa_crc, 2); - -#ifdef DEBUG_IOCTL_INFO - printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", - dev->name, psa.psa_crc[0], psa.psa_crc[1]); - - /* Check again (luxury !) */ - crc = psa_crc((unsigned char *) &psa, - sizeof(psa) - sizeof(psa.psa_crc_status)); - - if(crc != 0) - printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name); -#endif /* DEBUG_IOCTL_INFO */ -#endif /* SET_PSA_CRC */ -} /* update_psa_checksum */ - -/*------------------------------------------------------------------*/ -/* - * Write 1 byte to the MMC. - */ -static void -mmc_out(u_long base, - u_short o, - u_char d) -{ - int count = 0; - - /* Wait for MMC to go idle */ - while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) - udelay(10); - - outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base)); - outb(d, MMD(base)); -} - -/*------------------------------------------------------------------*/ -/* - * Routine to write bytes to the Modem Management Controller. - * We start by the end because it is the way it should be ! - */ -static void -mmc_write(u_long base, - u_char o, - u_char * b, - int n) -{ - o += n; - b += n; - - while(n-- > 0 ) - mmc_out(base, --o, *(--b)); -} /* mmc_write */ - -/*------------------------------------------------------------------*/ -/* - * Read 1 byte from the MMC. - * Optimised version for 1 byte, avoid using memory... - */ -static u_char -mmc_in(u_long base, - u_short o) -{ - int count = 0; - - while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) - udelay(10); - outb(o << 1, MMR(base)); /* Set the read address */ - - outb(0, MMD(base)); /* Required dummy write */ - - while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) - udelay(10); - return (u_char) (inb(MMD(base))); /* Now do the actual read */ -} - -/*------------------------------------------------------------------*/ -/* - * Routine to read bytes from the Modem Management Controller. - * The implementation is complicated by a lack of address lines, - * which prevents decoding of the low-order bit. - * (code has just been moved in the above function) - * We start by the end because it is the way it should be ! - */ -static void -mmc_read(u_long base, - u_char o, - u_char * b, - int n) -{ - o += n; - b += n; - - while(n-- > 0) - *(--b) = mmc_in(base, --o); -} /* mmc_read */ - -/*------------------------------------------------------------------*/ -/* - * Get the type of encryption available... - */ -static inline int -mmc_encr(u_long base) /* i/o port of the card */ -{ - int temp; - - temp = mmc_in(base, mmroff(0, mmr_des_avail)); - if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) - return 0; - else - return temp; -} - -/*------------------------------------------------------------------*/ -/* - * Wait for the frequency EEprom to complete a command... - */ -static void -fee_wait(u_long base, /* i/o port of the card */ - int delay, /* Base delay to wait for */ - int number) /* Number of time to wait */ -{ - int count = 0; /* Wait only a limited time */ - - while((count++ < number) && - (mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY)) - udelay(delay); -} - -/*------------------------------------------------------------------*/ -/* - * Read bytes from the Frequency EEprom (frequency select cards). - */ -static void -fee_read(u_long base, /* i/o port of the card */ - u_short o, /* destination offset */ - u_short * b, /* data buffer */ - int n) /* number of registers */ -{ - b += n; /* Position at the end of the area */ - - /* Write the address */ - mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); - - /* Loop on all buffer */ - while(n-- > 0) - { - /* Write the read command */ - mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ); - - /* Wait until EEprom is ready (should be quick !) */ - fee_wait(base, 10, 100); - - /* Read the value */ - *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) | - mmc_in(base, mmroff(0, mmr_fee_data_l))); - } -} - - -/*------------------------------------------------------------------*/ -/* - * Write bytes from the Frequency EEprom (frequency select cards). - * This is a bit complicated, because the frequency eeprom has to - * be unprotected and the write enabled. - * Jean II - */ -static void -fee_write(u_long base, /* i/o port of the card */ - u_short o, /* destination offset */ - u_short * b, /* data buffer */ - int n) /* number of registers */ -{ - b += n; /* Position at the end of the area */ - -#ifdef EEPROM_IS_PROTECTED /* disabled */ -#ifdef DOESNT_SEEM_TO_WORK /* disabled */ - /* Ask to read the protected register */ - mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); - - fee_wait(base, 10, 100); - - /* Read the protected register */ - printk("Protected 2 : %02X-%02X\n", - mmc_in(base, mmroff(0, mmr_fee_data_h)), - mmc_in(base, mmroff(0, mmr_fee_data_l))); -#endif /* DOESNT_SEEM_TO_WORK */ - - /* Enable protected register */ - mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); - mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); - - fee_wait(base, 10, 100); - - /* Unprotect area */ - mmc_out(base, mmwoff(0, mmw_fee_addr), o + n); - mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); -#ifdef DOESNT_SEEM_TO_WORK /* disabled */ - /* Or use : */ - mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); -#endif /* DOESNT_SEEM_TO_WORK */ - - fee_wait(base, 10, 100); -#endif /* EEPROM_IS_PROTECTED */ - - /* Write enable */ - mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); - mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); - - fee_wait(base, 10, 100); - - /* Write the EEprom address */ - mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); - - /* Loop on all buffer */ - while(n-- > 0) - { - /* Write the value */ - mmc_out(base, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); - mmc_out(base, mmwoff(0, mmw_fee_data_l), *b & 0xFF); - - /* Write the write command */ - mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE); - - /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */ - mdelay(10); - fee_wait(base, 10, 100); - } - - /* Write disable */ - mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); - mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); - - fee_wait(base, 10, 100); - -#ifdef EEPROM_IS_PROTECTED /* disabled */ - /* Reprotect EEprom */ - mmc_out(base, mmwoff(0, mmw_fee_addr), 0x00); - mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); - - fee_wait(base, 10, 100); -#endif /* EEPROM_IS_PROTECTED */ -} - -/******************* WaveLAN Roaming routines... ********************/ - -#ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */ - -static unsigned char WAVELAN_BEACON_ADDRESS[] = {0x09,0x00,0x0e,0x20,0x03,0x00}; - -static void wv_roam_init(struct net_device *dev) -{ - net_local *lp= netdev_priv(dev); - - /* Do not remove this unless you have a good reason */ - printk(KERN_NOTICE "%s: Warning, you have enabled roaming on" - " device %s !\n", dev->name, dev->name); - printk(KERN_NOTICE "Roaming is currently an experimental unsupported feature" - " of the Wavelan driver.\n"); - printk(KERN_NOTICE "It may work, but may also make the driver behave in" - " erratic ways or crash.\n"); - - lp->wavepoint_table.head=NULL; /* Initialise WavePoint table */ - lp->wavepoint_table.num_wavepoints=0; - lp->wavepoint_table.locked=0; - lp->curr_point=NULL; /* No default WavePoint */ - lp->cell_search=0; - - lp->cell_timer.data=(long)lp; /* Start cell expiry timer */ - lp->cell_timer.function=wl_cell_expiry; - lp->cell_timer.expires=jiffies+CELL_TIMEOUT; - add_timer(&lp->cell_timer); - - wv_nwid_filter(NWID_PROMISC,lp) ; /* Enter NWID promiscuous mode */ - /* to build up a good WavePoint */ - /* table... */ - printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name); -} - -static void wv_roam_cleanup(struct net_device *dev) -{ - wavepoint_history *ptr,*old_ptr; - net_local *lp= netdev_priv(dev); - - printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name); - - /* Fixme : maybe we should check that the timer exist before deleting it */ - del_timer(&lp->cell_timer); /* Remove cell expiry timer */ - ptr=lp->wavepoint_table.head; /* Clear device's WavePoint table */ - while(ptr!=NULL) - { - old_ptr=ptr; - ptr=ptr->next; - wl_del_wavepoint(old_ptr,lp); - } -} - -/* Enable/Disable NWID promiscuous mode on a given device */ -static void wv_nwid_filter(unsigned char mode, net_local *lp) -{ - mm_t m; - unsigned long flags; - -#ifdef WAVELAN_ROAMING_DEBUG - printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name); -#endif - - /* Disable interrupts & save flags */ - spin_lock_irqsave(&lp->spinlock, flags); - - m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; - mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); - - if(mode==NWID_PROMISC) - lp->cell_search=1; - else - lp->cell_search=0; - - /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore(&lp->spinlock, flags); -} - -/* Find a record in the WavePoint table matching a given NWID */ -static wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) -{ - wavepoint_history *ptr=lp->wavepoint_table.head; - - while(ptr!=NULL){ - if(ptr->nwid==nwid) - return ptr; - ptr=ptr->next; - } - return NULL; -} - -/* Create a new wavepoint table entry */ -static wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp) -{ - wavepoint_history *new_wavepoint; - -#ifdef WAVELAN_ROAMING_DEBUG - printk(KERN_DEBUG "WaveLAN: New Wavepoint, NWID:%.4X\n",nwid); -#endif - - if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS) - return NULL; - - new_wavepoint = kmalloc(sizeof(wavepoint_history),GFP_ATOMIC); - if(new_wavepoint==NULL) - return NULL; - - new_wavepoint->nwid=nwid; /* New WavePoints NWID */ - new_wavepoint->average_fast=0; /* Running Averages..*/ - new_wavepoint->average_slow=0; - new_wavepoint->qualptr=0; /* Start of ringbuffer */ - new_wavepoint->last_seq=seq-1; /* Last sequence no.seen */ - memset(new_wavepoint->sigqual,0,WAVEPOINT_HISTORY);/* Empty ringbuffer */ - - new_wavepoint->next=lp->wavepoint_table.head;/* Add to wavepoint table */ - new_wavepoint->prev=NULL; - - if(lp->wavepoint_table.head!=NULL) - lp->wavepoint_table.head->prev=new_wavepoint; - - lp->wavepoint_table.head=new_wavepoint; - - lp->wavepoint_table.num_wavepoints++; /* no. of visible wavepoints */ - - return new_wavepoint; -} - -/* Remove a wavepoint entry from WavePoint table */ -static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) -{ - if(wavepoint==NULL) - return; - - if(lp->curr_point==wavepoint) - lp->curr_point=NULL; - - if(wavepoint->prev!=NULL) - wavepoint->prev->next=wavepoint->next; - - if(wavepoint->next!=NULL) - wavepoint->next->prev=wavepoint->prev; - - if(lp->wavepoint_table.head==wavepoint) - lp->wavepoint_table.head=wavepoint->next; - - lp->wavepoint_table.num_wavepoints--; - kfree(wavepoint); -} - -/* Timer callback function - checks WavePoint table for stale entries */ -static void wl_cell_expiry(unsigned long data) -{ - net_local *lp=(net_local *)data; - wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point; - -#if WAVELAN_ROAMING_DEBUG > 1 - printk(KERN_DEBUG "WaveLAN: Wavepoint timeout, dev %s\n",lp->dev->name); -#endif - - if(lp->wavepoint_table.locked) - { -#if WAVELAN_ROAMING_DEBUG > 1 - printk(KERN_DEBUG "WaveLAN: Wavepoint table locked...\n"); -#endif - - lp->cell_timer.expires=jiffies+1; /* If table in use, come back later */ - add_timer(&lp->cell_timer); - return; - } - - while(wavepoint!=NULL) - { - if(time_after(jiffies, wavepoint->last_seen + CELL_TIMEOUT)) - { -#ifdef WAVELAN_ROAMING_DEBUG - printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid); -#endif - - old_point=wavepoint; - wavepoint=wavepoint->next; - wl_del_wavepoint(old_point,lp); - } - else - wavepoint=wavepoint->next; - } - lp->cell_timer.expires=jiffies+CELL_TIMEOUT; - add_timer(&lp->cell_timer); -} - -/* Update SNR history of a wavepoint */ -static void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) -{ - int i=0,num_missed=0,ptr=0; - int average_fast=0,average_slow=0; - - num_missed=(seq-wavepoint->last_seq)%WAVEPOINT_HISTORY;/* Have we missed - any beacons? */ - if(num_missed) - for(i=0;isigqual[wavepoint->qualptr++]=0; /* If so, enter them as 0's */ - wavepoint->qualptr %=WAVEPOINT_HISTORY; /* in the ringbuffer. */ - } - wavepoint->last_seen=jiffies; /* Add beacon to history */ - wavepoint->last_seq=seq; - wavepoint->sigqual[wavepoint->qualptr++]=sigqual; - wavepoint->qualptr %=WAVEPOINT_HISTORY; - ptr=(wavepoint->qualptr-WAVEPOINT_FAST_HISTORY+WAVEPOINT_HISTORY)%WAVEPOINT_HISTORY; - - for(i=0;isigqual[ptr++]; - ptr %=WAVEPOINT_HISTORY; - } - - average_slow=average_fast; - for(i=WAVEPOINT_FAST_HISTORY;isigqual[ptr++]; - ptr %=WAVEPOINT_HISTORY; - } - - wavepoint->average_fast=average_fast/WAVEPOINT_FAST_HISTORY; - wavepoint->average_slow=average_slow/WAVEPOINT_HISTORY; -} - -/* Perform a handover to a new WavePoint */ -static void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) -{ - unsigned int base = lp->dev->base_addr; - mm_t m; - unsigned long flags; - - if(wavepoint==lp->curr_point) /* Sanity check... */ - { - wv_nwid_filter(!NWID_PROMISC,lp); - return; - } - -#ifdef WAVELAN_ROAMING_DEBUG - printk(KERN_DEBUG "WaveLAN: Doing handover to %.4X, dev %s\n",wavepoint->nwid,lp->dev->name); -#endif - - /* Disable interrupts & save flags */ - spin_lock_irqsave(&lp->spinlock, flags); - - m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; - m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; - - mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); - - /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - wv_nwid_filter(!NWID_PROMISC,lp); - lp->curr_point=wavepoint; -} - -/* Called when a WavePoint beacon is received */ -static void wl_roam_gather(struct net_device * dev, - u_char * hdr, /* Beacon header */ - u_char * stats) /* SNR, Signal quality - of packet */ -{ - wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */ - unsigned short nwid=ntohs(beacon->nwid); - unsigned short sigqual=stats[2] & MMR_SGNL_QUAL; /* SNR of beacon */ - wavepoint_history *wavepoint=NULL; /* WavePoint table entry */ - net_local *lp = netdev_priv(dev); /* Device info */ - -#ifdef I_NEED_THIS_FEATURE - /* Some people don't need this, some other may need it */ - nwid=nwid^ntohs(beacon->domain_id); -#endif - -#if WAVELAN_ROAMING_DEBUG > 1 - printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name); - printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual); -#endif - - lp->wavepoint_table.locked=1; /* */ - - wavepoint=wl_roam_check(nwid,lp); /* Find WavePoint table entry */ - if(wavepoint==NULL) /* If no entry, Create a new one... */ - { - wavepoint=wl_new_wavepoint(nwid,beacon->seq,lp); - if(wavepoint==NULL) - goto out; - } - if(lp->curr_point==NULL) /* If this is the only WavePoint, */ - wv_roam_handover(wavepoint, lp); /* Jump on it! */ - - wl_update_history(wavepoint, sigqual, beacon->seq); /* Update SNR history - stats. */ - - if(lp->curr_point->average_slow < SEARCH_THRESH_LOW) /* If our current */ - if(!lp->cell_search) /* WavePoint is getting faint, */ - wv_nwid_filter(NWID_PROMISC,lp); /* start looking for a new one */ - - if(wavepoint->average_slow > - lp->curr_point->average_slow + WAVELAN_ROAMING_DELTA) - wv_roam_handover(wavepoint, lp); /* Handover to a better WavePoint */ - - if(lp->curr_point->average_slow > SEARCH_THRESH_HIGH) /* If our SNR is */ - if(lp->cell_search) /* getting better, drop out of cell search mode */ - wv_nwid_filter(!NWID_PROMISC,lp); - -out: - lp->wavepoint_table.locked=0; /* :-) */ -} - -/* Test this MAC frame a WavePoint beacon */ -static inline int WAVELAN_BEACON(unsigned char *data) -{ - wavepoint_beacon *beacon= (wavepoint_beacon *)data; - static const wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00}; - - if(memcmp(beacon,&beacon_template,9)==0) - return 1; - else - return 0; -} -#endif /* WAVELAN_ROAMING */ - -/************************ I82593 SUBROUTINES *************************/ -/* - * Useful subroutines to manage the Ethernet controller - */ - -/*------------------------------------------------------------------*/ -/* - * Routine to synchronously send a command to the i82593 chip. - * Should be called with interrupts disabled. - * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(), - * wv_82593_config() & wv_diag()) - */ -static int -wv_82593_cmd(struct net_device * dev, - char * str, - int cmd, - int result) -{ - unsigned int base = dev->base_addr; - int status; - int wait_completed; - long spin; - - /* Spin until the chip finishes executing its current command (if any) */ - spin = 1000; - do - { - /* Time calibration of the loop */ - udelay(10); - - /* Read the interrupt register */ - outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); - status = inb(LCSR(base)); - } - while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); - - /* If the interrupt hasn't been posted */ - if (spin < 0) { -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n", - str, status); -#endif - return(FALSE); - } - - /* Issue the command to the controller */ - outb(cmd, LCCR(base)); - - /* If we don't have to check the result of the command - * Note : this mean that the irq handler will deal with that */ - if(result == SR0_NO_RESULT) - return(TRUE); - - /* We are waiting for command completion */ - wait_completed = TRUE; - - /* Busy wait while the LAN controller executes the command. */ - spin = 1000; - do - { - /* Time calibration of the loop */ - udelay(10); - - /* Read the interrupt register */ - outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); - status = inb(LCSR(base)); - - /* Check if there was an interrupt posted */ - if((status & SR0_INTERRUPT)) - { - /* Acknowledge the interrupt */ - outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); - - /* Check if interrupt is a command completion */ - if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) && - ((status & SR0_BOTH_RX_TX) != 0x0) && - !(status & SR0_RECEPTION)) - { - /* Signal command completion */ - wait_completed = FALSE; - } - else - { - /* Note : Rx interrupts will be handled later, because we can - * handle multiple Rx packets at once */ -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_INFO "wv_82593_cmd: not our interrupt\n"); -#endif - } - } - } - while(wait_completed && (spin-- > 0)); - - /* If the interrupt hasn't be posted */ - if(wait_completed) - { -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n", - str, status); -#endif - return(FALSE); - } - - /* Check the return code returned by the card (see above) against - * the expected return code provided by the caller */ - if((status & SR0_EVENT_MASK) != result) - { -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n", - str, status); -#endif - return(FALSE); - } - - return(TRUE); -} /* wv_82593_cmd */ - -/*------------------------------------------------------------------*/ -/* - * This routine does a 593 op-code number 7, and obtains the diagnose - * status for the WaveLAN. - */ -static inline int -wv_diag(struct net_device * dev) -{ - return(wv_82593_cmd(dev, "wv_diag(): diagnose", - OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED)); -} /* wv_diag */ - -/*------------------------------------------------------------------*/ -/* - * Routine to read len bytes from the i82593's ring buffer, starting at - * chip address addr. The results read from the chip are stored in buf. - * The return value is the address to use for next the call. - */ -static int -read_ringbuf(struct net_device * dev, - int addr, - char * buf, - int len) -{ - unsigned int base = dev->base_addr; - int ring_ptr = addr; - int chunk_len; - char * buf_ptr = buf; - - /* Get all the buffer */ - while(len > 0) - { - /* Position the Program I/O Register at the ring buffer pointer */ - outb(ring_ptr & 0xff, PIORL(base)); - outb(((ring_ptr >> 8) & PIORH_MASK), PIORH(base)); - - /* First, determine how much we can read without wrapping around the - ring buffer */ - if((addr + len) < (RX_BASE + RX_SIZE)) - chunk_len = len; - else - chunk_len = RX_BASE + RX_SIZE - addr; - insb(PIOP(base), buf_ptr, chunk_len); - buf_ptr += chunk_len; - len -= chunk_len; - ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE; - } - return(ring_ptr); -} /* read_ringbuf */ - -/*------------------------------------------------------------------*/ -/* - * Reconfigure the i82593, or at least ask for it... - * Because wv_82593_config use the transmission buffer, we must do it - * when we are sure that there is no transmission, so we do it now - * or in wavelan_packet_xmit() (I can't find any better place, - * wavelan_interrupt is not an option...), so you may experience - * some delay sometime... - */ -static void -wv_82593_reconfig(struct net_device * dev) -{ - net_local * lp = netdev_priv(dev); - struct pcmcia_device * link = lp->link; - unsigned long flags; - - /* Arm the flag, will be cleard in wv_82593_config() */ - lp->reconfig_82593 = TRUE; - - /* Check if we can do it now ! */ - if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev))) - { - spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ - wv_82593_config(dev); - spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ - } - else - { -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG - "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n", - dev->name, dev->state, link->open); -#endif - } -} - -/********************* DEBUG & INFO SUBROUTINES *********************/ -/* - * This routines are used in the code to show debug informations. - * Most of the time, it dump the content of hardware structures... - */ - -#ifdef DEBUG_PSA_SHOW -/*------------------------------------------------------------------*/ -/* - * Print the formatted contents of the Parameter Storage Area. - */ -static void -wv_psa_show(psa_t * p) -{ - printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); - printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", - p->psa_io_base_addr_1, - p->psa_io_base_addr_2, - p->psa_io_base_addr_3, - p->psa_io_base_addr_4); - printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", - p->psa_rem_boot_addr_1, - p->psa_rem_boot_addr_2, - p->psa_rem_boot_addr_3); - printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); - printk("psa_int_req_no: %d\n", p->psa_int_req_no); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); - printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); - printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); - printk("psa_comp_number: %d, ", p->psa_comp_number); - printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); - printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", - p->psa_feature_select); - printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); - printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); - printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); - printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]); - printk("psa_nwid_select: %d\n", p->psa_nwid_select); - printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select); - printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_encryption_key[0], - p->psa_encryption_key[1], - p->psa_encryption_key[2], - p->psa_encryption_key[3], - p->psa_encryption_key[4], - p->psa_encryption_key[5], - p->psa_encryption_key[6], - p->psa_encryption_key[7]); - printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); - printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", - p->psa_call_code[0]); - printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - p->psa_call_code[0], - p->psa_call_code[1], - p->psa_call_code[2], - p->psa_call_code[3], - p->psa_call_code[4], - p->psa_call_code[5], - p->psa_call_code[6], - p->psa_call_code[7]); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_reserved[]: %02X:%02X\n", - p->psa_reserved[0], - p->psa_reserved[1]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); - printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); - printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); -} /* wv_psa_show */ -#endif /* DEBUG_PSA_SHOW */ - -#ifdef DEBUG_MMC_SHOW -/*------------------------------------------------------------------*/ -/* - * Print the formatted status of the Modem Management Controller. - * This function need to be completed... - */ -static void -wv_mmc_show(struct net_device * dev) -{ - unsigned int base = dev->base_addr; - net_local * lp = netdev_priv(dev); - mmr_t m; - - /* Basic check */ - if(hasr_read(base) & HASR_NO_CLK) - { - printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n", - dev->name); - return; - } - - spin_lock_irqsave(&lp->spinlock, flags); - - /* Read the mmc */ - mmc_out(base, mmwoff(0, mmw_freeze), 1); - mmc_read(base, 0, (u_char *)&m, sizeof(m)); - mmc_out(base, mmwoff(0, mmw_freeze), 0); - - /* Don't forget to update statistics */ - lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; - - spin_unlock_irqrestore(&lp->spinlock, flags); - - printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - m.mmr_unused0[0], - m.mmr_unused0[1], - m.mmr_unused0[2], - m.mmr_unused0[3], - m.mmr_unused0[4], - m.mmr_unused0[5], - m.mmr_unused0[6], - m.mmr_unused0[7]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n", - m.mmr_des_avail, m.mmr_des_status); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", - m.mmr_unused1[0], - m.mmr_unused1[1], - m.mmr_unused1[2], - m.mmr_unused1[3], - m.mmr_unused1[4]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", - m.mmr_dce_status, - (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"", - (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? - "loop test indicated," : "", - (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "", - (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? - "jabber timer expired," : ""); - printk(KERN_DEBUG "Dsp ID: %02X\n", - m.mmr_dsp_id); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", - m.mmr_unused2[0], - m.mmr_unused2[1]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", - (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, - (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); - printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", - m.mmr_thr_pre_set & MMR_THR_PRE_SET, - (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below"); - printk(KERN_DEBUG "signal_lvl: %d [%s], ", - m.mmr_signal_lvl & MMR_SIGNAL_LVL, - (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg"); - printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL, - (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update"); - printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, - (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0"); -#ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); -#endif /* DEBUG_SHOW_UNUSED */ -} /* wv_mmc_show */ -#endif /* DEBUG_MMC_SHOW */ - -#ifdef DEBUG_I82593_SHOW -/*------------------------------------------------------------------*/ -/* - * Print the formatted status of the i82593's receive unit. - */ -static void -wv_ru_show(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - - printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n"); - printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop); - /* - * Not implemented yet... - */ - printk("\n"); -} /* wv_ru_show */ -#endif /* DEBUG_I82593_SHOW */ - -#ifdef DEBUG_DEVICE_SHOW -/*------------------------------------------------------------------*/ -/* - * Print the formatted status of the WaveLAN PCMCIA device driver. - */ -static void -wv_dev_show(struct net_device * dev) -{ - printk(KERN_DEBUG "dev:"); - printk(" state=%lX,", dev->state); - printk(" trans_start=%ld,", dev->trans_start); - printk(" flags=0x%x,", dev->flags); - printk("\n"); -} /* wv_dev_show */ - -/*------------------------------------------------------------------*/ -/* - * Print the formatted status of the WaveLAN PCMCIA device driver's - * private information. - */ -static void -wv_local_show(struct net_device * dev) -{ - net_local *lp = netdev_priv(dev); - - printk(KERN_DEBUG "local:"); - /* - * Not implemented yet... - */ - printk("\n"); -} /* wv_local_show */ -#endif /* DEBUG_DEVICE_SHOW */ - -#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) -/*------------------------------------------------------------------*/ -/* - * Dump packet header (and content if necessary) on the screen - */ -static void -wv_packet_info(u_char * p, /* Packet to dump */ - int length, /* Length of the packet */ - char * msg1, /* Name of the device */ - char * msg2) /* Name of the function */ -{ - int i; - int maxi; - - printk(KERN_DEBUG "%s: %s(): dest %pM, length %d\n", - msg1, msg2, p, length); - printk(KERN_DEBUG "%s: %s(): src %pM, type 0x%02X%02X\n", - msg1, msg2, &p[6], p[12], p[13]); - -#ifdef DEBUG_PACKET_DUMP - - printk(KERN_DEBUG "data=\""); - - if((maxi = length) > DEBUG_PACKET_DUMP) - maxi = DEBUG_PACKET_DUMP; - for(i = 14; i < maxi; i++) - if(p[i] >= ' ' && p[i] <= '~') - printk(" %c", p[i]); - else - printk("%02X", p[i]); - if(maxi < length) - printk(".."); - printk("\"\n"); - printk(KERN_DEBUG "\n"); -#endif /* DEBUG_PACKET_DUMP */ -} -#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ - -/*------------------------------------------------------------------*/ -/* - * This is the information which is displayed by the driver at startup - * There is a lot of flag to configure it at your will... - */ -static void -wv_init_info(struct net_device * dev) -{ - unsigned int base = dev->base_addr; - psa_t psa; - - /* Read the parameter storage area */ - psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); - -#ifdef DEBUG_PSA_SHOW - wv_psa_show(&psa); -#endif -#ifdef DEBUG_MMC_SHOW - wv_mmc_show(dev); -#endif -#ifdef DEBUG_I82593_SHOW - wv_ru_show(dev); -#endif - -#ifdef DEBUG_BASIC_SHOW - /* Now, let's go for the basic stuff */ - printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr %pM", - dev->name, base, dev->irq, dev->dev_addr); - - /* Print current network id */ - if(psa.psa_nwid_select) - printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]); - else - printk(", nwid off"); - - /* If 2.00 card */ - if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - { - unsigned short freq; - - /* Ask the EEprom to read the frequency from the first area */ - fee_read(base, 0x00 /* 1st area - frequency... */, - &freq, 1); - - /* Print frequency */ - printk(", 2.00, %ld", (freq >> 6) + 2400L); - - /* Hack !!! */ - if(freq & 0x20) - printk(".5"); - } - else - { - printk(", PCMCIA, "); - switch (psa.psa_subband) - { - case PSA_SUBBAND_915: - printk("915"); - break; - case PSA_SUBBAND_2425: - printk("2425"); - break; - case PSA_SUBBAND_2460: - printk("2460"); - break; - case PSA_SUBBAND_2484: - printk("2484"); - break; - case PSA_SUBBAND_2430_5: - printk("2430.5"); - break; - default: - printk("unknown"); - } - } - - printk(" MHz\n"); -#endif /* DEBUG_BASIC_SHOW */ - -#ifdef DEBUG_VERSION_SHOW - /* Print version information */ - printk(KERN_NOTICE "%s", version); -#endif -} /* wv_init_info */ - -/********************* IOCTL, STATS & RECONFIG *********************/ -/* - * We found here routines that are called by Linux on differents - * occasions after the configuration and not for transmitting data - * These may be called when the user use ifconfig, /proc/net/dev - * or wireless extensions - */ - - -/*------------------------------------------------------------------*/ -/* - * Set or clear the multicast filter for this adaptor. - * num_addrs == -1 Promiscuous mode, receive all packets - * num_addrs == 0 Normal mode, clear multicast list - * num_addrs > 0 Multicast mode, receive normal and MC packets, - * and do best-effort filtering. - */ - -static void -wavelan_set_multicast_list(struct net_device * dev) -{ - net_local * lp = netdev_priv(dev); - -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name); -#endif - -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", - dev->name, dev->flags, dev->mc_count); -#endif - - if(dev->flags & IFF_PROMISC) - { - /* - * Enable promiscuous mode: receive all packets. - */ - if(!lp->promiscuous) - { - lp->promiscuous = 1; - lp->allmulticast = 0; - lp->mc_count = 0; - - wv_82593_reconfig(dev); - } - } - else - /* If all multicast addresses - * or too much multicast addresses for the hardware filter */ - if((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES)) - { - /* - * Disable promiscuous mode, but active the all multicast mode - */ - if(!lp->allmulticast) - { - lp->promiscuous = 0; - lp->allmulticast = 1; - lp->mc_count = 0; - - wv_82593_reconfig(dev); - } - } - else - /* If there is some multicast addresses to send */ - if(dev->mc_list != (struct dev_mc_list *) NULL) - { - /* - * Disable promiscuous mode, but receive all packets - * in multicast list - */ -#ifdef MULTICAST_AVOID - if(lp->promiscuous || lp->allmulticast || - (dev->mc_count != lp->mc_count)) -#endif - { - lp->promiscuous = 0; - lp->allmulticast = 0; - lp->mc_count = dev->mc_count; - - wv_82593_reconfig(dev); - } - } - else - { - /* - * Switch to normal mode: disable promiscuous mode and - * clear the multicast list. - */ - if(lp->promiscuous || lp->mc_count == 0) - { - lp->promiscuous = 0; - lp->allmulticast = 0; - lp->mc_count = 0; - - wv_82593_reconfig(dev); - } - } -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name); -#endif -} - -/*------------------------------------------------------------------*/ -/* - * This function doesn't exist... - * (Note : it was a nice way to test the reconfigure stuff...) - */ -#ifdef SET_MAC_ADDRESS -static int -wavelan_set_mac_address(struct net_device * dev, - void * addr) -{ - struct sockaddr * mac = addr; - - /* Copy the address */ - memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); - - /* Reconfig the beast */ - wv_82593_reconfig(dev); - - return 0; -} -#endif /* SET_MAC_ADDRESS */ - - -/*------------------------------------------------------------------*/ -/* - * Frequency setting (for hardware able of it) - * It's a bit complicated and you don't really want to look into it... - */ -static int -wv_set_frequency(u_long base, /* i/o port of the card */ - iw_freq * frequency) -{ - const int BAND_NUM = 10; /* Number of bands */ - long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ -#ifdef DEBUG_IOCTL_INFO - int i; -#endif - - /* Setting by frequency */ - /* Theoritically, you may set any frequency between - * the two limits with a 0.5 MHz precision. In practice, - * I don't want you to have trouble with local - * regulations... */ - if((frequency->e == 1) && - (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8)) - { - freq = ((frequency->m / 10000) - 24000L) / 5; - } - - /* Setting by channel (same as wfreqsel) */ - /* Warning : each channel is 22MHz wide, so some of the channels - * will interfere... */ - if((frequency->e == 0) && - (frequency->m >= 0) && (frequency->m < BAND_NUM)) - { - /* Get frequency offset. */ - freq = channel_bands[frequency->m] >> 1; - } - - /* Verify if the frequency is allowed */ - if(freq != 0L) - { - u_short table[10]; /* Authorized frequency table */ - - /* Read the frequency table */ - fee_read(base, 0x71 /* frequency table */, - table, 10); - -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "Frequency table :"); - for(i = 0; i < 10; i++) - { - printk(" %04X", - table[i]); - } - printk("\n"); -#endif - - /* Look in the table if the frequency is allowed */ - if(!(table[9 - ((freq - 24) / 16)] & - (1 << ((freq - 24) % 16)))) - return -EINVAL; /* not allowed */ - } - else - return -EINVAL; - - /* If we get a usable frequency */ - if(freq != 0L) - { - unsigned short area[16]; - unsigned short dac[2]; - unsigned short area_verify[16]; - unsigned short dac_verify[2]; - /* Corresponding gain (in the power adjust value table) - * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8 - * & WCIN062D.DOC, page 6.2.9 */ - unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; - int power_band = 0; /* Selected band */ - unsigned short power_adjust; /* Correct value */ - - /* Search for the gain */ - power_band = 0; - while((freq > power_limit[power_band]) && - (power_limit[++power_band] != 0)) - ; - - /* Read the first area */ - fee_read(base, 0x00, - area, 16); - - /* Read the DAC */ - fee_read(base, 0x60, - dac, 2); - - /* Read the new power adjust value */ - fee_read(base, 0x6B - (power_band >> 1), - &power_adjust, 1); - if(power_band & 0x1) - power_adjust >>= 8; - else - power_adjust &= 0xFF; - -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); - for(i = 0; i < 16; i++) - { - printk(" %04X", - area[i]); - } - printk("\n"); - - printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", - dac[0], dac[1]); -#endif - - /* Frequency offset (for info only...) */ - area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); - - /* Receiver Principle main divider coefficient */ - area[3] = (freq >> 1) + 2400L - 352L; - area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); - - /* Transmitter Main divider coefficient */ - area[13] = (freq >> 1) + 2400L; - area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); - - /* Others part of the area are flags, bit streams or unused... */ - - /* Set the value in the DAC */ - dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); - dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); - - /* Write the first area */ - fee_write(base, 0x00, - area, 16); - - /* Write the DAC */ - fee_write(base, 0x60, - dac, 2); - - /* We now should verify here that the EEprom writing was ok */ - - /* ReRead the first area */ - fee_read(base, 0x00, - area_verify, 16); - - /* ReRead the DAC */ - fee_read(base, 0x60, - dac_verify, 2); - - /* Compare */ - if(memcmp(area, area_verify, 16 * 2) || - memcmp(dac, dac_verify, 2 * 2)) - { -#ifdef DEBUG_IOCTL_ERROR - printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n"); -#endif - return -EOPNOTSUPP; - } - - /* We must download the frequency parameters to the - * synthetisers (from the EEprom - area 1) - * Note : as the EEprom is auto decremented, we set the end - * if the area... */ - mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F); - mmc_out(base, mmwoff(0, mmw_fee_ctrl), - MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); - - /* Wait until the download is finished */ - fee_wait(base, 100, 100); - - /* We must now download the power adjust value (gain) to - * the synthetisers (from the EEprom - area 7 - DAC) */ - mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61); - mmc_out(base, mmwoff(0, mmw_fee_ctrl), - MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); - - /* Wait until the download is finished */ - fee_wait(base, 100, 100); - -#ifdef DEBUG_IOCTL_INFO - /* Verification of what we have done... */ - - printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); - for(i = 0; i < 16; i++) - { - printk(" %04X", - area_verify[i]); - } - printk("\n"); - - printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", - dac_verify[0], dac_verify[1]); -#endif - - return 0; - } - else - return -EINVAL; /* Bah, never get there... */ -} - -/*------------------------------------------------------------------*/ -/* - * Give the list of available frequencies - */ -static int -wv_frequency_list(u_long base, /* i/o port of the card */ - iw_freq * list, /* List of frequency to fill */ - int max) /* Maximum number of frequencies */ -{ - u_short table[10]; /* Authorized frequency table */ - long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ - int i; /* index in the table */ - const int BAND_NUM = 10; /* Number of bands */ - int c = 0; /* Channel number */ - - /* Read the frequency table */ - fee_read(base, 0x71 /* frequency table */, - table, 10); - - /* Look all frequencies */ - i = 0; - for(freq = 0; freq < 150; freq++) - /* Look in the table if the frequency is allowed */ - if(table[9 - (freq / 16)] & (1 << (freq % 16))) - { - /* Compute approximate channel number */ - while((((channel_bands[c] >> 1) - 24) < freq) && - (c < BAND_NUM)) - c++; - list[i].i = c; /* Set the list index */ - - /* put in the list */ - list[i].m = (((freq + 24) * 5) + 24000L) * 10000; - list[i++].e = 1; - - /* Check number */ - if(i >= max) - return(i); - } - - return(i); -} - -#ifdef IW_WIRELESS_SPY -/*------------------------------------------------------------------*/ -/* - * Gather wireless spy statistics : for each packet, compare the source - * address with out list, and if match, get the stats... - * Sorry, but this function really need wireless extensions... - */ -static inline void -wl_spy_gather(struct net_device * dev, - u_char * mac, /* MAC address */ - u_char * stats) /* Statistics to gather */ -{ - struct iw_quality wstats; - - wstats.qual = stats[2] & MMR_SGNL_QUAL; - wstats.level = stats[0] & MMR_SIGNAL_LVL; - wstats.noise = stats[1] & MMR_SILENCE_LVL; - wstats.updated = 0x7; - - /* Update spy records */ - wireless_spy_update(dev, mac, &wstats); -} -#endif /* IW_WIRELESS_SPY */ - -#ifdef HISTOGRAM -/*------------------------------------------------------------------*/ -/* - * This function calculate an histogram on the signal level. - * As the noise is quite constant, it's like doing it on the SNR. - * We have defined a set of interval (lp->his_range), and each time - * the level goes in that interval, we increment the count (lp->his_sum). - * With this histogram you may detect if one wavelan is really weak, - * or you may also calculate the mean and standard deviation of the level... - */ -static inline void -wl_his_gather(struct net_device * dev, - u_char * stats) /* Statistics to gather */ -{ - net_local * lp = netdev_priv(dev); - u_char level = stats[0] & MMR_SIGNAL_LVL; - int i; - - /* Find the correct interval */ - i = 0; - while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++])) - ; - - /* Increment interval counter */ - (lp->his_sum[i])++; -} -#endif /* HISTOGRAM */ - -static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strncpy(info->driver, "wavelan_cs", sizeof(info->driver)-1); -} - -static const struct ethtool_ops ops = { - .get_drvinfo = wl_get_drvinfo -}; - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get protocol name - */ -static int wavelan_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - strcpy(wrqu->name, "WaveLAN"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set NWID - */ -static int wavelan_set_nwid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned int base = dev->base_addr; - net_local *lp = netdev_priv(dev); - psa_t psa; - mm_t m; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Set NWID in WaveLAN. */ - if (!wrqu->nwid.disabled) { - /* Set NWID in psa */ - psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; - psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; - psa.psa_nwid_select = 0x01; - psa_write(dev, - (char *) psa.psa_nwid - (char *) &psa, - (unsigned char *) psa.psa_nwid, 3); - - /* Set NWID in mmc. */ - m.w.mmw_netw_id_l = psa.psa_nwid[1]; - m.w.mmw_netw_id_h = psa.psa_nwid[0]; - mmc_write(base, - (char *) &m.w.mmw_netw_id_l - - (char *) &m, - (unsigned char *) &m.w.mmw_netw_id_l, 2); - mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); - } else { - /* Disable NWID in the psa. */ - psa.psa_nwid_select = 0x00; - psa_write(dev, - (char *) &psa.psa_nwid_select - - (char *) &psa, - (unsigned char *) &psa.psa_nwid_select, - 1); - - /* Disable NWID in the mmc (no filtering). */ - mmc_out(base, mmwoff(0, mmw_loopt_sel), - MMW_LOOPT_SEL_DIS_NWID); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev); - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get NWID - */ -static int wavelan_get_nwid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = netdev_priv(dev); - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Read the NWID. */ - psa_read(dev, - (char *) psa.psa_nwid - (char *) &psa, - (unsigned char *) psa.psa_nwid, 3); - wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrqu->nwid.disabled = !(psa.psa_nwid_select); - wrqu->nwid.fixed = 1; /* Superfluous */ - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set frequency - */ -static int wavelan_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned int base = dev->base_addr; - net_local *lp = netdev_priv(dev); - unsigned long flags; - int ret; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - ret = wv_set_frequency(base, &(wrqu->freq)); - else - ret = -EOPNOTSUPP; - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get frequency - */ -static int wavelan_get_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned int base = dev->base_addr; - net_local *lp = netdev_priv(dev); - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). - * Does it work for everybody, especially old cards? */ - if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - unsigned short freq; - - /* Ask the EEPROM to read the frequency from the first area. */ - fee_read(base, 0x00, &freq, 1); - wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; - wrqu->freq.e = 1; - } else { - psa_read(dev, - (char *) &psa.psa_subband - (char *) &psa, - (unsigned char *) &psa.psa_subband, 1); - - if (psa.psa_subband <= 4) { - wrqu->freq.m = fixed_bands[psa.psa_subband]; - wrqu->freq.e = (psa.psa_subband != 0); - } else - ret = -EOPNOTSUPP; - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set level threshold - */ -static int wavelan_set_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned int base = dev->base_addr; - net_local *lp = netdev_priv(dev); - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Set the level threshold. */ - /* We should complain loudly if wrqu->sens.fixed = 0, because we - * can't set auto mode... */ - psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; - psa_write(dev, - (char *) &psa.psa_thr_pre_set - (char *) &psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev); - mmc_out(base, mmwoff(0, mmw_thr_pre_set), - psa.psa_thr_pre_set); - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get level threshold - */ -static int wavelan_get_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = netdev_priv(dev); - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Read the level threshold. */ - psa_read(dev, - (char *) &psa.psa_thr_pre_set - (char *) &psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; - wrqu->sens.fixed = 1; - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set encryption key - */ -static int wavelan_set_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned int base = dev->base_addr; - net_local *lp = netdev_priv(dev); - unsigned long flags; - psa_t psa; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Check if capable of encryption */ - if (!mmc_encr(base)) { - ret = -EOPNOTSUPP; - } - - /* Check the size of the key */ - if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { - ret = -EINVAL; - } - - if(!ret) { - /* Basic checking... */ - if (wrqu->encoding.length == 8) { - /* Copy the key in the driver */ - memcpy(psa.psa_encryption_key, extra, - wrqu->encoding.length); - psa.psa_encryption_select = 1; - - psa_write(dev, - (char *) &psa.psa_encryption_select - - (char *) &psa, - (unsigned char *) &psa. - psa_encryption_select, 8 + 1); - - mmc_out(base, mmwoff(0, mmw_encr_enable), - MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); - mmc_write(base, mmwoff(0, mmw_encr_key), - (unsigned char *) &psa. - psa_encryption_key, 8); - } - - /* disable encryption */ - if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { - psa.psa_encryption_select = 0; - psa_write(dev, - (char *) &psa.psa_encryption_select - - (char *) &psa, - (unsigned char *) &psa. - psa_encryption_select, 1); - - mmc_out(base, mmwoff(0, mmw_encr_enable), 0); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev); - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get encryption key - */ -static int wavelan_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned int base = dev->base_addr; - net_local *lp = netdev_priv(dev); - psa_t psa; - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Check if encryption is available */ - if (!mmc_encr(base)) { - ret = -EOPNOTSUPP; - } else { - /* Read the encryption key */ - psa_read(dev, - (char *) &psa.psa_encryption_select - - (char *) &psa, - (unsigned char *) &psa. - psa_encryption_select, 1 + 8); - - /* encryption is enabled ? */ - if (psa.psa_encryption_select) - wrqu->encoding.flags = IW_ENCODE_ENABLED; - else - wrqu->encoding.flags = IW_ENCODE_DISABLED; - wrqu->encoding.flags |= mmc_encr(base); - - /* Copy the key to the user buffer */ - wrqu->encoding.length = 8; - memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -#ifdef WAVELAN_ROAMING_EXT -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set ESSID (domain) - */ -static int wavelan_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = netdev_priv(dev); - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Check if disable */ - if(wrqu->data.flags == 0) - lp->filter_domains = 0; - else { - char essid[IW_ESSID_MAX_SIZE + 1]; - char * endp; - - /* Terminate the string */ - memcpy(essid, extra, wrqu->data.length); - essid[IW_ESSID_MAX_SIZE] = '\0'; - -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "SetEssid : ``%s''\n", essid); -#endif /* DEBUG_IOCTL_INFO */ - - /* Convert to a number (note : Wavelan specific) */ - lp->domain_id = simple_strtoul(essid, &endp, 16); - /* Has it worked ? */ - if(endp > essid) - lp->filter_domains = 1; - else { - lp->filter_domains = 0; - ret = -EINVAL; - } - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get ESSID (domain) - */ -static int wavelan_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = netdev_priv(dev); - - /* Is the domain ID active ? */ - wrqu->data.flags = lp->filter_domains; - - /* Copy Domain ID into a string (Wavelan specific) */ - /* Sound crazy, be we can't have a snprintf in the kernel !!! */ - sprintf(extra, "%lX", lp->domain_id); - extra[IW_ESSID_MAX_SIZE] = '\0'; - - /* Set the length */ - wrqu->data.length = strlen(extra); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set AP address - */ -static int wavelan_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "Set AP to : %pM\n", wrqu->ap_addr.sa_data); -#endif /* DEBUG_IOCTL_INFO */ - - return -EOPNOTSUPP; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get AP address - */ -static int wavelan_get_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - /* Should get the real McCoy instead of own Ethernet address */ - memcpy(wrqu->ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - - return -EOPNOTSUPP; -} -#endif /* WAVELAN_ROAMING_EXT */ - -#ifdef WAVELAN_ROAMING -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set mode - */ -static int wavelan_set_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = netdev_priv(dev); - unsigned long flags; - int ret = 0; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Check mode */ - switch(wrqu->mode) { - case IW_MODE_ADHOC: - if(do_roaming) { - wv_roam_cleanup(dev); - do_roaming = 0; - } - break; - case IW_MODE_INFRA: - if(!do_roaming) { - wv_roam_init(dev); - do_roaming = 1; - } - break; - default: - ret = -EINVAL; - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get mode - */ -static int wavelan_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - if(do_roaming) - wrqu->mode = IW_MODE_INFRA; - else - wrqu->mode = IW_MODE_ADHOC; - - return 0; -} -#endif /* WAVELAN_ROAMING */ - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get range info - */ -static int wavelan_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned int base = dev->base_addr; - net_local *lp = netdev_priv(dev); - struct iw_range *range = (struct iw_range *) extra; - unsigned long flags; - int ret = 0; - - /* Set the length (very important for backward compatibility) */ - wrqu->data.length = sizeof(struct iw_range); - - /* Set all the info we don't care or don't know about to zero */ - memset(range, 0, sizeof(struct iw_range)); - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 9; - - /* Set information in the range struct. */ - range->throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ - range->min_nwid = 0x0000; - range->max_nwid = 0xFFFF; - - range->sensitivity = 0x3F; - range->max_qual.qual = MMR_SGNL_QUAL; - range->max_qual.level = MMR_SIGNAL_LVL; - range->max_qual.noise = MMR_SILENCE_LVL; - range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ - /* Need to get better values for those two */ - range->avg_qual.level = 30; - range->avg_qual.noise = 8; - - range->num_bitrates = 1; - range->bitrate[0] = 2000000; /* 2 Mb/s */ - - /* Event capability (kernel + driver) */ - range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) | - IW_EVENT_CAPA_MASK(0x8B04) | - IW_EVENT_CAPA_MASK(0x8B06)); - range->event_capa[1] = IW_EVENT_CAPA_K_1; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { - range->num_channels = 10; - range->num_frequency = wv_frequency_list(base, range->freq, - IW_MAX_FREQUENCIES); - } else - range->num_channels = range->num_frequency = 0; - - /* Encryption supported ? */ - if (mmc_encr(base)) { - range->encoding_size[0] = 8; /* DES = 64 bits key */ - range->num_encoding_sizes = 1; - range->max_encoding_tokens = 1; /* Only one key possible */ - } else { - range->num_encoding_sizes = 0; - range->max_encoding_tokens = 0; - } - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : set quality threshold - */ -static int wavelan_set_qthr(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned int base = dev->base_addr; - net_local *lp = netdev_priv(dev); - psa_t psa; - unsigned long flags; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - psa.psa_quality_thr = *(extra) & 0x0F; - psa_write(dev, - (char *) &psa.psa_quality_thr - (char *) &psa, - (unsigned char *) &psa.psa_quality_thr, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev); - mmc_out(base, mmwoff(0, mmw_quality_thr), - psa.psa_quality_thr); - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get quality threshold - */ -static int wavelan_get_qthr(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = netdev_priv(dev); - psa_t psa; - unsigned long flags; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - psa_read(dev, - (char *) &psa.psa_quality_thr - (char *) &psa, - (unsigned char *) &psa.psa_quality_thr, 1); - *(extra) = psa.psa_quality_thr & 0x0F; - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return 0; -} - -#ifdef WAVELAN_ROAMING -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : set roaming - */ -static int wavelan_set_roam(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = netdev_priv(dev); - unsigned long flags; - - /* Disable interrupts and save flags. */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Note : should check if user == root */ - if(do_roaming && (*extra)==0) - wv_roam_cleanup(dev); - else if(do_roaming==0 && (*extra)!=0) - wv_roam_init(dev); - - do_roaming = (*extra); - - /* Enable interrupts and restore flags. */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get quality threshold - */ -static int wavelan_get_roam(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - *(extra) = do_roaming; - - return 0; -} -#endif /* WAVELAN_ROAMING */ - -#ifdef HISTOGRAM -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : set histogram - */ -static int wavelan_set_histo(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = netdev_priv(dev); - - /* Check the number of intervals. */ - if (wrqu->data.length > 16) { - return(-E2BIG); - } - - /* Disable histo while we copy the addresses. - * As we don't disable interrupts, we need to do this */ - lp->his_number = 0; - - /* Are there ranges to copy? */ - if (wrqu->data.length > 0) { - /* Copy interval ranges to the driver */ - memcpy(lp->his_range, extra, wrqu->data.length); - - { - int i; - printk(KERN_DEBUG "Histo :"); - for(i = 0; i < wrqu->data.length; i++) - printk(" %d", lp->his_range[i]); - printk("\n"); - } - - /* Reset result structure. */ - memset(lp->his_sum, 0x00, sizeof(long) * 16); - } - - /* Now we can set the number of ranges */ - lp->his_number = wrqu->data.length; - - return(0); -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Private Handler : get histogram - */ -static int wavelan_get_histo(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = netdev_priv(dev); - - /* Set the number of intervals. */ - wrqu->data.length = lp->his_number; - - /* Give back the distribution statistics */ - if(lp->his_number > 0) - memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); - - return(0); -} -#endif /* HISTOGRAM */ - -/*------------------------------------------------------------------*/ -/* - * Structures to export the Wireless Handlers - */ - -static const struct iw_priv_args wavelan_private_args[] = { -/*{ cmd, set_args, get_args, name } */ - { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, - { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, - { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setroam" }, - { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" }, - { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, - { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, -}; - -static const iw_handler wavelan_handler[] = -{ - NULL, /* SIOCSIWNAME */ - wavelan_get_name, /* SIOCGIWNAME */ - wavelan_set_nwid, /* SIOCSIWNWID */ - wavelan_get_nwid, /* SIOCGIWNWID */ - wavelan_set_freq, /* SIOCSIWFREQ */ - wavelan_get_freq, /* SIOCGIWFREQ */ -#ifdef WAVELAN_ROAMING - wavelan_set_mode, /* SIOCSIWMODE */ - wavelan_get_mode, /* SIOCGIWMODE */ -#else /* WAVELAN_ROAMING */ - NULL, /* SIOCSIWMODE */ - NULL, /* SIOCGIWMODE */ -#endif /* WAVELAN_ROAMING */ - wavelan_set_sens, /* SIOCSIWSENS */ - wavelan_get_sens, /* SIOCGIWSENS */ - NULL, /* SIOCSIWRANGE */ - wavelan_get_range, /* SIOCGIWRANGE */ - NULL, /* SIOCSIWPRIV */ - NULL, /* SIOCGIWPRIV */ - NULL, /* SIOCSIWSTATS */ - NULL, /* SIOCGIWSTATS */ - iw_handler_set_spy, /* SIOCSIWSPY */ - iw_handler_get_spy, /* SIOCGIWSPY */ - iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ - iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ -#ifdef WAVELAN_ROAMING_EXT - wavelan_set_wap, /* SIOCSIWAP */ - wavelan_get_wap, /* SIOCGIWAP */ - NULL, /* -- hole -- */ - NULL, /* SIOCGIWAPLIST */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - wavelan_set_essid, /* SIOCSIWESSID */ - wavelan_get_essid, /* SIOCGIWESSID */ -#else /* WAVELAN_ROAMING_EXT */ - NULL, /* SIOCSIWAP */ - NULL, /* SIOCGIWAP */ - NULL, /* -- hole -- */ - NULL, /* SIOCGIWAPLIST */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - NULL, /* SIOCSIWESSID */ - NULL, /* SIOCGIWESSID */ -#endif /* WAVELAN_ROAMING_EXT */ - NULL, /* SIOCSIWNICKN */ - NULL, /* SIOCGIWNICKN */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - NULL, /* SIOCSIWRATE */ - NULL, /* SIOCGIWRATE */ - NULL, /* SIOCSIWRTS */ - NULL, /* SIOCGIWRTS */ - NULL, /* SIOCSIWFRAG */ - NULL, /* SIOCGIWFRAG */ - NULL, /* SIOCSIWTXPOW */ - NULL, /* SIOCGIWTXPOW */ - NULL, /* SIOCSIWRETRY */ - NULL, /* SIOCGIWRETRY */ - wavelan_set_encode, /* SIOCSIWENCODE */ - wavelan_get_encode, /* SIOCGIWENCODE */ -}; - -static const iw_handler wavelan_private_handler[] = -{ - wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ - wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ -#ifdef WAVELAN_ROAMING - wavelan_set_roam, /* SIOCIWFIRSTPRIV + 2 */ - wavelan_get_roam, /* SIOCIWFIRSTPRIV + 3 */ -#else /* WAVELAN_ROAMING */ - NULL, /* SIOCIWFIRSTPRIV + 2 */ - NULL, /* SIOCIWFIRSTPRIV + 3 */ -#endif /* WAVELAN_ROAMING */ -#ifdef HISTOGRAM - wavelan_set_histo, /* SIOCIWFIRSTPRIV + 4 */ - wavelan_get_histo, /* SIOCIWFIRSTPRIV + 5 */ -#endif /* HISTOGRAM */ -}; - -static const struct iw_handler_def wavelan_handler_def = -{ - .num_standard = ARRAY_SIZE(wavelan_handler), - .num_private = ARRAY_SIZE(wavelan_private_handler), - .num_private_args = ARRAY_SIZE(wavelan_private_args), - .standard = wavelan_handler, - .private = wavelan_private_handler, - .private_args = wavelan_private_args, - .get_wireless_stats = wavelan_get_wireless_stats, -}; - -/*------------------------------------------------------------------*/ -/* - * Get wireless statistics - * Called by /proc/net/wireless... - */ -static iw_stats * -wavelan_get_wireless_stats(struct net_device * dev) -{ - unsigned int base = dev->base_addr; - net_local * lp = netdev_priv(dev); - mmr_t m; - iw_stats * wstats; - unsigned long flags; - -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); -#endif - - /* Disable interrupts & save flags */ - spin_lock_irqsave(&lp->spinlock, flags); - - wstats = &lp->wstats; - - /* Get data from the mmc */ - mmc_out(base, mmwoff(0, mmw_freeze), 1); - - mmc_read(base, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); - mmc_read(base, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2); - mmc_read(base, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4); - - mmc_out(base, mmwoff(0, mmw_freeze), 0); - - /* Copy data to wireless stuff */ - wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; - wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; - wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; - wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; - wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | - ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | - ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); - wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; - wstats->discard.code = 0L; - wstats->discard.misc = 0L; - - /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore(&lp->spinlock, flags); - -#ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); -#endif - return &lp->wstats; -} - -/************************* PACKET RECEPTION *************************/ -/* - * This part deal with receiving the packets. - * The interrupt handler get an interrupt when a packet has been - * successfully received and called this part... - */ - -/*------------------------------------------------------------------*/ -/* - * Calculate the starting address of the frame pointed to by the receive - * frame pointer and verify that the frame seem correct - * (called by wv_packet_rcv()) - */ -static int -wv_start_of_frame(struct net_device * dev, - int rfp, /* end of frame */ - int wrap) /* start of buffer */ -{ - unsigned int base = dev->base_addr; - int rp; - int len; - - rp = (rfp - 5 + RX_SIZE) % RX_SIZE; - outb(rp & 0xff, PIORL(base)); - outb(((rp >> 8) & PIORH_MASK), PIORH(base)); - len = inb(PIOP(base)); - len |= inb(PIOP(base)) << 8; - - /* Sanity checks on size */ - /* Frame too big */ - if(len > MAXDATAZ + 100) - { -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO "%s: wv_start_of_frame: Received frame too large, rfp %d len 0x%x\n", - dev->name, rfp, len); -#endif - return(-1); - } - - /* Frame too short */ - if(len < 7) - { -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO "%s: wv_start_of_frame: Received null frame, rfp %d len 0x%x\n", - dev->name, rfp, len); -#endif - return(-1); - } - - /* Wrap around buffer */ - if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE)) /* magic formula ! */ - { -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO "%s: wv_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n", - dev->name, wrap, rfp, len); -#endif - return(-1); - } - - return((rp - len + RX_SIZE) % RX_SIZE); -} /* wv_start_of_frame */ - -/*------------------------------------------------------------------*/ -/* - * This routine does the actual copy of data (including the ethernet - * header structure) from the WaveLAN card to an sk_buff chain that - * will be passed up to the network interface layer. NOTE: We - * currently don't handle trailer protocols (neither does the rest of - * the network interface), so if that is needed, it will (at least in - * part) be added here. The contents of the receive ring buffer are - * copied to a message chain that is then passed to the kernel. - * - * Note: if any errors occur, the packet is "dropped on the floor" - * (called by wv_packet_rcv()) - */ -static void -wv_packet_read(struct net_device * dev, - int fd_p, - int sksize) -{ - net_local * lp = netdev_priv(dev); - struct sk_buff * skb; - -#ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", - dev->name, fd_p, sksize); -#endif - - /* Allocate some buffer for the new packet */ - if((skb = dev_alloc_skb(sksize+2)) == (struct sk_buff *) NULL) - { -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n", - dev->name, sksize); -#endif - dev->stats.rx_dropped++; - /* - * Not only do we want to return here, but we also need to drop the - * packet on the floor to clear the interrupt. - */ - return; - } - - skb_reserve(skb, 2); - fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize); - skb->protocol = eth_type_trans(skb, dev); - -#ifdef DEBUG_RX_INFO - wv_packet_info(skb_mac_header(skb), sksize, dev->name, "wv_packet_read"); -#endif /* DEBUG_RX_INFO */ - - /* Statistics gathering & stuff associated. - * It seem a bit messy with all the define, but it's really simple... */ - if( -#ifdef IW_WIRELESS_SPY - (lp->spy_data.spy_number > 0) || -#endif /* IW_WIRELESS_SPY */ -#ifdef HISTOGRAM - (lp->his_number > 0) || -#endif /* HISTOGRAM */ -#ifdef WAVELAN_ROAMING - (do_roaming) || -#endif /* WAVELAN_ROAMING */ - 0) - { - u_char stats[3]; /* Signal level, Noise level, Signal quality */ - - /* read signal level, silence level and signal quality bytes */ - fd_p = read_ringbuf(dev, (fd_p + 4) % RX_SIZE + RX_BASE, - stats, 3); -#ifdef DEBUG_RX_INFO - printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", - dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F); -#endif - -#ifdef WAVELAN_ROAMING - if(do_roaming) - if(WAVELAN_BEACON(skb->data)) - wl_roam_gather(dev, skb->data, stats); -#endif /* WAVELAN_ROAMING */ - -#ifdef WIRELESS_SPY - wl_spy_gather(dev, skb_mac_header(skb) + WAVELAN_ADDR_SIZE, stats); -#endif /* WIRELESS_SPY */ -#ifdef HISTOGRAM - wl_his_gather(dev, stats); -#endif /* HISTOGRAM */ - } - - /* - * Hand the packet to the Network Module - */ - netif_rx(skb); - - /* Keep stats up to date */ - dev->stats.rx_packets++; - dev->stats.rx_bytes += sksize; - -#ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); -#endif - return; -} - -/*------------------------------------------------------------------*/ -/* - * This routine is called by the interrupt handler to initiate a - * packet transfer from the card to the network interface layer above - * this driver. This routine checks if a buffer has been successfully - * received by the WaveLAN card. If so, the routine wv_packet_read is - * called to do the actual transfer of the card's data including the - * ethernet header into a packet consisting of an sk_buff chain. - * (called by wavelan_interrupt()) - * Note : the spinlock is already grabbed for us and irq are disabled. - */ -static void -wv_packet_rcv(struct net_device * dev) -{ - unsigned int base = dev->base_addr; - net_local * lp = netdev_priv(dev); - int newrfp; - int rp; - int len; - int f_start; - int status; - int i593_rfp; - int stat_ptr; - u_char c[4]; - -#ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: ->wv_packet_rcv()\n", dev->name); -#endif - - /* Get the new receive frame pointer from the i82593 chip */ - outb(CR0_STATUS_2 | OP0_NOP, LCCR(base)); - i593_rfp = inb(LCSR(base)); - i593_rfp |= inb(LCSR(base)) << 8; - i593_rfp %= RX_SIZE; - - /* Get the new receive frame pointer from the WaveLAN card. - * It is 3 bytes more than the increment of the i82593 receive - * frame pointer, for each packet. This is because it includes the - * 3 roaming bytes added by the mmc. - */ - newrfp = inb(RPLL(base)); - newrfp |= inb(RPLH(base)) << 8; - newrfp %= RX_SIZE; - -#ifdef DEBUG_RX_INFO - printk(KERN_DEBUG "%s: wv_packet_rcv(): i593_rfp %d stop %d newrfp %d lp->rfp %d\n", - dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); -#endif - -#ifdef DEBUG_RX_ERROR - /* If no new frame pointer... */ - if(lp->overrunning || newrfp == lp->rfp) - printk(KERN_INFO "%s: wv_packet_rcv(): no new frame: i593_rfp %d stop %d newrfp %d lp->rfp %d\n", - dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); -#endif - - /* Read all frames (packets) received */ - while(newrfp != lp->rfp) - { - /* A frame is composed of the packet, followed by a status word, - * the length of the frame (word) and the mmc info (SNR & qual). - * It's because the length is at the end that we can only scan - * frames backward. */ - - /* Find the first frame by skipping backwards over the frames */ - rp = newrfp; /* End of last frame */ - while(((f_start = wv_start_of_frame(dev, rp, newrfp)) != lp->rfp) && - (f_start != -1)) - rp = f_start; - - /* If we had a problem */ - if(f_start == -1) - { -#ifdef DEBUG_RX_ERROR - printk(KERN_INFO "wavelan_cs: cannot find start of frame "); - printk(" i593_rfp %d stop %d newrfp %d lp->rfp %d\n", - i593_rfp, lp->stop, newrfp, lp->rfp); -#endif - lp->rfp = rp; /* Get to the last usable frame */ - continue; - } - - /* f_start point to the beggining of the first frame received - * and rp to the beggining of the next one */ - - /* Read status & length of the frame */ - stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE; - stat_ptr = read_ringbuf(dev, stat_ptr, c, 4); - status = c[0] | (c[1] << 8); - len = c[2] | (c[3] << 8); - - /* Check status */ - if((status & RX_RCV_OK) != RX_RCV_OK) - { - dev->stats.rx_errors++; - if(status & RX_NO_SFD) - dev->stats.rx_frame_errors++; - if(status & RX_CRC_ERR) - dev->stats.rx_crc_errors++; - if(status & RX_OVRRUN) - dev->stats.rx_over_errors++; - -#ifdef DEBUG_RX_FAIL - printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n", - dev->name, status); -#endif - } - else - /* Read the packet and transmit to Linux */ - wv_packet_read(dev, f_start, len - 2); - - /* One frame has been processed, skip it */ - lp->rfp = rp; - } - - /* - * Update the frame stop register, but set it to less than - * the full 8K to allow space for 3 bytes of signal strength - * per packet. - */ - lp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; - outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); - outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); - outb(OP1_SWIT_TO_PORT_0, LCCR(base)); - -#ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: <-wv_packet_rcv()\n", dev->name); -#endif -} - -/*********************** PACKET TRANSMISSION ***********************/ -/* - * This part deal with sending packet through the wavelan - * We copy the packet to the send buffer and then issue the send - * command to the i82593. The result of this operation will be - * checked in wavelan_interrupt() - */ - -/*------------------------------------------------------------------*/ -/* - * This routine fills in the appropriate registers and memory - * locations on the WaveLAN card and starts the card off on - * the transmit. - * (called in wavelan_packet_xmit()) - */ -static void -wv_packet_write(struct net_device * dev, - void * buf, - short length) -{ - net_local * lp = netdev_priv(dev); - unsigned int base = dev->base_addr; - unsigned long flags; - int clen = length; - register u_short xmtdata_base = TX_BASE; - -#ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); -#endif - - spin_lock_irqsave(&lp->spinlock, flags); - - /* Write the length of data buffer followed by the buffer */ - outb(xmtdata_base & 0xff, PIORL(base)); - outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); - outb(clen & 0xff, PIOP(base)); /* lsb */ - outb(clen >> 8, PIOP(base)); /* msb */ - - /* Send the data */ - outsb(PIOP(base), buf, clen); - - /* Indicate end of transmit chain */ - outb(OP0_NOP, PIOP(base)); - /* josullvn@cs.cmu.edu: need to send a second NOP for alignment... */ - outb(OP0_NOP, PIOP(base)); - - /* Reset the transmit DMA pointer */ - hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); - hacr_write(base, HACR_DEFAULT); - /* Send the transmit command */ - wv_82593_cmd(dev, "wv_packet_write(): transmit", - OP0_TRANSMIT, SR0_NO_RESULT); - - /* Make sure the watchdog will keep quiet for a while */ - dev->trans_start = jiffies; - - /* Keep stats up to date */ - dev->stats.tx_bytes += length; - - spin_unlock_irqrestore(&lp->spinlock, flags); - -#ifdef DEBUG_TX_INFO - wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); -#endif /* DEBUG_TX_INFO */ - -#ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); -#endif -} - -/*------------------------------------------------------------------*/ -/* - * This routine is called when we want to send a packet (NET3 callback) - * In this routine, we check if the harware is ready to accept - * the packet. We also prevent reentrance. Then, we call the function - * to send the packet... - */ -static netdev_tx_t -wavelan_packet_xmit(struct sk_buff * skb, - struct net_device * dev) -{ - net_local * lp = netdev_priv(dev); - unsigned long flags; - -#ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, - (unsigned) skb); -#endif - - /* - * Block a timer-based transmit from overlapping a previous transmit. - * In other words, prevent reentering this routine. - */ - netif_stop_queue(dev); - - /* If somebody has asked to reconfigure the controller, - * we can do it now */ - if(lp->reconfig_82593) - { - spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ - wv_82593_config(dev); - spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ - /* Note : the configure procedure was totally synchronous, - * so the Tx buffer is now free */ - } - - /* Check if we need some padding */ - /* Note : on wireless the propagation time is in the order of 1us, - * and we don't have the Ethernet specific requirement of beeing - * able to detect collisions, therefore in theory we don't really - * need to pad. Jean II */ - if (skb_padto(skb, ETH_ZLEN)) - return NETDEV_TX_OK; - - wv_packet_write(dev, skb->data, skb->len); - - dev_kfree_skb(skb); - -#ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); -#endif - return NETDEV_TX_OK; -} - -/********************** HARDWARE CONFIGURATION **********************/ -/* - * This part do the real job of starting and configuring the hardware. - */ - -/*------------------------------------------------------------------*/ -/* - * Routine to initialize the Modem Management Controller. - * (called by wv_hw_config()) - */ -static int -wv_mmc_init(struct net_device * dev) -{ - unsigned int base = dev->base_addr; - psa_t psa; - mmw_t m; - int configured; - int i; /* Loop counter */ - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); -#endif - - /* Read the parameter storage area */ - psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); - - /* - * Check the first three octets of the MAC addr for the manufacturer's code. - * Note: If you get the error message below, you've got a - * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on - * how to configure your card... - */ - for (i = 0; i < ARRAY_SIZE(MAC_ADDRESSES); i++) - if ((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) && - (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) && - (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2])) - break; - - /* If we have not found it... */ - if (i == ARRAY_SIZE(MAC_ADDRESSES)) - { -#ifdef DEBUG_CONFIG_ERRORS - printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n", - dev->name, psa.psa_univ_mac_addr[0], - psa.psa_univ_mac_addr[1], psa.psa_univ_mac_addr[2]); -#endif - return FALSE; - } - - /* Get the MAC address */ - memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE); - -#ifdef USE_PSA_CONFIG - configured = psa.psa_conf_status & 1; -#else - configured = 0; -#endif - - /* Is the PSA is not configured */ - if(!configured) - { - /* User will be able to configure NWID after (with iwconfig) */ - psa.psa_nwid[0] = 0; - psa.psa_nwid[1] = 0; - - /* As NWID is not set : no NWID checking */ - psa.psa_nwid_select = 0; - - /* Disable encryption */ - psa.psa_encryption_select = 0; - - /* Set to standard values - * 0x04 for AT, - * 0x01 for MCA, - * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) - */ - if (psa.psa_comp_number & 1) - psa.psa_thr_pre_set = 0x01; - else - psa.psa_thr_pre_set = 0x04; - psa.psa_quality_thr = 0x03; - - /* It is configured */ - psa.psa_conf_status |= 1; - -#ifdef USE_PSA_CONFIG - /* Write the psa */ - psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, - (unsigned char *)psa.psa_nwid, 4); - psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, - (unsigned char *)&psa.psa_thr_pre_set, 1); - psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, - (unsigned char *)&psa.psa_quality_thr, 1); - psa_write(dev, (char *)&psa.psa_conf_status - (char *)&psa, - (unsigned char *)&psa.psa_conf_status, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev); -#endif /* USE_PSA_CONFIG */ - } - - /* Zero the mmc structure */ - memset(&m, 0x00, sizeof(m)); - - /* Copy PSA info to the mmc */ - m.mmw_netw_id_l = psa.psa_nwid[1]; - m.mmw_netw_id_h = psa.psa_nwid[0]; - - if(psa.psa_nwid_select & 1) - m.mmw_loopt_sel = 0x00; - else - m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; - - memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, - sizeof(m.mmw_encr_key)); - - if(psa.psa_encryption_select) - m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; - else - m.mmw_encr_enable = 0; - - m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; - m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; - - /* - * Set default modem control parameters. - * See NCR document 407-0024326 Rev. A. - */ - m.mmw_jabber_enable = 0x01; - m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; - m.mmw_ifs = 0x20; - m.mmw_mod_delay = 0x04; - m.mmw_jam_time = 0x38; - - m.mmw_des_io_invert = 0; - m.mmw_freeze = 0; - m.mmw_decay_prm = 0; - m.mmw_decay_updat_prm = 0; - - /* Write all info to mmc */ - mmc_write(base, 0, (u_char *)&m, sizeof(m)); - - /* The following code start the modem of the 2.00 frequency - * selectable cards at power on. It's not strictly needed for the - * following boots... - * The original patch was by Joe Finney for the PCMCIA driver, but - * I've cleaned it a bit and add documentation. - * Thanks to Loeke Brederveld from Lucent for the info. - */ - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * (does it work for everybody ? - especially old cards...) */ - /* Note : WFREQSEL verify that it is able to read from EEprom - * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID - * is 0xA (Xilinx version) or 0xB (Ariadne version). - * My test is more crude but do work... */ - if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - { - /* We must download the frequency parameters to the - * synthetisers (from the EEprom - area 1) - * Note : as the EEprom is auto decremented, we set the end - * if the area... */ - m.mmw_fee_addr = 0x0F; - m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; - mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, - (unsigned char *)&m.mmw_fee_ctrl, 2); - - /* Wait until the download is finished */ - fee_wait(base, 100, 100); - -#ifdef DEBUG_CONFIG_INFO - /* The frequency was in the last word downloaded... */ - mmc_read(base, (char *)&m.mmw_fee_data_l - (char *)&m, - (unsigned char *)&m.mmw_fee_data_l, 2); - - /* Print some info for the user */ - printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n", - dev->name, - ((m.mmw_fee_data_h << 4) | - (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L); -#endif - - /* We must now download the power adjust value (gain) to - * the synthetisers (from the EEprom - area 7 - DAC) */ - m.mmw_fee_addr = 0x61; - m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; - mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, - (unsigned char *)&m.mmw_fee_ctrl, 2); - - /* Wait until the download is finished */ - } /* if 2.00 card */ - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); -#endif - return TRUE; -} - -/*------------------------------------------------------------------*/ -/* - * Routine to gracefully turn off reception, and wait for any commands - * to complete. - * (called in wv_ru_start() and wavelan_close() and wavelan_event()) - */ -static int -wv_ru_stop(struct net_device * dev) -{ - unsigned int base = dev->base_addr; - net_local * lp = netdev_priv(dev); - unsigned long flags; - int status; - int spin; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); -#endif - - spin_lock_irqsave(&lp->spinlock, flags); - - /* First, send the LAN controller a stop receive command */ - wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", - OP0_STOP_RCV, SR0_NO_RESULT); - - /* Then, spin until the receive unit goes idle */ - spin = 300; - do - { - udelay(10); - outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); - status = inb(LCSR(base)); - } - while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0)); - - /* Now, spin until the chip finishes executing its current command */ - do - { - udelay(10); - outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); - status = inb(LCSR(base)); - } - while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); - - spin_unlock_irqrestore(&lp->spinlock, flags); - - /* If there was a problem */ - if(spin <= 0) - { -#ifdef DEBUG_CONFIG_ERRORS - printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n", - dev->name); -#endif - return FALSE; - } - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_ru_stop()\n", dev->name); -#endif - return TRUE; -} /* wv_ru_stop */ - -/*------------------------------------------------------------------*/ -/* - * This routine starts the receive unit running. First, it checks if - * the card is actually ready. Then the card is instructed to receive - * packets again. - * (called in wv_hw_reset() & wavelan_open()) - */ -static int -wv_ru_start(struct net_device * dev) -{ - unsigned int base = dev->base_addr; - net_local * lp = netdev_priv(dev); - unsigned long flags; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); -#endif - - /* - * We need to start from a quiescent state. To do so, we could check - * if the card is already running, but instead we just try to shut - * it down. First, we disable reception (in case it was already enabled). - */ - if(!wv_ru_stop(dev)) - return FALSE; - - spin_lock_irqsave(&lp->spinlock, flags); - - /* Now we know that no command is being executed. */ - - /* Set the receive frame pointer and stop pointer */ - lp->rfp = 0; - outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); - - /* Reset ring management. This sets the receive frame pointer to 1 */ - outb(OP1_RESET_RING_MNGMT, LCCR(base)); - -#if 0 - /* XXX the i82593 manual page 6-4 seems to indicate that the stop register - should be set as below */ - /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/ -#elif 0 - /* but I set it 0 instead */ - lp->stop = 0; -#else - /* but I set it to 3 bytes per packet less than 8K */ - lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; -#endif - outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); - outb(OP1_INT_ENABLE, LCCR(base)); - outb(OP1_SWIT_TO_PORT_0, LCCR(base)); - - /* Reset receive DMA pointer */ - hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); - hacr_write_slow(base, HACR_DEFAULT); - - /* Receive DMA on channel 1 */ - wv_82593_cmd(dev, "wv_ru_start(): rcv-enable", - CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT); - -#ifdef DEBUG_I82593_SHOW - { - int status; - int opri; - int spin = 10000; - - /* spin until the chip starts receiving */ - do - { - outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); - status = inb(LCSR(base)); - if(spin-- <= 0) - break; - } - while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) && - ((status & SR3_RCV_STATE_MASK) != SR3_RCV_READY)); - printk(KERN_DEBUG "rcv status is 0x%x [i:%d]\n", - (status & SR3_RCV_STATE_MASK), i); - } -#endif - - spin_unlock_irqrestore(&lp->spinlock, flags); - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); -#endif - return TRUE; -} - -/*------------------------------------------------------------------*/ -/* - * This routine does a standard config of the WaveLAN controller (i82593). - * In the ISA driver, this is integrated in wavelan_hardware_reset() - * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) - */ -static int -wv_82593_config(struct net_device * dev) -{ - unsigned int base = dev->base_addr; - net_local * lp = netdev_priv(dev); - struct i82593_conf_block cfblk; - int ret = TRUE; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name); -#endif - - /* Create & fill i82593 config block - * - * Now conform to Wavelan document WCIN085B - */ - memset(&cfblk, 0x00, sizeof(struct i82593_conf_block)); - cfblk.d6mod = FALSE; /* Run in i82593 advanced mode */ - cfblk.fifo_limit = 5; /* = 56 B rx and 40 B tx fifo thresholds */ - cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */ - cfblk.fifo_32 = 1; - cfblk.throttle_enb = FALSE; - cfblk.contin = TRUE; /* enable continuous mode */ - cfblk.cntrxint = FALSE; /* enable continuous mode receive interrupts */ - cfblk.addr_len = WAVELAN_ADDR_SIZE; - cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */ - cfblk.preamb_len = 0; /* 2 bytes preamble (SFD) */ - cfblk.loopback = FALSE; - cfblk.lin_prio = 0; /* conform to 802.3 backoff algorithm */ - cfblk.exp_prio = 5; /* conform to 802.3 backoff algorithm */ - cfblk.bof_met = 1; /* conform to 802.3 backoff algorithm */ - cfblk.ifrm_spc = 0x20 >> 4; /* 32 bit times interframe spacing */ - cfblk.slottim_low = 0x20 >> 5; /* 32 bit times slot time */ - cfblk.slottim_hi = 0x0; - cfblk.max_retr = 15; - cfblk.prmisc = ((lp->promiscuous) ? TRUE: FALSE); /* Promiscuous mode */ - cfblk.bc_dis = FALSE; /* Enable broadcast reception */ - cfblk.crs_1 = TRUE; /* Transmit without carrier sense */ - cfblk.nocrc_ins = FALSE; /* i82593 generates CRC */ - cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */ - cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */ - cfblk.cs_filter = 0; /* CS is recognized immediately */ - cfblk.crs_src = FALSE; /* External carrier sense */ - cfblk.cd_filter = 0; /* CD is recognized immediately */ - cfblk.min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length 64 bytes */ - cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */ - cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */ - cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */ - cfblk.artx = TRUE; /* Disable automatic retransmission */ - cfblk.sarec = TRUE; /* Disable source addr trig of CD */ - cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */ - cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */ - cfblk.lbpkpol = TRUE; /* Loopback pin active high */ - cfblk.fdx = FALSE; /* Disable full duplex operation */ - cfblk.dummy_6 = 0x3f; /* all ones */ - cfblk.mult_ia = FALSE; /* No multiple individual addresses */ - cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */ - cfblk.dummy_1 = TRUE; /* set to 1 */ - cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */ -#ifdef MULTICAST_ALL - cfblk.mc_all = (lp->allmulticast ? TRUE: FALSE); /* Allow all multicasts */ -#else - cfblk.mc_all = FALSE; /* No multicast all mode */ -#endif - cfblk.rcv_mon = 0; /* Monitor mode disabled */ - cfblk.frag_acpt = TRUE; /* Do not accept fragments */ - cfblk.tstrttrs = FALSE; /* No start transmission threshold */ - cfblk.fretx = TRUE; /* FIFO automatic retransmission */ - cfblk.syncrqs = FALSE; /* Synchronous DRQ deassertion... */ - cfblk.sttlen = TRUE; /* 6 byte status registers */ - cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */ - cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */ - cfblk.rbuf_size = RX_SIZE>>11; /* Set receive buffer size */ - cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */ - -#ifdef DEBUG_I82593_SHOW - print_hex_dump(KERN_DEBUG, "wavelan_cs: config block: ", DUMP_PREFIX_NONE, - 16, 1, &cfblk, sizeof(struct i82593_conf_block), false); -#endif - - /* Copy the config block to the i82593 */ - outb(TX_BASE & 0xff, PIORL(base)); - outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); - outb(sizeof(struct i82593_conf_block) & 0xff, PIOP(base)); /* lsb */ - outb(sizeof(struct i82593_conf_block) >> 8, PIOP(base)); /* msb */ - outsb(PIOP(base), (char *) &cfblk, sizeof(struct i82593_conf_block)); - - /* reset transmit DMA pointer */ - hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); - hacr_write(base, HACR_DEFAULT); - if(!wv_82593_cmd(dev, "wv_82593_config(): configure", - OP0_CONFIGURE, SR0_CONFIGURE_DONE)) - ret = FALSE; - - /* Initialize adapter's ethernet MAC address */ - outb(TX_BASE & 0xff, PIORL(base)); - outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); - outb(WAVELAN_ADDR_SIZE, PIOP(base)); /* byte count lsb */ - outb(0, PIOP(base)); /* byte count msb */ - outsb(PIOP(base), &dev->dev_addr[0], WAVELAN_ADDR_SIZE); - - /* reset transmit DMA pointer */ - hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); - hacr_write(base, HACR_DEFAULT); - if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup", - OP0_IA_SETUP, SR0_IA_SETUP_DONE)) - ret = FALSE; - -#ifdef WAVELAN_ROAMING - /* If roaming is enabled, join the "Beacon Request" multicast group... */ - /* But only if it's not in there already! */ - if(do_roaming) - dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1); -#endif /* WAVELAN_ROAMING */ - - /* If any multicast address to set */ - if(lp->mc_count) - { - struct dev_mc_list * dmi; - int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; - -#ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n", - dev->name, lp->mc_count); - for(dmi=dev->mc_list; dmi; dmi=dmi->next) - printk(KERN_DEBUG " %pM\n", dmi->dmi_addr); -#endif - - /* Initialize adapter's ethernet multicast addresses */ - outb(TX_BASE & 0xff, PIORL(base)); - outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); - outb(addrs_len & 0xff, PIOP(base)); /* byte count lsb */ - outb((addrs_len >> 8), PIOP(base)); /* byte count msb */ - for(dmi=dev->mc_list; dmi; dmi=dmi->next) - outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen); - - /* reset transmit DMA pointer */ - hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); - hacr_write(base, HACR_DEFAULT); - if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup", - OP0_MC_SETUP, SR0_MC_SETUP_DONE)) - ret = FALSE; - lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */ - } - - /* Job done, clear the flag */ - lp->reconfig_82593 = FALSE; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name); -#endif - return(ret); -} - -/*------------------------------------------------------------------*/ -/* - * Read the Access Configuration Register, perform a software reset, - * and then re-enable the card's software. - * - * If I understand correctly : reset the pcmcia interface of the - * wavelan. - * (called by wv_config()) - */ -static int -wv_pcmcia_reset(struct net_device * dev) -{ - int i; - conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; - struct pcmcia_device * link = ((net_local *)netdev_priv(dev))->link; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name); -#endif - - i = pcmcia_access_configuration_register(link, ®); - if (i != 0) - { - cs_error(link, AccessConfigurationRegister, i); - return FALSE; - } - -#ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n", - dev->name, (u_int) reg.Value); -#endif - - reg.Action = CS_WRITE; - reg.Value = reg.Value | COR_SW_RESET; - i = pcmcia_access_configuration_register(link, ®); - if (i != 0) - { - cs_error(link, AccessConfigurationRegister, i); - return FALSE; - } - - reg.Action = CS_WRITE; - reg.Value = COR_LEVEL_IRQ | COR_CONFIG; - i = pcmcia_access_configuration_register(link, ®); - if (i != 0) - { - cs_error(link, AccessConfigurationRegister, i); - return FALSE; - } - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name); -#endif - return TRUE; -} - -/*------------------------------------------------------------------*/ -/* - * wavelan_hw_config() is called after a CARD_INSERTION event is - * received, to configure the wavelan hardware. - * Note that the reception will be enabled in wavelan->open(), so the - * device is configured but idle... - * Performs the following actions: - * 1. A pcmcia software reset (using wv_pcmcia_reset()) - * 2. A power reset (reset DMA) - * 3. Reset the LAN controller - * 4. Initialize the radio modem (using wv_mmc_init) - * 5. Configure LAN controller (using wv_82593_config) - * 6. Perform a diagnostic on the LAN controller - * (called by wavelan_event() & wv_hw_reset()) - */ -static int -wv_hw_config(struct net_device * dev) -{ - net_local * lp = netdev_priv(dev); - unsigned int base = dev->base_addr; - unsigned long flags; - int ret = FALSE; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name); -#endif - - /* compile-time check the sizes of structures */ - BUILD_BUG_ON(sizeof(psa_t) != PSA_SIZE); - BUILD_BUG_ON(sizeof(mmw_t) != MMW_SIZE); - BUILD_BUG_ON(sizeof(mmr_t) != MMR_SIZE); - - /* Reset the pcmcia interface */ - if(wv_pcmcia_reset(dev) == FALSE) - return FALSE; - - /* Disable interrupts */ - spin_lock_irqsave(&lp->spinlock, flags); - - /* Disguised goto ;-) */ - do - { - /* Power UP the module + reset the modem + reset host adapter - * (in fact, reset DMA channels) */ - hacr_write_slow(base, HACR_RESET); - hacr_write(base, HACR_DEFAULT); - - /* Check if the module has been powered up... */ - if(hasr_read(base) & HASR_NO_CLK) - { -#ifdef DEBUG_CONFIG_ERRORS - printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n", - dev->name); -#endif - break; - } - - /* initialize the modem */ - if(wv_mmc_init(dev) == FALSE) - { -#ifdef DEBUG_CONFIG_ERRORS - printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n", - dev->name); -#endif - break; - } - - /* reset the LAN controller (i82593) */ - outb(OP0_RESET, LCCR(base)); - mdelay(1); /* A bit crude ! */ - - /* Initialize the LAN controller */ - if(wv_82593_config(dev) == FALSE) - { -#ifdef DEBUG_CONFIG_ERRORS - printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", - dev->name); -#endif - break; - } - - /* Diagnostic */ - if(wv_diag(dev) == FALSE) - { -#ifdef DEBUG_CONFIG_ERRORS - printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n", - dev->name); -#endif - break; - } - - /* - * insert code for loopback test here - */ - - /* The device is now configured */ - lp->configured = 1; - ret = TRUE; - } - while(0); - - /* Re-enable interrupts */ - spin_unlock_irqrestore(&lp->spinlock, flags); - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); -#endif - return(ret); -} - -/*------------------------------------------------------------------*/ -/* - * Totally reset the wavelan and restart it. - * Performs the following actions: - * 1. Call wv_hw_config() - * 2. Start the LAN controller's receive unit - * (called by wavelan_event(), wavelan_watchdog() and wavelan_open()) - */ -static void -wv_hw_reset(struct net_device * dev) -{ - net_local * lp = netdev_priv(dev); - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name); -#endif - - lp->nresets++; - lp->configured = 0; - - /* Call wv_hw_config() for most of the reset & init stuff */ - if(wv_hw_config(dev) == FALSE) - return; - - /* start receive unit */ - wv_ru_start(dev); - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); -#endif -} - -/*------------------------------------------------------------------*/ -/* - * wv_pcmcia_config() is called after a CARD_INSERTION event is - * received, to configure the PCMCIA socket, and to make the ethernet - * device available to the system. - * (called by wavelan_event()) - */ -static int -wv_pcmcia_config(struct pcmcia_device * link) -{ - struct net_device * dev = (struct net_device *) link->priv; - int i; - win_req_t req; - memreq_t mem; - net_local * lp = netdev_priv(dev); - - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link); -#endif - - do - { - i = pcmcia_request_io(link, &link->io); - if (i != 0) - { - cs_error(link, RequestIO, i); - break; - } - - /* - * Now allocate an interrupt line. Note that this does not - * actually assign a handler to the interrupt. - */ - i = pcmcia_request_irq(link, &link->irq); - if (i != 0) - { - cs_error(link, RequestIRQ, i); - break; - } - - /* - * This actually configures the PCMCIA socket -- setting up - * the I/O windows and the interrupt mapping. - */ - link->conf.ConfigIndex = 1; - i = pcmcia_request_configuration(link, &link->conf); - if (i != 0) - { - cs_error(link, RequestConfiguration, i); - break; - } - - /* - * Allocate a small memory window. Note that the struct pcmcia_device - * structure provides space for one window handle -- if your - * device needs several windows, you'll need to keep track of - * the handles in your private data structure, link->priv. - */ - req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; - req.Base = req.Size = 0; - req.AccessSpeed = mem_speed; - i = pcmcia_request_window(&link, &req, &link->win); - if (i != 0) - { - cs_error(link, RequestWindow, i); - break; - } - - lp->mem = ioremap(req.Base, req.Size); - dev->mem_start = (u_long)lp->mem; - dev->mem_end = dev->mem_start + req.Size; - - mem.CardOffset = 0; mem.Page = 0; - i = pcmcia_map_mem_page(link->win, &mem); - if (i != 0) - { - cs_error(link, MapMemPage, i); - break; - } - - /* Feed device with this info... */ - dev->irq = link->irq.AssignedIRQ; - dev->base_addr = link->io.BasePort1; - netif_start_queue(dev); - -#ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART %p IRQ %d IOPORT 0x%x\n", - lp->mem, dev->irq, (u_int) dev->base_addr); -#endif - - SET_NETDEV_DEV(dev, &handle_to_dev(link)); - i = register_netdev(dev); - if(i != 0) - { -#ifdef DEBUG_CONFIG_ERRORS - printk(KERN_INFO "wv_pcmcia_config(): register_netdev() failed\n"); -#endif - break; - } - } - while(0); /* Humm... Disguised goto !!! */ - - /* If any step failed, release any partially configured state */ - if(i != 0) - { - wv_pcmcia_release(link); - return FALSE; - } - - strcpy(((net_local *) netdev_priv(dev))->node.dev_name, dev->name); - link->dev_node = &((net_local *) netdev_priv(dev))->node; - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "<-wv_pcmcia_config()\n"); -#endif - return TRUE; -} - -/*------------------------------------------------------------------*/ -/* - * After a card is removed, wv_pcmcia_release() will unregister the net - * device, and release the PCMCIA configuration. If the device is - * still open, this will be postponed until it is closed. - */ -static void -wv_pcmcia_release(struct pcmcia_device *link) -{ - struct net_device * dev = (struct net_device *) link->priv; - net_local * lp = netdev_priv(dev); - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); -#endif - - iounmap(lp->mem); - pcmcia_disable_device(link); - -#ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); -#endif -} - -/************************ INTERRUPT HANDLING ************************/ - -/* - * This function is the interrupt handler for the WaveLAN card. This - * routine will be called whenever: - * 1. A packet is received. - * 2. A packet has successfully been transferred and the unit is - * ready to transmit another packet. - * 3. A command has completed execution. - */ -static irqreturn_t -wavelan_interrupt(int irq, - void * dev_id) -{ - struct net_device * dev = dev_id; - net_local * lp; - unsigned int base; - int status0; - u_int tx_status; - -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); -#endif - - lp = netdev_priv(dev); - base = dev->base_addr; - -#ifdef DEBUG_INTERRUPT_INFO - /* Check state of our spinlock (it should be cleared) */ - if(spin_is_locked(&lp->spinlock)) - printk(KERN_DEBUG - "%s: wavelan_interrupt(): spinlock is already locked !!!\n", - dev->name); -#endif - - /* Prevent reentrancy. We need to do that because we may have - * multiple interrupt handler running concurently. - * It is safe because interrupts are disabled before aquiring - * the spinlock. */ - spin_lock(&lp->spinlock); - - /* Treat all pending interrupts */ - while(1) - { - /* ---------------- INTERRUPT CHECKING ---------------- */ - /* - * Look for the interrupt and verify the validity - */ - outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); - status0 = inb(LCSR(base)); - -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG "status0 0x%x [%s => 0x%x]", status0, - (status0&SR0_INTERRUPT)?"int":"no int",status0&~SR0_INTERRUPT); - if(status0&SR0_INTERRUPT) - { - printk(" [%s => %d]\n", (status0 & SR0_CHNL) ? "chnl" : - ((status0 & SR0_EXECUTION) ? "cmd" : - ((status0 & SR0_RECEPTION) ? "recv" : "unknown")), - (status0 & SR0_EVENT_MASK)); - } - else - printk("\n"); -#endif - - /* Return if no actual interrupt from i82593 (normal exit) */ - if(!(status0 & SR0_INTERRUPT)) - break; - - /* If interrupt is both Rx and Tx or none... - * This code in fact is there to catch the spurious interrupt - * when you remove the wavelan pcmcia card from the socket */ - if(((status0 & SR0_BOTH_RX_TX) == SR0_BOTH_RX_TX) || - ((status0 & SR0_BOTH_RX_TX) == 0x0)) - { -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_INFO "%s: wv_interrupt(): bogus interrupt (or from dead card) : %X\n", - dev->name, status0); -#endif - /* Acknowledge the interrupt */ - outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); - break; - } - - /* ----------------- RECEIVING PACKET ----------------- */ - /* - * When the wavelan signal the reception of a new packet, - * we call wv_packet_rcv() to copy if from the buffer and - * send it to NET3 - */ - if(status0 & SR0_RECEPTION) - { -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG "%s: wv_interrupt(): receive\n", dev->name); -#endif - - if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) - { -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n", - dev->name); -#endif - dev->stats.rx_over_errors++; - lp->overrunning = 1; - } - - /* Get the packet */ - wv_packet_rcv(dev); - lp->overrunning = 0; - - /* Acknowledge the interrupt */ - outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); - continue; - } - - /* ---------------- COMMAND COMPLETION ---------------- */ - /* - * Interrupts issued when the i82593 has completed a command. - * Most likely : transmission done - */ - - /* If a transmission has been done */ - if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || - (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE || - (status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) - { -#ifdef DEBUG_TX_ERROR - if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) - printk(KERN_INFO "%s: wv_interrupt(): packet transmitted without CRC.\n", - dev->name); -#endif - - /* Get transmission status */ - tx_status = inb(LCSR(base)); - tx_status |= (inb(LCSR(base)) << 8); -#ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG "%s: wv_interrupt(): transmission done\n", - dev->name); - { - u_int rcv_bytes; - u_char status3; - rcv_bytes = inb(LCSR(base)); - rcv_bytes |= (inb(LCSR(base)) << 8); - status3 = inb(LCSR(base)); - printk(KERN_DEBUG "tx_status 0x%02x rcv_bytes 0x%02x status3 0x%x\n", - tx_status, rcv_bytes, (u_int) status3); - } -#endif - /* Check for possible errors */ - if((tx_status & TX_OK) != TX_OK) - { - dev->stats.tx_errors++; - - if(tx_status & TX_FRTL) - { -#ifdef DEBUG_TX_ERROR - printk(KERN_INFO "%s: wv_interrupt(): frame too long\n", - dev->name); -#endif - } - if(tx_status & TX_UND_RUN) - { -#ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n", - dev->name); -#endif - dev->stats.tx_aborted_errors++; - } - if(tx_status & TX_LOST_CTS) - { -#ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name); -#endif - dev->stats.tx_carrier_errors++; - } - if(tx_status & TX_LOST_CRS) - { -#ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n", - dev->name); -#endif - dev->stats.tx_carrier_errors++; - } - if(tx_status & TX_HRT_BEAT) - { -#ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name); -#endif - dev->stats.tx_heartbeat_errors++; - } - if(tx_status & TX_DEFER) - { -#ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG "%s: wv_interrupt(): channel jammed\n", - dev->name); -#endif - } - /* Ignore late collisions since they're more likely to happen - * here (the WaveLAN design prevents the LAN controller from - * receiving while it is transmitting). We take action only when - * the maximum retransmit attempts is exceeded. - */ - if(tx_status & TX_COLL) - { - if(tx_status & TX_MAX_COL) - { -#ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG "%s: wv_interrupt(): channel congestion\n", - dev->name); -#endif - if(!(tx_status & TX_NCOL_MASK)) - { - dev->stats.collisions += 0x10; - } - } - } - } /* if(!(tx_status & TX_OK)) */ - - dev->stats.collisions += (tx_status & TX_NCOL_MASK); - dev->stats.tx_packets++; - - netif_wake_queue(dev); - outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ - } - else /* if interrupt = transmit done or retransmit done */ - { -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "wavelan_cs: unknown interrupt, status0 = %02x\n", - status0); -#endif - outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ - } - } /* while(1) */ - - spin_unlock(&lp->spinlock); - -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); -#endif - - /* We always return IRQ_HANDLED, because we will receive empty - * interrupts under normal operations. Anyway, it doesn't matter - * as we are dealing with an ISA interrupt that can't be shared. - * - * Explanation : under heavy receive, the following happens : - * ->wavelan_interrupt() - * (status0 & SR0_INTERRUPT) != 0 - * ->wv_packet_rcv() - * (status0 & SR0_INTERRUPT) != 0 - * ->wv_packet_rcv() - * (status0 & SR0_INTERRUPT) == 0 // i.e. no more event - * <-wavelan_interrupt() - * ->wavelan_interrupt() - * (status0 & SR0_INTERRUPT) == 0 // i.e. empty interrupt - * <-wavelan_interrupt() - * Jean II */ - return IRQ_HANDLED; -} /* wv_interrupt */ - -/*------------------------------------------------------------------*/ -/* - * Watchdog: when we start a transmission, a timer is set for us in the - * kernel. If the transmission completes, this timer is disabled. If - * the timer expires, we are called and we try to unlock the hardware. - * - * Note : This watchdog is move clever than the one in the ISA driver, - * because it try to abort the current command before reseting - * everything... - * On the other hand, it's a bit simpler, because we don't have to - * deal with the multiple Tx buffers... - */ -static void -wavelan_watchdog(struct net_device * dev) -{ - net_local * lp = netdev_priv(dev); - unsigned int base = dev->base_addr; - unsigned long flags; - int aborted = FALSE; - -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); -#endif - -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", - dev->name); -#endif - - spin_lock_irqsave(&lp->spinlock, flags); - - /* Ask to abort the current command */ - outb(OP0_ABORT, LCCR(base)); - - /* Wait for the end of the command (a bit hackish) */ - if(wv_82593_cmd(dev, "wavelan_watchdog(): abort", - OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED)) - aborted = TRUE; - - /* Release spinlock here so that wv_hw_reset() can grab it */ - spin_unlock_irqrestore(&lp->spinlock, flags); - - /* Check if we were successful in aborting it */ - if(!aborted) - { - /* It seem that it wasn't enough */ -#ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wavelan_watchdog: abort failed, trying reset\n", - dev->name); -#endif - wv_hw_reset(dev); - } - -#ifdef DEBUG_PSA_SHOW - { - psa_t psa; - psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); - wv_psa_show(&psa); - } -#endif -#ifdef DEBUG_MMC_SHOW - wv_mmc_show(dev); -#endif -#ifdef DEBUG_I82593_SHOW - wv_ru_show(dev); -#endif - - /* We are no more waiting for something... */ - netif_wake_queue(dev); - -#ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); -#endif -} - -/********************* CONFIGURATION CALLBACKS *********************/ -/* - * Here are the functions called by the pcmcia package (cardmgr) and - * linux networking (NET3) for initialization, configuration and - * deinstallations of the Wavelan Pcmcia Hardware. - */ - -/*------------------------------------------------------------------*/ -/* - * Configure and start up the WaveLAN PCMCIA adaptor. - * Called by NET3 when it "open" the device. - */ -static int -wavelan_open(struct net_device * dev) -{ - net_local * lp = netdev_priv(dev); - struct pcmcia_device * link = lp->link; - unsigned int base = dev->base_addr; - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, - (unsigned int) dev); -#endif - - /* Check if the modem is powered up (wavelan_close() power it down */ - if(hasr_read(base) & HASR_NO_CLK) - { - /* Power up (power up time is 250us) */ - hacr_write(base, HACR_DEFAULT); - - /* Check if the module has been powered up... */ - if(hasr_read(base) & HASR_NO_CLK) - { -#ifdef DEBUG_CONFIG_ERRORS - printk(KERN_WARNING "%s: wavelan_open(): modem not connected\n", - dev->name); -#endif - return FALSE; - } - } - - /* Start reception and declare the driver ready */ - if(!lp->configured) - return FALSE; - if(!wv_ru_start(dev)) - wv_hw_reset(dev); /* If problem : reset */ - netif_start_queue(dev); - - /* Mark the device as used */ - link->open++; - -#ifdef WAVELAN_ROAMING - if(do_roaming) - wv_roam_init(dev); -#endif /* WAVELAN_ROAMING */ - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); -#endif - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Shutdown the WaveLAN PCMCIA adaptor. - * Called by NET3 when it "close" the device. - */ -static int -wavelan_close(struct net_device * dev) -{ - struct pcmcia_device * link = ((net_local *)netdev_priv(dev))->link; - unsigned int base = dev->base_addr; - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, - (unsigned int) dev); -#endif - - /* If the device isn't open, then nothing to do */ - if(!link->open) - { -#ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "%s: wavelan_close(): device not open\n", dev->name); -#endif - return 0; - } - -#ifdef WAVELAN_ROAMING - /* Cleanup of roaming stuff... */ - if(do_roaming) - wv_roam_cleanup(dev); -#endif /* WAVELAN_ROAMING */ - - link->open--; - - /* If the card is still present */ - if(netif_running(dev)) - { - netif_stop_queue(dev); - - /* Stop receiving new messages and wait end of transmission */ - wv_ru_stop(dev); - - /* Power down the module */ - hacr_write(base, HACR_DEFAULT & (~HACR_PWR_STAT)); - } - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); -#endif - return 0; -} - -static const struct net_device_ops wavelan_netdev_ops = { - .ndo_open = wavelan_open, - .ndo_stop = wavelan_close, - .ndo_start_xmit = wavelan_packet_xmit, - .ndo_set_multicast_list = wavelan_set_multicast_list, -#ifdef SET_MAC_ADDRESS - .ndo_set_mac_address = wavelan_set_mac_address, -#endif - .ndo_tx_timeout = wavelan_watchdog, - .ndo_change_mtu = eth_change_mtu, - .ndo_validate_addr = eth_validate_addr, -}; - -/*------------------------------------------------------------------*/ -/* - * wavelan_attach() creates an "instance" of the driver, allocating - * local data structures for one device (one interface). The device - * is registered with Card Services. - * - * The dev_link structure is initialized, but we don't actually - * configure the card at this point -- we wait until we receive a - * card insertion event. - */ -static int -wavelan_probe(struct pcmcia_device *p_dev) -{ - struct net_device * dev; /* Interface generic data */ - net_local * lp; /* Interface specific data */ - int ret; - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "-> wavelan_attach()\n"); -#endif - - /* The io structure describes IO port mapping */ - p_dev->io.NumPorts1 = 8; - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - p_dev->io.IOAddrLines = 3; - - /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; - p_dev->irq.Handler = wavelan_interrupt; - - /* General socket configuration */ - p_dev->conf.Attributes = CONF_ENABLE_IRQ; - p_dev->conf.IntType = INT_MEMORY_AND_IO; - - /* Allocate the generic data structure */ - dev = alloc_etherdev(sizeof(net_local)); - if (!dev) - return -ENOMEM; - - p_dev->priv = p_dev->irq.Instance = dev; - - lp = netdev_priv(dev); - - /* Init specific data */ - lp->configured = 0; - lp->reconfig_82593 = FALSE; - lp->nresets = 0; - /* Multicast stuff */ - lp->promiscuous = 0; - lp->allmulticast = 0; - lp->mc_count = 0; - - /* Init spinlock */ - spin_lock_init(&lp->spinlock); - - /* back links */ - lp->dev = dev; - - /* wavelan NET3 callbacks */ - dev->netdev_ops = &wavelan_netdev_ops; - dev->watchdog_timeo = WATCHDOG_JIFFIES; - SET_ETHTOOL_OPS(dev, &ops); - - dev->wireless_handlers = &wavelan_handler_def; - lp->wireless_data.spy_data = &lp->spy_data; - dev->wireless_data = &lp->wireless_data; - - /* Other specific data */ - dev->mtu = WAVELAN_MTU; - - ret = wv_pcmcia_config(p_dev); - if (ret) - return ret; - - ret = wv_hw_config(dev); - if (ret) { - dev->irq = 0; - pcmcia_disable_device(p_dev); - return ret; - } - - wv_init_info(dev); - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "<- wavelan_attach()\n"); -#endif - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * This deletes a driver "instance". The device is de-registered with - * Card Services. If it has been released, all local data structures - * are freed. Otherwise, the structures will be freed when the device - * is released. - */ -static void -wavelan_detach(struct pcmcia_device *link) -{ -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link); -#endif - - /* Some others haven't done their job : give them another chance */ - wv_pcmcia_release(link); - - /* Free pieces */ - if(link->priv) - { - struct net_device * dev = (struct net_device *) link->priv; - - /* Remove ourselves from the kernel list of ethernet devices */ - /* Warning : can't be called from interrupt, timer or wavelan_close() */ - if (link->dev_node) - unregister_netdev(dev); - link->dev_node = NULL; - ((net_local *)netdev_priv(dev))->link = NULL; - ((net_local *)netdev_priv(dev))->dev = NULL; - free_netdev(dev); - } - -#ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "<- wavelan_detach()\n"); -#endif -} - -static int wavelan_suspend(struct pcmcia_device *link) -{ - struct net_device * dev = (struct net_device *) link->priv; - - /* NB: wavelan_close will be called, but too late, so we are - * obliged to close nicely the wavelan here. David, could you - * close the device before suspending them ? And, by the way, - * could you, on resume, add a "route add -net ..." after the - * ifconfig up ? Thanks... */ - - /* Stop receiving new messages and wait end of transmission */ - wv_ru_stop(dev); - - if (link->open) - netif_device_detach(dev); - - /* Power down the module */ - hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT)); - - return 0; -} - -static int wavelan_resume(struct pcmcia_device *link) -{ - struct net_device * dev = (struct net_device *) link->priv; - - if (link->open) { - wv_hw_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - - -static struct pcmcia_device_id wavelan_ids[] = { - PCMCIA_DEVICE_PROD_ID12("AT&T","WaveLAN/PCMCIA", 0xe7c5affd, 0x1bc50975), - PCMCIA_DEVICE_PROD_ID12("Digital", "RoamAbout/DS", 0x9999ab35, 0x00d05e06), - PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/PCMCIA", 0x23eb9949, 0x1bc50975), - PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/PCMCIA", 0x24358cd4, 0x1bc50975), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, wavelan_ids); - -static struct pcmcia_driver wavelan_driver = { - .owner = THIS_MODULE, - .drv = { - .name = "wavelan_cs", - }, - .probe = wavelan_probe, - .remove = wavelan_detach, - .id_table = wavelan_ids, - .suspend = wavelan_suspend, - .resume = wavelan_resume, -}; - -static int __init -init_wavelan_cs(void) -{ - return pcmcia_register_driver(&wavelan_driver); -} - -static void __exit -exit_wavelan_cs(void) -{ - pcmcia_unregister_driver(&wavelan_driver); -} - -module_init(init_wavelan_cs); -module_exit(exit_wavelan_cs); diff --git a/drivers/net/wireless/wavelan_cs.h b/drivers/net/wireless/wavelan_cs.h deleted file mode 100644 index 2e4bfe4147c6..000000000000 --- a/drivers/net/wireless/wavelan_cs.h +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Wavelan Pcmcia driver - * - * Jean II - HPLB '96 - * - * Reorganization and extension of the driver. - * Original copyright follow. See wavelan_cs.h for details. - * - * This file contain the declarations of the Wavelan hardware. Note that - * the Pcmcia Wavelan include a i82593 controller (see definitions in - * file i82593.h). - * - * The main difference between the pcmcia hardware and the ISA one is - * the Ethernet Controller (i82593 instead of i82586). The i82593 allow - * only one send buffer. The PSA (Parameter Storage Area : EEprom for - * permanent storage of various info) is memory mapped, but not the - * MMI (Modem Management Interface). - */ - -/* - * Definitions for the AT&T GIS (formerly NCR) WaveLAN PCMCIA card: - * An Ethernet-like radio transceiver controlled by an Intel 82593 - * coprocessor. - * - * - **************************************************************************** - * Copyright 1995 - * Anthony D. Joseph - * Massachusetts Institute of Technology - * - * Permission to use, copy, modify, and distribute this program - * for any purpose and without fee is hereby granted, provided - * that this copyright and permission notice appear on all copies - * and supporting documentation, the name of M.I.T. not be used - * in advertising or publicity pertaining to distribution of the - * program without specific prior permission, and notice be given - * in supporting documentation that copying and distribution is - * by permission of M.I.T. M.I.T. makes no representations about - * the suitability of this software for any purpose. It is pro- - * vided "as is" without express or implied warranty. - **************************************************************************** - * - * - * Credits: - * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht for - * providing extremely useful information about WaveLAN PCMCIA hardware - * - * This driver is based upon several other drivers, in particular: - * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter - * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter - * Anders Klemets' PCMCIA WaveLAN adapter driver - * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter - */ - -#ifndef _WAVELAN_CS_H -#define _WAVELAN_CS_H - -/************************** MAGIC NUMBERS ***************************/ - -/* The detection of the wavelan card is made by reading the MAC address - * from the card and checking it. If you have a non AT&T product (OEM, - * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this - * part to accommodate your hardware... - */ -static const unsigned char MAC_ADDRESSES[][3] = -{ - { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */ - { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */ - { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ - { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ - /* Add your card here and send me the patch ! */ -}; - -/* - * Constants used to convert channels to frequencies - */ - -/* Frequency available in the 2.0 modem, in units of 250 kHz - * (as read in the offset register of the dac area). - * Used to map channel numbers used by `wfreqsel' to frequencies - */ -static const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, - 0xD0, 0xF0, 0xF8, 0x150 }; - -/* Frequencies of the 1.0 modem (fixed frequencies). - * Use to map the PSA `subband' to a frequency - * Note : all frequencies apart from the first one need to be multiplied by 10 - */ -static const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; - - -/*************************** PC INTERFACE ****************************/ - -/* WaveLAN host interface definitions */ - -#define LCCR(base) (base) /* LAN Controller Command Register */ -#define LCSR(base) (base) /* LAN Controller Status Register */ -#define HACR(base) (base+0x1) /* Host Adapter Command Register */ -#define HASR(base) (base+0x1) /* Host Adapter Status Register */ -#define PIORL(base) (base+0x2) /* Program I/O Register Low */ -#define RPLL(base) (base+0x2) /* Receive Pointer Latched Low */ -#define PIORH(base) (base+0x3) /* Program I/O Register High */ -#define RPLH(base) (base+0x3) /* Receive Pointer Latched High */ -#define PIOP(base) (base+0x4) /* Program I/O Port */ -#define MMR(base) (base+0x6) /* MMI Address Register */ -#define MMD(base) (base+0x7) /* MMI Data Register */ - -/* Host Adaptor Command Register bit definitions */ - -#define HACR_LOF (1 << 3) /* Lock Out Flag, toggle every 250ms */ -#define HACR_PWR_STAT (1 << 4) /* Power State, 1=active, 0=sleep */ -#define HACR_TX_DMA_RESET (1 << 5) /* Reset transmit DMA ptr on high */ -#define HACR_RX_DMA_RESET (1 << 6) /* Reset receive DMA ptr on high */ -#define HACR_ROM_WEN (1 << 7) /* EEPROM write enabled when true */ - -#define HACR_RESET (HACR_TX_DMA_RESET | HACR_RX_DMA_RESET) -#define HACR_DEFAULT (HACR_PWR_STAT) - -/* Host Adapter Status Register bit definitions */ - -#define HASR_MMI_BUSY (1 << 2) /* MMI is busy when true */ -#define HASR_LOF (1 << 3) /* Lock out flag status */ -#define HASR_NO_CLK (1 << 4) /* active when modem not connected */ - -/* Miscellaneous bit definitions */ - -#define PIORH_SEL_TX (1 << 5) /* PIOR points to 0=rx/1=tx buffer */ -#define MMR_MMI_WR (1 << 0) /* Next MMI cycle is 0=read, 1=write */ -#define PIORH_MASK 0x1f /* only low 5 bits are significant */ -#define RPLH_MASK 0x1f /* only low 5 bits are significant */ -#define MMI_ADDR_MASK 0x7e /* Bits 1-6 of MMR are significant */ - -/* Attribute Memory map */ - -#define CIS_ADDR 0x0000 /* Card Information Status Register */ -#define PSA_ADDR 0x0e00 /* Parameter Storage Area address */ -#define EEPROM_ADDR 0x1000 /* EEPROM address (unused ?) */ -#define COR_ADDR 0x4000 /* Configuration Option Register */ - -/* Configuration Option Register bit definitions */ - -#define COR_CONFIG (1 << 0) /* Config Index, 0 when unconfigured */ -#define COR_SW_RESET (1 << 7) /* Software Reset on true */ -#define COR_LEVEL_IRQ (1 << 6) /* Level IRQ */ - -/* Local Memory map */ - -#define RX_BASE 0x0000 /* Receive memory, 8 kB */ -#define TX_BASE 0x2000 /* Transmit memory, 2 kB */ -#define UNUSED_BASE 0x2800 /* Unused, 22 kB */ -#define RX_SIZE (TX_BASE-RX_BASE) /* Size of receive area */ -#define RX_SIZE_SHIFT 6 /* Bits to shift in stop register */ - -#define TRUE 1 -#define FALSE 0 - -#define MOD_ENAL 1 -#define MOD_PROM 2 - -/* Size of a MAC address */ -#define WAVELAN_ADDR_SIZE 6 - -/* Maximum size of Wavelan packet */ -#define WAVELAN_MTU 1500 - -#define MAXDATAZ (6 + 6 + 2 + WAVELAN_MTU) - -/********************** PARAMETER STORAGE AREA **********************/ - -/* - * Parameter Storage Area (PSA). - */ -typedef struct psa_t psa_t; -struct psa_t -{ - /* For the PCMCIA Adapter, locations 0x00-0x0F are unused and fixed at 00 */ - unsigned char psa_io_base_addr_1; /* [0x00] Base address 1 ??? */ - unsigned char psa_io_base_addr_2; /* [0x01] Base address 2 */ - unsigned char psa_io_base_addr_3; /* [0x02] Base address 3 */ - unsigned char psa_io_base_addr_4; /* [0x03] Base address 4 */ - unsigned char psa_rem_boot_addr_1; /* [0x04] Remote Boot Address 1 */ - unsigned char psa_rem_boot_addr_2; /* [0x05] Remote Boot Address 2 */ - unsigned char psa_rem_boot_addr_3; /* [0x06] Remote Boot Address 3 */ - unsigned char psa_holi_params; /* [0x07] HOst Lan Interface (HOLI) Parameters */ - unsigned char psa_int_req_no; /* [0x08] Interrupt Request Line */ - unsigned char psa_unused0[7]; /* [0x09-0x0F] unused */ - - unsigned char psa_univ_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x10-0x15] Universal (factory) MAC Address */ - unsigned char psa_local_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x16-1B] Local MAC Address */ - unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */ -#define PSA_UNIVERSAL 0 /* Universal (factory) */ -#define PSA_LOCAL 1 /* Local */ - unsigned char psa_comp_number; /* [0x1D] Compatability Number: */ -#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ -#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ -#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ -#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ -#define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */ - unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ - unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */ -#define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */ - unsigned char psa_subband; /* [0x20] Subband */ -#define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */ -#define PSA_SUBBAND_2425 1 /* 2425 MHz */ -#define PSA_SUBBAND_2460 2 /* 2460 MHz */ -#define PSA_SUBBAND_2484 3 /* 2484 MHz */ -#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ - unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */ - unsigned char psa_mod_delay; /* [0x22] Modem Delay ??? (reserved) */ - unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */ - unsigned char psa_nwid_select; /* [0x25] Network ID Select On Off */ - unsigned char psa_encryption_select; /* [0x26] Encryption On Off */ - unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ - unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */ - unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ - unsigned char psa_nwid_prefix[2]; /* [0x38-0x39] Roaming domain */ - unsigned char psa_reserved[2]; /* [0x3A-0x3B] Reserved - fixed 00 */ - unsigned char psa_conf_status; /* [0x3C] Conf Status, bit 0=1:config*/ - unsigned char psa_crc[2]; /* [0x3D] CRC-16 over PSA */ - unsigned char psa_crc_status; /* [0x3F] CRC Valid Flag */ -}; - -/* Size for structure checking (if padding is correct) */ -#define PSA_SIZE 64 - -/* Calculate offset of a field in the above structure - * Warning : only even addresses are used */ -#define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL)) - -/******************** MODEM MANAGEMENT INTERFACE ********************/ - -/* - * Modem Management Controller (MMC) write structure. - */ -typedef struct mmw_t mmw_t; -struct mmw_t -{ - unsigned char mmw_encr_key[8]; /* encryption key */ - unsigned char mmw_encr_enable; /* enable/disable encryption */ -#define MMW_ENCR_ENABLE_MODE 0x02 /* Mode of security option */ -#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option */ - unsigned char mmw_unused0[1]; /* unused */ - unsigned char mmw_des_io_invert; /* Encryption option */ -#define MMW_DES_IO_INVERT_RES 0x0F /* Reserved */ -#define MMW_DES_IO_INVERT_CTRL 0xF0 /* Control ??? (set to 0) */ - unsigned char mmw_unused1[5]; /* unused */ - unsigned char mmw_loopt_sel; /* looptest selection */ -#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* disable NWID filtering */ -#define MMW_LOOPT_SEL_INT 0x20 /* activate Attention Request */ -#define MMW_LOOPT_SEL_LS 0x10 /* looptest w/o collision avoidance */ -#define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */ -#define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */ -#define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */ -#define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */ - unsigned char mmw_jabber_enable; /* jabber timer enable */ - /* Abort transmissions > 200 ms */ - unsigned char mmw_freeze; /* freeze / unfreeeze signal level */ - /* 0 : signal level & qual updated for every new message, 1 : frozen */ - unsigned char mmw_anten_sel; /* antenna selection */ -#define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */ -#define MMW_ANTEN_SEL_ALG_EN 0x02 /* antenna selection algo. enable */ - unsigned char mmw_ifs; /* inter frame spacing */ - /* min time between transmission in bit periods (.5 us) - bit 0 ignored */ - unsigned char mmw_mod_delay; /* modem delay (synchro) */ - unsigned char mmw_jam_time; /* jamming time (after collision) */ - unsigned char mmw_unused2[1]; /* unused */ - unsigned char mmw_thr_pre_set; /* level threshold preset */ - /* Discard all packet with signal < this value (4) */ - unsigned char mmw_decay_prm; /* decay parameters */ - unsigned char mmw_decay_updat_prm; /* decay update parameterz */ - unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ - /* Discard all packet with quality < this value (3) */ - unsigned char mmw_netw_id_l; /* NWID low order byte */ - unsigned char mmw_netw_id_h; /* NWID high order byte */ - /* Network ID or Domain : create virtual net on the air */ - - /* 2.0 Hardware extension - frequency selection support */ - unsigned char mmw_mode_select; /* for analog tests (set to 0) */ - unsigned char mmw_unused3[1]; /* unused */ - unsigned char mmw_fee_ctrl; /* frequency eeprom control */ -#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions */ -#define MMW_FEE_CTRL_DWLD 0x08 /* Download eeprom to mmc */ -#define MMW_FEE_CTRL_CMD 0x07 /* EEprom commands : */ -#define MMW_FEE_CTRL_READ 0x06 /* Read */ -#define MMW_FEE_CTRL_WREN 0x04 /* Write enable */ -#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address */ -#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses */ -#define MMW_FEE_CTRL_WDS 0x04 /* Write disable */ -#define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */ -#define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */ -#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers */ -#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write addr in protect register */ -#define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */ - /* Never issue this command (PRDS) : it's irreversible !!! */ - - unsigned char mmw_fee_addr; /* EEprom address */ -#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel */ -#define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */ -#define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */ -#define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */ -#define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */ -#define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */ - - unsigned char mmw_fee_data_l; /* Write data to EEprom */ - unsigned char mmw_fee_data_h; /* high octet */ - unsigned char mmw_ext_ant; /* Setting for external antenna */ -#define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */ -#define MMW_EXT_ANT_POL 0x02 /* Polarity of the antenna */ -#define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ -#define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ -#define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ -} __attribute__((packed)); - -/* Size for structure checking (if padding is correct) */ -#define MMW_SIZE 37 - -/* Calculate offset of a field in the above structure */ -#define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) - - -/* - * Modem Management Controller (MMC) read structure. - */ -typedef struct mmr_t mmr_t; -struct mmr_t -{ - unsigned char mmr_unused0[8]; /* unused */ - unsigned char mmr_des_status; /* encryption status */ - unsigned char mmr_des_avail; /* encryption available (0x55 read) */ -#define MMR_DES_AVAIL_DES 0x55 /* DES available */ -#define MMR_DES_AVAIL_AES 0x33 /* AES (AT&T) available */ - unsigned char mmr_des_io_invert; /* des I/O invert register */ - unsigned char mmr_unused1[5]; /* unused */ - unsigned char mmr_dce_status; /* DCE status */ -#define MMR_DCE_STATUS_RX_BUSY 0x01 /* receiver busy */ -#define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ -#define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ -#define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ -#define MMR_DCE_STATUS 0x0F /* mask to get the bits */ - unsigned char mmr_dsp_id; /* DSP id (AA = Daedalus rev A) */ - unsigned char mmr_unused2[2]; /* unused */ - unsigned char mmr_correct_nwid_l; /* # of correct NWID's rxd (low) */ - unsigned char mmr_correct_nwid_h; /* # of correct NWID's rxd (high) */ - /* Warning : Read high order octet first !!! */ - unsigned char mmr_wrong_nwid_l; /* # of wrong NWID's rxd (low) */ - unsigned char mmr_wrong_nwid_h; /* # of wrong NWID's rxd (high) */ - unsigned char mmr_thr_pre_set; /* level threshold preset */ -#define MMR_THR_PRE_SET 0x3F /* level threshold preset */ -#define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */ - unsigned char mmr_signal_lvl; /* signal level */ -#define MMR_SIGNAL_LVL 0x3F /* signal level */ -#define MMR_SIGNAL_LVL_VALID 0x80 /* Updated since last read */ - unsigned char mmr_silence_lvl; /* silence level (noise) */ -#define MMR_SILENCE_LVL 0x3F /* silence level */ -#define MMR_SILENCE_LVL_VALID 0x80 /* Updated since last read */ - unsigned char mmr_sgnl_qual; /* signal quality */ -#define MMR_SGNL_QUAL 0x0F /* signal quality */ -#define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */ - unsigned char mmr_netw_id_l; /* NWID low order byte ??? */ - unsigned char mmr_unused3[3]; /* unused */ - - /* 2.0 Hardware extension - frequency selection support */ - unsigned char mmr_fee_status; /* Status of frequency eeprom */ -#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision id */ -#define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */ -#define MMR_FEE_STATUS_BUSY 0x04 /* EEprom busy */ - unsigned char mmr_unused4[1]; /* unused */ - unsigned char mmr_fee_data_l; /* Read data from eeprom (low) */ - unsigned char mmr_fee_data_h; /* Read data from eeprom (high) */ -}; - -/* Size for structure checking (if padding is correct) */ -#define MMR_SIZE 36 - -/* Calculate offset of a field in the above structure */ -#define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) - - -/* Make the two above structures one */ -typedef union mm_t -{ - struct mmw_t w; /* Write to the mmc */ - struct mmr_t r; /* Read from the mmc */ -} mm_t; - -#endif /* _WAVELAN_CS_H */ diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h deleted file mode 100644 index 81d91531c4f9..000000000000 --- a/drivers/net/wireless/wavelan_cs.p.h +++ /dev/null @@ -1,766 +0,0 @@ -/* - * Wavelan Pcmcia driver - * - * Jean II - HPLB '96 - * - * Reorganisation and extension of the driver. - * - * This file contain all definition and declarations necessary for the - * wavelan pcmcia driver. This file is a private header, so it should - * be included only on wavelan_cs.c !!! - */ - -#ifndef WAVELAN_CS_P_H -#define WAVELAN_CS_P_H - -/************************** DOCUMENTATION **************************/ -/* - * This driver provide a Linux interface to the Wavelan Pcmcia hardware - * The Wavelan is a product of Lucent (http://www.wavelan.com/). - * This division was formerly part of NCR and then AT&T. - * Wavelan are also distributed by DEC (RoamAbout DS)... - * - * To know how to use this driver, read the PCMCIA HOWTO. - * If you want to exploit the many other fonctionalities, look comments - * in the code... - * - * This driver is the result of the effort of many peoples (see below). - */ - -/* ------------------------ SPECIFIC NOTES ------------------------ */ -/* - * Web page - * -------- - * I try to maintain a web page with the Wireless LAN Howto at : - * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html - * - * SMP - * --- - * We now are SMP compliant (I eventually fixed the remaining bugs). - * The driver has been tested on a dual P6-150 and survived my usual - * set of torture tests. - * Anyway, I spent enough time chasing interrupt re-entrancy during - * errors or reconfigure, and I designed the locked/unlocked sections - * of the driver with great care, and with the recent addition of - * the spinlock (thanks to the new API), we should be quite close to - * the truth. - * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), - * but better safe than sorry (especially at 2 Mb/s ;-). - * - * I have also looked into disabling only our interrupt on the card - * (via HACR) instead of all interrupts in the processor (via cli), - * so that other driver are not impacted, and it look like it's - * possible, but it's very tricky to do right (full of races). As - * the gain would be mostly for SMP systems, it can wait... - * - * Debugging and options - * --------------------- - * You will find below a set of '#define" allowing a very fine control - * on the driver behaviour and the debug messages printed. - * The main options are : - * o WAVELAN_ROAMING, for the experimental roaming support. - * o SET_PSA_CRC, to have your card correctly recognised by - * an access point and the Point-to-Point diagnostic tool. - * o USE_PSA_CONFIG, to read configuration from the PSA (EEprom) - * (otherwise we always start afresh with some defaults) - * - * wavelan_cs.o is darn too big - * ------------------------- - * That's true ! There is a very simple way to reduce the driver - * object by 33% (yes !). Comment out the following line : - * #include - * Other compile options can also reduce the size of it... - * - * MAC address and hardware detection : - * ---------------------------------- - * The detection code of the wavelan chech that the first 3 - * octets of the MAC address fit the company code. This type of - * detection work well for AT&T cards (because the AT&T code is - * hardcoded in wavelan_cs.h), but of course will fail for other - * manufacturer. - * - * If you are sure that your card is derived from the wavelan, - * here is the way to configure it : - * 1) Get your MAC address - * a) With your card utilities (wfreqsel, instconf, ...) - * b) With the driver : - * o compile the kernel with DEBUG_CONFIG_INFO enabled - * o Boot and look the card messages - * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan_cs.h) - * 3) Compile & verify - * 4) Send me the MAC code - I will include it in the next version... - * - */ - -/* --------------------- WIRELESS EXTENSIONS --------------------- */ -/* - * This driver is the first one to support "wireless extensions". - * This set of extensions provide you some way to control the wireless - * caracteristics of the hardware in a standard way and support for - * applications for taking advantage of it (like Mobile IP). - * - * It might be a good idea as well to fetch the wireless tools to - * configure the device and play a bit. - */ - -/* ---------------------------- FILES ---------------------------- */ -/* - * wavelan_cs.c : The actual code for the driver - C functions - * - * wavelan_cs.p.h : Private header : local types / vars for the driver - * - * wavelan_cs.h : Description of the hardware interface & structs - * - * i82593.h : Description if the Ethernet controller - */ - -/* --------------------------- HISTORY --------------------------- */ -/* - * The history of the Wavelan drivers is as complicated as history of - * the Wavelan itself (NCR -> AT&T -> Lucent). - * - * All started with Anders Klemets , - * writing a Wavelan ISA driver for the MACH microkernel. Girish - * Welling had also worked on it. - * Keith Moore modify this for the Pcmcia hardware. - * - * Robert Morris port these two drivers to BSDI - * and add specific Pcmcia support (there is currently no equivalent - * of the PCMCIA package under BSD...). - * - * Jim Binkley port both BSDI drivers to FreeBSD. - * - * Bruce Janson port the BSDI ISA driver to Linux. - * - * Anthony D. Joseph started modify Bruce driver - * (with help of the BSDI PCMCIA driver) for PCMCIA. - * Yunzhou Li finished is work. - * Joe Finney patched the driver to start - * correctly 2.00 cards (2.4 GHz with frequency selection). - * David Hinds integrated the whole in his - * Pcmcia package (+ bug corrections). - * - * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some - * patchs to the Pcmcia driver. After, I added code in the ISA driver - * for Wireless Extensions and full support of frequency selection - * cards. Now, I'm doing the same to the Pcmcia driver + some - * reorganisation. - * Loeke Brederveld from Lucent has given me - * much needed informations on the Wavelan hardware. - */ - -/* By the way : for the copyright & legal stuff : - * Almost everybody wrote code under GNU or BSD license (or alike), - * and want that their original copyright remain somewhere in the - * code (for myself, I go with the GPL). - * Nobody want to take responsibility for anything, except the fame... - */ - -/* --------------------------- CREDITS --------------------------- */ -/* - * Credits: - * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht and - * Loeke Brederveld of Lucent for providing extremely useful - * information about WaveLAN PCMCIA hardware - * - * This driver is based upon several other drivers, in particular: - * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter - * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter - * Anders Klemets' PCMCIA WaveLAN adapter driver - * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter - * - * Additional Credits: - * - * This software was originally developed under Linux 1.2.3 - * (Slackware 2.0 distribution). - * And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+) - * with an HP OmniBook 4000 and then a 5500. - * - * It is based on other device drivers and information either written - * or supplied by: - * James Ashton (jaa101@syseng.anu.edu.au), - * Ajay Bakre (bakre@paul.rutgers.edu), - * Donald Becker (becker@super.org), - * Jim Binkley , - * Loeke Brederveld , - * Allan Creighton (allanc@cs.su.oz.au), - * Brent Elphick , - * Joe Finney , - * Matthew Geier (matthew@cs.su.oz.au), - * Remo di Giovanni (remo@cs.su.oz.au), - * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), - * David Hinds , - * Jan Hoogendoorn (c/o marteijn@lucent.com), - * Bruce Janson , - * Anthony D. Joseph , - * Anders Klemets (klemets@paul.rutgers.edu), - * Yunzhou Li , - * Marc Meertens (mmeertens@lucent.com), - * Keith Moore, - * Robert Morris (rtm@das.harvard.edu), - * Ian Parkin (ian@cs.su.oz.au), - * John Rosenberg (johnr@cs.su.oz.au), - * George Rossi (george@phm.gov.au), - * Arthur Scott (arthur@cs.su.oz.au), - * Stanislav Sinyagin - * Peter Storey, - * Jean Tourrilhes , - * Girish Welling (welling@paul.rutgers.edu) - * Clark Woodworth - * Yongguang Zhang ... - */ - -/* ------------------------- IMPROVEMENTS ------------------------- */ -/* - * I proudly present : - * - * Changes made in 2.8.22 : - * ---------------------- - * - improved wv_set_multicast_list - * - catch spurious interrupt - * - correct release of the device - * - * Changes mades in release : - * ------------------------ - * - Reorganisation of the code, function name change - * - Creation of private header (wavelan_cs.h) - * - Reorganised debug messages - * - More comments, history, ... - * - Configure earlier (in "insert" instead of "open") - * and do things only once - * - mmc_init : configure the PSA if not done - * - mmc_init : 2.00 detection better code for 2.00 init - * - better info at startup - * - Correct a HUGE bug (volatile & uncalibrated busy loop) - * in wv_82593_cmd => config speedup - * - Stop receiving & power down on close (and power up on open) - * use "ifconfig down" & "ifconfig up ; route add -net ..." - * - Send packets : add watchdog instead of pooling - * - Receive : check frame wrap around & try to recover some frames - * - wavelan_set_multicast_list : avoid reset - * - add wireless extensions (ioctl & get_wireless_stats) - * get/set nwid/frequency on fly, info for /proc/net/wireless - * - Suppress useless stuff from lp (net_local), but add link - * - More inlines - * - Lot of others minor details & cleanups - * - * Changes made in second release : - * ------------------------------ - * - Optimise wv_85893_reconfig stuff, fix potential problems - * - Change error values for ioctl - * - Non blocking wv_ru_stop() + call wv_reset() in case of problems - * - Remove development printk from wavelan_watchdog() - * - Remove of the watchdog to wavelan_close instead of wavelan_release - * fix potential problems... - * - Start debugging suspend stuff (but it's still a bit weird) - * - Debug & optimize dump header/packet in Rx & Tx (debug) - * - Use "readb" and "writeb" to be kernel 2.1 compliant - * - Better handling of bogus interrupts - * - Wireless extension : SETSPY and GETSPY - * - Remove old stuff (stats - for those needing it, just ask me...) - * - Make wireless extensions optional - * - * Changes made in third release : - * ----------------------------- - * - cleanups & typos - * - modif wireless ext (spy -> only one pointer) - * - new private ioctl to set/get quality & level threshold - * - Init : correct default value of level threshold for pcmcia - * - kill watchdog in hw_reset - * - more 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) - * - Add message level (debug stuff in /var/adm/debug & errors not - * displayed at console and still in /var/adm/messages) - * - * Changes made in fourth release : - * ------------------------------ - * - multicast support (yes !) thanks to Yongguang Zhang. - * - * Changes made in fifth release (2.9.0) : - * ------------------------------------- - * - Revisited multicast code (it was mostly wrong). - * - protect code in wv_82593_reconfig with dev->tbusy (oups !) - * - * Changes made in sixth release (2.9.1a) : - * -------------------------------------- - * - Change the detection code for multi manufacturer code support - * - Correct bug (hang kernel) in init when we were "rejecting" a card - * - * Changes made in seventh release (2.9.1b) : - * ---------------------------------------- - * - Update to wireless extensions changes - * - Silly bug in card initial configuration (psa_conf_status) - * - * Changes made in eigth release : - * ----------------------------- - * - Small bug in debug code (probably not the last one...) - * - 1.2.13 support (thanks to Clark Woodworth) - * - * Changes made for release in 2.9.2b : - * ---------------------------------- - * - Level threshold is now a standard wireless extension (version 4 !) - * - modules parameters types for kernel > 2.1.17 - * - updated man page - * - Others cleanup from David Hinds - * - * Changes made for release in 2.9.5 : - * --------------------------------- - * - byte count stats (courtesy of David Hinds) - * - Remove dev_tint stuff (courtesy of David Hinds) - * - Others cleanup from David Hinds - * - Encryption setting from Brent Elphick (thanks a lot !) - * - 'base' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) - * - * Changes made for release in 2.9.6 : - * --------------------------------- - * - fix bug : no longuer disable watchdog in case of bogus interrupt - * - increase timeout in config code for picky hardware - * - mask unused bits in status (Wireless Extensions) - * - * Changes integrated by Justin Seger & David Hinds : - * ----------------------------------------------------------------- - * - Roaming "hack" from Joe Finney - * - PSA CRC code from Bob Gray - * - Better initialisation of the i82593 controller - * from Joseph K. O'Sullivan - * - * Changes made for release in 3.0.10 : - * ---------------------------------- - * - Fix eject "hang" of the driver under 2.2.X : - * o create wv_flush_stale_links() - * o Rename wavelan_release to wv_pcmcia_release & move up - * o move unregister_netdev to wavelan_detach() - * o wavelan_release() no longer call wavelan_detach() - * o Suppress "release" timer - * o Other cleanups & fixes - * - New MAC address in the probe - * - Reorg PSA_CRC code (endian neutral & cleaner) - * - Correct initialisation of the i82593 from Lucent manual - * - Put back the watchdog, with larger timeout - * - TRANSMIT_NO_CRC is a "normal" error, so recover from it - * from Derrick J Brashear - * - Better handling of TX and RX normal failure conditions - * - #ifdef out all the roaming code - * - Add ESSID & "AP current address" ioctl stubs - * - General cleanup of the code - * - * Changes made for release in 3.0.13 : - * ---------------------------------- - * - Re-enable compilation of roaming code by default, but with - * do_roaming = 0 - * - Nuke `nwid=nwid^ntohs(beacon->domain_id)' in wl_roam_gather - * at the demand of John Carol Langford - * - Introduced WAVELAN_ROAMING_EXT for incomplete ESSID stuff. - * - * Changes made for release in 3.0.15 : - * ---------------------------------- - * - Change e-mail and web page addresses - * - Watchdog timer is now correctly expressed in HZ, not in jiffies - * - Add channel number to the list of frequencies in range - * - Add the (short) list of bit-rates in range - * - Developp a new sensitivity... (sens.value & sens.fixed) - * - * Changes made for release in 3.1.2 : - * --------------------------------- - * - Fix check for root permission (break instead of exit) - * - New nwid & encoding setting (Wireless Extension 9) - * - * Changes made for release in 3.1.12 : - * ---------------------------------- - * - reworked wv_82593_cmd to avoid using the IRQ handler and doing - * ugly things with interrupts. - * - Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog - * - Update to new network API (softnet - 2.3.43) : - * o replace dev->tbusy (David + me) - * o replace dev->tstart (David + me) - * o remove dev->interrupt (David) - * o add SMP locking via spinlock in splxx (me) - * o add spinlock in interrupt handler (me) - * o use kernel watchdog instead of ours (me) - * o verify that all the changes make sense and work (me) - * - Re-sync kernel/pcmcia versions (not much actually) - * - A few other cleanups (David & me)... - * - * Changes made for release in 3.1.22 : - * ---------------------------------- - * - Check that SMP works, remove annoying log message - * - * Changes made for release in 3.1.24 : - * ---------------------------------- - * - Fix unfrequent card lockup when watchdog was reseting the hardware : - * o control first busy loop in wv_82593_cmd() - * o Extend spinlock protection in wv_hw_config() - * - * Changes made for release in 3.1.33 : - * ---------------------------------- - * - Optional use new driver API for Wireless Extensions : - * o got rid of wavelan_ioctl() - * o use a bunch of iw_handler instead - * - * Changes made for release in 3.2.1 : - * --------------------------------- - * - Set dev->trans_start to avoid filling the logs - * (and generating useless abort commands) - * - Avoid deadlocks in mmc_out()/mmc_in() - * - * Wishes & dreams: - * ---------------- - * - Cleanup and integrate the roaming code - * (std debug, set DomainID, decay avg and co...) - */ - -/***************************** INCLUDES *****************************/ - -/* Linux headers that we need */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include /* Wireless extensions */ -#include /* New driver API */ - -/* Pcmcia headers that we need */ -#include -#include -#include -#include -#include - -/* Wavelan declarations */ -#include "i82593.h" /* Definitions for the Intel chip */ - -#include "wavelan_cs.h" /* Others bits of the hardware */ - -/************************** DRIVER OPTIONS **************************/ -/* - * `#define' or `#undef' the following constant to change the behaviour - * of the driver... - */ -#define WAVELAN_ROAMING /* Include experimental roaming code */ -#undef WAVELAN_ROAMING_EXT /* Enable roaming wireless extensions */ -#undef SET_PSA_CRC /* Set the CRC in PSA (slower) */ -#define USE_PSA_CONFIG /* Use info from the PSA */ -#undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */ -#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ -#undef SET_MAC_ADDRESS /* Experimental */ - -/* Warning : these stuff will slow down the driver... */ -#define WIRELESS_SPY /* Enable spying addresses */ -#undef HISTOGRAM /* Enable histogram of sig level... */ - -/****************************** DEBUG ******************************/ - -#undef DEBUG_MODULE_TRACE /* Module insertion/removal */ -#undef DEBUG_CALLBACK_TRACE /* Calls made by Linux */ -#undef DEBUG_INTERRUPT_TRACE /* Calls to handler */ -#undef DEBUG_INTERRUPT_INFO /* type of interrupt & so on */ -#define DEBUG_INTERRUPT_ERROR /* problems */ -#undef DEBUG_CONFIG_TRACE /* Trace the config functions */ -#undef DEBUG_CONFIG_INFO /* What's going on... */ -#define DEBUG_CONFIG_ERRORS /* Errors on configuration */ -#undef DEBUG_TX_TRACE /* Transmission calls */ -#undef DEBUG_TX_INFO /* Header of the transmitted packet */ -#undef DEBUG_TX_FAIL /* Normal failure conditions */ -#define DEBUG_TX_ERROR /* Unexpected conditions */ -#undef DEBUG_RX_TRACE /* Transmission calls */ -#undef DEBUG_RX_INFO /* Header of the transmitted packet */ -#undef DEBUG_RX_FAIL /* Normal failure conditions */ -#define DEBUG_RX_ERROR /* Unexpected conditions */ -#undef DEBUG_PACKET_DUMP /* Dump packet on the screen */ -#undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ -#undef DEBUG_IOCTL_INFO /* Various debug info */ -#define DEBUG_IOCTL_ERROR /* What's going wrong */ -#define DEBUG_BASIC_SHOW /* Show basic startup info */ -#undef DEBUG_VERSION_SHOW /* Print version info */ -#undef DEBUG_PSA_SHOW /* Dump psa to screen */ -#undef DEBUG_MMC_SHOW /* Dump mmc to screen */ -#undef DEBUG_SHOW_UNUSED /* Show also unused fields */ -#undef DEBUG_I82593_SHOW /* Show i82593 status */ -#undef DEBUG_DEVICE_SHOW /* Show device parameters */ - -/************************ CONSTANTS & MACROS ************************/ - -#ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan_cs.c : v24 (SMP + wireless extensions) 11/1/02\n"; -#endif - -/* Watchdog temporisation */ -#define WATCHDOG_JIFFIES (256*HZ/100) - -/* Fix a bug in some old wireless extension definitions */ -#ifndef IW_ESSID_MAX_SIZE -#define IW_ESSID_MAX_SIZE 32 -#endif - -/* ------------------------ PRIVATE IOCTL ------------------------ */ - -#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ -#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ -#define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */ -#define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */ - -#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 4 /* Set histogram ranges */ -#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 5 /* Get histogram values */ - -/*************************** WaveLAN Roaming **************************/ -#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ - -#define WAVELAN_ROAMING_DEBUG 0 /* 1 = Trace of handover decisions */ - /* 2 = Info on each beacon rcvd... */ -#define MAX_WAVEPOINTS 7 /* Max visible at one time */ -#define WAVEPOINT_HISTORY 5 /* SNR sample history slow search */ -#define WAVEPOINT_FAST_HISTORY 2 /* SNR sample history fast search */ -#define SEARCH_THRESH_LOW 10 /* SNR to enter cell search */ -#define SEARCH_THRESH_HIGH 13 /* SNR to leave cell search */ -#define WAVELAN_ROAMING_DELTA 1 /* Hysteresis value (+/- SNR) */ -#define CELL_TIMEOUT 2*HZ /* in jiffies */ - -#define FAST_CELL_SEARCH 1 /* Boolean values... */ -#define NWID_PROMISC 1 /* for code clarity. */ - -typedef struct wavepoint_beacon -{ - unsigned char dsap, /* Unused */ - ssap, /* Unused */ - ctrl, /* Unused */ - O,U,I, /* Unused */ - spec_id1, /* Unused */ - spec_id2, /* Unused */ - pdu_type, /* Unused */ - seq; /* WavePoint beacon sequence number */ - __be16 domain_id, /* WavePoint Domain ID */ - nwid; /* WavePoint NWID */ -} wavepoint_beacon; - -typedef struct wavepoint_history -{ - unsigned short nwid; /* WavePoint's NWID */ - int average_slow; /* SNR running average */ - int average_fast; /* SNR running average */ - unsigned char sigqual[WAVEPOINT_HISTORY]; /* Ringbuffer of recent SNR's */ - unsigned char qualptr; /* Index into ringbuffer */ - unsigned char last_seq; /* Last seq. no seen for WavePoint */ - struct wavepoint_history *next; /* Next WavePoint in table */ - struct wavepoint_history *prev; /* Previous WavePoint in table */ - unsigned long last_seen; /* Time of last beacon recvd, jiffies */ -} wavepoint_history; - -struct wavepoint_table -{ - wavepoint_history *head; /* Start of ringbuffer */ - int num_wavepoints; /* No. of WavePoints visible */ - unsigned char locked; /* Table lock */ -}; - -#endif /* WAVELAN_ROAMING */ - -/****************************** TYPES ******************************/ - -/* Shortcuts */ -typedef struct iw_statistics iw_stats; -typedef struct iw_quality iw_qual; -typedef struct iw_freq iw_freq; -typedef struct net_local net_local; -typedef struct timer_list timer_list; - -/* Basic types */ -typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ - -/* - * Static specific data for the interface. - * - * For each network interface, Linux keep data in two structure. "device" - * keep the generic data (same format for everybody) and "net_local" keep - * the additional specific data. - */ -struct net_local -{ - dev_node_t node; /* ???? What is this stuff ???? */ - struct net_device * dev; /* Reverse link... */ - spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ - struct pcmcia_device * link; /* pcmcia structure */ - int nresets; /* Number of hw resets */ - u_char configured; /* If it is configured */ - u_char reconfig_82593; /* Need to reconfigure the controller */ - u_char promiscuous; /* Promiscuous mode */ - u_char allmulticast; /* All Multicast mode */ - int mc_count; /* Number of multicast addresses */ - - int stop; /* Current i82593 Stop Hit Register */ - int rfp; /* Last DMA machine receive pointer */ - int overrunning; /* Receiver overrun flag */ - - iw_stats wstats; /* Wireless specific stats */ - - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; - -#ifdef HISTOGRAM - int his_number; /* Number of intervals */ - u_char his_range[16]; /* Boundaries of interval ]n-1; n] */ - u_long his_sum[16]; /* Sum in interval */ -#endif /* HISTOGRAM */ -#ifdef WAVELAN_ROAMING - u_long domain_id; /* Domain ID we lock on for roaming */ - int filter_domains; /* Check Domain ID of beacon found */ - struct wavepoint_table wavepoint_table; /* Table of visible WavePoints*/ - wavepoint_history * curr_point; /* Current wavepoint */ - int cell_search; /* Searching for new cell? */ - struct timer_list cell_timer; /* Garbage collection */ -#endif /* WAVELAN_ROAMING */ - void __iomem *mem; -}; - -/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ -static inline u_char /* data */ - hasr_read(u_long); /* Read the host interface : base address */ -static void - hacr_write(u_long, /* Write to host interface : base address */ - u_char), /* data */ - hacr_write_slow(u_long, - u_char); -static void - psa_read(struct net_device *, /* Read the Parameter Storage Area */ - int, /* offset in PSA */ - u_char *, /* buffer to fill */ - int), /* size to read */ - psa_write(struct net_device *, /* Write to the PSA */ - int, /* Offset in psa */ - u_char *, /* Buffer in memory */ - int); /* Length of buffer */ -static void - mmc_out(u_long, /* Write 1 byte to the Modem Manag Control */ - u_short, - u_char), - mmc_write(u_long, /* Write n bytes to the MMC */ - u_char, - u_char *, - int); -static u_char /* Read 1 byte from the MMC */ - mmc_in(u_long, - u_short); -static void - mmc_read(u_long, /* Read n bytes from the MMC */ - u_char, - u_char *, - int), - fee_wait(u_long, /* Wait for frequency EEprom : base address */ - int, /* Base delay to wait for */ - int); /* Number of time to wait */ -static void - fee_read(u_long, /* Read the frequency EEprom : base address */ - u_short, /* destination offset */ - u_short *, /* data buffer */ - int); /* number of registers */ -/* ---------------------- I82593 SUBROUTINES ----------------------- */ -static int - wv_82593_cmd(struct net_device *, /* synchronously send a command to i82593 */ - char *, - int, - int); -static inline int - wv_diag(struct net_device *); /* Diagnostique the i82593 */ -static int - read_ringbuf(struct net_device *, /* Read a receive buffer */ - int, - char *, - int); -static void - wv_82593_reconfig(struct net_device *); /* Reconfigure the controller */ -/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ -static void - wv_init_info(struct net_device *); /* display startup info */ -/* ------------------- IOCTL, STATS & RECONFIG ------------------- */ -static iw_stats * - wavelan_get_wireless_stats(struct net_device *); -/* ----------------------- PACKET RECEPTION ----------------------- */ -static int - wv_start_of_frame(struct net_device *, /* Seek beggining of current frame */ - int, /* end of frame */ - int); /* start of buffer */ -static void - wv_packet_read(struct net_device *, /* Read a packet from a frame */ - int, - int), - wv_packet_rcv(struct net_device *); /* Read all packets waiting */ -/* --------------------- PACKET TRANSMISSION --------------------- */ -static void - wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer */ - void *, - short); -static netdev_tx_t - wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ - struct net_device *); -/* -------------------- HARDWARE CONFIGURATION -------------------- */ -static int - wv_mmc_init(struct net_device *); /* Initialize the modem */ -static int - wv_ru_stop(struct net_device *), /* Stop the i82593 receiver unit */ - wv_ru_start(struct net_device *); /* Start the i82593 receiver unit */ -static int - wv_82593_config(struct net_device *); /* Configure the i82593 */ -static int - wv_pcmcia_reset(struct net_device *); /* Reset the pcmcia interface */ -static int - wv_hw_config(struct net_device *); /* Reset & configure the whole hardware */ -static void - wv_hw_reset(struct net_device *); /* Same, + start receiver unit */ -static int - wv_pcmcia_config(struct pcmcia_device *); /* Configure the pcmcia interface */ -static void - wv_pcmcia_release(struct pcmcia_device *);/* Remove a device */ -/* ---------------------- INTERRUPT HANDLING ---------------------- */ -static irqreturn_t - wavelan_interrupt(int, /* Interrupt handler */ - void *); -static void - wavelan_watchdog(struct net_device *); /* Transmission watchdog */ -/* ------------------- CONFIGURATION CALLBACKS ------------------- */ -static int - wavelan_open(struct net_device *), /* Open the device */ - wavelan_close(struct net_device *); /* Close the device */ -static void - wavelan_detach(struct pcmcia_device *p_dev); /* Destroy a removed device */ - -/**************************** VARIABLES ****************************/ - -/* - * Parameters that can be set with 'insmod' - * The exact syntax is 'insmod wavelan_cs.o =' - */ - -/* Shared memory speed, in ns */ -static int mem_speed = 0; - -/* New module interface */ -module_param(mem_speed, int, 0); - -#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ -/* Enable roaming mode ? No ! Please keep this to 0 */ -static int do_roaming = 0; -module_param(do_roaming, bool, 0); -#endif /* WAVELAN_ROAMING */ - -MODULE_LICENSE("GPL"); - -#endif /* WAVELAN_CS_P_H */ - diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index ca946ca3823b..c1082f20534c 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -135,5 +135,7 @@ source "drivers/staging/strip/Kconfig" source "drivers/staging/arlan/Kconfig" +source "drivers/staging/wavelan/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index ed92324178bd..7bccdd3e7fab 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -49,3 +49,5 @@ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_COWLOOP) += cowloop/ obj-$(CONFIG_STRIP) += strip/ obj-$(CONFIG_ARLAN) += arlan/ +obj-$(CONFIG_WAVELAN) += wavelan/ +obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan/ diff --git a/drivers/staging/wavelan/Kconfig b/drivers/staging/wavelan/Kconfig new file mode 100644 index 000000000000..786060e025c0 --- /dev/null +++ b/drivers/staging/wavelan/Kconfig @@ -0,0 +1,38 @@ +config WAVELAN + tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support" + depends on ISA + select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV + ---help--- + The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is + a Radio LAN (wireless Ethernet-like Local Area Network) using the + radio frequencies 900 MHz and 2.4 GHz. + + If you want to use an ISA WaveLAN card under Linux, say Y and read + the Ethernet-HOWTO, available from + . Some more specific + information is contained in + and in the source code + . + + You will also need the wireless tools package available from + . + Please read the man pages contained therein. + + To compile this driver as a module, choose M here: the module will be + called wavelan. + +config PCMCIA_WAVELAN + tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support" + depends on PCMCIA + select WIRELESS_EXT + select WEXT_SPY + select WEXT_PRIV + help + Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA + (PC-card) wireless Ethernet networking card to your computer. This + driver is for the non-IEEE-802.11 Wavelan cards. + + To compile this driver as a module, choose M here: the module will be + called wavelan_cs. If unsure, say N. diff --git a/drivers/staging/wavelan/Makefile b/drivers/staging/wavelan/Makefile new file mode 100644 index 000000000000..1cde17c69a43 --- /dev/null +++ b/drivers/staging/wavelan/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_WAVELAN) += wavelan.o +obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o diff --git a/drivers/staging/wavelan/i82586.h b/drivers/staging/wavelan/i82586.h new file mode 100644 index 000000000000..5f65b250646f --- /dev/null +++ b/drivers/staging/wavelan/i82586.h @@ -0,0 +1,413 @@ +/* + * Intel 82586 IEEE 802.3 Ethernet LAN Coprocessor. + * + * See: + * Intel Microcommunications 1991 + * p1-1 to p1-37 + * Intel order No. 231658 + * ISBN 1-55512-119-5 + * + * Unfortunately, the above chapter mentions neither + * the System Configuration Pointer (SCP) nor the + * Intermediate System Configuration Pointer (ISCP), + * so we probably need to look elsewhere for the + * whole story -- some recommend the "Intel LAN + * Components manual" but I have neither a copy + * nor a full reference. But "elsewhere" may be + * in the same publication... + * The description of a later device, the + * "82596CA High-Performance 32-Bit Local Area Network + * Coprocessor", (ibid. p1-38 to p1-109) does mention + * the SCP and ISCP and also has an i82586 compatibility + * mode. Even more useful is "AP-235 An 82586 Data Link + * Driver" (ibid. p1-337 to p1-417). + */ + +#define I82586_MEMZ (64 * 1024) + +#define I82586_SCP_ADDR (I82586_MEMZ - sizeof(scp_t)) + +#define ADDR_LEN 6 +#define I82586NULL 0xFFFF + +#define toff(t,p,f) (unsigned short)((void *)(&((t *)((void *)0 + (p)))->f) - (void *)0) + +/* + * System Configuration Pointer (SCP). + */ +typedef struct scp_t scp_t; +struct scp_t +{ + unsigned short scp_sysbus; /* 82586 bus width: */ +#define SCP_SY_16BBUS (0x0 << 0) /* 16 bits */ +#define SCP_SY_8BBUS (0x1 << 0) /* 8 bits. */ + unsigned short scp_junk[2]; /* Unused */ + unsigned short scp_iscpl; /* lower 16 bits of ISCP_ADDR */ + unsigned short scp_iscph; /* upper 16 bits of ISCP_ADDR */ +}; + +/* + * Intermediate System Configuration Pointer (ISCP). + */ +typedef struct iscp_t iscp_t; +struct iscp_t +{ + unsigned short iscp_busy; /* set by CPU before first CA, */ + /* cleared by 82586 after read. */ + unsigned short iscp_offset; /* offset of SCB */ + unsigned short iscp_basel; /* base of SCB */ + unsigned short iscp_baseh; /* " */ +}; + +/* + * System Control Block (SCB). + * The 82586 writes its status to scb_status and then + * raises an interrupt to alert the CPU. + * The CPU writes a command to scb_command and + * then issues a Channel Attention (CA) to alert the 82586. + */ +typedef struct scb_t scb_t; +struct scb_t +{ + unsigned short scb_status; /* Status of 82586 */ +#define SCB_ST_INT (0xF << 12) /* Some of: */ +#define SCB_ST_CX (0x1 << 15) /* Cmd completed */ +#define SCB_ST_FR (0x1 << 14) /* Frame received */ +#define SCB_ST_CNA (0x1 << 13) /* Cmd unit not active */ +#define SCB_ST_RNR (0x1 << 12) /* Rcv unit not ready */ +#define SCB_ST_JUNK0 (0x1 << 11) /* 0 */ +#define SCB_ST_CUS (0x7 << 8) /* Cmd unit status */ +#define SCB_ST_CUS_IDLE (0 << 8) /* Idle */ +#define SCB_ST_CUS_SUSP (1 << 8) /* Suspended */ +#define SCB_ST_CUS_ACTV (2 << 8) /* Active */ +#define SCB_ST_JUNK1 (0x1 << 7) /* 0 */ +#define SCB_ST_RUS (0x7 << 4) /* Rcv unit status */ +#define SCB_ST_RUS_IDLE (0 << 4) /* Idle */ +#define SCB_ST_RUS_SUSP (1 << 4) /* Suspended */ +#define SCB_ST_RUS_NRES (2 << 4) /* No resources */ +#define SCB_ST_RUS_RDY (4 << 4) /* Ready */ + unsigned short scb_command; /* Next command */ +#define SCB_CMD_ACK_CX (0x1 << 15) /* Ack cmd completion */ +#define SCB_CMD_ACK_FR (0x1 << 14) /* Ack frame received */ +#define SCB_CMD_ACK_CNA (0x1 << 13) /* Ack CU not active */ +#define SCB_CMD_ACK_RNR (0x1 << 12) /* Ack RU not ready */ +#define SCB_CMD_JUNKX (0x1 << 11) /* Unused */ +#define SCB_CMD_CUC (0x7 << 8) /* Command Unit command */ +#define SCB_CMD_CUC_NOP (0 << 8) /* Nop */ +#define SCB_CMD_CUC_GO (1 << 8) /* Start cbl_offset */ +#define SCB_CMD_CUC_RES (2 << 8) /* Resume execution */ +#define SCB_CMD_CUC_SUS (3 << 8) /* Suspend " */ +#define SCB_CMD_CUC_ABT (4 << 8) /* Abort " */ +#define SCB_CMD_RESET (0x1 << 7) /* Reset chip (hardware) */ +#define SCB_CMD_RUC (0x7 << 4) /* Receive Unit command */ +#define SCB_CMD_RUC_NOP (0 << 4) /* Nop */ +#define SCB_CMD_RUC_GO (1 << 4) /* Start rfa_offset */ +#define SCB_CMD_RUC_RES (2 << 4) /* Resume reception */ +#define SCB_CMD_RUC_SUS (3 << 4) /* Suspend " */ +#define SCB_CMD_RUC_ABT (4 << 4) /* Abort " */ + unsigned short scb_cbl_offset; /* Offset of first command unit */ + /* Action Command */ + unsigned short scb_rfa_offset; /* Offset of first Receive */ + /* Frame Descriptor in the */ + /* Receive Frame Area */ + unsigned short scb_crcerrs; /* Properly aligned frames */ + /* received with a CRC error */ + unsigned short scb_alnerrs; /* Misaligned frames received */ + /* with a CRC error */ + unsigned short scb_rscerrs; /* Frames lost due to no space */ + unsigned short scb_ovrnerrs; /* Frames lost due to slow bus */ +}; + +#define scboff(p,f) toff(scb_t, p, f) + +/* + * The eight Action Commands. + */ +typedef enum acmd_e acmd_e; +enum acmd_e +{ + acmd_nop = 0, /* Do nothing */ + acmd_ia_setup = 1, /* Load an (ethernet) address into the */ + /* 82586 */ + acmd_configure = 2, /* Update the 82586 operating parameters */ + acmd_mc_setup = 3, /* Load a list of (ethernet) multicast */ + /* addresses into the 82586 */ + acmd_transmit = 4, /* Transmit a frame */ + acmd_tdr = 5, /* Perform a Time Domain Reflectometer */ + /* test on the serial link */ + acmd_dump = 6, /* Copy 82586 registers to memory */ + acmd_diagnose = 7, /* Run an internal self test */ +}; + +/* + * Generic Action Command header. + */ +typedef struct ach_t ach_t; +struct ach_t +{ + unsigned short ac_status; /* Command status: */ +#define AC_SFLD_C (0x1 << 15) /* Command completed */ +#define AC_SFLD_B (0x1 << 14) /* Busy executing */ +#define AC_SFLD_OK (0x1 << 13) /* Completed error free */ +#define AC_SFLD_A (0x1 << 12) /* Command aborted */ +#define AC_SFLD_FAIL (0x1 << 11) /* Selftest failed */ +#define AC_SFLD_S10 (0x1 << 10) /* No carrier sense */ + /* during transmission */ +#define AC_SFLD_S9 (0x1 << 9) /* Tx unsuccessful: */ + /* (stopped) lost CTS */ +#define AC_SFLD_S8 (0x1 << 8) /* Tx unsuccessful: */ + /* (stopped) slow DMA */ +#define AC_SFLD_S7 (0x1 << 7) /* Tx deferred: */ + /* other link traffic */ +#define AC_SFLD_S6 (0x1 << 6) /* Heart Beat: collision */ + /* detect after last tx */ +#define AC_SFLD_S5 (0x1 << 5) /* Tx stopped: */ + /* excessive collisions */ +#define AC_SFLD_MAXCOL (0xF << 0) /* Collision count */ + unsigned short ac_command; /* Command specifier: */ +#define AC_CFLD_EL (0x1 << 15) /* End of command list */ +#define AC_CFLD_S (0x1 << 14) /* Suspend on completion */ +#define AC_CFLD_I (0x1 << 13) /* Interrupt on completion */ +#define AC_CFLD_CMD (0x7 << 0) /* acmd_e */ + unsigned short ac_link; /* Next Action Command */ +}; + +#define acoff(p,f) toff(ach_t, p, f) + +/* + * The Nop Action Command. + */ +typedef struct ac_nop_t ac_nop_t; +struct ac_nop_t +{ + ach_t nop_h; +}; + +/* + * The IA-Setup Action Command. + */ +typedef struct ac_ias_t ac_ias_t; +struct ac_ias_t +{ + ach_t ias_h; + unsigned char ias_addr[ADDR_LEN]; /* The (ethernet) address */ +}; + +/* + * The Configure Action Command. + */ +typedef struct ac_cfg_t ac_cfg_t; +struct ac_cfg_t +{ + ach_t cfg_h; + unsigned char cfg_byte_cnt; /* Size foll data: 4-12 */ +#define AC_CFG_BYTE_CNT(v) (((v) & 0xF) << 0) + unsigned char cfg_fifolim; /* FIFO threshold */ +#define AC_CFG_FIFOLIM(v) (((v) & 0xF) << 0) + unsigned char cfg_byte8; +#define AC_CFG_SAV_BF(v) (((v) & 0x1) << 7) /* Save rxd bad frames */ +#define AC_CFG_SRDY(v) (((v) & 0x1) << 6) /* SRDY/ARDY pin means */ + /* external sync. */ + unsigned char cfg_byte9; +#define AC_CFG_ELPBCK(v) (((v) & 0x1) << 7) /* External loopback */ +#define AC_CFG_ILPBCK(v) (((v) & 0x1) << 6) /* Internal loopback */ +#define AC_CFG_PRELEN(v) (((v) & 0x3) << 4) /* Preamble length */ +#define AC_CFG_PLEN_2 0 /* 2 bytes */ +#define AC_CFG_PLEN_4 1 /* 4 bytes */ +#define AC_CFG_PLEN_8 2 /* 8 bytes */ +#define AC_CFG_PLEN_16 3 /* 16 bytes */ +#define AC_CFG_ALOC(v) (((v) & 0x1) << 3) /* Addr/len data is */ + /* explicit in buffers */ +#define AC_CFG_ADDRLEN(v) (((v) & 0x7) << 0) /* Bytes per address */ + unsigned char cfg_byte10; +#define AC_CFG_BOFMET(v) (((v) & 0x1) << 7) /* Use alternate expo. */ + /* backoff method */ +#define AC_CFG_ACR(v) (((v) & 0x7) << 4) /* Accelerated cont. res. */ +#define AC_CFG_LINPRIO(v) (((v) & 0x7) << 0) /* Linear priority */ + unsigned char cfg_ifs; /* Interframe spacing */ + unsigned char cfg_slotl; /* Slot time (low byte) */ + unsigned char cfg_byte13; +#define AC_CFG_RETRYNUM(v) (((v) & 0xF) << 4) /* Max. collision retry */ +#define AC_CFG_SLTTMHI(v) (((v) & 0x7) << 0) /* Slot time (high bits) */ + unsigned char cfg_byte14; +#define AC_CFG_FLGPAD(v) (((v) & 0x1) << 7) /* Pad with HDLC flags */ +#define AC_CFG_BTSTF(v) (((v) & 0x1) << 6) /* Do HDLC bitstuffing */ +#define AC_CFG_CRC16(v) (((v) & 0x1) << 5) /* 16 bit CCITT CRC */ +#define AC_CFG_NCRC(v) (((v) & 0x1) << 4) /* Insert no CRC */ +#define AC_CFG_TNCRS(v) (((v) & 0x1) << 3) /* Tx even if no carrier */ +#define AC_CFG_MANCH(v) (((v) & 0x1) << 2) /* Manchester coding */ +#define AC_CFG_BCDIS(v) (((v) & 0x1) << 1) /* Disable broadcast */ +#define AC_CFG_PRM(v) (((v) & 0x1) << 0) /* Promiscuous mode */ + unsigned char cfg_byte15; +#define AC_CFG_ICDS(v) (((v) & 0x1) << 7) /* Internal collision */ + /* detect source */ +#define AC_CFG_CDTF(v) (((v) & 0x7) << 4) /* Collision detect */ + /* filter in bit times */ +#define AC_CFG_ICSS(v) (((v) & 0x1) << 3) /* Internal carrier */ + /* sense source */ +#define AC_CFG_CSTF(v) (((v) & 0x7) << 0) /* Carrier sense */ + /* filter in bit times */ + unsigned short cfg_min_frm_len; +#define AC_CFG_MNFRM(v) (((v) & 0xFF) << 0) /* Min. bytes/frame (<= 255) */ +}; + +/* + * The MC-Setup Action Command. + */ +typedef struct ac_mcs_t ac_mcs_t; +struct ac_mcs_t +{ + ach_t mcs_h; + unsigned short mcs_cnt; /* No. of bytes of MC addresses */ +#if 0 + unsigned char mcs_data[ADDR_LEN]; /* The first MC address .. */ + ... +#endif +}; + +#define I82586_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ + +/* + * The Transmit Action Command. + */ +typedef struct ac_tx_t ac_tx_t; +struct ac_tx_t +{ + ach_t tx_h; + unsigned short tx_tbd_offset; /* Address of list of buffers. */ +#if 0 +Linux packets are passed down with the destination MAC address +and length/type field already prepended to the data, +so we do not need to insert it. Consistent with this +we must also set the AC_CFG_ALOC(..) flag during the +ac_cfg_t action command. + unsigned char tx_addr[ADDR_LEN]; /* The frame dest. address */ + unsigned short tx_length; /* The frame length */ +#endif /* 0 */ +}; + +/* + * The Time Domain Reflectometer Action Command. + */ +typedef struct ac_tdr_t ac_tdr_t; +struct ac_tdr_t +{ + ach_t tdr_h; + unsigned short tdr_result; /* Result. */ +#define AC_TDR_LNK_OK (0x1 << 15) /* No link problem */ +#define AC_TDR_XCVR_PRB (0x1 << 14) /* Txcvr cable problem */ +#define AC_TDR_ET_OPN (0x1 << 13) /* Open on the link */ +#define AC_TDR_ET_SRT (0x1 << 12) /* Short on the link */ +#define AC_TDR_TIME (0x7FF << 0) /* Distance to problem */ + /* site in transmit */ + /* clock cycles */ +}; + +/* + * The Dump Action Command. + */ +typedef struct ac_dmp_t ac_dmp_t; +struct ac_dmp_t +{ + ach_t dmp_h; + unsigned short dmp_offset; /* Result. */ +}; + +/* + * Size of the result of the dump command. + */ +#define DUMPBYTES 170 + +/* + * The Diagnose Action Command. + */ +typedef struct ac_dgn_t ac_dgn_t; +struct ac_dgn_t +{ + ach_t dgn_h; +}; + +/* + * Transmit Buffer Descriptor (TBD). + */ +typedef struct tbd_t tbd_t; +struct tbd_t +{ + unsigned short tbd_status; /* Written by the CPU */ +#define TBD_STATUS_EOF (0x1 << 15) /* This TBD is the */ + /* last for this frame */ +#define TBD_STATUS_ACNT (0x3FFF << 0) /* Actual count of data */ + /* bytes in this buffer */ + unsigned short tbd_next_bd_offset; /* Next in list */ + unsigned short tbd_bufl; /* Buffer address (low) */ + unsigned short tbd_bufh; /* " " (high) */ +}; + +/* + * Receive Buffer Descriptor (RBD). + */ +typedef struct rbd_t rbd_t; +struct rbd_t +{ + unsigned short rbd_status; /* Written by the 82586 */ +#define RBD_STATUS_EOF (0x1 << 15) /* This RBD is the */ + /* last for this frame */ +#define RBD_STATUS_F (0x1 << 14) /* ACNT field is valid */ +#define RBD_STATUS_ACNT (0x3FFF << 0) /* Actual no. of data */ + /* bytes in this buffer */ + unsigned short rbd_next_rbd_offset; /* Next rbd in list */ + unsigned short rbd_bufl; /* Data pointer (low) */ + unsigned short rbd_bufh; /* " " (high) */ + unsigned short rbd_el_size; /* EL+Data buf. size */ +#define RBD_EL (0x1 << 15) /* This BD is the */ + /* last in the list */ +#define RBD_SIZE (0x3FFF << 0) /* No. of bytes the */ + /* buffer can hold */ +}; + +#define rbdoff(p,f) toff(rbd_t, p, f) + +/* + * Frame Descriptor (FD). + */ +typedef struct fd_t fd_t; +struct fd_t +{ + unsigned short fd_status; /* Written by the 82586 */ +#define FD_STATUS_C (0x1 << 15) /* Completed storing frame */ +#define FD_STATUS_B (0x1 << 14) /* FD was consumed by RU */ +#define FD_STATUS_OK (0x1 << 13) /* Frame rxd successfully */ +#define FD_STATUS_S11 (0x1 << 11) /* CRC error */ +#define FD_STATUS_S10 (0x1 << 10) /* Alignment error */ +#define FD_STATUS_S9 (0x1 << 9) /* Ran out of resources */ +#define FD_STATUS_S8 (0x1 << 8) /* Rx DMA overrun */ +#define FD_STATUS_S7 (0x1 << 7) /* Frame too short */ +#define FD_STATUS_S6 (0x1 << 6) /* No EOF flag */ + unsigned short fd_command; /* Command */ +#define FD_COMMAND_EL (0x1 << 15) /* Last FD in list */ +#define FD_COMMAND_S (0x1 << 14) /* Suspend RU after rx */ + unsigned short fd_link_offset; /* Next FD */ + unsigned short fd_rbd_offset; /* First RBD (data) */ + /* Prepared by CPU, */ + /* updated by 82586 */ +#if 0 +I think the rest is unused since we +have set AC_CFG_ALOC(..). However, just +in case, we leave the space. +#endif /* 0 */ + unsigned char fd_dest[ADDR_LEN]; /* Destination address */ + /* Written by 82586 */ + unsigned char fd_src[ADDR_LEN]; /* Source address */ + /* Written by 82586 */ + unsigned short fd_length; /* Frame length or type */ + /* Written by 82586 */ +}; + +#define fdoff(p,f) toff(fd_t, p, f) + +/* + * This software may only be used and distributed + * according to the terms of the GNU General Public License. + * + * For more details, see wavelan.c. + */ diff --git a/drivers/staging/wavelan/i82593.h b/drivers/staging/wavelan/i82593.h new file mode 100644 index 000000000000..afac5c7a323d --- /dev/null +++ b/drivers/staging/wavelan/i82593.h @@ -0,0 +1,229 @@ +/* + * Definitions for Intel 82593 CSMA/CD Core LAN Controller + * The definitions are taken from the 1992 users manual with Intel + * order number 297125-001. + * + * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp + * + * Copyright 1994, Anders Klemets + * + * HISTORY + * i82593.h,v + * Revision 1.4 2005/11/4 09:15:00 baroniunas + * Modified copyright with permission of author as follows: + * + * "If I82539.H is the only file with my copyright statement + * that is included in the Source Forge project, then you have + * my approval to change the copyright statement to be a GPL + * license, in the way you proposed on October 10." + * + * Revision 1.1 1996/07/17 15:23:12 root + * Initial revision + * + * Revision 1.3 1995/04/05 15:13:58 adj + * Initial alpha release + * + * Revision 1.2 1994/06/16 23:57:31 klemets + * Mirrored all the fields in the configuration block. + * + * Revision 1.1 1994/06/02 20:25:34 klemets + * Initial revision + * + * + */ +#ifndef _I82593_H +#define _I82593_H + +/* Intel 82593 CSMA/CD Core LAN Controller */ + +/* Port 0 Command Register definitions */ + +/* Execution operations */ +#define OP0_NOP 0 /* CHNL = 0 */ +#define OP0_SWIT_TO_PORT_1 0 /* CHNL = 1 */ +#define OP0_IA_SETUP 1 +#define OP0_CONFIGURE 2 +#define OP0_MC_SETUP 3 +#define OP0_TRANSMIT 4 +#define OP0_TDR 5 +#define OP0_DUMP 6 +#define OP0_DIAGNOSE 7 +#define OP0_TRANSMIT_NO_CRC 9 +#define OP0_RETRANSMIT 12 +#define OP0_ABORT 13 +/* Reception operations */ +#define OP0_RCV_ENABLE 8 +#define OP0_RCV_DISABLE 10 +#define OP0_STOP_RCV 11 +/* Status pointer control operations */ +#define OP0_FIX_PTR 15 /* CHNL = 1 */ +#define OP0_RLS_PTR 15 /* CHNL = 0 */ +#define OP0_RESET 14 + +#define CR0_CHNL (1 << 4) /* 0=Channel 0, 1=Channel 1 */ +#define CR0_STATUS_0 0x00 +#define CR0_STATUS_1 0x20 +#define CR0_STATUS_2 0x40 +#define CR0_STATUS_3 0x60 +#define CR0_INT_ACK (1 << 7) /* 0=No ack, 1=acknowledge */ + +/* Port 0 Status Register definitions */ + +#define SR0_NO_RESULT 0 /* dummy */ +#define SR0_EVENT_MASK 0x0f +#define SR0_IA_SETUP_DONE 1 +#define SR0_CONFIGURE_DONE 2 +#define SR0_MC_SETUP_DONE 3 +#define SR0_TRANSMIT_DONE 4 +#define SR0_TDR_DONE 5 +#define SR0_DUMP_DONE 6 +#define SR0_DIAGNOSE_PASSED 7 +#define SR0_TRANSMIT_NO_CRC_DONE 9 +#define SR0_RETRANSMIT_DONE 12 +#define SR0_EXECUTION_ABORTED 13 +#define SR0_END_OF_FRAME 8 +#define SR0_RECEPTION_ABORTED 10 +#define SR0_DIAGNOSE_FAILED 15 +#define SR0_STOP_REG_HIT 11 + +#define SR0_CHNL (1 << 4) +#define SR0_EXECUTION (1 << 5) +#define SR0_RECEPTION (1 << 6) +#define SR0_INTERRUPT (1 << 7) +#define SR0_BOTH_RX_TX (SR0_EXECUTION | SR0_RECEPTION) + +#define SR3_EXEC_STATE_MASK 0x03 +#define SR3_EXEC_IDLE 0 +#define SR3_TX_ABORT_IN_PROGRESS 1 +#define SR3_EXEC_ACTIVE 2 +#define SR3_ABORT_IN_PROGRESS 3 +#define SR3_EXEC_CHNL (1 << 2) +#define SR3_STP_ON_NO_RSRC (1 << 3) +#define SR3_RCVING_NO_RSRC (1 << 4) +#define SR3_RCV_STATE_MASK 0x60 +#define SR3_RCV_IDLE 0x00 +#define SR3_RCV_READY 0x20 +#define SR3_RCV_ACTIVE 0x40 +#define SR3_RCV_STOP_IN_PROG 0x60 +#define SR3_RCV_CHNL (1 << 7) + +/* Port 1 Command Register definitions */ + +#define OP1_NOP 0 +#define OP1_SWIT_TO_PORT_0 1 +#define OP1_INT_DISABLE 2 +#define OP1_INT_ENABLE 3 +#define OP1_SET_TS 5 +#define OP1_RST_TS 7 +#define OP1_POWER_DOWN 8 +#define OP1_RESET_RING_MNGMT 11 +#define OP1_RESET 14 +#define OP1_SEL_RST 15 + +#define CR1_STATUS_4 0x00 +#define CR1_STATUS_5 0x20 +#define CR1_STATUS_6 0x40 +#define CR1_STOP_REG_UPDATE (1 << 7) + +/* Receive frame status bits */ + +#define RX_RCLD (1 << 0) +#define RX_IA_MATCH (1 << 1) +#define RX_NO_AD_MATCH (1 << 2) +#define RX_NO_SFD (1 << 3) +#define RX_SRT_FRM (1 << 7) +#define RX_OVRRUN (1 << 8) +#define RX_ALG_ERR (1 << 10) +#define RX_CRC_ERR (1 << 11) +#define RX_LEN_ERR (1 << 12) +#define RX_RCV_OK (1 << 13) +#define RX_TYP_LEN (1 << 15) + +/* Transmit status bits */ + +#define TX_NCOL_MASK 0x0f +#define TX_FRTL (1 << 4) +#define TX_MAX_COL (1 << 5) +#define TX_HRT_BEAT (1 << 6) +#define TX_DEFER (1 << 7) +#define TX_UND_RUN (1 << 8) +#define TX_LOST_CTS (1 << 9) +#define TX_LOST_CRS (1 << 10) +#define TX_LTCOL (1 << 11) +#define TX_OK (1 << 13) +#define TX_COLL (1 << 15) + +struct i82593_conf_block { + u_char fifo_limit : 4, + forgnesi : 1, + fifo_32 : 1, + d6mod : 1, + throttle_enb : 1; + u_char throttle : 6, + cntrxint : 1, + contin : 1; + u_char addr_len : 3, + acloc : 1, + preamb_len : 2, + loopback : 2; + u_char lin_prio : 3, + tbofstop : 1, + exp_prio : 3, + bof_met : 1; + u_char : 4, + ifrm_spc : 4; + u_char : 5, + slottim_low : 3; + u_char slottim_hi : 3, + : 1, + max_retr : 4; + u_char prmisc : 1, + bc_dis : 1, + : 1, + crs_1 : 1, + nocrc_ins : 1, + crc_1632 : 1, + : 1, + crs_cdt : 1; + u_char cs_filter : 3, + crs_src : 1, + cd_filter : 3, + : 1; + u_char : 2, + min_fr_len : 6; + u_char lng_typ : 1, + lng_fld : 1, + rxcrc_xf : 1, + artx : 1, + sarec : 1, + tx_jabber : 1, /* why is this called max_len in the manual? */ + hash_1 : 1, + lbpkpol : 1; + u_char : 6, + fdx : 1, + : 1; + u_char dummy_6 : 6, /* supposed to be ones */ + mult_ia : 1, + dis_bof : 1; + u_char dummy_1 : 1, /* supposed to be one */ + tx_ifs_retrig : 2, + mc_all : 1, + rcv_mon : 2, + frag_acpt : 1, + tstrttrs : 1; + u_char fretx : 1, + runt_eop : 1, + hw_sw_pin : 1, + big_endn : 1, + syncrqs : 1, + sttlen : 1, + tx_eop : 1, + rx_eop : 1; + u_char rbuf_size : 5, + rcvstop : 1, + : 2; +}; + +#define I82593_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ + +#endif /* _I82593_H */ diff --git a/drivers/staging/wavelan/wavelan.c b/drivers/staging/wavelan/wavelan.c new file mode 100644 index 000000000000..d634b2da3b84 --- /dev/null +++ b/drivers/staging/wavelan/wavelan.c @@ -0,0 +1,4383 @@ +/* + * WaveLAN ISA driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * Original copyright follows (also see the end of this file). + * See wavelan.p.h for details. + * + * + * + * AT&T GIS (nee NCR) WaveLAN card: + * An Ethernet-like radio transceiver + * controlled by an Intel 82586 coprocessor. + */ + +#include "wavelan.p.h" /* Private header */ + +/************************* MISC SUBROUTINES **************************/ +/* + * Subroutines which won't fit in one of the following category + * (WaveLAN modem or i82586) + */ + +/*------------------------------------------------------------------*/ +/* + * Translate irq number to PSA irq parameter + */ +static u8 wv_irq_to_psa(int irq) +{ + if (irq < 0 || irq >= ARRAY_SIZE(irqvals)) + return 0; + + return irqvals[irq]; +} + +/*------------------------------------------------------------------*/ +/* + * Translate PSA irq parameter to irq number + */ +static int __init wv_psa_to_irq(u8 irqval) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(irqvals); i++) + if (irqvals[i] == irqval) + return i; + + return -1; +} + +/********************* HOST ADAPTER SUBROUTINES *********************/ +/* + * Useful subroutines to manage the WaveLAN ISA interface + * + * One major difference with the PCMCIA hardware (except the port mapping) + * is that we have to keep the state of the Host Control Register + * because of the interrupt enable & bus size flags. + */ + +/*------------------------------------------------------------------*/ +/* + * Read from card's Host Adaptor Status Register. + */ +static inline u16 hasr_read(unsigned long ioaddr) +{ + return (inw(HASR(ioaddr))); +} /* hasr_read */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. + */ +static inline void hacr_write(unsigned long ioaddr, u16 hacr) +{ + outw(hacr, HACR(ioaddr)); +} /* hacr_write */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. Include a delay for + * those times when it is needed. + */ +static void hacr_write_slow(unsigned long ioaddr, u16 hacr) +{ + hacr_write(ioaddr, hacr); + /* delay might only be needed sometimes */ + mdelay(1); +} /* hacr_write_slow */ + +/*------------------------------------------------------------------*/ +/* + * Set the channel attention bit. + */ +static inline void set_chan_attn(unsigned long ioaddr, u16 hacr) +{ + hacr_write(ioaddr, hacr | HACR_CA); +} /* set_chan_attn */ + +/*------------------------------------------------------------------*/ +/* + * Reset, and then set host adaptor into default mode. + */ +static inline void wv_hacr_reset(unsigned long ioaddr) +{ + hacr_write_slow(ioaddr, HACR_RESET); + hacr_write(ioaddr, HACR_DEFAULT); +} /* wv_hacr_reset */ + +/*------------------------------------------------------------------*/ +/* + * Set the I/O transfer over the ISA bus to 8-bit mode + */ +static inline void wv_16_off(unsigned long ioaddr, u16 hacr) +{ + hacr &= ~HACR_16BITS; + hacr_write(ioaddr, hacr); +} /* wv_16_off */ + +/*------------------------------------------------------------------*/ +/* + * Set the I/O transfer over the ISA bus to 8-bit mode + */ +static inline void wv_16_on(unsigned long ioaddr, u16 hacr) +{ + hacr |= HACR_16BITS; + hacr_write(ioaddr, hacr); +} /* wv_16_on */ + +/*------------------------------------------------------------------*/ +/* + * Disable interrupts on the WaveLAN hardware. + * (called by wv_82586_stop()) + */ +static inline void wv_ints_off(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + + lp->hacr &= ~HACR_INTRON; + hacr_write(ioaddr, lp->hacr); +} /* wv_ints_off */ + +/*------------------------------------------------------------------*/ +/* + * Enable interrupts on the WaveLAN hardware. + * (called by wv_hw_reset()) + */ +static inline void wv_ints_on(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + + lp->hacr |= HACR_INTRON; + hacr_write(ioaddr, lp->hacr); +} /* wv_ints_on */ + +/******************* MODEM MANAGEMENT SUBROUTINES *******************/ +/* + * Useful subroutines to manage the modem of the WaveLAN + */ + +/*------------------------------------------------------------------*/ +/* + * Read the Parameter Storage Area from the WaveLAN card's memory + */ +/* + * Read bytes from the PSA. + */ +static void psa_read(unsigned long ioaddr, u16 hacr, int o, /* offset in PSA */ + u8 * b, /* buffer to fill */ + int n) +{ /* size to read */ + wv_16_off(ioaddr, hacr); + + while (n-- > 0) { + outw(o, PIOR2(ioaddr)); + o++; + *b++ = inb(PIOP2(ioaddr)); + } + + wv_16_on(ioaddr, hacr); +} /* psa_read */ + +/*------------------------------------------------------------------*/ +/* + * Write the Parameter Storage Area to the WaveLAN card's memory. + */ +static void psa_write(unsigned long ioaddr, u16 hacr, int o, /* Offset in PSA */ + u8 * b, /* Buffer in memory */ + int n) +{ /* Length of buffer */ + int count = 0; + + wv_16_off(ioaddr, hacr); + + while (n-- > 0) { + outw(o, PIOR2(ioaddr)); + o++; + + outb(*b, PIOP2(ioaddr)); + b++; + + /* Wait for the memory to finish its write cycle */ + count = 0; + while ((count++ < 100) && + (hasr_read(ioaddr) & HASR_PSA_BUSY)) mdelay(1); + } + + wv_16_on(ioaddr, hacr); +} /* psa_write */ + +#ifdef SET_PSA_CRC +/*------------------------------------------------------------------*/ +/* + * Calculate the PSA CRC + * Thanks to Valster, Nico for the code + * NOTE: By specifying a length including the CRC position the + * returned value should be zero. (i.e. a correct checksum in the PSA) + * + * The Windows drivers don't use the CRC, but the AP and the PtP tool + * depend on it. + */ +static u16 psa_crc(u8 * psa, /* The PSA */ + int size) +{ /* Number of short for CRC */ + int byte_cnt; /* Loop on the PSA */ + u16 crc_bytes = 0; /* Data in the PSA */ + int bit_cnt; /* Loop on the bits of the short */ + + for (byte_cnt = 0; byte_cnt < size; byte_cnt++) { + crc_bytes ^= psa[byte_cnt]; /* Its an xor */ + + for (bit_cnt = 1; bit_cnt < 9; bit_cnt++) { + if (crc_bytes & 0x0001) + crc_bytes = (crc_bytes >> 1) ^ 0xA001; + else + crc_bytes >>= 1; + } + } + + return crc_bytes; +} /* psa_crc */ +#endif /* SET_PSA_CRC */ + +/*------------------------------------------------------------------*/ +/* + * update the checksum field in the Wavelan's PSA + */ +static void update_psa_checksum(struct net_device * dev, unsigned long ioaddr, u16 hacr) +{ +#ifdef SET_PSA_CRC + psa_t psa; + u16 crc; + + /* read the parameter storage area */ + psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa)); + + /* update the checksum */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc[0]) - + sizeof(psa.psa_crc[1]) + - sizeof(psa.psa_crc_status)); + + psa.psa_crc[0] = crc & 0xFF; + psa.psa_crc[1] = (crc & 0xFF00) >> 8; + + /* Write it ! */ + psa_write(ioaddr, hacr, (char *) &psa.psa_crc - (char *) &psa, + (unsigned char *) &psa.psa_crc, 2); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", + dev->name, psa.psa_crc[0], psa.psa_crc[1]); + + /* Check again (luxury !) */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc_status)); + + if (crc != 0) + printk(KERN_WARNING + "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", + dev->name); +#endif /* DEBUG_IOCTL_INFO */ +#endif /* SET_PSA_CRC */ +} /* update_psa_checksum */ + +/*------------------------------------------------------------------*/ +/* + * Write 1 byte to the MMC. + */ +static void mmc_out(unsigned long ioaddr, u16 o, u8 d) +{ + int count = 0; + + /* Wait for MMC to go idle */ + while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) + udelay(10); + + outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr)); +} + +/*------------------------------------------------------------------*/ +/* + * Routine to write bytes to the Modem Management Controller. + * We start at the end because it is the way it should be! + */ +static void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n) +{ + o += n; + b += n; + + while (n-- > 0) + mmc_out(ioaddr, --o, *(--b)); +} /* mmc_write */ + +/*------------------------------------------------------------------*/ +/* + * Read a byte from the MMC. + * Optimised version for 1 byte, avoid using memory. + */ +static u8 mmc_in(unsigned long ioaddr, u16 o) +{ + int count = 0; + + while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) + udelay(10); + outw(o << 1, MMCR(ioaddr)); + + while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) + udelay(10); + return (u8) (inw(MMCR(ioaddr)) >> 8); +} + +/*------------------------------------------------------------------*/ +/* + * Routine to read bytes from the Modem Management Controller. + * The implementation is complicated by a lack of address lines, + * which prevents decoding of the low-order bit. + * (code has just been moved in the above function) + * We start at the end because it is the way it should be! + */ +static inline void mmc_read(unsigned long ioaddr, u8 o, u8 * b, int n) +{ + o += n; + b += n; + + while (n-- > 0) + *(--b) = mmc_in(ioaddr, --o); +} /* mmc_read */ + +/*------------------------------------------------------------------*/ +/* + * Get the type of encryption available. + */ +static inline int mmc_encr(unsigned long ioaddr) +{ /* I/O port of the card */ + int temp; + + temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail)); + if ((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) + return 0; + else + return temp; +} + +/*------------------------------------------------------------------*/ +/* + * Wait for the frequency EEPROM to complete a command. + * I hope this one will be optimally inlined. + */ +static inline void fee_wait(unsigned long ioaddr, /* I/O port of the card */ + int delay, /* Base delay to wait for */ + int number) +{ /* Number of time to wait */ + int count = 0; /* Wait only a limited time */ + + while ((count++ < number) && + (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + MMR_FEE_STATUS_BUSY)) udelay(delay); +} + +/*------------------------------------------------------------------*/ +/* + * Read bytes from the Frequency EEPROM (frequency select cards). + */ +static void fee_read(unsigned long ioaddr, /* I/O port of the card */ + u16 o, /* destination offset */ + u16 * b, /* data buffer */ + int n) +{ /* number of registers */ + b += n; /* Position at the end of the area */ + + /* Write the address */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while (n-- > 0) { + /* Write the read command */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ); + + /* Wait until EEPROM is ready (should be quick). */ + fee_wait(ioaddr, 10, 100); + + /* Read the value. */ + *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) | + mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); + } +} + + +/*------------------------------------------------------------------*/ +/* + * Write bytes from the Frequency EEPROM (frequency select cards). + * This is a bit complicated, because the frequency EEPROM has to + * be unprotected and the write enabled. + * Jean II + */ +static void fee_write(unsigned long ioaddr, /* I/O port of the card */ + u16 o, /* destination offset */ + u16 * b, /* data buffer */ + int n) +{ /* number of registers */ + b += n; /* Position at the end of the area. */ + +#ifdef EEPROM_IS_PROTECTED /* disabled */ +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* Ask to read the protected register */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); + + fee_wait(ioaddr, 10, 100); + + /* Read the protected register. */ + printk("Protected 2: %02X-%02X\n", + mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)), + mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); +#endif /* DOESNT_SEEM_TO_WORK */ + + /* Enable protected register. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); + + fee_wait(ioaddr, 10, 100); + + /* Unprotect area. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* or use: */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); +#endif /* DOESNT_SEEM_TO_WORK */ + + fee_wait(ioaddr, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ + + /* Write enable. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); + + fee_wait(ioaddr, 10, 100); + + /* Write the EEPROM address. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while (n-- > 0) { + /* Write the value. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); + mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF); + + /* Write the write command. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_WRITE); + + /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */ + mdelay(10); + fee_wait(ioaddr, 10, 100); + } + + /* Write disable. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); + + fee_wait(ioaddr, 10, 100); + +#ifdef EEPROM_IS_PROTECTED /* disabled */ + /* Reprotect EEPROM. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); + + fee_wait(ioaddr, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ +} + +/************************ I82586 SUBROUTINES *************************/ +/* + * Useful subroutines to manage the Ethernet controller + */ + +/*------------------------------------------------------------------*/ +/* + * Read bytes from the on-board RAM. + * Why does inlining this function make it fail? + */ +static /*inline */ void obram_read(unsigned long ioaddr, + u16 o, u8 * b, int n) +{ + outw(o, PIOR1(ioaddr)); + insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); +} + +/*------------------------------------------------------------------*/ +/* + * Write bytes to the on-board RAM. + */ +static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n) +{ + outw(o, PIOR1(ioaddr)); + outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); +} + +/*------------------------------------------------------------------*/ +/* + * Acknowledge the reading of the status issued by the i82586. + */ +static void wv_ack(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + u16 scb_cs; + int i; + + obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + scb_cs &= SCB_ST_INT; + + if (scb_cs == 0) + return; + + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if (scb_cs == 0) + break; + + udelay(10); + } + udelay(100); + +#ifdef DEBUG_CONFIG_ERROR + if (i <= 0) + printk(KERN_INFO + "%s: wv_ack(): board not accepting command.\n", + dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * Set channel attention bit and busy wait until command has + * completed, then acknowledge completion of the command. + */ +static int wv_synchronous_cmd(struct net_device * dev, const char *str) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + u16 scb_cmd; + ach_t cb; + int i; + + scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cmd, sizeof(scb_cmd)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, + sizeof(cb)); + if (cb.ac_status & AC_SFLD_C) + break; + + udelay(10); + } + udelay(100); + + if (i <= 0 || !(cb.ac_status & AC_SFLD_OK)) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "%s: %s failed; status = 0x%x\n", + dev->name, str, cb.ac_status); +#endif +#ifdef DEBUG_I82586_SHOW + wv_scb_show(ioaddr); +#endif + return -1; + } + + /* Ack the status */ + wv_ack(dev); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Configuration commands completion interrupt. + * Check if done, and if OK. + */ +static int +wv_config_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) +{ + unsigned short mcs_addr; + unsigned short status; + int ret; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name); +#endif + + mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t) + + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t); + + /* Read the status of the last command (set mc list). */ + obram_read(ioaddr, acoff(mcs_addr, ac_status), + (unsigned char *) &status, sizeof(status)); + + /* If not completed -> exit */ + if ((status & AC_SFLD_C) == 0) + ret = 0; /* Not ready to be scrapped */ + else { +#ifdef DEBUG_CONFIG_ERROR + unsigned short cfg_addr; + unsigned short ias_addr; + + /* Check mc_config command */ + if ((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO + "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n", + dev->name, status); + + /* check ia-config command */ + ias_addr = mcs_addr - sizeof(ac_ias_t); + obram_read(ioaddr, acoff(ias_addr, ac_status), + (unsigned char *) &status, sizeof(status)); + if ((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO + "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n", + dev->name, status); + + /* Check config command. */ + cfg_addr = ias_addr - sizeof(ac_cfg_t); + obram_read(ioaddr, acoff(cfg_addr, ac_status), + (unsigned char *) &status, sizeof(status)); + if ((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO + "%s: wv_config_complete(): configure failed; status = 0x%x\n", + dev->name, status); +#endif /* DEBUG_CONFIG_ERROR */ + + ret = 1; /* Ready to be scrapped */ + } + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, + ret); +#endif + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Command completion interrupt. + * Reclaim as many freed tx buffers as we can. + * (called in wavelan_interrupt()). + * Note : the spinlock is already grabbed for us. + */ +static int wv_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp) +{ + int nreaped = 0; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name); +#endif + + /* Loop on all the transmit buffers */ + while (lp->tx_first_in_use != I82586NULL) { + unsigned short tx_status; + + /* Read the first transmit buffer */ + obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), + (unsigned char *) &tx_status, + sizeof(tx_status)); + + /* If not completed -> exit */ + if ((tx_status & AC_SFLD_C) == 0) + break; + + /* Hack for reconfiguration */ + if (tx_status == 0xFFFF) + if (!wv_config_complete(dev, ioaddr, lp)) + break; /* Not completed */ + + /* We now remove this buffer */ + nreaped++; + --lp->tx_n_in_use; + +/* +if (lp->tx_n_in_use > 0) + printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]); +*/ + + /* Was it the last one? */ + if (lp->tx_n_in_use <= 0) + lp->tx_first_in_use = I82586NULL; + else { + /* Next one in the chain */ + lp->tx_first_in_use += TXBLOCKZ; + if (lp->tx_first_in_use >= + OFFSET_CU + + NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -= + NTXBLOCKS * TXBLOCKZ; + } + + /* Hack for reconfiguration */ + if (tx_status == 0xFFFF) + continue; + + /* Now, check status of the finished command */ + if (tx_status & AC_SFLD_OK) { + int ncollisions; + + dev->stats.tx_packets++; + ncollisions = tx_status & AC_SFLD_MAXCOL; + dev->stats.collisions += ncollisions; +#ifdef DEBUG_TX_INFO + if (ncollisions > 0) + printk(KERN_DEBUG + "%s: wv_complete(): tx completed after %d collisions.\n", + dev->name, ncollisions); +#endif + } else { + dev->stats.tx_errors++; + if (tx_status & AC_SFLD_S10) { + dev->stats.tx_carrier_errors++; +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG + "%s: wv_complete(): tx error: no CS.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S9) { + dev->stats.tx_carrier_errors++; +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG + "%s: wv_complete(): tx error: lost CTS.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S8) { + dev->stats.tx_fifo_errors++; +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG + "%s: wv_complete(): tx error: slow DMA.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S6) { + dev->stats.tx_heartbeat_errors++; +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG + "%s: wv_complete(): tx error: heart beat.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S5) { + dev->stats.tx_aborted_errors++; +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG + "%s: wv_complete(): tx error: too many collisions.\n", + dev->name); +#endif + } + } + +#ifdef DEBUG_TX_INFO + printk(KERN_DEBUG + "%s: wv_complete(): tx completed, tx_status 0x%04x\n", + dev->name, tx_status); +#endif + } + +#ifdef DEBUG_INTERRUPT_INFO + if (nreaped > 1) + printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", + dev->name, nreaped); +#endif + + /* + * Inform upper layers. + */ + if (lp->tx_n_in_use < NTXBLOCKS - 1) { + netif_wake_queue(dev); + } +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name); +#endif + return nreaped; +} + +/*------------------------------------------------------------------*/ +/* + * Reconfigure the i82586, or at least ask for it. + * Because wv_82586_config uses a transmission buffer, we must do it + * when we are sure that there is one left, so we do it now + * or in wavelan_packet_xmit() (I can't find any better place, + * wavelan_interrupt is not an option), so you may experience + * delays sometimes. + */ +static void wv_82586_reconfig(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long flags; + + /* Arm the flag, will be cleard in wv_82586_config() */ + lp->reconfig_82586 = 1; + + /* Check if we can do it now ! */ + if((netif_running(dev)) && !(netif_queue_stopped(dev))) { + spin_lock_irqsave(&lp->spinlock, flags); + /* May fail */ + wv_82586_config(dev); + spin_unlock_irqrestore(&lp->spinlock, flags); + } + else { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG + "%s: wv_82586_reconfig(): delayed (state = %lX)\n", + dev->name, dev->state); +#endif + } +} + +/********************* DEBUG & INFO SUBROUTINES *********************/ +/* + * This routine is used in the code to show information for debugging. + * Most of the time, it dumps the contents of hardware structures. + */ + +#ifdef DEBUG_PSA_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted contents of the Parameter Storage Area. + */ +static void wv_psa_show(psa_t * p) +{ + printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); + printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", + p->psa_io_base_addr_1, + p->psa_io_base_addr_2, + p->psa_io_base_addr_3, p->psa_io_base_addr_4); + printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", + p->psa_rem_boot_addr_1, + p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3); + printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); + printk("psa_int_req_no: %d\n", p->psa_int_req_no); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); + printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); + printk(KERN_DEBUG "psa_univ_local_sel: %d, ", + p->psa_univ_local_sel); + printk("psa_comp_number: %d, ", p->psa_comp_number); + printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); + printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", + p->psa_feature_select); + printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); + printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); + printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); + printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], + p->psa_nwid[1]); + printk("psa_nwid_select: %d\n", p->psa_nwid_select); + printk(KERN_DEBUG "psa_encryption_select: %d, ", + p->psa_encryption_select); + printk + ("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_encryption_key[0], p->psa_encryption_key[1], + p->psa_encryption_key[2], p->psa_encryption_key[3], + p->psa_encryption_key[4], p->psa_encryption_key[5], + p->psa_encryption_key[6], p->psa_encryption_key[7]); + printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); + printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", + p->psa_call_code[0]); + printk + ("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_call_code[0], p->psa_call_code[1], p->psa_call_code[2], + p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5], + p->psa_call_code[6], p->psa_call_code[7]); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "psa_reserved[]: %02X:%02X\n", + p->psa_reserved[0], + p->psa_reserved[1]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); + printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); + printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); +} /* wv_psa_show */ +#endif /* DEBUG_PSA_SHOW */ + +#ifdef DEBUG_MMC_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the Modem Management Controller. + * This function needs to be completed. + */ +static void wv_mmc_show(struct net_device * dev) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); + mmr_t m; + + /* Basic check */ + if (hasr_read(ioaddr) & HASR_NO_CLK) { + printk(KERN_WARNING + "%s: wv_mmc_show: modem not connected\n", + dev->name); + return; + } + + /* Read the mmc */ + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); + mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m)); + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); + + /* Don't forget to update statistics */ + lp->wstats.discard.nwid += + (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; + + printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG + "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused0[0], m.mmr_unused0[1], m.mmr_unused0[2], + m.mmr_unused0[3], m.mmr_unused0[4], m.mmr_unused0[5], + m.mmr_unused0[6], m.mmr_unused0[7]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n", + m.mmr_des_avail, m.mmr_des_status); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused1[0], + m.mmr_unused1[1], + m.mmr_unused1[2], m.mmr_unused1[3], m.mmr_unused1[4]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", + m.mmr_dce_status, + (m. + mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? + "energy detected," : "", + (m. + mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? + "loop test indicated," : "", + (m. + mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? + "transmitter on," : "", + (m. + mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? + "jabber timer expired," : ""); + printk(KERN_DEBUG "Dsp ID: %02X\n", m.mmr_dsp_id); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", + m.mmr_unused2[0], m.mmr_unused2[1]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", + (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, + (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); + printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", + m.mmr_thr_pre_set & MMR_THR_PRE_SET, + (m. + mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : + "below"); + printk(KERN_DEBUG "signal_lvl: %d [%s], ", + m.mmr_signal_lvl & MMR_SIGNAL_LVL, + (m. + mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : + "no new msg"); + printk("silence_lvl: %d [%s], ", + m.mmr_silence_lvl & MMR_SILENCE_LVL, + (m. + mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : + "no new update"); + printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, + (m. + mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : + "Antenna 0"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); +#endif /* DEBUG_SHOW_UNUSED */ +} /* wv_mmc_show */ +#endif /* DEBUG_MMC_SHOW */ + +#ifdef DEBUG_I82586_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the last block of the i82586 memory. + */ +static void wv_scb_show(unsigned long ioaddr) +{ + scb_t scb; + + obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, + sizeof(scb)); + + printk(KERN_DEBUG "##### WaveLAN system control block: #####\n"); + + printk(KERN_DEBUG "status: "); + printk("stat 0x%x[%s%s%s%s] ", + (scb. + scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | + SCB_ST_RNR)) >> 12, + (scb. + scb_status & SCB_ST_CX) ? "command completion interrupt," : + "", (scb.scb_status & SCB_ST_FR) ? "frame received," : "", + (scb. + scb_status & SCB_ST_CNA) ? "command unit not active," : "", + (scb. + scb_status & SCB_ST_RNR) ? "receiving unit not ready," : + ""); + printk("cus 0x%x[%s%s%s] ", (scb.scb_status & SCB_ST_CUS) >> 8, + ((scb.scb_status & SCB_ST_CUS) == + SCB_ST_CUS_IDLE) ? "idle" : "", + ((scb.scb_status & SCB_ST_CUS) == + SCB_ST_CUS_SUSP) ? "suspended" : "", + ((scb.scb_status & SCB_ST_CUS) == + SCB_ST_CUS_ACTV) ? "active" : ""); + printk("rus 0x%x[%s%s%s%s]\n", (scb.scb_status & SCB_ST_RUS) >> 4, + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_IDLE) ? "idle" : "", + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_SUSP) ? "suspended" : "", + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_NRES) ? "no resources" : "", + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_RDY) ? "ready" : ""); + + printk(KERN_DEBUG "command: "); + printk("ack 0x%x[%s%s%s%s] ", + (scb. + scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR | + SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12, + (scb. + scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "", + (scb. + scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "", + (scb. + scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "", + (scb. + scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : ""); + printk("cuc 0x%x[%s%s%s%s%s] ", + (scb.scb_command & SCB_CMD_CUC) >> 8, + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_NOP) ? "nop" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_GO) ? "start cbl_offset" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_RES) ? "resume execution" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_SUS) ? "suspend execution" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_ABT) ? "abort execution" : ""); + printk("ruc 0x%x[%s%s%s%s%s]\n", + (scb.scb_command & SCB_CMD_RUC) >> 4, + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_NOP) ? "nop" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_GO) ? "start rfa_offset" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_RES) ? "resume reception" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_SUS) ? "suspend reception" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_ABT) ? "abort reception" : ""); + + printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset); + printk("rfa_offset 0x%x\n", scb.scb_rfa_offset); + + printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs); + printk("alnerrs %d ", scb.scb_alnerrs); + printk("rscerrs %d ", scb.scb_rscerrs); + printk("ovrnerrs %d\n", scb.scb_ovrnerrs); +} + +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the i82586's receive unit. + */ +static void wv_ru_show(struct net_device * dev) +{ + printk(KERN_DEBUG + "##### WaveLAN i82586 receiver unit status: #####\n"); + printk(KERN_DEBUG "ru:"); + /* + * Not implemented yet + */ + printk("\n"); +} /* wv_ru_show */ + +/*------------------------------------------------------------------*/ +/* + * Display info about one control block of the i82586 memory. + */ +static void wv_cu_show_one(struct net_device * dev, net_local * lp, int i, u16 p) +{ + unsigned long ioaddr; + ac_tx_t actx; + + ioaddr = dev->base_addr; + + printk("%d: 0x%x:", i, p); + + obram_read(ioaddr, p, (unsigned char *) &actx, sizeof(actx)); + printk(" status=0x%x,", actx.tx_h.ac_status); + printk(" command=0x%x,", actx.tx_h.ac_command); + + /* + { + tbd_t tbd; + + obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd)); + printk(" tbd_status=0x%x,", tbd.tbd_status); + } + */ + + printk("|"); +} + +/*------------------------------------------------------------------*/ +/* + * Print status of the command unit of the i82586. + */ +static void wv_cu_show(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned int i; + u16 p; + + printk(KERN_DEBUG + "##### WaveLAN i82586 command unit status: #####\n"); + + printk(KERN_DEBUG); + for (i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) { + wv_cu_show_one(dev, lp, i, p); + + p += TXBLOCKZ; + if (p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) + p -= NTXBLOCKS * TXBLOCKZ; + } + printk("\n"); +} +#endif /* DEBUG_I82586_SHOW */ + +#ifdef DEBUG_DEVICE_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver. + */ +static void wv_dev_show(struct net_device * dev) +{ + printk(KERN_DEBUG "dev:"); + printk(" state=%lX,", dev->state); + printk(" trans_start=%ld,", dev->trans_start); + printk(" flags=0x%x,", dev->flags); + printk("\n"); +} /* wv_dev_show */ + +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver's + * private information. + */ +static void wv_local_show(struct net_device * dev) +{ + net_local *lp; + + lp = netdev_priv(dev); + + printk(KERN_DEBUG "local:"); + printk(" tx_n_in_use=%d,", lp->tx_n_in_use); + printk(" hacr=0x%x,", lp->hacr); + printk(" rx_head=0x%x,", lp->rx_head); + printk(" rx_last=0x%x,", lp->rx_last); + printk(" tx_first_free=0x%x,", lp->tx_first_free); + printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use); + printk("\n"); +} /* wv_local_show */ +#endif /* DEBUG_DEVICE_SHOW */ + +#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) +/*------------------------------------------------------------------*/ +/* + * Dump packet header (and content if necessary) on the screen + */ +static inline void wv_packet_info(u8 * p, /* Packet to dump */ + int length, /* Length of the packet */ + char *msg1, /* Name of the device */ + char *msg2) +{ /* Name of the function */ + int i; + int maxi; + + printk(KERN_DEBUG + "%s: %s(): dest %pM, length %d\n", + msg1, msg2, p, length); + printk(KERN_DEBUG + "%s: %s(): src %pM, type 0x%02X%02X\n", + msg1, msg2, &p[6], p[12], p[13]); + +#ifdef DEBUG_PACKET_DUMP + + printk(KERN_DEBUG "data=\""); + + if ((maxi = length) > DEBUG_PACKET_DUMP) + maxi = DEBUG_PACKET_DUMP; + for (i = 14; i < maxi; i++) + if (p[i] >= ' ' && p[i] <= '~') + printk(" %c", p[i]); + else + printk("%02X", p[i]); + if (maxi < length) + printk(".."); + printk("\"\n"); + printk(KERN_DEBUG "\n"); +#endif /* DEBUG_PACKET_DUMP */ +} +#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ + +/*------------------------------------------------------------------*/ +/* + * This is the information which is displayed by the driver at startup. + * There are lots of flags for configuring it to your liking. + */ +static void wv_init_info(struct net_device * dev) +{ + short ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); + psa_t psa; + + /* Read the parameter storage area */ + psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); + +#ifdef DEBUG_PSA_SHOW + wv_psa_show(&psa); +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82586_SHOW + wv_cu_show(dev); +#endif + +#ifdef DEBUG_BASIC_SHOW + /* Now, let's go for the basic stuff. */ + printk(KERN_NOTICE "%s: WaveLAN at %#x, %pM, IRQ %d", + dev->name, ioaddr, dev->dev_addr, dev->irq); + + /* Print current network ID. */ + if (psa.psa_nwid_select) + printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], + psa.psa_nwid[1]); + else + printk(", nwid off"); + + /* If 2.00 card */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(ioaddr, 0x00, &freq, 1); + + /* Print frequency */ + printk(", 2.00, %ld", (freq >> 6) + 2400L); + + /* Hack! */ + if (freq & 0x20) + printk(".5"); + } else { + printk(", PC"); + switch (psa.psa_comp_number) { + case PSA_COMP_PC_AT_915: + case PSA_COMP_PC_AT_2400: + printk("-AT"); + break; + case PSA_COMP_PC_MC_915: + case PSA_COMP_PC_MC_2400: + printk("-MC"); + break; + case PSA_COMP_PCMCIA_915: + printk("MCIA"); + break; + default: + printk("?"); + } + printk(", "); + switch (psa.psa_subband) { + case PSA_SUBBAND_915: + printk("915"); + break; + case PSA_SUBBAND_2425: + printk("2425"); + break; + case PSA_SUBBAND_2460: + printk("2460"); + break; + case PSA_SUBBAND_2484: + printk("2484"); + break; + case PSA_SUBBAND_2430_5: + printk("2430.5"); + break; + default: + printk("?"); + } + } + + printk(" MHz\n"); +#endif /* DEBUG_BASIC_SHOW */ + +#ifdef DEBUG_VERSION_SHOW + /* Print version information */ + printk(KERN_NOTICE "%s", version); +#endif +} /* wv_init_info */ + +/********************* IOCTL, STATS & RECONFIG *********************/ +/* + * We found here routines that are called by Linux on different + * occasions after the configuration and not for transmitting data + * These may be called when the user use ifconfig, /proc/net/dev + * or wireless extensions + */ + + +/*------------------------------------------------------------------*/ +/* + * Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. + */ +static void wavelan_set_multicast_list(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", + dev->name); +#endif + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG + "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", + dev->name, dev->flags, dev->mc_count); +#endif + + /* Are we asking for promiscuous mode, + * or all multicast addresses (we don't have that!) + * or too many multicast addresses for the hardware filter? */ + if ((dev->flags & IFF_PROMISC) || + (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) { + /* + * Enable promiscuous mode: receive all packets. + */ + if (!lp->promiscuous) { + lp->promiscuous = 1; + lp->mc_count = 0; + + wv_82586_reconfig(dev); + } + } else + /* Are there multicast addresses to send? */ + if (dev->mc_list != (struct dev_mc_list *) NULL) { + /* + * Disable promiscuous mode, but receive all packets + * in multicast list + */ +#ifdef MULTICAST_AVOID + if (lp->promiscuous || (dev->mc_count != lp->mc_count)) +#endif + { + lp->promiscuous = 0; + lp->mc_count = dev->mc_count; + + wv_82586_reconfig(dev); + } + } else { + /* + * Switch to normal mode: disable promiscuous mode and + * clear the multicast list. + */ + if (lp->promiscuous || lp->mc_count == 0) { + lp->promiscuous = 0; + lp->mc_count = 0; + + wv_82586_reconfig(dev); + } + } +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", + dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This function doesn't exist. + * (Note : it was a nice way to test the reconfigure stuff...) + */ +#ifdef SET_MAC_ADDRESS +static int wavelan_set_mac_address(struct net_device * dev, void *addr) +{ + struct sockaddr *mac = addr; + + /* Copy the address. */ + memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); + + /* Reconfigure the beast. */ + wv_82586_reconfig(dev); + + return 0; +} +#endif /* SET_MAC_ADDRESS */ + + +/*------------------------------------------------------------------*/ +/* + * Frequency setting (for hardware capable of it) + * It's a bit complicated and you don't really want to look into it. + * (called in wavelan_ioctl) + */ +static int wv_set_frequency(unsigned long ioaddr, /* I/O port of the card */ + iw_freq * frequency) +{ + const int BAND_NUM = 10; /* Number of bands */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ +#ifdef DEBUG_IOCTL_INFO + int i; +#endif + + /* Setting by frequency */ + /* Theoretically, you may set any frequency between + * the two limits with a 0.5 MHz precision. In practice, + * I don't want you to have trouble with local regulations. + */ + if ((frequency->e == 1) && + (frequency->m >= (int) 2.412e8) + && (frequency->m <= (int) 2.487e8)) { + freq = ((frequency->m / 10000) - 24000L) / 5; + } + + /* Setting by channel (same as wfreqsel) */ + /* Warning: each channel is 22 MHz wide, so some of the channels + * will interfere. */ + if ((frequency->e == 0) && (frequency->m < BAND_NUM)) { + /* Get frequency offset. */ + freq = channel_bands[frequency->m] >> 1; + } + + /* Verify that the frequency is allowed. */ + if (freq != 0L) { + u16 table[10]; /* Authorized frequency table */ + + /* Read the frequency table. */ + fee_read(ioaddr, 0x71, table, 10); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Frequency table: "); + for (i = 0; i < 10; i++) { + printk(" %04X", table[i]); + } + printk("\n"); +#endif + + /* Look in the table to see whether the frequency is allowed. */ + if (!(table[9 - ((freq - 24) / 16)] & + (1 << ((freq - 24) % 16)))) return -EINVAL; /* not allowed */ + } else + return -EINVAL; + + /* if we get a usable frequency */ + if (freq != 0L) { + unsigned short area[16]; + unsigned short dac[2]; + unsigned short area_verify[16]; + unsigned short dac_verify[2]; + /* Corresponding gain (in the power adjust value table) + * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8 + * and WCIN062D.DOC, page 6.2.9. */ + unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; + int power_band = 0; /* Selected band */ + unsigned short power_adjust; /* Correct value */ + + /* Search for the gain. */ + power_band = 0; + while ((freq > power_limit[power_band]) && + (power_limit[++power_band] != 0)); + + /* Read the first area. */ + fee_read(ioaddr, 0x00, area, 16); + + /* Read the DAC. */ + fee_read(ioaddr, 0x60, dac, 2); + + /* Read the new power adjust value. */ + fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, + 1); + if (power_band & 0x1) + power_adjust >>= 8; + else + power_adjust &= 0xFF; + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); + for (i = 0; i < 16; i++) { + printk(" %04X", area[i]); + } + printk("\n"); + + printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", + dac[0], dac[1]); +#endif + + /* Frequency offset (for info only) */ + area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); + + /* Receiver Principle main divider coefficient */ + area[3] = (freq >> 1) + 2400L - 352L; + area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Transmitter Main divider coefficient */ + area[13] = (freq >> 1) + 2400L; + area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Other parts of the area are flags, bit streams or unused. */ + + /* Set the value in the DAC. */ + dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); + dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); + + /* Write the first area. */ + fee_write(ioaddr, 0x00, area, 16); + + /* Write the DAC. */ + fee_write(ioaddr, 0x60, dac, 2); + + /* We now should verify here that the writing of the EEPROM went OK. */ + + /* Reread the first area. */ + fee_read(ioaddr, 0x00, area_verify, 16); + + /* Reread the DAC. */ + fee_read(ioaddr, 0x60, dac_verify, 2); + + /* Compare. */ + if (memcmp(area, area_verify, 16 * 2) || + memcmp(dac, dac_verify, 2 * 2)) { +#ifdef DEBUG_IOCTL_ERROR + printk(KERN_INFO + "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n"); +#endif + return -EOPNOTSUPP; + } + + /* We must download the frequency parameters to the + * synthesizers (from the EEPROM - area 1) + * Note: as the EEPROM is automatically decremented, we set the end + * if the area... */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait until the download is finished. */ + fee_wait(ioaddr, 100, 100); + + /* We must now download the power adjust value (gain) to + * the synthesizers (from the EEPROM - area 7 - DAC). */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait for the download to finish. */ + fee_wait(ioaddr, 100, 100); + +#ifdef DEBUG_IOCTL_INFO + /* Verification of what we have done */ + + printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); + for (i = 0; i < 16; i++) { + printk(" %04X", area_verify[i]); + } + printk("\n"); + + printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", + dac_verify[0], dac_verify[1]); +#endif + + return 0; + } else + return -EINVAL; /* Bah, never get there... */ +} + +/*------------------------------------------------------------------*/ +/* + * Give the list of available frequencies. + */ +static int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */ + iw_freq * list, /* List of frequencies to fill */ + int max) +{ /* Maximum number of frequencies */ + u16 table[10]; /* Authorized frequency table */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ + int i; /* index in the table */ + int c = 0; /* Channel number */ + + /* Read the frequency table. */ + fee_read(ioaddr, 0x71 /* frequency table */ , table, 10); + + /* Check all frequencies. */ + i = 0; + for (freq = 0; freq < 150; freq++) + /* Look in the table if the frequency is allowed */ + if (table[9 - (freq / 16)] & (1 << (freq % 16))) { + /* Compute approximate channel number */ + while ((c < ARRAY_SIZE(channel_bands)) && + (((channel_bands[c] >> 1) - 24) < freq)) + c++; + list[i].i = c; /* Set the list index */ + + /* put in the list */ + list[i].m = (((freq + 24) * 5) + 24000L) * 10000; + list[i++].e = 1; + + /* Check number. */ + if (i >= max) + return (i); + } + + return (i); +} + +#ifdef IW_WIRELESS_SPY +/*------------------------------------------------------------------*/ +/* + * Gather wireless spy statistics: for each packet, compare the source + * address with our list, and if they match, get the statistics. + * Sorry, but this function really needs the wireless extensions. + */ +static inline void wl_spy_gather(struct net_device * dev, + u8 * mac, /* MAC address */ + u8 * stats) /* Statistics to gather */ +{ + struct iw_quality wstats; + + wstats.qual = stats[2] & MMR_SGNL_QUAL; + wstats.level = stats[0] & MMR_SIGNAL_LVL; + wstats.noise = stats[1] & MMR_SILENCE_LVL; + wstats.updated = 0x7; + + /* Update spy records */ + wireless_spy_update(dev, mac, &wstats); +} +#endif /* IW_WIRELESS_SPY */ + +#ifdef HISTOGRAM +/*------------------------------------------------------------------*/ +/* + * This function calculates a histogram of the signal level. + * As the noise is quite constant, it's like doing it on the SNR. + * We have defined a set of interval (lp->his_range), and each time + * the level goes in that interval, we increment the count (lp->his_sum). + * With this histogram you may detect if one WaveLAN is really weak, + * or you may also calculate the mean and standard deviation of the level. + */ +static inline void wl_his_gather(struct net_device * dev, u8 * stats) +{ /* Statistics to gather */ + net_local *lp = netdev_priv(dev); + u8 level = stats[0] & MMR_SIGNAL_LVL; + int i; + + /* Find the correct interval. */ + i = 0; + while ((i < (lp->his_number - 1)) + && (level >= lp->his_range[i++])); + + /* Increment interval counter. */ + (lp->his_sum[i])++; +} +#endif /* HISTOGRAM */ + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get protocol name + */ +static int wavelan_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + strcpy(wrqu->name, "WaveLAN"); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set NWID + */ +static int wavelan_set_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); /* lp is not unused */ + psa_t psa; + mm_t m; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set NWID in WaveLAN. */ + if (!wrqu->nwid.disabled) { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; + psa.psa_nwid_select = 0x01; + psa_write(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + + /* Set NWID in mmc. */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(ioaddr, + (char *) &m.w.mmw_netw_id_l - + (char *) &m, + (unsigned char *) &m.w.mmw_netw_id_l, 2); + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); + } else { + /* Disable NWID in the psa. */ + psa.psa_nwid_select = 0x00; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_nwid_select - + (char *) &psa, + (unsigned char *) &psa.psa_nwid_select, + 1); + + /* Disable NWID in the mmc (no filtering). */ + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), + MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get NWID + */ +static int wavelan_get_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Read the NWID. */ + psa_read(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrqu->nwid.disabled = !(psa.psa_nwid_select); + wrqu->nwid.fixed = 1; /* Superfluous */ + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set frequency + */ +static int wavelan_set_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); /* lp is not unused */ + unsigned long flags; + int ret; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(ioaddr, &(wrqu->freq)); + else + ret = -EOPNOTSUPP; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get frequency + */ +static int wavelan_get_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). + * Does it work for everybody, especially old cards? */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(ioaddr, 0x00, &freq, 1); + wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrqu->freq.e = 1; + } else { + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_subband - (char *) &psa, + (unsigned char *) &psa.psa_subband, 1); + + if (psa.psa_subband <= 4) { + wrqu->freq.m = fixed_bands[psa.psa_subband]; + wrqu->freq.e = (psa.psa_subband != 0); + } else + ret = -EOPNOTSUPP; + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set level threshold + */ +static int wavelan_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set the level threshold. */ + /* We should complain loudly if wrqu->sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), + psa.psa_thr_pre_set); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get level threshold + */ +static int wavelan_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Read the level threshold. */ + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; + wrqu->sens.fixed = 1; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set encryption key + */ +static int wavelan_set_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); /* lp is not unused */ + unsigned long flags; + psa_t psa; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if capable of encryption */ + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + } + + /* Check the size of the key */ + if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { + ret = -EINVAL; + } + + if(!ret) { + /* Basic checking... */ + if (wrqu->encoding.length == 8) { + /* Copy the key in the driver */ + memcpy(psa.psa_encryption_key, extra, + wrqu->encoding.length); + psa.psa_encryption_select = 1; + + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 8 + 1); + + mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); + mmc_write(ioaddr, mmwoff(0, mmw_encr_key), + (unsigned char *) &psa. + psa_encryption_key, 8); + } + + /* disable encryption */ + if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { + psa.psa_encryption_select = 0; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1); + + mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get encryption key + */ +static int wavelan_get_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); /* lp is not unused */ + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if encryption is available */ + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + } else { + /* Read the encryption key */ + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1 + 8); + + /* encryption is enabled ? */ + if (psa.psa_encryption_select) + wrqu->encoding.flags = IW_ENCODE_ENABLED; + else + wrqu->encoding.flags = IW_ENCODE_DISABLED; + wrqu->encoding.flags |= mmc_encr(ioaddr); + + /* Copy the key to the user buffer */ + wrqu->encoding.length = 8; + memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get range info + */ +static int wavelan_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); /* lp is not unused */ + struct iw_range *range = (struct iw_range *) extra; + unsigned long flags; + int ret = 0; + + /* Set the length (very important for backward compatibility) */ + wrqu->data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know about to zero */ + memset(range, 0, sizeof(struct iw_range)); + + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 9; + + /* Set information in the range struct. */ + range->throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ + range->min_nwid = 0x0000; + range->max_nwid = 0xFFFF; + + range->sensitivity = 0x3F; + range->max_qual.qual = MMR_SGNL_QUAL; + range->max_qual.level = MMR_SIGNAL_LVL; + range->max_qual.noise = MMR_SILENCE_LVL; + range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ + /* Need to get better values for those two */ + range->avg_qual.level = 30; + range->avg_qual.noise = 8; + + range->num_bitrates = 1; + range->bitrate[0] = 2000000; /* 2 Mb/s */ + + /* Event capability (kernel + driver) */ + range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) | + IW_EVENT_CAPA_MASK(0x8B04)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + range->num_channels = 10; + range->num_frequency = wv_frequency_list(ioaddr, range->freq, + IW_MAX_FREQUENCIES); + } else + range->num_channels = range->num_frequency = 0; + + /* Encryption supported ? */ + if (mmc_encr(ioaddr)) { + range->encoding_size[0] = 8; /* DES = 64 bits key */ + range->num_encoding_sizes = 1; + range->max_encoding_tokens = 1; /* Only one key possible */ + } else { + range->num_encoding_sizes = 0; + range->max_encoding_tokens = 0; + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set quality threshold + */ +static int wavelan_set_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); /* lp is not unused */ + psa_t psa; + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa.psa_quality_thr = *(extra) & 0x0F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), + psa.psa_quality_thr); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get quality threshold + */ +static int wavelan_get_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); /* lp is not unused */ + psa_t psa; + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + *(extra) = psa.psa_quality_thr & 0x0F; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} + +#ifdef HISTOGRAM +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set histogram + */ +static int wavelan_set_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = netdev_priv(dev); /* lp is not unused */ + + /* Check the number of intervals. */ + if (wrqu->data.length > 16) { + return(-E2BIG); + } + + /* Disable histo while we copy the addresses. + * As we don't disable interrupts, we need to do this */ + lp->his_number = 0; + + /* Are there ranges to copy? */ + if (wrqu->data.length > 0) { + /* Copy interval ranges to the driver */ + memcpy(lp->his_range, extra, wrqu->data.length); + + { + int i; + printk(KERN_DEBUG "Histo :"); + for(i = 0; i < wrqu->data.length; i++) + printk(" %d", lp->his_range[i]); + printk("\n"); + } + + /* Reset result structure. */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); + } + + /* Now we can set the number of ranges */ + lp->his_number = wrqu->data.length; + + return(0); +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get histogram + */ +static int wavelan_get_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = netdev_priv(dev); /* lp is not unused */ + + /* Set the number of intervals. */ + wrqu->data.length = lp->his_number; + + /* Give back the distribution statistics */ + if(lp->his_number > 0) + memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); + + return(0); +} +#endif /* HISTOGRAM */ + +/*------------------------------------------------------------------*/ +/* + * Structures to export the Wireless Handlers + */ + +static const iw_handler wavelan_handler[] = +{ + NULL, /* SIOCSIWNAME */ + wavelan_get_name, /* SIOCGIWNAME */ + wavelan_set_nwid, /* SIOCSIWNWID */ + wavelan_get_nwid, /* SIOCGIWNWID */ + wavelan_set_freq, /* SIOCSIWFREQ */ + wavelan_get_freq, /* SIOCGIWFREQ */ + NULL, /* SIOCSIWMODE */ + NULL, /* SIOCGIWMODE */ + wavelan_set_sens, /* SIOCSIWSENS */ + wavelan_get_sens, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + wavelan_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ + NULL, /* SIOCSIWAP */ + NULL, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWESSID */ + NULL, /* SIOCGIWESSID */ + NULL, /* SIOCSIWNICKN */ + NULL, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWRATE */ + NULL, /* SIOCGIWRATE */ + NULL, /* SIOCSIWRTS */ + NULL, /* SIOCGIWRTS */ + NULL, /* SIOCSIWFRAG */ + NULL, /* SIOCGIWFRAG */ + NULL, /* SIOCSIWTXPOW */ + NULL, /* SIOCGIWTXPOW */ + NULL, /* SIOCSIWRETRY */ + NULL, /* SIOCGIWRETRY */ + /* Bummer ! Why those are only at the end ??? */ + wavelan_set_encode, /* SIOCSIWENCODE */ + wavelan_get_encode, /* SIOCGIWENCODE */ +}; + +static const iw_handler wavelan_private_handler[] = +{ + wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ + wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ +#ifdef HISTOGRAM + wavelan_set_histo, /* SIOCIWFIRSTPRIV + 2 */ + wavelan_get_histo, /* SIOCIWFIRSTPRIV + 3 */ +#endif /* HISTOGRAM */ +}; + +static const struct iw_priv_args wavelan_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, + { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, + { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, + { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, +}; + +static const struct iw_handler_def wavelan_handler_def = +{ + .num_standard = ARRAY_SIZE(wavelan_handler), + .num_private = ARRAY_SIZE(wavelan_private_handler), + .num_private_args = ARRAY_SIZE(wavelan_private_args), + .standard = wavelan_handler, + .private = wavelan_private_handler, + .private_args = wavelan_private_args, + .get_wireless_stats = wavelan_get_wireless_stats, +}; + +/*------------------------------------------------------------------*/ +/* + * Get wireless statistics. + * Called by /proc/net/wireless + */ +static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); + mmr_t m; + iw_stats *wstats; + unsigned long flags; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", + dev->name); +#endif + + /* Check */ + if (lp == (net_local *) NULL) + return (iw_stats *) NULL; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + wstats = &lp->wstats; + + /* Get data from the mmc. */ + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); + + mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); + mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, + 2); + mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, + 4); + + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); + + /* Copy data to wireless stuff. */ + wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; + wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; + wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; + wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; + wstats->qual.updated = (((m. mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) + | ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) + | ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); + wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; + wstats->discard.code = 0L; + wstats->discard.misc = 0L; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", + dev->name); +#endif + return &lp->wstats; +} + +/************************* PACKET RECEPTION *************************/ +/* + * This part deals with receiving the packets. + * The interrupt handler gets an interrupt when a packet has been + * successfully received and calls this part. + */ + +/*------------------------------------------------------------------*/ +/* + * This routine does the actual copying of data (including the Ethernet + * header structure) from the WaveLAN card to an sk_buff chain that + * will be passed up to the network interface layer. NOTE: we + * currently don't handle trailer protocols (neither does the rest of + * the network interface), so if that is needed, it will (at least in + * part) be added here. The contents of the receive ring buffer are + * copied to a message chain that is then passed to the kernel. + * + * Note: if any errors occur, the packet is "dropped on the floor". + * (called by wv_packet_rcv()) + */ +static void +wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + struct sk_buff *skb; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", + dev->name, buf_off, sksize); +#endif + + /* Allocate buffer for the data */ + if ((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO + "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n", + dev->name, sksize); +#endif + dev->stats.rx_dropped++; + return; + } + + /* Copy the packet to the buffer. */ + obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize); + skb->protocol = eth_type_trans(skb, dev); + +#ifdef DEBUG_RX_INFO + wv_packet_info(skb_mac_header(skb), sksize, dev->name, + "wv_packet_read"); +#endif /* DEBUG_RX_INFO */ + + /* Statistics-gathering and associated stuff. + * It seem a bit messy with all the define, but it's really + * simple... */ + if ( +#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ + (lp->spy_data.spy_number > 0) || +#endif /* IW_WIRELESS_SPY */ +#ifdef HISTOGRAM + (lp->his_number > 0) || +#endif /* HISTOGRAM */ + 0) { + u8 stats[3]; /* signal level, noise level, signal quality */ + + /* Read signal level, silence level and signal quality bytes */ + /* Note: in the PCMCIA hardware, these are part of the frame. + * It seems that for the ISA hardware, it's nowhere to be + * found in the frame, so I'm obliged to do this (it has a + * side effect on /proc/net/wireless). + * Any ideas? + */ + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); + mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3); + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); + +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG + "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", + dev->name, stats[0] & 0x3F, stats[1] & 0x3F, + stats[2] & 0x0F); +#endif + + /* Spying stuff */ +#ifdef IW_WIRELESS_SPY + wl_spy_gather(dev, skb_mac_header(skb) + WAVELAN_ADDR_SIZE, + stats); +#endif /* IW_WIRELESS_SPY */ +#ifdef HISTOGRAM + wl_his_gather(dev, stats); +#endif /* HISTOGRAM */ + } + + /* + * Hand the packet to the network module. + */ + netif_rx(skb); + + /* Keep statistics up to date */ + dev->stats.rx_packets++; + dev->stats.rx_bytes += sksize; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * Transfer as many packets as we can + * from the device RAM. + * (called in wavelan_interrupt()). + * Note : the spinlock is already grabbed for us. + */ +static void wv_receive(struct net_device * dev) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); + fd_t fd; + rbd_t rbd; + int nreaped = 0; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name); +#endif + + /* Loop on each received packet. */ + for (;;) { + obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, + sizeof(fd)); + + /* Note about the status : + * It start up to be 0 (the value we set). Then, when the RU + * grab the buffer to prepare for reception, it sets the + * FD_STATUS_B flag. When the RU has finished receiving the + * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate + * completion and set the other flags to indicate the eventual + * errors. FD_STATUS_OK indicates that the reception was OK. + */ + + /* If the current frame is not complete, we have reached the end. */ + if ((fd.fd_status & FD_STATUS_C) != FD_STATUS_C) + break; /* This is how we exit the loop. */ + + nreaped++; + + /* Check whether frame was correctly received. */ + if ((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) { + /* Does the frame contain a pointer to the data? Let's check. */ + if (fd.fd_rbd_offset != I82586NULL) { + /* Read the receive buffer descriptor */ + obram_read(ioaddr, fd.fd_rbd_offset, + (unsigned char *) &rbd, + sizeof(rbd)); + +#ifdef DEBUG_RX_ERROR + if ((rbd.rbd_status & RBD_STATUS_EOF) != + RBD_STATUS_EOF) printk(KERN_INFO + "%s: wv_receive(): missing EOF flag.\n", + dev->name); + + if ((rbd.rbd_status & RBD_STATUS_F) != + RBD_STATUS_F) printk(KERN_INFO + "%s: wv_receive(): missing F flag.\n", + dev->name); +#endif /* DEBUG_RX_ERROR */ + + /* Read the packet and transmit to Linux */ + wv_packet_read(dev, rbd.rbd_bufl, + rbd. + rbd_status & + RBD_STATUS_ACNT); + } +#ifdef DEBUG_RX_ERROR + else /* if frame has no data */ + printk(KERN_INFO + "%s: wv_receive(): frame has no data.\n", + dev->name); +#endif + } else { /* If reception was no successful */ + + dev->stats.rx_errors++; + +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG + "%s: wv_receive(): frame not received successfully (%X).\n", + dev->name, fd.fd_status); +#endif + +#ifdef DEBUG_RX_ERROR + if ((fd.fd_status & FD_STATUS_S6) != 0) + printk(KERN_INFO + "%s: wv_receive(): no EOF flag.\n", + dev->name); +#endif + + if ((fd.fd_status & FD_STATUS_S7) != 0) { + dev->stats.rx_length_errors++; +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG + "%s: wv_receive(): frame too short.\n", + dev->name); +#endif + } + + if ((fd.fd_status & FD_STATUS_S8) != 0) { + dev->stats.rx_over_errors++; +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG + "%s: wv_receive(): rx DMA overrun.\n", + dev->name); +#endif + } + + if ((fd.fd_status & FD_STATUS_S9) != 0) { + dev->stats.rx_fifo_errors++; +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG + "%s: wv_receive(): ran out of resources.\n", + dev->name); +#endif + } + + if ((fd.fd_status & FD_STATUS_S10) != 0) { + dev->stats.rx_frame_errors++; +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG + "%s: wv_receive(): alignment error.\n", + dev->name); +#endif + } + + if ((fd.fd_status & FD_STATUS_S11) != 0) { + dev->stats.rx_crc_errors++; +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG + "%s: wv_receive(): CRC error.\n", + dev->name); +#endif + } + } + + fd.fd_status = 0; + obram_write(ioaddr, fdoff(lp->rx_head, fd_status), + (unsigned char *) &fd.fd_status, + sizeof(fd.fd_status)); + + fd.fd_command = FD_COMMAND_EL; + obram_write(ioaddr, fdoff(lp->rx_head, fd_command), + (unsigned char *) &fd.fd_command, + sizeof(fd.fd_command)); + + fd.fd_command = 0; + obram_write(ioaddr, fdoff(lp->rx_last, fd_command), + (unsigned char *) &fd.fd_command, + sizeof(fd.fd_command)); + + lp->rx_last = lp->rx_head; + lp->rx_head = fd.fd_link_offset; + } /* for(;;) -> loop on all frames */ + +#ifdef DEBUG_RX_INFO + if (nreaped > 1) + printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n", + dev->name, nreaped); +#endif +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name); +#endif +} + +/*********************** PACKET TRANSMISSION ***********************/ +/* + * This part deals with sending packets through the WaveLAN. + * + */ + +/*------------------------------------------------------------------*/ +/* + * This routine fills in the appropriate registers and memory + * locations on the WaveLAN card and starts the card off on + * the transmit. + * + * The principle: + * Each block contains a transmit command, a NOP command, + * a transmit block descriptor and a buffer. + * The CU read the transmit block which point to the tbd, + * read the tbd and the content of the buffer. + * When it has finish with it, it goes to the next command + * which in our case is the NOP. The NOP points on itself, + * so the CU stop here. + * When we add the next block, we modify the previous nop + * to make it point on the new tx command. + * Simple, isn't it ? + * + * (called in wavelan_packet_xmit()) + */ +static int wv_packet_write(struct net_device * dev, void *buf, short length) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + unsigned short txblock; + unsigned short txpred; + unsigned short tx_addr; + unsigned short nop_addr; + unsigned short tbd_addr; + unsigned short buf_addr; + ac_tx_t tx; + ac_nop_t nop; + tbd_t tbd; + int clen = length; + unsigned long flags; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, + length); +#endif + + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check nothing bad has happened */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { +#ifdef DEBUG_TX_ERROR + printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", + dev->name); +#endif + spin_unlock_irqrestore(&lp->spinlock, flags); + return 1; + } + + /* Calculate addresses of next block and previous block. */ + txblock = lp->tx_first_free; + txpred = txblock - TXBLOCKZ; + if (txpred < OFFSET_CU) + txpred += NTXBLOCKS * TXBLOCKZ; + lp->tx_first_free += TXBLOCKZ; + if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) + lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; + + lp->tx_n_in_use++; + + /* Calculate addresses of the different parts of the block. */ + tx_addr = txblock; + nop_addr = tx_addr + sizeof(tx); + tbd_addr = nop_addr + sizeof(nop); + buf_addr = tbd_addr + sizeof(tbd); + + /* + * Transmit command + */ + tx.tx_h.ac_status = 0; + obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), + (unsigned char *) &tx.tx_h.ac_status, + sizeof(tx.tx_h.ac_status)); + + /* + * NOP command + */ + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = nop_addr; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); + + /* + * Transmit buffer descriptor + */ + tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen); + tbd.tbd_next_bd_offset = I82586NULL; + tbd.tbd_bufl = buf_addr; + tbd.tbd_bufh = 0; + obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd)); + + /* + * Data + */ + obram_write(ioaddr, buf_addr, buf, length); + + /* + * Overwrite the predecessor NOP link + * so that it points to this txblock. + */ + nop_addr = txpred + sizeof(tx); + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = txblock; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); + + /* Make sure the watchdog will keep quiet for a while */ + dev->trans_start = jiffies; + + /* Keep stats up to date. */ + dev->stats.tx_bytes += length; + + if (lp->tx_first_in_use == I82586NULL) + lp->tx_first_in_use = txblock; + + if (lp->tx_n_in_use < NTXBLOCKS - 1) + netif_wake_queue(dev); + + spin_unlock_irqrestore(&lp->spinlock, flags); + +#ifdef DEBUG_TX_INFO + wv_packet_info((u8 *) buf, length, dev->name, + "wv_packet_write"); +#endif /* DEBUG_TX_INFO */ + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); +#endif + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * This routine is called when we want to send a packet (NET3 callback) + * In this routine, we check if the harware is ready to accept + * the packet. We also prevent reentrance. Then we call the function + * to send the packet. + */ +static netdev_tx_t wavelan_packet_xmit(struct sk_buff *skb, + struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long flags; + char data[ETH_ZLEN]; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, + (unsigned) skb); +#endif + + /* + * Block a timer-based transmit from overlapping. + * In other words, prevent reentering this routine. + */ + netif_stop_queue(dev); + + /* If somebody has asked to reconfigure the controller, + * we can do it now. + */ + if (lp->reconfig_82586) { + spin_lock_irqsave(&lp->spinlock, flags); + wv_82586_config(dev); + spin_unlock_irqrestore(&lp->spinlock, flags); + /* Check that we can continue */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) + return NETDEV_TX_BUSY; + } + + /* Do we need some padding? */ + /* Note : on wireless the propagation time is in the order of 1us, + * and we don't have the Ethernet specific requirement of beeing + * able to detect collisions, therefore in theory we don't really + * need to pad. Jean II */ + if (skb->len < ETH_ZLEN) { + memset(data, 0, ETH_ZLEN); + skb_copy_from_linear_data(skb, data, skb->len); + /* Write packet on the card */ + if(wv_packet_write(dev, data, ETH_ZLEN)) + return NETDEV_TX_BUSY; /* We failed */ + } + else if(wv_packet_write(dev, skb->data, skb->len)) + return NETDEV_TX_BUSY; /* We failed */ + + + dev_kfree_skb(skb); + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); +#endif + return NETDEV_TX_OK; +} + +/*********************** HARDWARE CONFIGURATION ***********************/ +/* + * This part does the real job of starting and configuring the hardware. + */ + +/*--------------------------------------------------------------------*/ +/* + * Routine to initialize the Modem Management Controller. + * (called by wv_hw_reset()) + */ +static int wv_mmc_init(struct net_device * dev) +{ + unsigned long ioaddr = dev->base_addr; + net_local *lp = netdev_priv(dev); + psa_t psa; + mmw_t m; + int configured; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); +#endif + + /* Read the parameter storage area. */ + psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); + +#ifdef USE_PSA_CONFIG + configured = psa.psa_conf_status & 1; +#else + configured = 0; +#endif + + /* Is the PSA is not configured */ + if (!configured) { + /* User will be able to configure NWID later (with iwconfig). */ + psa.psa_nwid[0] = 0; + psa.psa_nwid[1] = 0; + + /* no NWID checking since NWID is not set */ + psa.psa_nwid_select = 0; + + /* Disable encryption */ + psa.psa_encryption_select = 0; + + /* Set to standard values: + * 0x04 for AT, + * 0x01 for MCA, + * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) + */ + if (psa.psa_comp_number & 1) + psa.psa_thr_pre_set = 0x01; + else + psa.psa_thr_pre_set = 0x04; + psa.psa_quality_thr = 0x03; + + /* It is configured */ + psa.psa_conf_status |= 1; + +#ifdef USE_PSA_CONFIG + /* Write the psa. */ + psa_write(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 4); + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_conf_status - (char *) &psa, + (unsigned char *) &psa.psa_conf_status, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); +#endif + } + + /* Zero the mmc structure. */ + memset(&m, 0x00, sizeof(m)); + + /* Copy PSA info to the mmc. */ + m.mmw_netw_id_l = psa.psa_nwid[1]; + m.mmw_netw_id_h = psa.psa_nwid[0]; + + if (psa.psa_nwid_select & 1) + m.mmw_loopt_sel = 0x00; + else + m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; + + memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, + sizeof(m.mmw_encr_key)); + + if (psa.psa_encryption_select) + m.mmw_encr_enable = + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; + else + m.mmw_encr_enable = 0; + + m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; + m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; + + /* + * Set default modem control parameters. + * See NCR document 407-0024326 Rev. A. + */ + m.mmw_jabber_enable = 0x01; + m.mmw_freeze = 0; + m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; + m.mmw_ifs = 0x20; + m.mmw_mod_delay = 0x04; + m.mmw_jam_time = 0x38; + + m.mmw_des_io_invert = 0; + m.mmw_decay_prm = 0; + m.mmw_decay_updat_prm = 0; + + /* Write all info to MMC. */ + mmc_write(ioaddr, 0, (u8 *) & m, sizeof(m)); + + /* The following code starts the modem of the 2.00 frequency + * selectable cards at power on. It's not strictly needed for the + * following boots. + * The original patch was by Joe Finney for the PCMCIA driver, but + * I've cleaned it up a bit and added documentation. + * Thanks to Loeke Brederveld from Lucent for the info. + */ + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) + * Does it work for everybody, especially old cards? */ + /* Note: WFREQSEL verifies that it is able to read a sensible + * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID + * is 0xA (Xilinx version) or 0xB (Ariadne version). + * My test is more crude but does work. */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + /* We must download the frequency parameters to the + * synthesizers (from the EEPROM - area 1) + * Note: as the EEPROM is automatically decremented, we set the end + * if the area... */ + m.mmw_fee_addr = 0x0F; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, + (unsigned char *) &m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished. */ + fee_wait(ioaddr, 100, 100); + +#ifdef DEBUG_CONFIG_INFO + /* The frequency was in the last word downloaded. */ + mmc_read(ioaddr, (char *) &m.mmw_fee_data_l - (char *) &m, + (unsigned char *) &m.mmw_fee_data_l, 2); + + /* Print some info for the user. */ + printk(KERN_DEBUG + "%s: WaveLAN 2.00 recognised (frequency select). Current frequency = %ld\n", + dev->name, + ((m. + mmw_fee_data_h << 4) | (m.mmw_fee_data_l >> 4)) * + 5 / 2 + 24000L); +#endif + + /* We must now download the power adjust value (gain) to + * the synthesizers (from the EEPROM - area 7 - DAC). */ + m.mmw_fee_addr = 0x61; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, + (unsigned char *) &m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished. */ + } + /* if 2.00 card */ +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Construct the fd and rbd structures. + * Start the receive unit. + * (called by wv_hw_reset()) + */ +static int wv_ru_start(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + u16 scb_cs; + fd_t fd; + rbd_t rbd; + u16 rx; + u16 rx_next; + int i; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); +#endif + + obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if ((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY) + return 0; + + lp->rx_head = OFFSET_RU; + + for (i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) { + rx_next = + (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ; + + fd.fd_status = 0; + fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0; + fd.fd_link_offset = rx_next; + fd.fd_rbd_offset = rx + sizeof(fd); + obram_write(ioaddr, rx, (unsigned char *) &fd, sizeof(fd)); + + rbd.rbd_status = 0; + rbd.rbd_next_rbd_offset = I82586NULL; + rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd); + rbd.rbd_bufh = 0; + rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ); + obram_write(ioaddr, rx + sizeof(fd), + (unsigned char *) &rbd, sizeof(rbd)); + + lp->rx_last = rx; + } + + obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset), + (unsigned char *) &lp->rx_head, sizeof(lp->rx_head)); + + scb_cs = SCB_CMD_RUC_GO; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if (scb_cs == 0) + break; + + udelay(10); + } + + if (i <= 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wavelan_ru_start(): board not accepting command.\n", + dev->name); +#endif + return -1; + } +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Initialise the transmit blocks. + * Start the command unit executing the NOP + * self-loop of the first transmit block. + * + * Here we create the list of send buffers used to transmit packets + * between the PC and the command unit. For each buffer, we create a + * buffer descriptor (pointing on the buffer), a transmit command + * (pointing to the buffer descriptor) and a NOP command. + * The transmit command is linked to the NOP, and the NOP to itself. + * When we will have finished executing the transmit command, we will + * then loop on the NOP. By releasing the NOP link to a new command, + * we may send another buffer. + * + * (called by wv_hw_reset()) + */ +static int wv_cu_start(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + int i; + u16 txblock; + u16 first_nop; + u16 scb_cs; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name); +#endif + + lp->tx_first_free = OFFSET_CU; + lp->tx_first_in_use = I82586NULL; + + for (i = 0, txblock = OFFSET_CU; + i < NTXBLOCKS; i++, txblock += TXBLOCKZ) { + ac_tx_t tx; + ac_nop_t nop; + tbd_t tbd; + unsigned short tx_addr; + unsigned short nop_addr; + unsigned short tbd_addr; + unsigned short buf_addr; + + tx_addr = txblock; + nop_addr = tx_addr + sizeof(tx); + tbd_addr = nop_addr + sizeof(nop); + buf_addr = tbd_addr + sizeof(tbd); + + tx.tx_h.ac_status = 0; + tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I; + tx.tx_h.ac_link = nop_addr; + tx.tx_tbd_offset = tbd_addr; + obram_write(ioaddr, tx_addr, (unsigned char *) &tx, + sizeof(tx)); + + nop.nop_h.ac_status = 0; + nop.nop_h.ac_command = acmd_nop; + nop.nop_h.ac_link = nop_addr; + obram_write(ioaddr, nop_addr, (unsigned char *) &nop, + sizeof(nop)); + + tbd.tbd_status = TBD_STATUS_EOF; + tbd.tbd_next_bd_offset = I82586NULL; + tbd.tbd_bufl = buf_addr; + tbd.tbd_bufh = 0; + obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, + sizeof(tbd)); + } + + first_nop = + OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t); + obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset), + (unsigned char *) &first_nop, sizeof(first_nop)); + + scb_cs = SCB_CMD_CUC_GO; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if (scb_cs == 0) + break; + + udelay(10); + } + + if (i <= 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wavelan_cu_start(): board not accepting command.\n", + dev->name); +#endif + return -1; + } + + lp->tx_n_in_use = 0; + netif_start_queue(dev); +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * This routine does a standard configuration of the WaveLAN + * controller (i82586). + * + * It initialises the scp, iscp and scb structure + * The first two are just pointers to the next. + * The last one is used for basic configuration and for basic + * communication (interrupt status). + * + * (called by wv_hw_reset()) + */ +static int wv_82586_start(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + scp_t scp; /* system configuration pointer */ + iscp_t iscp; /* intermediate scp */ + scb_t scb; /* system control block */ + ach_t cb; /* Action command header */ + u8 zeroes[512]; + int i; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name); +#endif + + /* + * Clear the onboard RAM. + */ + memset(&zeroes[0], 0x00, sizeof(zeroes)); + for (i = 0; i < I82586_MEMZ; i += sizeof(zeroes)) + obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes)); + + /* + * Construct the command unit structures: + * scp, iscp, scb, cb. + */ + memset(&scp, 0x00, sizeof(scp)); + scp.scp_sysbus = SCP_SY_16BBUS; + scp.scp_iscpl = OFFSET_ISCP; + obram_write(ioaddr, OFFSET_SCP, (unsigned char *) &scp, + sizeof(scp)); + + memset(&iscp, 0x00, sizeof(iscp)); + iscp.iscp_busy = 1; + iscp.iscp_offset = OFFSET_SCB; + obram_write(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, + sizeof(iscp)); + + /* Our first command is to reset the i82586. */ + memset(&scb, 0x00, sizeof(scb)); + scb.scb_command = SCB_CMD_RESET; + scb.scb_cbl_offset = OFFSET_CU; + scb.scb_rfa_offset = OFFSET_RU; + obram_write(ioaddr, OFFSET_SCB, (unsigned char *) &scb, + sizeof(scb)); + + set_chan_attn(ioaddr, lp->hacr); + + /* Wait for command to finish. */ + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, + sizeof(iscp)); + + if (iscp.iscp_busy == (unsigned short) 0) + break; + + udelay(10); + } + + if (i <= 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wv_82586_start(): iscp_busy timeout.\n", + dev->name); +#endif + return -1; + } + + /* Check command completion. */ + for (i = 15; i > 0; i--) { + obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, + sizeof(scb)); + + if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA)) + break; + + udelay(10); + } + + if (i <= 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n", + dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status); +#endif + return -1; + } + + wv_ack(dev); + + /* Set the action command header. */ + memset(&cb, 0x00, sizeof(cb)); + cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose); + cb.ac_link = OFFSET_CU; + obram_write(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); + + if (wv_synchronous_cmd(dev, "diag()") == -1) + return -1; + + obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); + if (cb.ac_status & AC_SFLD_FAIL) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wv_82586_start(): i82586 Self Test failed.\n", + dev->name); +#endif + return -1; + } +#ifdef DEBUG_I82586_SHOW + wv_scb_show(ioaddr); +#endif + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * This routine does a standard configuration of the WaveLAN + * controller (i82586). + * + * This routine is a violent hack. We use the first free transmit block + * to make our configuration. In the buffer area, we create the three + * configuration commands (linked). We make the previous NOP point to + * the beginning of the buffer instead of the tx command. After, we go + * as usual to the NOP command. + * Note that only the last command (mc_set) will generate an interrupt. + * + * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit()) + */ +static void wv_82586_config(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + unsigned short txblock; + unsigned short txpred; + unsigned short tx_addr; + unsigned short nop_addr; + unsigned short tbd_addr; + unsigned short cfg_addr; + unsigned short ias_addr; + unsigned short mcs_addr; + ac_tx_t tx; + ac_nop_t nop; + ac_cfg_t cfg; /* Configure action */ + ac_ias_t ias; /* IA-setup action */ + ac_mcs_t mcs; /* Multicast setup */ + struct dev_mc_list *dmi; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name); +#endif + + /* Check nothing bad has happened */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "%s: wv_82586_config(): Tx queue full.\n", + dev->name); +#endif + return; + } + + /* Calculate addresses of next block and previous block. */ + txblock = lp->tx_first_free; + txpred = txblock - TXBLOCKZ; + if (txpred < OFFSET_CU) + txpred += NTXBLOCKS * TXBLOCKZ; + lp->tx_first_free += TXBLOCKZ; + if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) + lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; + + lp->tx_n_in_use++; + + /* Calculate addresses of the different parts of the block. */ + tx_addr = txblock; + nop_addr = tx_addr + sizeof(tx); + tbd_addr = nop_addr + sizeof(nop); + cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */ + ias_addr = cfg_addr + sizeof(cfg); + mcs_addr = ias_addr + sizeof(ias); + + /* + * Transmit command + */ + tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */ + obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), + (unsigned char *) &tx.tx_h.ac_status, + sizeof(tx.tx_h.ac_status)); + + /* + * NOP command + */ + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = nop_addr; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); + + /* Create a configure action. */ + memset(&cfg, 0x00, sizeof(cfg)); + + /* + * For Linux we invert AC_CFG_ALOC() so as to conform + * to the way that net packets reach us from above. + * (See also ac_tx_t.) + * + * Updated from Wavelan Manual WCIN085B + */ + cfg.cfg_byte_cnt = + AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t)); + cfg.cfg_fifolim = AC_CFG_FIFOLIM(4); + cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0); + cfg.cfg_byte9 = AC_CFG_ELPBCK(0) | + AC_CFG_ILPBCK(0) | + AC_CFG_PRELEN(AC_CFG_PLEN_2) | + AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE); + cfg.cfg_byte10 = AC_CFG_BOFMET(1) | + AC_CFG_ACR(6) | AC_CFG_LINPRIO(0); + cfg.cfg_ifs = 0x20; + cfg.cfg_slotl = 0x0C; + cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | AC_CFG_SLTTMHI(0); + cfg.cfg_byte14 = AC_CFG_FLGPAD(0) | + AC_CFG_BTSTF(0) | + AC_CFG_CRC16(0) | + AC_CFG_NCRC(0) | + AC_CFG_TNCRS(1) | + AC_CFG_MANCH(0) | + AC_CFG_BCDIS(0) | AC_CFG_PRM(lp->promiscuous); + cfg.cfg_byte15 = AC_CFG_ICDS(0) | + AC_CFG_CDTF(0) | AC_CFG_ICSS(0) | AC_CFG_CSTF(0); +/* + cfg.cfg_min_frm_len = AC_CFG_MNFRM(64); +*/ + cfg.cfg_min_frm_len = AC_CFG_MNFRM(8); + + cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure); + cfg.cfg_h.ac_link = ias_addr; + obram_write(ioaddr, cfg_addr, (unsigned char *) &cfg, sizeof(cfg)); + + /* Set up the MAC address */ + memset(&ias, 0x00, sizeof(ias)); + ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup); + ias.ias_h.ac_link = mcs_addr; + memcpy(&ias.ias_addr[0], (unsigned char *) &dev->dev_addr[0], + sizeof(ias.ias_addr)); + obram_write(ioaddr, ias_addr, (unsigned char *) &ias, sizeof(ias)); + + /* Initialize adapter's Ethernet multicast addresses */ + memset(&mcs, 0x00, sizeof(mcs)); + mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup); + mcs.mcs_h.ac_link = nop_addr; + mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count; + obram_write(ioaddr, mcs_addr, (unsigned char *) &mcs, sizeof(mcs)); + + /* Any address to set? */ + if (lp->mc_count) { + for (dmi = dev->mc_list; dmi; dmi = dmi->next) + outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr, + WAVELAN_ADDR_SIZE >> 1); + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG + "%s: wv_82586_config(): set %d multicast addresses:\n", + dev->name, lp->mc_count); + for (dmi = dev->mc_list; dmi; dmi = dmi->next) + printk(KERN_DEBUG " %pM\n", dmi->dmi_addr); +#endif + } + + /* + * Overwrite the predecessor NOP link + * so that it points to the configure action. + */ + nop_addr = txpred + sizeof(tx); + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = cfg_addr; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); + + /* Job done, clear the flag */ + lp->reconfig_82586 = 0; + + if (lp->tx_first_in_use == I82586NULL) + lp->tx_first_in_use = txblock; + + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) + netif_stop_queue(dev); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This routine, called by wavelan_close(), gracefully stops the + * WaveLAN controller (i82586). + * (called by wavelan_close()) + */ +static void wv_82586_stop(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + u16 scb_cmd; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name); +#endif + + /* Suspend both command unit and receive unit. */ + scb_cmd = + (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & + SCB_CMD_RUC_SUS); + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cmd, sizeof(scb_cmd)); + set_chan_attn(ioaddr, lp->hacr); + + /* No more interrupts */ + wv_ints_off(dev); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * Totally reset the WaveLAN and restart it. + * Performs the following actions: + * 1. A power reset (reset DMA) + * 2. Initialize the radio modem (using wv_mmc_init) + * 3. Reset & Configure LAN controller (using wv_82586_start) + * 4. Start the LAN controller's command unit + * 5. Start the LAN controller's receive unit + * (called by wavelan_interrupt(), wavelan_watchdog() & wavelan_open()) + */ +static int wv_hw_reset(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* Increase the number of resets done. */ + lp->nresets++; + + wv_hacr_reset(ioaddr); + lp->hacr = HACR_DEFAULT; + + if ((wv_mmc_init(dev) < 0) || (wv_82586_start(dev) < 0)) + return -1; + + /* Enable the card to send interrupts. */ + wv_ints_on(dev); + + /* Start card functions */ + if (wv_cu_start(dev) < 0) + return -1; + + /* Setup the controller and parameters */ + wv_82586_config(dev); + + /* Finish configuration with the receive unit */ + if (wv_ru_start(dev) < 0) + return -1; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Check if there is a WaveLAN at the specific base address. + * As a side effect, this reads the MAC address. + * (called in wavelan_probe() and init_module()) + */ +static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac) +{ + int i; /* Loop counter */ + + /* Check if the base address if available. */ + if (!request_region(ioaddr, sizeof(ha_t), "wavelan probe")) + return -EBUSY; /* ioaddr already used */ + + /* Reset host interface */ + wv_hacr_reset(ioaddr); + + /* Read the MAC address from the parameter storage area. */ + psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr), + mac, 6); + + release_region(ioaddr, sizeof(ha_t)); + + /* + * Check the first three octets of the address for the manufacturer's code. + * Note: if this can't find your WaveLAN card, you've got a + * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on + * how to configure your card. + */ + for (i = 0; i < ARRAY_SIZE(MAC_ADDRESSES); i++) + if ((mac[0] == MAC_ADDRESSES[i][0]) && + (mac[1] == MAC_ADDRESSES[i][1]) && + (mac[2] == MAC_ADDRESSES[i][2])) + return 0; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_WARNING + "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n", + ioaddr, mac[0], mac[1], mac[2]); +#endif + return -ENODEV; +} + +/************************ INTERRUPT HANDLING ************************/ + +/* + * This function is the interrupt handler for the WaveLAN card. This + * routine will be called whenever: + */ +static irqreturn_t wavelan_interrupt(int irq, void *dev_id) +{ + struct net_device *dev; + unsigned long ioaddr; + net_local *lp; + u16 hasr; + u16 status; + u16 ack_cmd; + + dev = dev_id; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); +#endif + + lp = netdev_priv(dev); + ioaddr = dev->base_addr; + +#ifdef DEBUG_INTERRUPT_INFO + /* Check state of our spinlock */ + if(spin_is_locked(&lp->spinlock)) + printk(KERN_DEBUG + "%s: wavelan_interrupt(): spinlock is already locked !!!\n", + dev->name); +#endif + + /* Prevent reentrancy. We need to do that because we may have + * multiple interrupt handler running concurrently. + * It is safe because interrupts are disabled before acquiring + * the spinlock. */ + spin_lock(&lp->spinlock); + + /* We always had spurious interrupts at startup, but lately I + * saw them comming *between* the request_irq() and the + * spin_lock_irqsave() in wavelan_open(), so the spinlock + * protection is no enough. + * So, we also check lp->hacr that will tell us is we enabled + * irqs or not (see wv_ints_on()). + * We can't use netif_running(dev) because we depend on the + * proper processing of the irq generated during the config. */ + + /* Which interrupt it is ? */ + hasr = hasr_read(ioaddr); + +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_INFO + "%s: wavelan_interrupt(): hasr 0x%04x; hacr 0x%04x.\n", + dev->name, hasr, lp->hacr); +#endif + + /* Check modem interrupt */ + if ((hasr & HASR_MMC_INTR) && (lp->hacr & HACR_MMC_INT_ENABLE)) { + u8 dce_status; + + /* + * Interrupt from the modem management controller. + * This will clear it -- ignored for now. + */ + mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, + sizeof(dce_status)); + +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", + dev->name, dce_status); +#endif + } + + /* Check if not controller interrupt */ + if (((hasr & HASR_82586_INTR) == 0) || + ((lp->hacr & HACR_82586_INT_ENABLE) == 0)) { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_interrupt(): interrupt not coming from i82586 - hasr 0x%04x.\n", + dev->name, hasr); +#endif + spin_unlock (&lp->spinlock); + return IRQ_NONE; + } + + /* Read interrupt data. */ + obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), + (unsigned char *) &status, sizeof(status)); + + /* + * Acknowledge the interrupt(s). + */ + ack_cmd = status & SCB_ST_INT; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &ack_cmd, sizeof(ack_cmd)); + set_chan_attn(ioaddr, lp->hacr); + +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n", + dev->name, status); +#endif + + /* Command completed. */ + if ((status & SCB_ST_CX) == SCB_ST_CX) { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG + "%s: wavelan_interrupt(): command completed.\n", + dev->name); +#endif + wv_complete(dev, ioaddr, lp); + } + + /* Frame received. */ + if ((status & SCB_ST_FR) == SCB_ST_FR) { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG + "%s: wavelan_interrupt(): received packet.\n", + dev->name); +#endif + wv_receive(dev); + } + + /* Check the state of the command unit. */ + if (((status & SCB_ST_CNA) == SCB_ST_CNA) || + (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && + (netif_running(dev)))) { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_interrupt(): CU inactive -- restarting\n", + dev->name); +#endif + wv_hw_reset(dev); + } + + /* Check the state of the command unit. */ + if (((status & SCB_ST_RNR) == SCB_ST_RNR) || + (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && + (netif_running(dev)))) { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_interrupt(): RU not ready -- restarting\n", + dev->name); +#endif + wv_hw_reset(dev); + } + + /* Release spinlock */ + spin_unlock (&lp->spinlock); + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); +#endif + return IRQ_HANDLED; +} + +/*------------------------------------------------------------------*/ +/* + * Watchdog: when we start a transmission, a timer is set for us in the + * kernel. If the transmission completes, this timer is disabled. If + * the timer expires, we are called and we try to unlock the hardware. + */ +static void wavelan_watchdog(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + u_long ioaddr = dev->base_addr; + unsigned long flags; + unsigned int nreaped; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); +#endif + +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", + dev->name); +#endif + + /* Check that we came here for something */ + if (lp->tx_n_in_use <= 0) { + return; + } + + spin_lock_irqsave(&lp->spinlock, flags); + + /* Try to see if some buffers are not free (in case we missed + * an interrupt */ + nreaped = wv_complete(dev, ioaddr, lp); + +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG + "%s: wavelan_watchdog(): %d reaped, %d remain.\n", + dev->name, nreaped, lp->tx_n_in_use); +#endif + +#ifdef DEBUG_PSA_SHOW + { + psa_t psa; + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + wv_psa_show(&psa); + } +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82586_SHOW + wv_cu_show(dev); +#endif + + /* If no buffer has been freed */ + if (nreaped == 0) { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO + "%s: wavelan_watchdog(): cleanup failed, trying reset\n", + dev->name); +#endif + wv_hw_reset(dev); + } + + /* At this point, we should have some free Tx buffer ;-) */ + if (lp->tx_n_in_use < NTXBLOCKS - 1) + netif_wake_queue(dev); + + spin_unlock_irqrestore(&lp->spinlock, flags); + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); +#endif +} + +/********************* CONFIGURATION CALLBACKS *********************/ +/* + * Here are the functions called by the Linux networking code (NET3) + * for initialization, configuration and deinstallations of the + * WaveLAN ISA hardware. + */ + +/*------------------------------------------------------------------*/ +/* + * Configure and start up the WaveLAN PCMCIA adaptor. + * Called by NET3 when it "opens" the device. + */ +static int wavelan_open(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long flags; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* Check irq */ + if (dev->irq == 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", + dev->name); +#endif + return -ENXIO; + } + + if (request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0) + { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", + dev->name); +#endif + return -EAGAIN; + } + + spin_lock_irqsave(&lp->spinlock, flags); + + if (wv_hw_reset(dev) != -1) { + netif_start_queue(dev); + } else { + free_irq(dev->irq, dev); +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wavelan_open(): impossible to start the card\n", + dev->name); +#endif + spin_unlock_irqrestore(&lp->spinlock, flags); + return -EAGAIN; + } + spin_unlock_irqrestore(&lp->spinlock, flags); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Shut down the WaveLAN ISA card. + * Called by NET3 when it "closes" the device. + */ +static int wavelan_close(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + unsigned long flags; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + netif_stop_queue(dev); + + /* + * Flush the Tx and disable Rx. + */ + spin_lock_irqsave(&lp->spinlock, flags); + wv_82586_stop(dev); + spin_unlock_irqrestore(&lp->spinlock, flags); + + free_irq(dev->irq, dev); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); +#endif + return 0; +} + +static const struct net_device_ops wavelan_netdev_ops = { + .ndo_open = wavelan_open, + .ndo_stop = wavelan_close, + .ndo_start_xmit = wavelan_packet_xmit, + .ndo_set_multicast_list = wavelan_set_multicast_list, + .ndo_tx_timeout = wavelan_watchdog, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +#ifdef SET_MAC_ADDRESS + .ndo_set_mac_address = wavelan_set_mac_address +#else + .ndo_set_mac_address = eth_mac_addr, +#endif +}; + + +/*------------------------------------------------------------------*/ +/* + * Probe an I/O address, and if the WaveLAN is there configure the + * device structure + * (called by wavelan_probe() and via init_module()). + */ +static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) +{ + u8 irq_mask; + int irq; + net_local *lp; + mac_addr mac; + int err; + + if (!request_region(ioaddr, sizeof(ha_t), "wavelan")) + return -EADDRINUSE; + + err = wv_check_ioaddr(ioaddr, mac); + if (err) + goto out; + + memcpy(dev->dev_addr, mac, 6); + + dev->base_addr = ioaddr; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%lx)\n", + dev->name, (unsigned int) dev, ioaddr); +#endif + + /* Check IRQ argument on command line. */ + if (dev->irq != 0) { + irq_mask = wv_irq_to_psa(dev->irq); + + if (irq_mask == 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_WARNING + "%s: wavelan_config(): invalid IRQ %d ignored.\n", + dev->name, dev->irq); +#endif + dev->irq = 0; + } else { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG + "%s: wavelan_config(): changing IRQ to %d\n", + dev->name, dev->irq); +#endif + psa_write(ioaddr, HACR_DEFAULT, + psaoff(0, psa_int_req_no), &irq_mask, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, HACR_DEFAULT); + wv_hacr_reset(ioaddr); + } + } + + psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), + &irq_mask, 1); + if ((irq = wv_psa_to_irq(irq_mask)) == -1) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO + "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", + dev->name, irq_mask); +#endif + err = -EAGAIN; + goto out; + } + + dev->irq = irq; + + dev->mem_start = 0x0000; + dev->mem_end = 0x0000; + dev->if_port = 0; + + /* Initialize device structures */ + memset(netdev_priv(dev), 0, sizeof(net_local)); + lp = netdev_priv(dev); + + /* Back link to the device structure. */ + lp->dev = dev; + /* Add the device at the beginning of the linked list. */ + lp->next = wavelan_list; + wavelan_list = lp; + + lp->hacr = HACR_DEFAULT; + + /* Multicast stuff */ + lp->promiscuous = 0; + lp->mc_count = 0; + + /* Init spinlock */ + spin_lock_init(&lp->spinlock); + + dev->netdev_ops = &wavelan_netdev_ops; + dev->watchdog_timeo = WATCHDOG_JIFFIES; + dev->wireless_handlers = &wavelan_handler_def; + lp->wireless_data.spy_data = &lp->spy_data; + dev->wireless_data = &lp->wireless_data; + + dev->mtu = WAVELAN_MTU; + + /* Display nice information. */ + wv_init_info(dev); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); +#endif + return 0; +out: + release_region(ioaddr, sizeof(ha_t)); + return err; +} + +/*------------------------------------------------------------------*/ +/* + * Check for a network adaptor of this type. Return '0' iff one + * exists. There seem to be different interpretations of + * the initial value of dev->base_addr. + * We follow the example in drivers/net/ne.c. + * (called in "Space.c") + */ +struct net_device * __init wavelan_probe(int unit) +{ + struct net_device *dev; + short base_addr; + int def_irq; + int i; + int r = 0; + + /* compile-time check the sizes of structures */ + BUILD_BUG_ON(sizeof(psa_t) != PSA_SIZE); + BUILD_BUG_ON(sizeof(mmw_t) != MMW_SIZE); + BUILD_BUG_ON(sizeof(mmr_t) != MMR_SIZE); + BUILD_BUG_ON(sizeof(ha_t) != HA_SIZE); + + dev = alloc_etherdev(sizeof(net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + base_addr = dev->base_addr; + def_irq = dev->irq; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG + "%s: ->wavelan_probe(dev=%p (base_addr=0x%x))\n", + dev->name, dev, (unsigned int) dev->base_addr); +#endif + + /* Don't probe at all. */ + if (base_addr < 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_WARNING + "%s: wavelan_probe(): invalid base address\n", + dev->name); +#endif + r = -ENXIO; + } else if (base_addr > 0x100) { /* Check a single specified location. */ + r = wavelan_config(dev, base_addr); +#ifdef DEBUG_CONFIG_INFO + if (r != 0) + printk(KERN_DEBUG + "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n", + dev->name, base_addr); +#endif + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); +#endif + } else { /* Scan all possible addresses of the WaveLAN hardware. */ + for (i = 0; i < ARRAY_SIZE(iobase); i++) { + dev->irq = def_irq; + if (wavelan_config(dev, iobase[i]) == 0) { +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG + "%s: <-wavelan_probe()\n", + dev->name); +#endif + break; + } + } + if (i == ARRAY_SIZE(iobase)) + r = -ENODEV; + } + if (r) + goto out; + r = register_netdev(dev); + if (r) + goto out1; + return dev; +out1: + release_region(dev->base_addr, sizeof(ha_t)); + wavelan_list = wavelan_list->next; +out: + free_netdev(dev); + return ERR_PTR(r); +} + +/****************************** MODULE ******************************/ +/* + * Module entry point: insertion and removal + */ + +#ifdef MODULE +/*------------------------------------------------------------------*/ +/* + * Insertion of the module + * I'm now quite proud of the multi-device support. + */ +int __init init_module(void) +{ + int ret = -EIO; /* Return error if no cards found */ + int i; + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "-> init_module()\n"); +#endif + + /* If probing is asked */ + if (io[0] == 0) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_WARNING + "WaveLAN init_module(): doing device probing (bad !)\n"); + printk(KERN_WARNING + "Specify base addresses while loading module to correct the problem\n"); +#endif + + /* Copy the basic set of address to be probed. */ + for (i = 0; i < ARRAY_SIZE(iobase); i++) + io[i] = iobase[i]; + } + + + /* Loop on all possible base addresses. */ + for (i = 0; i < ARRAY_SIZE(io) && io[i] != 0; i++) { + struct net_device *dev = alloc_etherdev(sizeof(net_local)); + if (!dev) + break; + if (name[i]) + strcpy(dev->name, name[i]); /* Copy name */ + dev->base_addr = io[i]; + dev->irq = irq[i]; + + /* Check if there is something at this base address. */ + if (wavelan_config(dev, io[i]) == 0) { + if (register_netdev(dev) != 0) { + release_region(dev->base_addr, sizeof(ha_t)); + wavelan_list = wavelan_list->next; + } else { + ret = 0; + continue; + } + } + free_netdev(dev); + } + +#ifdef DEBUG_CONFIG_ERROR + if (!wavelan_list) + printk(KERN_WARNING + "WaveLAN init_module(): no device found\n"); +#endif + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "<- init_module()\n"); +#endif + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Removal of the module + */ +void cleanup_module(void) +{ +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "-> cleanup_module()\n"); +#endif + + /* Loop on all devices and release them. */ + while (wavelan_list) { + struct net_device *dev = wavelan_list->dev; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG + "%s: cleanup_module(): removing device at 0x%x\n", + dev->name, (unsigned int) dev); +#endif + unregister_netdev(dev); + + release_region(dev->base_addr, sizeof(ha_t)); + wavelan_list = wavelan_list->next; + + free_netdev(dev); + } + +#ifdef DEBUG_MODULE_TRACE + printk(KERN_DEBUG "<- cleanup_module()\n"); +#endif +} +#endif /* MODULE */ +MODULE_LICENSE("GPL"); + +/* + * This software may only be used and distributed + * according to the terms of the GNU General Public License. + * + * This software was developed as a component of the + * Linux operating system. + * It is based on other device drivers and information + * either written or supplied by: + * Ajay Bakre (bakre@paul.rutgers.edu), + * Donald Becker (becker@scyld.com), + * Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com), + * Anders Klemets (klemets@it.kth.se), + * Vladimir V. Kolpakov (w@stier.koenig.ru), + * Marc Meertens (Marc.Meertens@Utrecht.NCR.com), + * Pauline Middelink (middelin@polyware.iaf.nl), + * Robert Morris (rtm@das.harvard.edu), + * Jean Tourrilhes (jt@hplb.hpl.hp.com), + * Girish Welling (welling@paul.rutgers.edu), + * + * Thanks go also to: + * James Ashton (jaa101@syseng.anu.edu.au), + * Alan Cox (alan@lxorguk.ukuu.org.uk), + * Allan Creighton (allanc@cs.usyd.edu.au), + * Matthew Geier (matthew@cs.usyd.edu.au), + * Remo di Giovanni (remo@cs.usyd.edu.au), + * Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de), + * Vipul Gupta (vgupta@cs.binghamton.edu), + * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), + * Tim Nicholson (tim@cs.usyd.edu.au), + * Ian Parkin (ian@cs.usyd.edu.au), + * John Rosenberg (johnr@cs.usyd.edu.au), + * George Rossi (george@phm.gov.au), + * Arthur Scott (arthur@cs.usyd.edu.au), + * Peter Storey, + * for their assistance and advice. + * + * Please send bug reports, updates, comments to: + * + * Bruce Janson Email: bruce@cs.usyd.edu.au + * Basser Department of Computer Science Phone: +61-2-9351-3423 + * University of Sydney, N.S.W., 2006, AUSTRALIA Fax: +61-2-9351-3838 + */ diff --git a/drivers/staging/wavelan/wavelan.h b/drivers/staging/wavelan/wavelan.h new file mode 100644 index 000000000000..9ab360558ffd --- /dev/null +++ b/drivers/staging/wavelan/wavelan.h @@ -0,0 +1,370 @@ +/* + * WaveLAN ISA driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * Original copyright follows. See wavelan.p.h for details. + * + * This file contains the declarations for the WaveLAN hardware. Note that + * the WaveLAN ISA includes a i82586 controller (see definitions in + * file i82586.h). + * + * The main difference between the ISA hardware and the PCMCIA one is + * the Ethernet controller (i82586 instead of i82593). + * The i82586 allows multiple transmit buffers. The PSA needs to be accessed + * through the host interface. + */ + +#ifndef _WAVELAN_H +#define _WAVELAN_H + +/************************** MAGIC NUMBERS ***************************/ + +/* Detection of the WaveLAN card is done by reading the MAC + * address from the card and checking it. If you have a non-AT&T + * product (OEM, like DEC RoamAbout, Digital Ocean, or Epson), + * you might need to modify this part to accommodate your hardware. + */ +static const char MAC_ADDRESSES[][3] = +{ + { 0x08, 0x00, 0x0E }, /* AT&T WaveLAN (standard) & DEC RoamAbout */ + { 0x08, 0x00, 0x6A }, /* AT&T WaveLAN (alternate) */ + { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ + { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ + /* Add your card here and send me the patch! */ +}; + +#define WAVELAN_ADDR_SIZE 6 /* Size of a MAC address */ + +#define WAVELAN_MTU 1500 /* Maximum size of WaveLAN packet */ + +#define MAXDATAZ (WAVELAN_ADDR_SIZE + WAVELAN_ADDR_SIZE + 2 + WAVELAN_MTU) + +/* + * Constants used to convert channels to frequencies + */ + +/* Frequency available in the 2.0 modem, in units of 250 kHz + * (as read in the offset register of the dac area). + * Used to map channel numbers used by `wfreqsel' to frequencies + */ +static const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, + 0xD0, 0xF0, 0xF8, 0x150 }; + +/* Frequencies of the 1.0 modem (fixed frequencies). + * Use to map the PSA `subband' to a frequency + * Note : all frequencies apart from the first one need to be multiplied by 10 + */ +static const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; + + + +/*************************** PC INTERFACE ****************************/ + +/* + * Host Adaptor structure. + * (base is board port address). + */ +typedef union hacs_u hacs_u; +union hacs_u +{ + unsigned short hu_command; /* Command register */ +#define HACR_RESET 0x0001 /* Reset board */ +#define HACR_CA 0x0002 /* Set Channel Attention for 82586 */ +#define HACR_16BITS 0x0004 /* 16-bit operation (0 => 8bits) */ +#define HACR_OUT0 0x0008 /* General purpose output pin 0 */ + /* not used - must be 1 */ +#define HACR_OUT1 0x0010 /* General purpose output pin 1 */ + /* not used - must be 1 */ +#define HACR_82586_INT_ENABLE 0x0020 /* Enable 82586 interrupts */ +#define HACR_MMC_INT_ENABLE 0x0040 /* Enable MMC interrupts */ +#define HACR_INTR_CLR_ENABLE 0x0080 /* Enable interrupt status read/clear */ + unsigned short hu_status; /* Status Register */ +#define HASR_82586_INTR 0x0001 /* Interrupt request from 82586 */ +#define HASR_MMC_INTR 0x0002 /* Interrupt request from MMC */ +#define HASR_MMC_BUSY 0x0004 /* MMC busy indication */ +#define HASR_PSA_BUSY 0x0008 /* LAN parameter storage area busy */ +} __attribute__ ((packed)); + +typedef struct ha_t ha_t; +struct ha_t +{ + hacs_u ha_cs; /* Command and status registers */ +#define ha_command ha_cs.hu_command +#define ha_status ha_cs.hu_status + unsigned short ha_mmcr; /* Modem Management Ctrl Register */ + unsigned short ha_pior0; /* Program I/O Address Register Port 0 */ + unsigned short ha_piop0; /* Program I/O Port 0 */ + unsigned short ha_pior1; /* Program I/O Address Register Port 1 */ + unsigned short ha_piop1; /* Program I/O Port 1 */ + unsigned short ha_pior2; /* Program I/O Address Register Port 2 */ + unsigned short ha_piop2; /* Program I/O Port 2 */ +}; + +#define HA_SIZE 16 + +#define hoff(p,f) (unsigned short)((void *)(&((ha_t *)((void *)0 + (p)))->f) - (void *)0) +#define HACR(p) hoff(p, ha_command) +#define HASR(p) hoff(p, ha_status) +#define MMCR(p) hoff(p, ha_mmcr) +#define PIOR0(p) hoff(p, ha_pior0) +#define PIOP0(p) hoff(p, ha_piop0) +#define PIOR1(p) hoff(p, ha_pior1) +#define PIOP1(p) hoff(p, ha_piop1) +#define PIOR2(p) hoff(p, ha_pior2) +#define PIOP2(p) hoff(p, ha_piop2) + +/* + * Program I/O Mode Register values. + */ +#define STATIC_PIO 0 /* Mode 1: static mode */ + /* RAM access ??? */ +#define AUTOINCR_PIO 1 /* Mode 2: auto increment mode */ + /* RAM access ??? */ +#define AUTODECR_PIO 2 /* Mode 3: auto decrement mode */ + /* RAM access ??? */ +#define PARAM_ACCESS_PIO 3 /* Mode 4: LAN parameter access mode */ + /* Parameter access. */ +#define PIO_MASK 3 /* register mask */ +#define PIOM(cmd,piono) ((u_short)cmd << 10 << (piono * 2)) + +#define HACR_DEFAULT (HACR_OUT0 | HACR_OUT1 | HACR_16BITS | PIOM(STATIC_PIO, 0) | PIOM(AUTOINCR_PIO, 1) | PIOM(PARAM_ACCESS_PIO, 2)) +#define HACR_INTRON (HACR_82586_INT_ENABLE | HACR_MMC_INT_ENABLE | HACR_INTR_CLR_ENABLE) + +/************************** MEMORY LAYOUT **************************/ + +/* + * Onboard 64 k RAM layout. + * (Offsets from 0x0000.) + */ +#define OFFSET_RU 0x0000 /* 75% memory */ +#define OFFSET_CU 0xC000 /* 25% memory */ +#define OFFSET_SCB (OFFSET_ISCP - sizeof(scb_t)) +#define OFFSET_ISCP (OFFSET_SCP - sizeof(iscp_t)) +#define OFFSET_SCP I82586_SCP_ADDR + +#define RXBLOCKZ (sizeof(fd_t) + sizeof(rbd_t) + MAXDATAZ) +#define TXBLOCKZ (sizeof(ac_tx_t) + sizeof(ac_nop_t) + sizeof(tbd_t) + MAXDATAZ) + +#define NRXBLOCKS ((OFFSET_CU - OFFSET_RU) / RXBLOCKZ) +#define NTXBLOCKS ((OFFSET_SCB - OFFSET_CU) / TXBLOCKZ) + +/********************** PARAMETER STORAGE AREA **********************/ + +/* + * Parameter Storage Area (PSA). + */ +typedef struct psa_t psa_t; +struct psa_t +{ + unsigned char psa_io_base_addr_1; /* [0x00] Base address 1 ??? */ + unsigned char psa_io_base_addr_2; /* [0x01] Base address 2 */ + unsigned char psa_io_base_addr_3; /* [0x02] Base address 3 */ + unsigned char psa_io_base_addr_4; /* [0x03] Base address 4 */ + unsigned char psa_rem_boot_addr_1; /* [0x04] Remote Boot Address 1 */ + unsigned char psa_rem_boot_addr_2; /* [0x05] Remote Boot Address 2 */ + unsigned char psa_rem_boot_addr_3; /* [0x06] Remote Boot Address 3 */ + unsigned char psa_holi_params; /* [0x07] HOst Lan Interface (HOLI) Parameters */ + unsigned char psa_int_req_no; /* [0x08] Interrupt Request Line */ + unsigned char psa_unused0[7]; /* [0x09-0x0F] unused */ + + unsigned char psa_univ_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x10-0x15] Universal (factory) MAC Address */ + unsigned char psa_local_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x16-1B] Local MAC Address */ + unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */ +#define PSA_UNIVERSAL 0 /* Universal (factory) */ +#define PSA_LOCAL 1 /* Local */ + unsigned char psa_comp_number; /* [0x1D] Compatibility Number: */ +#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ +#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ +#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ +#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ +#define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */ + unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ + unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */ +#define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */ + unsigned char psa_subband; /* [0x20] Subband */ +#define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */ +#define PSA_SUBBAND_2425 1 /* 2425 MHz */ +#define PSA_SUBBAND_2460 2 /* 2460 MHz */ +#define PSA_SUBBAND_2484 3 /* 2484 MHz */ +#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ + unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */ + unsigned char psa_mod_delay; /* [0x22] Modem Delay (?) (reserved) */ + unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */ + unsigned char psa_nwid_select; /* [0x25] Network ID Select On/Off */ + unsigned char psa_encryption_select; /* [0x26] Encryption On/Off */ + unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ + unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */ + unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ + unsigned char psa_nwid_prefix[2]; /* [0x38-0x39] Roaming domain */ + unsigned char psa_reserved[2]; /* [0x3A-0x3B] Reserved - fixed 00 */ + unsigned char psa_conf_status; /* [0x3C] Conf Status, bit 0=1:config*/ + unsigned char psa_crc[2]; /* [0x3D] CRC-16 over PSA */ + unsigned char psa_crc_status; /* [0x3F] CRC Valid Flag */ +}; + +#define PSA_SIZE 64 + +/* Calculate offset of a field in the above structure. + * Warning: only even addresses are used. */ +#define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL)) + +/******************** MODEM MANAGEMENT INTERFACE ********************/ + +/* + * Modem Management Controller (MMC) write structure. + */ +typedef struct mmw_t mmw_t; +struct mmw_t +{ + unsigned char mmw_encr_key[8]; /* encryption key */ + unsigned char mmw_encr_enable; /* Enable or disable encryption. */ +#define MMW_ENCR_ENABLE_MODE 0x02 /* mode of security option */ +#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option. */ + unsigned char mmw_unused0[1]; /* unused */ + unsigned char mmw_des_io_invert; /* encryption option */ +#define MMW_DES_IO_INVERT_RES 0x0F /* reserved */ +#define MMW_DES_IO_INVERT_CTRL 0xF0 /* control (?) (set to 0) */ + unsigned char mmw_unused1[5]; /* unused */ + unsigned char mmw_loopt_sel; /* looptest selection */ +#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* Disable NWID filtering. */ +#define MMW_LOOPT_SEL_INT 0x20 /* Activate Attention Request. */ +#define MMW_LOOPT_SEL_LS 0x10 /* looptest, no collision avoidance */ +#define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */ +#define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */ +#define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */ +#define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */ + unsigned char mmw_jabber_enable; /* jabber timer enable */ + /* Abort transmissions > 200 ms */ + unsigned char mmw_freeze; /* freeze or unfreeze signal level */ + /* 0 : signal level & qual updated for every new message, 1 : frozen */ + unsigned char mmw_anten_sel; /* antenna selection */ +#define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */ +#define MMW_ANTEN_SEL_ALG_EN 0x02 /* antenna selection algo. enable */ + unsigned char mmw_ifs; /* inter frame spacing */ + /* min time between transmission in bit periods (.5 us) - bit 0 ignored */ + unsigned char mmw_mod_delay; /* modem delay (synchro) */ + unsigned char mmw_jam_time; /* jamming time (after collision) */ + unsigned char mmw_unused2[1]; /* unused */ + unsigned char mmw_thr_pre_set; /* level threshold preset */ + /* Discard all packet with signal < this value (4) */ + unsigned char mmw_decay_prm; /* decay parameters */ + unsigned char mmw_decay_updat_prm; /* decay update parameters */ + unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ + /* Discard all packet with quality < this value (3) */ + unsigned char mmw_netw_id_l; /* NWID low order byte */ + unsigned char mmw_netw_id_h; /* NWID high order byte */ + /* Network ID or Domain : create virtual net on the air */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmw_mode_select; /* for analog tests (set to 0) */ + unsigned char mmw_unused3[1]; /* unused */ + unsigned char mmw_fee_ctrl; /* frequency EEPROM control */ +#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions. */ +#define MMW_FEE_CTRL_DWLD 0x08 /* Download EEPROM to mmc. */ +#define MMW_FEE_CTRL_CMD 0x07 /* EEPROM commands: */ +#define MMW_FEE_CTRL_READ 0x06 /* Read */ +#define MMW_FEE_CTRL_WREN 0x04 /* Write enable */ +#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address. */ +#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses. */ +#define MMW_FEE_CTRL_WDS 0x04 /* Write disable */ +#define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */ +#define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */ +#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers. */ +#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write address in protect register */ +#define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */ + /* Never issue the PRDS command: it's irreversible! */ + + unsigned char mmw_fee_addr; /* EEPROM address */ +#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel. */ +#define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */ +#define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */ +#define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */ +#define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */ +#define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */ + + unsigned char mmw_fee_data_l; /* Write data to EEPROM. */ + unsigned char mmw_fee_data_h; /* high octet */ + unsigned char mmw_ext_ant; /* Setting for external antenna */ +#define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */ +#define MMW_EXT_ANT_POL 0x02 /* Polarity of the antenna */ +#define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ +#define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ +#define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ +} __attribute__ ((packed)); + +#define MMW_SIZE 37 + +#define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) + +/* + * Modem Management Controller (MMC) read structure. + */ +typedef struct mmr_t mmr_t; +struct mmr_t +{ + unsigned char mmr_unused0[8]; /* unused */ + unsigned char mmr_des_status; /* encryption status */ + unsigned char mmr_des_avail; /* encryption available (0x55 read) */ +#define MMR_DES_AVAIL_DES 0x55 /* DES available */ +#define MMR_DES_AVAIL_AES 0x33 /* AES (AT&T) available */ + unsigned char mmr_des_io_invert; /* des I/O invert register */ + unsigned char mmr_unused1[5]; /* unused */ + unsigned char mmr_dce_status; /* DCE status */ +#define MMR_DCE_STATUS_RX_BUSY 0x01 /* receiver busy */ +#define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ +#define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ +#define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ +#define MMR_DCE_STATUS 0x0F /* mask to get the bits */ + unsigned char mmr_dsp_id; /* DSP ID (AA = Daedalus rev A) */ + unsigned char mmr_unused2[2]; /* unused */ + unsigned char mmr_correct_nwid_l; /* # of correct NWIDs rxd (low) */ + unsigned char mmr_correct_nwid_h; /* # of correct NWIDs rxd (high) */ + /* Warning: read high-order octet first! */ + unsigned char mmr_wrong_nwid_l; /* # of wrong NWIDs rxd (low) */ + unsigned char mmr_wrong_nwid_h; /* # of wrong NWIDs rxd (high) */ + unsigned char mmr_thr_pre_set; /* level threshold preset */ +#define MMR_THR_PRE_SET 0x3F /* level threshold preset */ +#define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */ + unsigned char mmr_signal_lvl; /* signal level */ +#define MMR_SIGNAL_LVL 0x3F /* signal level */ +#define MMR_SIGNAL_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_silence_lvl; /* silence level (noise) */ +#define MMR_SILENCE_LVL 0x3F /* silence level */ +#define MMR_SILENCE_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_sgnl_qual; /* signal quality */ +#define MMR_SGNL_QUAL 0x0F /* signal quality */ +#define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */ + unsigned char mmr_netw_id_l; /* NWID low order byte (?) */ + unsigned char mmr_unused3[3]; /* unused */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmr_fee_status; /* Status of frequency EEPROM */ +#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision ID */ +#define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */ +#define MMR_FEE_STATUS_BUSY 0x04 /* EEPROM busy */ + unsigned char mmr_unused4[1]; /* unused */ + unsigned char mmr_fee_data_l; /* Read data from EEPROM (low) */ + unsigned char mmr_fee_data_h; /* Read data from EEPROM (high) */ +} __attribute__ ((packed)); + +#define MMR_SIZE 36 + +#define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) + +/* Make the two above structures one */ +typedef union mm_t +{ + struct mmw_t w; /* Write to the mmc */ + struct mmr_t r; /* Read from the mmc */ +} mm_t; + +#endif /* _WAVELAN_H */ + +/* + * This software may only be used and distributed + * according to the terms of the GNU General Public License. + * + * For more details, see wavelan.c. + */ diff --git a/drivers/staging/wavelan/wavelan.p.h b/drivers/staging/wavelan/wavelan.p.h new file mode 100644 index 000000000000..dbe8de6e5f52 --- /dev/null +++ b/drivers/staging/wavelan/wavelan.p.h @@ -0,0 +1,696 @@ +/* + * WaveLAN ISA driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * + * This file contains all definitions and declarations necessary for the + * WaveLAN ISA driver. This file is a private header, so it should + * be included only in wavelan.c! + */ + +#ifndef WAVELAN_P_H +#define WAVELAN_P_H + +/************************** DOCUMENTATION ***************************/ +/* + * This driver provides a Linux interface to the WaveLAN ISA hardware. + * The WaveLAN is a product of Lucent (http://www.wavelan.com/). + * This division was formerly part of NCR and then AT&T. + * WaveLANs are also distributed by DEC (RoamAbout DS) and Digital Ocean. + * + * To learn how to use this driver, read the NET3 HOWTO. + * If you want to exploit the many other functionalities, read the comments + * in the code. + * + * This driver is the result of the effort of many people (see below). + */ + +/* ------------------------ SPECIFIC NOTES ------------------------ */ +/* + * Web page + * -------- + * I try to maintain a web page with the Wireless LAN Howto at : + * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + * + * SMP + * --- + * We now are SMP compliant (I eventually fixed the remaining bugs). + * The driver has been tested on a dual P6-150 and survived my usual + * set of torture tests. + * Anyway, I spent enough time chasing interrupt re-entrancy during + * errors or reconfigure, and I designed the locked/unlocked sections + * of the driver with great care, and with the recent addition of + * the spinlock (thanks to the new API), we should be quite close to + * the truth. + * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), + * but better safe than sorry (especially at 2 Mb/s ;-). + * + * I have also looked into disabling only our interrupt on the card + * (via HACR) instead of all interrupts in the processor (via cli), + * so that other driver are not impacted, and it look like it's + * possible, but it's very tricky to do right (full of races). As + * the gain would be mostly for SMP systems, it can wait... + * + * Debugging and options + * --------------------- + * You will find below a set of '#define" allowing a very fine control + * on the driver behaviour and the debug messages printed. + * The main options are : + * o SET_PSA_CRC, to have your card correctly recognised by + * an access point and the Point-to-Point diagnostic tool. + * o USE_PSA_CONFIG, to read configuration from the PSA (EEprom) + * (otherwise we always start afresh with some defaults) + * + * wavelan.o is too darned big + * --------------------------- + * That's true! There is a very simple way to reduce the driver + * object by 33%! Comment out the following line: + * #include + * Other compile options can also reduce the size of it... + * + * MAC address and hardware detection: + * ----------------------------------- + * The detection code for the WaveLAN checks that the first three + * octets of the MAC address fit the company code. This type of + * detection works well for AT&T cards (because the AT&T code is + * hardcoded in wavelan.h), but of course will fail for other + * manufacturers. + * + * If you are sure that your card is derived from the WaveLAN, + * here is the way to configure it: + * 1) Get your MAC address + * a) With your card utilities (wfreqsel, instconf, etc.) + * b) With the driver: + * o compile the kernel with DEBUG_CONFIG_INFO enabled + * o Boot and look the card messages + * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h) + * 3) Compile and verify + * 4) Send me the MAC code. I will include it in the next version. + * + */ + +/* --------------------- WIRELESS EXTENSIONS --------------------- */ +/* + * This driver is the first to support "wireless extensions". + * This set of extensions provides a standard way to control the wireless + * characteristics of the hardware. Applications such as mobile IP may + * take advantage of it. + * + * It might be a good idea as well to fetch the wireless tools to + * configure the device and play a bit. + */ + +/* ---------------------------- FILES ---------------------------- */ +/* + * wavelan.c: actual code for the driver: C functions + * + * wavelan.p.h: private header: local types and variables for driver + * + * wavelan.h: description of the hardware interface and structs + * + * i82586.h: description of the Ethernet controller + */ + +/* --------------------------- HISTORY --------------------------- */ +/* + * This is based on information in the drivers' headers. It may not be + * accurate, and I guarantee only my best effort. + * + * The history of the WaveLAN drivers is as complicated as the history of + * the WaveLAN itself (NCR -> AT&T -> Lucent). + * + * It all started with Anders Klemets + * writing a WaveLAN ISA driver for the Mach microkernel. Girish + * Welling had also worked on it. + * Keith Moore modified this for the PCMCIA hardware. + * + * Robert Morris ported these two drivers to BSDI + * and added specific PCMCIA support (there is currently no equivalent + * of the PCMCIA package under BSD). + * + * Jim Binkley ported both BSDI drivers to FreeBSD. + * + * Bruce Janson ported the BSDI ISA driver to Linux. + * + * Anthony D. Joseph started to modify Bruce's driver + * (with help of the BSDI PCMCIA driver) for PCMCIA. + * Yunzhou Li finished this work. + * Joe Finney patched the driver to start + * 2.00 cards correctly (2.4 GHz with frequency selection). + * David Hinds integrated the whole in his + * PCMCIA package (and bug corrections). + * + * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some + * patches to the PCMCIA driver. Later, I added code in the ISA driver + * for Wireless Extensions and full support of frequency selection + * cards. Then, I did the same to the PCMCIA driver, and did some + * reorganisation. Finally, I came back to the ISA driver to + * upgrade it at the same level as the PCMCIA one and reorganise + * the code. + * Loeke Brederveld from Lucent has given me + * much needed information on the WaveLAN hardware. + */ + +/* The original copyrights and literature mention others' names and + * credits. I don't know what their part in this development was. + */ + +/* By the way, for the copyright and legal stuff: + * almost everybody wrote code under the GNU or BSD license (or similar), + * and want their original copyright to remain somewhere in the + * code (for myself, I go with the GPL). + * Nobody wants to take responsibility for anything, except the fame. + */ + +/* --------------------------- CREDITS --------------------------- */ +/* + * This software was developed as a component of the + * Linux operating system. + * It is based on other device drivers and information + * either written or supplied by: + * Ajay Bakre , + * Donald Becker , + * Loeke Brederveld , + * Brent Elphick , + * Anders Klemets , + * Vladimir V. Kolpakov , + * Marc Meertens , + * Pauline Middelink , + * Robert Morris , + * Jean Tourrilhes , + * Girish Welling , + * Clark Woodworth + * Yongguang Zhang + * + * Thanks go also to: + * James Ashton , + * Alan Cox , + * Allan Creighton , + * Matthew Geier , + * Remo di Giovanni , + * Eckhard Grah , + * Vipul Gupta , + * Mark Hagan , + * Tim Nicholson , + * Ian Parkin , + * John Rosenberg , + * George Rossi , + * Arthur Scott , + * Stanislav Sinyagin + * and Peter Storey for their assistance and advice. + * + * Additional Credits: + * + * My development has been done initially under Debian 1.1 (Linux 2.0.x) + * and now under Debian 2.2, initially with an HP Vectra XP/60, and now + * an HP Vectra XP/90. + * + */ + +/* ------------------------- IMPROVEMENTS ------------------------- */ +/* + * I proudly present: + * + * Changes made in first pre-release: + * ---------------------------------- + * - reorganisation of the code, function name change + * - creation of private header (wavelan.p.h) + * - reorganised debug messages + * - more comments, history, etc. + * - mmc_init: configure the PSA if not done + * - mmc_init: correct default value of level threshold for PCMCIA + * - mmc_init: 2.00 detection better code for 2.00 initialization + * - better info at startup + * - IRQ setting (note: this setting is permanent) + * - watchdog: change strategy (and solve module removal problems) + * - add wireless extensions (ioctl and get_wireless_stats) + * get/set nwid/frequency on fly, info for /proc/net/wireless + * - more wireless extensions: SETSPY and GETSPY + * - make wireless extensions optional + * - private ioctl to set/get quality and level threshold, histogram + * - remove /proc/net/wavelan + * - suppress useless stuff from lp (net_local) + * - kernel 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) + * - add message level (debug stuff in /var/adm/debug and errors not + * displayed at console and still in /var/adm/messages) + * - multi device support + * - start fixing the probe (init code) + * - more inlines + * - man page + * - many other minor details and cleanups + * + * Changes made in second pre-release: + * ----------------------------------- + * - clean up init code (probe and module init) + * - better multiple device support (module) + * - name assignment (module) + * + * Changes made in third pre-release: + * ---------------------------------- + * - be more conservative on timers + * - preliminary support for multicast (I still lack some details) + * + * Changes made in fourth pre-release: + * ----------------------------------- + * - multicast (revisited and finished) + * - avoid reset in set_multicast_list (a really big hack) + * if somebody could apply this code for other i82586 based drivers + * - share onboard memory 75% RU and 25% CU (instead of 50/50) + * + * Changes made for release in 2.1.15: + * ----------------------------------- + * - change the detection code for multi manufacturer code support + * + * Changes made for release in 2.1.17: + * ----------------------------------- + * - update to wireless extensions changes + * - silly bug in card initial configuration (psa_conf_status) + * + * Changes made for release in 2.1.27 & 2.0.30: + * -------------------------------------------- + * - small bug in debug code (probably not the last one...) + * - remove extern keyword for wavelan_probe() + * - level threshold is now a standard wireless extension (version 4 !) + * - modules parameters types (new module interface) + * + * Changes made for release in 2.1.36: + * ----------------------------------- + * - byte count stats (courtesy of David Hinds) + * - remove dev_tint stuff (courtesy of David Hinds) + * - encryption setting from Brent Elphick (thanks a lot!) + * - 'ioaddr' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) + * + * Other changes (not by me) : + * ------------------------- + * - Spelling and gramar "rectification". + * + * Changes made for release in 2.0.37 & 2.2.2 : + * ------------------------------------------ + * - Correct status in /proc/net/wireless + * - Set PSA CRC to make PtP diagnostic tool happy (Bob Gray) + * - Module init code don't fail if we found at least one card in + * the address list (Karlis Peisenieks) + * - Missing parenthesis (Christopher Peterson) + * - Correct i82586 configuration parameters + * - Encryption initialisation bug (Robert McCormack) + * - New mac addresses detected in the probe + * - Increase watchdog for busy environments + * + * Changes made for release in 2.0.38 & 2.2.7 : + * ------------------------------------------ + * - Correct the reception logic to better report errors and avoid + * sending bogus packet up the stack + * - Delay RU config to avoid corrupting first received packet + * - Change config completion code (to actually check something) + * - Avoid reading out of bound in skbuf to transmit + * - Rectify a lot of (useless) debugging code + * - Change the way to `#ifdef SET_PSA_CRC' + * + * Changes made for release in 2.2.11 & 2.3.13 : + * ------------------------------------------- + * - Change e-mail and web page addresses + * - Watchdog timer is now correctly expressed in HZ, not in jiffies + * - Add channel number to the list of frequencies in range + * - Add the (short) list of bit-rates in range + * - Developp a new sensitivity... (sens.value & sens.fixed) + * + * Changes made for release in 2.2.14 & 2.3.23 : + * ------------------------------------------- + * - Fix check for root permission (break instead of exit) + * - New nwid & encoding setting (Wireless Extension 9) + * + * Changes made for release in 2.3.49 : + * ---------------------------------- + * - Indentation reformating (Alan) + * - Update to new network API (softnet - 2.3.43) : + * o replace dev->tbusy (Alan) + * o replace dev->tstart (Alan) + * o remove dev->interrupt (Alan) + * o add SMP locking via spinlock in splxx (me) + * o add spinlock in interrupt handler (me) + * o use kernel watchdog instead of ours (me) + * o increase watchdog timeout (kernel is more sensitive) (me) + * o verify that all the changes make sense and work (me) + * - Fixup a potential gotcha when reconfiguring and thighten a bit + * the interactions with Tx queue. + * + * Changes made for release in 2.4.0 : + * --------------------------------- + * - Fix spinlock stupid bugs that I left in. The driver is now SMP + * compliant and doesn't lockup at startup. + * + * Changes made for release in 2.5.2 : + * --------------------------------- + * - Use new driver API for Wireless Extensions : + * o got rid of wavelan_ioctl() + * o use a bunch of iw_handler instead + * + * Changes made for release in 2.5.35 : + * ---------------------------------- + * - Set dev->trans_start to avoid filling the logs + * - Handle better spurious/bogus interrupt + * - Avoid deadlocks in mmc_out()/mmc_in() + * + * Wishes & dreams: + * ---------------- + * - roaming (see Pcmcia driver) + */ + +/***************************** INCLUDES *****************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* Wireless extensions */ +#include /* Wireless handlers */ + +/* WaveLAN declarations */ +#include "i82586.h" +#include "wavelan.h" + +/************************** DRIVER OPTIONS **************************/ +/* + * `#define' or `#undef' the following constant to change the behaviour + * of the driver... + */ +#undef SET_PSA_CRC /* Calculate and set the CRC on PSA (slower) */ +#define USE_PSA_CONFIG /* Use info from the PSA. */ +#undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */ +#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ +#undef SET_MAC_ADDRESS /* Experimental */ + +/* Warning: this stuff will slow down the driver. */ +#define WIRELESS_SPY /* Enable spying addresses. */ +#undef HISTOGRAM /* Enable histogram of signal level. */ + +/****************************** DEBUG ******************************/ + +#undef DEBUG_MODULE_TRACE /* module insertion/removal */ +#undef DEBUG_CALLBACK_TRACE /* calls made by Linux */ +#undef DEBUG_INTERRUPT_TRACE /* calls to handler */ +#undef DEBUG_INTERRUPT_INFO /* type of interrupt and so on */ +#define DEBUG_INTERRUPT_ERROR /* problems */ +#undef DEBUG_CONFIG_TRACE /* Trace the config functions. */ +#undef DEBUG_CONFIG_INFO /* what's going on */ +#define DEBUG_CONFIG_ERROR /* errors on configuration */ +#undef DEBUG_TX_TRACE /* transmission calls */ +#undef DEBUG_TX_INFO /* header of the transmitted packet */ +#undef DEBUG_TX_FAIL /* Normal failure conditions */ +#define DEBUG_TX_ERROR /* Unexpected conditions */ +#undef DEBUG_RX_TRACE /* transmission calls */ +#undef DEBUG_RX_INFO /* header of the received packet */ +#undef DEBUG_RX_FAIL /* Normal failure conditions */ +#define DEBUG_RX_ERROR /* Unexpected conditions */ + +#undef DEBUG_PACKET_DUMP /* Dump packet on the screen if defined to 32. */ +#undef DEBUG_IOCTL_TRACE /* misc. call by Linux */ +#undef DEBUG_IOCTL_INFO /* various debugging info */ +#define DEBUG_IOCTL_ERROR /* what's going wrong */ +#define DEBUG_BASIC_SHOW /* Show basic startup info. */ +#undef DEBUG_VERSION_SHOW /* Print version info. */ +#undef DEBUG_PSA_SHOW /* Dump PSA to screen. */ +#undef DEBUG_MMC_SHOW /* Dump mmc to screen. */ +#undef DEBUG_SHOW_UNUSED /* Show unused fields too. */ +#undef DEBUG_I82586_SHOW /* Show i82586 status. */ +#undef DEBUG_DEVICE_SHOW /* Show device parameters. */ + +/************************ CONSTANTS & MACROS ************************/ + +#ifdef DEBUG_VERSION_SHOW +static const char *version = "wavelan.c : v24 (SMP + wireless extensions) 11/12/01\n"; +#endif + +/* Watchdog temporisation */ +#define WATCHDOG_JIFFIES (512*HZ/100) + +/* ------------------------ PRIVATE IOCTL ------------------------ */ + +#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ +#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ + +#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 2 /* Set histogram ranges */ +#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 3 /* Get histogram values */ + +/****************************** TYPES ******************************/ + +/* Shortcuts */ +typedef struct iw_statistics iw_stats; +typedef struct iw_quality iw_qual; +typedef struct iw_freq iw_freq;typedef struct net_local net_local; +typedef struct timer_list timer_list; + +/* Basic types */ +typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ + +/* + * Static specific data for the interface. + * + * For each network interface, Linux keeps data in two structures: "device" + * keeps the generic data (same format for everybody) and "net_local" keeps + * additional specific data. + */ +struct net_local +{ + net_local * next; /* linked list of the devices */ + struct net_device * dev; /* reverse link */ + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ + int nresets; /* number of hardware resets */ + u_char reconfig_82586; /* We need to reconfigure the controller. */ + u_char promiscuous; /* promiscuous mode */ + int mc_count; /* number of multicast addresses */ + u_short hacr; /* current host interface state */ + + int tx_n_in_use; + u_short rx_head; + u_short rx_last; + u_short tx_first_free; + u_short tx_first_in_use; + + iw_stats wstats; /* Wireless-specific statistics */ + + struct iw_spy_data spy_data; + struct iw_public_data wireless_data; + +#ifdef HISTOGRAM + int his_number; /* number of intervals */ + u_char his_range[16]; /* boundaries of interval ]n-1; n] */ + u_long his_sum[16]; /* sum in interval */ +#endif /* HISTOGRAM */ +}; + +/**************************** PROTOTYPES ****************************/ + +/* ----------------------- MISC. SUBROUTINES ------------------------ */ +static u_char + wv_irq_to_psa(int); +static int + wv_psa_to_irq(u_char); +/* ------------------- HOST ADAPTER SUBROUTINES ------------------- */ +static inline u_short /* data */ + hasr_read(u_long); /* Read the host interface: base address */ +static inline void + hacr_write(u_long, /* Write to host interface: base address */ + u_short), /* data */ + hacr_write_slow(u_long, + u_short), + set_chan_attn(u_long, /* ioaddr */ + u_short), /* hacr */ + wv_hacr_reset(u_long), /* ioaddr */ + wv_16_off(u_long, /* ioaddr */ + u_short), /* hacr */ + wv_16_on(u_long, /* ioaddr */ + u_short), /* hacr */ + wv_ints_off(struct net_device *), + wv_ints_on(struct net_device *); +/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ +static void + psa_read(u_long, /* Read the Parameter Storage Area. */ + u_short, /* hacr */ + int, /* offset in PSA */ + u_char *, /* buffer to fill */ + int), /* size to read */ + psa_write(u_long, /* Write to the PSA. */ + u_short, /* hacr */ + int, /* offset in PSA */ + u_char *, /* buffer in memory */ + int); /* length of buffer */ +static inline void + mmc_out(u_long, /* Write 1 byte to the Modem Manag Control. */ + u_short, + u_char), + mmc_write(u_long, /* Write n bytes to the MMC. */ + u_char, + u_char *, + int); +static inline u_char /* Read 1 byte from the MMC. */ + mmc_in(u_long, + u_short); +static inline void + mmc_read(u_long, /* Read n bytes from the MMC. */ + u_char, + u_char *, + int), + fee_wait(u_long, /* Wait for frequency EEPROM: base address */ + int, /* base delay to wait for */ + int); /* time to wait */ +static void + fee_read(u_long, /* Read the frequency EEPROM: base address */ + u_short, /* destination offset */ + u_short *, /* data buffer */ + int); /* number of registers */ +/* ---------------------- I82586 SUBROUTINES ----------------------- */ +static /*inline*/ void + obram_read(u_long, /* ioaddr */ + u_short, /* o */ + u_char *, /* b */ + int); /* n */ +static inline void + obram_write(u_long, /* ioaddr */ + u_short, /* o */ + u_char *, /* b */ + int); /* n */ +static void + wv_ack(struct net_device *); +static inline int + wv_synchronous_cmd(struct net_device *, + const char *), + wv_config_complete(struct net_device *, + u_long, + net_local *); +static int + wv_complete(struct net_device *, + u_long, + net_local *); +static inline void + wv_82586_reconfig(struct net_device *); +/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ +#ifdef DEBUG_I82586_SHOW +static void + wv_scb_show(unsigned short); +#endif +static inline void + wv_init_info(struct net_device *); /* display startup info */ +/* ------------------- IOCTL, STATS & RECONFIG ------------------- */ +static iw_stats * + wavelan_get_wireless_stats(struct net_device *); +static void + wavelan_set_multicast_list(struct net_device *); +/* ----------------------- PACKET RECEPTION ----------------------- */ +static inline void + wv_packet_read(struct net_device *, /* Read a packet from a frame. */ + u_short, + int), + wv_receive(struct net_device *); /* Read all packets waiting. */ +/* --------------------- PACKET TRANSMISSION --------------------- */ +static inline int + wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer. */ + void *, + short); +static netdev_tx_t + wavelan_packet_xmit(struct sk_buff *, /* Send a packet. */ + struct net_device *); +/* -------------------- HARDWARE CONFIGURATION -------------------- */ +static inline int + wv_mmc_init(struct net_device *), /* Initialize the modem. */ + wv_ru_start(struct net_device *), /* Start the i82586 receiver unit. */ + wv_cu_start(struct net_device *), /* Start the i82586 command unit. */ + wv_82586_start(struct net_device *); /* Start the i82586. */ +static void + wv_82586_config(struct net_device *); /* Configure the i82586. */ +static inline void + wv_82586_stop(struct net_device *); +static int + wv_hw_reset(struct net_device *), /* Reset the WaveLAN hardware. */ + wv_check_ioaddr(u_long, /* ioaddr */ + u_char *); /* mac address (read) */ +/* ---------------------- INTERRUPT HANDLING ---------------------- */ +static irqreturn_t + wavelan_interrupt(int, /* interrupt handler */ + void *); +static void + wavelan_watchdog(struct net_device *); /* transmission watchdog */ +/* ------------------- CONFIGURATION CALLBACKS ------------------- */ +static int + wavelan_open(struct net_device *), /* Open the device. */ + wavelan_close(struct net_device *), /* Close the device. */ + wavelan_config(struct net_device *, unsigned short);/* Configure one device. */ +extern struct net_device *wavelan_probe(int unit); /* See Space.c. */ + +/**************************** VARIABLES ****************************/ + +/* + * This is the root of the linked list of WaveLAN drivers + * It is use to verify that we don't reuse the same base address + * for two different drivers and to clean up when removing the module. + */ +static net_local * wavelan_list = (net_local *) NULL; + +/* + * This table is used to translate the PSA value to IRQ number + * and vice versa. + */ +static u_char irqvals[] = +{ + 0, 0, 0, 0x01, + 0x02, 0x04, 0, 0x08, + 0, 0, 0x10, 0x20, + 0x40, 0, 0, 0x80, +}; + +/* + * Table of the available I/O addresses (base addresses) for WaveLAN + */ +static unsigned short iobase[] = +{ +#if 0 + /* Leave out 0x3C0 for now -- seems to clash with some video + * controllers. + * Leave out the others too -- we will always use 0x390 and leave + * 0x300 for the Ethernet device. + * Jean II: 0x3E0 is fine as well. + */ + 0x300, 0x390, 0x3E0, 0x3C0 +#endif /* 0 */ + 0x390, 0x3E0 +}; + +#ifdef MODULE +/* Parameters set by insmod */ +static int io[4]; +static int irq[4]; +static char *name[4]; +module_param_array(io, int, NULL, 0); +module_param_array(irq, int, NULL, 0); +module_param_array(name, charp, NULL, 0); + +MODULE_PARM_DESC(io, "WaveLAN I/O base address(es),required"); +MODULE_PARM_DESC(irq, "WaveLAN IRQ number(s)"); +MODULE_PARM_DESC(name, "WaveLAN interface neme(s)"); +#endif /* MODULE */ + +#endif /* WAVELAN_P_H */ diff --git a/drivers/staging/wavelan/wavelan_cs.c b/drivers/staging/wavelan/wavelan_cs.c new file mode 100644 index 000000000000..431a20ec6db6 --- /dev/null +++ b/drivers/staging/wavelan/wavelan_cs.c @@ -0,0 +1,4635 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * Original copyright follow. See wavelan_cs.p.h for details. + * + * This code is derived from Anthony D. Joseph's code and all the changes here + * are also under the original copyright below. + * + * This code supports version 2.00 of WaveLAN/PCMCIA cards (2.4GHz), and + * can work on Linux 2.0.36 with support of David Hinds' PCMCIA Card Services + * + * Joe Finney (joe@comp.lancs.ac.uk) at Lancaster University in UK added + * critical code in the routine to initialize the Modem Management Controller. + * + * Thanks to Alan Cox and Bruce Janson for their advice. + * + * -- Yunzhou Li (scip4166@nus.sg) + * +#ifdef WAVELAN_ROAMING + * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu) + * based on patch by Joe Finney from Lancaster University. +#endif + * + * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An + * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor. + * + * A non-shared memory PCMCIA ethernet driver for linux + * + * ISA version modified to support PCMCIA by Anthony Joseph (adj@lcs.mit.edu) + * + * + * Joseph O'Sullivan & John Langford (josullvn@cs.cmu.edu & jcl@cs.cmu.edu) + * + * Apr 2 '98 made changes to bring the i82593 control/int handling in line + * with offical specs... + * + **************************************************************************** + * Copyright 1995 + * Anthony D. Joseph + * Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this program + * for any purpose and without fee is hereby granted, provided + * that this copyright and permission notice appear on all copies + * and supporting documentation, the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * program without specific prior permission, and notice be given + * in supporting documentation that copying and distribution is + * by permission of M.I.T. M.I.T. makes no representations about + * the suitability of this software for any purpose. It is pro- + * vided "as is" without express or implied warranty. + **************************************************************************** + * + */ + +/* Do *NOT* add other headers here, you are guaranteed to be wrong - Jean II */ +#include "wavelan_cs.p.h" /* Private header */ + +#ifdef WAVELAN_ROAMING +static void wl_cell_expiry(unsigned long data); +static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp); +static void wv_nwid_filter(unsigned char mode, net_local *lp); +#endif /* WAVELAN_ROAMING */ + +/************************* MISC SUBROUTINES **************************/ +/* + * Subroutines which won't fit in one of the following category + * (wavelan modem or i82593) + */ + +/******************* MODEM MANAGEMENT SUBROUTINES *******************/ +/* + * Useful subroutines to manage the modem of the wavelan + */ + +/*------------------------------------------------------------------*/ +/* + * Read from card's Host Adaptor Status Register. + */ +static inline u_char +hasr_read(u_long base) +{ + return(inb(HASR(base))); +} /* hasr_read */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. + */ +static inline void +hacr_write(u_long base, + u_char hacr) +{ + outb(hacr, HACR(base)); +} /* hacr_write */ + +/*------------------------------------------------------------------*/ +/* + * Write to card's Host Adapter Command Register. Include a delay for + * those times when it is needed. + */ +static void +hacr_write_slow(u_long base, + u_char hacr) +{ + hacr_write(base, hacr); + /* delay might only be needed sometimes */ + mdelay(1); +} /* hacr_write_slow */ + +/*------------------------------------------------------------------*/ +/* + * Read the Parameter Storage Area from the WaveLAN card's memory + */ +static void +psa_read(struct net_device * dev, + int o, /* offset in PSA */ + u_char * b, /* buffer to fill */ + int n) /* size to read */ +{ + net_local *lp = netdev_priv(dev); + u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1); + + while(n-- > 0) + { + *b++ = readb(ptr); + /* Due to a lack of address decode pins, the WaveLAN PCMCIA card + * only supports reading even memory addresses. That means the + * increment here MUST be two. + * Because of that, we can't use memcpy_fromio()... + */ + ptr += 2; + } +} /* psa_read */ + +/*------------------------------------------------------------------*/ +/* + * Write the Parameter Storage Area to the WaveLAN card's memory + */ +static void +psa_write(struct net_device * dev, + int o, /* Offset in psa */ + u_char * b, /* Buffer in memory */ + int n) /* Length of buffer */ +{ + net_local *lp = netdev_priv(dev); + u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1); + int count = 0; + unsigned int base = dev->base_addr; + /* As there seem to have no flag PSA_BUSY as in the ISA model, we are + * oblige to verify this address to know when the PSA is ready... */ + volatile u_char __iomem *verify = lp->mem + PSA_ADDR + + (psaoff(0, psa_comp_number) << 1); + + /* Authorize writing to PSA */ + hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN); + + while(n-- > 0) + { + /* write to PSA */ + writeb(*b++, ptr); + ptr += 2; + + /* I don't have the spec, so I don't know what the correct + * sequence to write is. This hack seem to work for me... */ + count = 0; + while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100)) + mdelay(1); + } + + /* Put the host interface back in standard state */ + hacr_write(base, HACR_DEFAULT); +} /* psa_write */ + +#ifdef SET_PSA_CRC +/*------------------------------------------------------------------*/ +/* + * Calculate the PSA CRC + * Thanks to Valster, Nico for the code + * NOTE: By specifying a length including the CRC position the + * returned value should be zero. (i.e. a correct checksum in the PSA) + * + * The Windows drivers don't use the CRC, but the AP and the PtP tool + * depend on it. + */ +static u_short +psa_crc(unsigned char * psa, /* The PSA */ + int size) /* Number of short for CRC */ +{ + int byte_cnt; /* Loop on the PSA */ + u_short crc_bytes = 0; /* Data in the PSA */ + int bit_cnt; /* Loop on the bits of the short */ + + for(byte_cnt = 0; byte_cnt < size; byte_cnt++ ) + { + crc_bytes ^= psa[byte_cnt]; /* Its an xor */ + + for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ ) + { + if(crc_bytes & 0x0001) + crc_bytes = (crc_bytes >> 1) ^ 0xA001; + else + crc_bytes >>= 1 ; + } + } + + return crc_bytes; +} /* psa_crc */ +#endif /* SET_PSA_CRC */ + +/*------------------------------------------------------------------*/ +/* + * update the checksum field in the Wavelan's PSA + */ +static void +update_psa_checksum(struct net_device * dev) +{ +#ifdef SET_PSA_CRC + psa_t psa; + u_short crc; + + /* read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + + /* update the checksum */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1]) + - sizeof(psa.psa_crc_status)); + + psa.psa_crc[0] = crc & 0xFF; + psa.psa_crc[1] = (crc & 0xFF00) >> 8; + + /* Write it ! */ + psa_write(dev, (char *)&psa.psa_crc - (char *)&psa, + (unsigned char *)&psa.psa_crc, 2); + +#ifdef DEBUG_IOCTL_INFO + printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", + dev->name, psa.psa_crc[0], psa.psa_crc[1]); + + /* Check again (luxury !) */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc_status)); + + if(crc != 0) + printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name); +#endif /* DEBUG_IOCTL_INFO */ +#endif /* SET_PSA_CRC */ +} /* update_psa_checksum */ + +/*------------------------------------------------------------------*/ +/* + * Write 1 byte to the MMC. + */ +static void +mmc_out(u_long base, + u_short o, + u_char d) +{ + int count = 0; + + /* Wait for MMC to go idle */ + while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) + udelay(10); + + outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base)); + outb(d, MMD(base)); +} + +/*------------------------------------------------------------------*/ +/* + * Routine to write bytes to the Modem Management Controller. + * We start by the end because it is the way it should be ! + */ +static void +mmc_write(u_long base, + u_char o, + u_char * b, + int n) +{ + o += n; + b += n; + + while(n-- > 0 ) + mmc_out(base, --o, *(--b)); +} /* mmc_write */ + +/*------------------------------------------------------------------*/ +/* + * Read 1 byte from the MMC. + * Optimised version for 1 byte, avoid using memory... + */ +static u_char +mmc_in(u_long base, + u_short o) +{ + int count = 0; + + while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) + udelay(10); + outb(o << 1, MMR(base)); /* Set the read address */ + + outb(0, MMD(base)); /* Required dummy write */ + + while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY)) + udelay(10); + return (u_char) (inb(MMD(base))); /* Now do the actual read */ +} + +/*------------------------------------------------------------------*/ +/* + * Routine to read bytes from the Modem Management Controller. + * The implementation is complicated by a lack of address lines, + * which prevents decoding of the low-order bit. + * (code has just been moved in the above function) + * We start by the end because it is the way it should be ! + */ +static void +mmc_read(u_long base, + u_char o, + u_char * b, + int n) +{ + o += n; + b += n; + + while(n-- > 0) + *(--b) = mmc_in(base, --o); +} /* mmc_read */ + +/*------------------------------------------------------------------*/ +/* + * Get the type of encryption available... + */ +static inline int +mmc_encr(u_long base) /* i/o port of the card */ +{ + int temp; + + temp = mmc_in(base, mmroff(0, mmr_des_avail)); + if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) + return 0; + else + return temp; +} + +/*------------------------------------------------------------------*/ +/* + * Wait for the frequency EEprom to complete a command... + */ +static void +fee_wait(u_long base, /* i/o port of the card */ + int delay, /* Base delay to wait for */ + int number) /* Number of time to wait */ +{ + int count = 0; /* Wait only a limited time */ + + while((count++ < number) && + (mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY)) + udelay(delay); +} + +/*------------------------------------------------------------------*/ +/* + * Read bytes from the Frequency EEprom (frequency select cards). + */ +static void +fee_read(u_long base, /* i/o port of the card */ + u_short o, /* destination offset */ + u_short * b, /* data buffer */ + int n) /* number of registers */ +{ + b += n; /* Position at the end of the area */ + + /* Write the address */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while(n-- > 0) + { + /* Write the read command */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ); + + /* Wait until EEprom is ready (should be quick !) */ + fee_wait(base, 10, 100); + + /* Read the value */ + *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) | + mmc_in(base, mmroff(0, mmr_fee_data_l))); + } +} + + +/*------------------------------------------------------------------*/ +/* + * Write bytes from the Frequency EEprom (frequency select cards). + * This is a bit complicated, because the frequency eeprom has to + * be unprotected and the write enabled. + * Jean II + */ +static void +fee_write(u_long base, /* i/o port of the card */ + u_short o, /* destination offset */ + u_short * b, /* data buffer */ + int n) /* number of registers */ +{ + b += n; /* Position at the end of the area */ + +#ifdef EEPROM_IS_PROTECTED /* disabled */ +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* Ask to read the protected register */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); + + fee_wait(base, 10, 100); + + /* Read the protected register */ + printk("Protected 2 : %02X-%02X\n", + mmc_in(base, mmroff(0, mmr_fee_data_h)), + mmc_in(base, mmroff(0, mmr_fee_data_l))); +#endif /* DOESNT_SEEM_TO_WORK */ + + /* Enable protected register */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); + + fee_wait(base, 10, 100); + + /* Unprotect area */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); +#ifdef DOESNT_SEEM_TO_WORK /* disabled */ + /* Or use : */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); +#endif /* DOESNT_SEEM_TO_WORK */ + + fee_wait(base, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ + + /* Write enable */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); + + fee_wait(base, 10, 100); + + /* Write the EEprom address */ + mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while(n-- > 0) + { + /* Write the value */ + mmc_out(base, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); + mmc_out(base, mmwoff(0, mmw_fee_data_l), *b & 0xFF); + + /* Write the write command */ + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE); + + /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */ + mdelay(10); + fee_wait(base, 10, 100); + } + + /* Write disable */ + mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); + + fee_wait(base, 10, 100); + +#ifdef EEPROM_IS_PROTECTED /* disabled */ + /* Reprotect EEprom */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x00); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); + + fee_wait(base, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ +} + +/******************* WaveLAN Roaming routines... ********************/ + +#ifdef WAVELAN_ROAMING /* Conditional compile, see wavelan_cs.h */ + +static unsigned char WAVELAN_BEACON_ADDRESS[] = {0x09,0x00,0x0e,0x20,0x03,0x00}; + +static void wv_roam_init(struct net_device *dev) +{ + net_local *lp= netdev_priv(dev); + + /* Do not remove this unless you have a good reason */ + printk(KERN_NOTICE "%s: Warning, you have enabled roaming on" + " device %s !\n", dev->name, dev->name); + printk(KERN_NOTICE "Roaming is currently an experimental unsupported feature" + " of the Wavelan driver.\n"); + printk(KERN_NOTICE "It may work, but may also make the driver behave in" + " erratic ways or crash.\n"); + + lp->wavepoint_table.head=NULL; /* Initialise WavePoint table */ + lp->wavepoint_table.num_wavepoints=0; + lp->wavepoint_table.locked=0; + lp->curr_point=NULL; /* No default WavePoint */ + lp->cell_search=0; + + lp->cell_timer.data=(long)lp; /* Start cell expiry timer */ + lp->cell_timer.function=wl_cell_expiry; + lp->cell_timer.expires=jiffies+CELL_TIMEOUT; + add_timer(&lp->cell_timer); + + wv_nwid_filter(NWID_PROMISC,lp) ; /* Enter NWID promiscuous mode */ + /* to build up a good WavePoint */ + /* table... */ + printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name); +} + +static void wv_roam_cleanup(struct net_device *dev) +{ + wavepoint_history *ptr,*old_ptr; + net_local *lp= netdev_priv(dev); + + printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name); + + /* Fixme : maybe we should check that the timer exist before deleting it */ + del_timer(&lp->cell_timer); /* Remove cell expiry timer */ + ptr=lp->wavepoint_table.head; /* Clear device's WavePoint table */ + while(ptr!=NULL) + { + old_ptr=ptr; + ptr=ptr->next; + wl_del_wavepoint(old_ptr,lp); + } +} + +/* Enable/Disable NWID promiscuous mode on a given device */ +static void wv_nwid_filter(unsigned char mode, net_local *lp) +{ + mm_t m; + unsigned long flags; + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name); +#endif + + /* Disable interrupts & save flags */ + spin_lock_irqsave(&lp->spinlock, flags); + + m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; + mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); + + if(mode==NWID_PROMISC) + lp->cell_search=1; + else + lp->cell_search=0; + + /* ReEnable interrupts & restore flags */ + spin_unlock_irqrestore(&lp->spinlock, flags); +} + +/* Find a record in the WavePoint table matching a given NWID */ +static wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp) +{ + wavepoint_history *ptr=lp->wavepoint_table.head; + + while(ptr!=NULL){ + if(ptr->nwid==nwid) + return ptr; + ptr=ptr->next; + } + return NULL; +} + +/* Create a new wavepoint table entry */ +static wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp) +{ + wavepoint_history *new_wavepoint; + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: New Wavepoint, NWID:%.4X\n",nwid); +#endif + + if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS) + return NULL; + + new_wavepoint = kmalloc(sizeof(wavepoint_history),GFP_ATOMIC); + if(new_wavepoint==NULL) + return NULL; + + new_wavepoint->nwid=nwid; /* New WavePoints NWID */ + new_wavepoint->average_fast=0; /* Running Averages..*/ + new_wavepoint->average_slow=0; + new_wavepoint->qualptr=0; /* Start of ringbuffer */ + new_wavepoint->last_seq=seq-1; /* Last sequence no.seen */ + memset(new_wavepoint->sigqual,0,WAVEPOINT_HISTORY);/* Empty ringbuffer */ + + new_wavepoint->next=lp->wavepoint_table.head;/* Add to wavepoint table */ + new_wavepoint->prev=NULL; + + if(lp->wavepoint_table.head!=NULL) + lp->wavepoint_table.head->prev=new_wavepoint; + + lp->wavepoint_table.head=new_wavepoint; + + lp->wavepoint_table.num_wavepoints++; /* no. of visible wavepoints */ + + return new_wavepoint; +} + +/* Remove a wavepoint entry from WavePoint table */ +static void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp) +{ + if(wavepoint==NULL) + return; + + if(lp->curr_point==wavepoint) + lp->curr_point=NULL; + + if(wavepoint->prev!=NULL) + wavepoint->prev->next=wavepoint->next; + + if(wavepoint->next!=NULL) + wavepoint->next->prev=wavepoint->prev; + + if(lp->wavepoint_table.head==wavepoint) + lp->wavepoint_table.head=wavepoint->next; + + lp->wavepoint_table.num_wavepoints--; + kfree(wavepoint); +} + +/* Timer callback function - checks WavePoint table for stale entries */ +static void wl_cell_expiry(unsigned long data) +{ + net_local *lp=(net_local *)data; + wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point; + +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: Wavepoint timeout, dev %s\n",lp->dev->name); +#endif + + if(lp->wavepoint_table.locked) + { +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: Wavepoint table locked...\n"); +#endif + + lp->cell_timer.expires=jiffies+1; /* If table in use, come back later */ + add_timer(&lp->cell_timer); + return; + } + + while(wavepoint!=NULL) + { + if(time_after(jiffies, wavepoint->last_seen + CELL_TIMEOUT)) + { +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid); +#endif + + old_point=wavepoint; + wavepoint=wavepoint->next; + wl_del_wavepoint(old_point,lp); + } + else + wavepoint=wavepoint->next; + } + lp->cell_timer.expires=jiffies+CELL_TIMEOUT; + add_timer(&lp->cell_timer); +} + +/* Update SNR history of a wavepoint */ +static void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq) +{ + int i=0,num_missed=0,ptr=0; + int average_fast=0,average_slow=0; + + num_missed=(seq-wavepoint->last_seq)%WAVEPOINT_HISTORY;/* Have we missed + any beacons? */ + if(num_missed) + for(i=0;isigqual[wavepoint->qualptr++]=0; /* If so, enter them as 0's */ + wavepoint->qualptr %=WAVEPOINT_HISTORY; /* in the ringbuffer. */ + } + wavepoint->last_seen=jiffies; /* Add beacon to history */ + wavepoint->last_seq=seq; + wavepoint->sigqual[wavepoint->qualptr++]=sigqual; + wavepoint->qualptr %=WAVEPOINT_HISTORY; + ptr=(wavepoint->qualptr-WAVEPOINT_FAST_HISTORY+WAVEPOINT_HISTORY)%WAVEPOINT_HISTORY; + + for(i=0;isigqual[ptr++]; + ptr %=WAVEPOINT_HISTORY; + } + + average_slow=average_fast; + for(i=WAVEPOINT_FAST_HISTORY;isigqual[ptr++]; + ptr %=WAVEPOINT_HISTORY; + } + + wavepoint->average_fast=average_fast/WAVEPOINT_FAST_HISTORY; + wavepoint->average_slow=average_slow/WAVEPOINT_HISTORY; +} + +/* Perform a handover to a new WavePoint */ +static void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) +{ + unsigned int base = lp->dev->base_addr; + mm_t m; + unsigned long flags; + + if(wavepoint==lp->curr_point) /* Sanity check... */ + { + wv_nwid_filter(!NWID_PROMISC,lp); + return; + } + +#ifdef WAVELAN_ROAMING_DEBUG + printk(KERN_DEBUG "WaveLAN: Doing handover to %.4X, dev %s\n",wavepoint->nwid,lp->dev->name); +#endif + + /* Disable interrupts & save flags */ + spin_lock_irqsave(&lp->spinlock, flags); + + m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; + m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; + + mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); + + /* ReEnable interrupts & restore flags */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + wv_nwid_filter(!NWID_PROMISC,lp); + lp->curr_point=wavepoint; +} + +/* Called when a WavePoint beacon is received */ +static void wl_roam_gather(struct net_device * dev, + u_char * hdr, /* Beacon header */ + u_char * stats) /* SNR, Signal quality + of packet */ +{ + wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */ + unsigned short nwid=ntohs(beacon->nwid); + unsigned short sigqual=stats[2] & MMR_SGNL_QUAL; /* SNR of beacon */ + wavepoint_history *wavepoint=NULL; /* WavePoint table entry */ + net_local *lp = netdev_priv(dev); /* Device info */ + +#ifdef I_NEED_THIS_FEATURE + /* Some people don't need this, some other may need it */ + nwid=nwid^ntohs(beacon->domain_id); +#endif + +#if WAVELAN_ROAMING_DEBUG > 1 + printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name); + printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual); +#endif + + lp->wavepoint_table.locked=1; /* */ + + wavepoint=wl_roam_check(nwid,lp); /* Find WavePoint table entry */ + if(wavepoint==NULL) /* If no entry, Create a new one... */ + { + wavepoint=wl_new_wavepoint(nwid,beacon->seq,lp); + if(wavepoint==NULL) + goto out; + } + if(lp->curr_point==NULL) /* If this is the only WavePoint, */ + wv_roam_handover(wavepoint, lp); /* Jump on it! */ + + wl_update_history(wavepoint, sigqual, beacon->seq); /* Update SNR history + stats. */ + + if(lp->curr_point->average_slow < SEARCH_THRESH_LOW) /* If our current */ + if(!lp->cell_search) /* WavePoint is getting faint, */ + wv_nwid_filter(NWID_PROMISC,lp); /* start looking for a new one */ + + if(wavepoint->average_slow > + lp->curr_point->average_slow + WAVELAN_ROAMING_DELTA) + wv_roam_handover(wavepoint, lp); /* Handover to a better WavePoint */ + + if(lp->curr_point->average_slow > SEARCH_THRESH_HIGH) /* If our SNR is */ + if(lp->cell_search) /* getting better, drop out of cell search mode */ + wv_nwid_filter(!NWID_PROMISC,lp); + +out: + lp->wavepoint_table.locked=0; /* :-) */ +} + +/* Test this MAC frame a WavePoint beacon */ +static inline int WAVELAN_BEACON(unsigned char *data) +{ + wavepoint_beacon *beacon= (wavepoint_beacon *)data; + static const wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00}; + + if(memcmp(beacon,&beacon_template,9)==0) + return 1; + else + return 0; +} +#endif /* WAVELAN_ROAMING */ + +/************************ I82593 SUBROUTINES *************************/ +/* + * Useful subroutines to manage the Ethernet controller + */ + +/*------------------------------------------------------------------*/ +/* + * Routine to synchronously send a command to the i82593 chip. + * Should be called with interrupts disabled. + * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(), + * wv_82593_config() & wv_diag()) + */ +static int +wv_82593_cmd(struct net_device * dev, + char * str, + int cmd, + int result) +{ + unsigned int base = dev->base_addr; + int status; + int wait_completed; + long spin; + + /* Spin until the chip finishes executing its current command (if any) */ + spin = 1000; + do + { + /* Time calibration of the loop */ + udelay(10); + + /* Read the interrupt register */ + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + } + while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); + + /* If the interrupt hasn't been posted */ + if (spin < 0) { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n", + str, status); +#endif + return(FALSE); + } + + /* Issue the command to the controller */ + outb(cmd, LCCR(base)); + + /* If we don't have to check the result of the command + * Note : this mean that the irq handler will deal with that */ + if(result == SR0_NO_RESULT) + return(TRUE); + + /* We are waiting for command completion */ + wait_completed = TRUE; + + /* Busy wait while the LAN controller executes the command. */ + spin = 1000; + do + { + /* Time calibration of the loop */ + udelay(10); + + /* Read the interrupt register */ + outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); + status = inb(LCSR(base)); + + /* Check if there was an interrupt posted */ + if((status & SR0_INTERRUPT)) + { + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + + /* Check if interrupt is a command completion */ + if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) && + ((status & SR0_BOTH_RX_TX) != 0x0) && + !(status & SR0_RECEPTION)) + { + /* Signal command completion */ + wait_completed = FALSE; + } + else + { + /* Note : Rx interrupts will be handled later, because we can + * handle multiple Rx packets at once */ +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_INFO "wv_82593_cmd: not our interrupt\n"); +#endif + } + } + } + while(wait_completed && (spin-- > 0)); + + /* If the interrupt hasn't be posted */ + if(wait_completed) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n", + str, status); +#endif + return(FALSE); + } + + /* Check the return code returned by the card (see above) against + * the expected return code provided by the caller */ + if((status & SR0_EVENT_MASK) != result) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n", + str, status); +#endif + return(FALSE); + } + + return(TRUE); +} /* wv_82593_cmd */ + +/*------------------------------------------------------------------*/ +/* + * This routine does a 593 op-code number 7, and obtains the diagnose + * status for the WaveLAN. + */ +static inline int +wv_diag(struct net_device * dev) +{ + return(wv_82593_cmd(dev, "wv_diag(): diagnose", + OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED)); +} /* wv_diag */ + +/*------------------------------------------------------------------*/ +/* + * Routine to read len bytes from the i82593's ring buffer, starting at + * chip address addr. The results read from the chip are stored in buf. + * The return value is the address to use for next the call. + */ +static int +read_ringbuf(struct net_device * dev, + int addr, + char * buf, + int len) +{ + unsigned int base = dev->base_addr; + int ring_ptr = addr; + int chunk_len; + char * buf_ptr = buf; + + /* Get all the buffer */ + while(len > 0) + { + /* Position the Program I/O Register at the ring buffer pointer */ + outb(ring_ptr & 0xff, PIORL(base)); + outb(((ring_ptr >> 8) & PIORH_MASK), PIORH(base)); + + /* First, determine how much we can read without wrapping around the + ring buffer */ + if((addr + len) < (RX_BASE + RX_SIZE)) + chunk_len = len; + else + chunk_len = RX_BASE + RX_SIZE - addr; + insb(PIOP(base), buf_ptr, chunk_len); + buf_ptr += chunk_len; + len -= chunk_len; + ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE; + } + return(ring_ptr); +} /* read_ringbuf */ + +/*------------------------------------------------------------------*/ +/* + * Reconfigure the i82593, or at least ask for it... + * Because wv_82593_config use the transmission buffer, we must do it + * when we are sure that there is no transmission, so we do it now + * or in wavelan_packet_xmit() (I can't find any better place, + * wavelan_interrupt is not an option...), so you may experience + * some delay sometime... + */ +static void +wv_82593_reconfig(struct net_device * dev) +{ + net_local * lp = netdev_priv(dev); + struct pcmcia_device * link = lp->link; + unsigned long flags; + + /* Arm the flag, will be cleard in wv_82593_config() */ + lp->reconfig_82593 = TRUE; + + /* Check if we can do it now ! */ + if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev))) + { + spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ + wv_82593_config(dev); + spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ + } + else + { +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG + "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n", + dev->name, dev->state, link->open); +#endif + } +} + +/********************* DEBUG & INFO SUBROUTINES *********************/ +/* + * This routines are used in the code to show debug informations. + * Most of the time, it dump the content of hardware structures... + */ + +#ifdef DEBUG_PSA_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted contents of the Parameter Storage Area. + */ +static void +wv_psa_show(psa_t * p) +{ + printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); + printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", + p->psa_io_base_addr_1, + p->psa_io_base_addr_2, + p->psa_io_base_addr_3, + p->psa_io_base_addr_4); + printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", + p->psa_rem_boot_addr_1, + p->psa_rem_boot_addr_2, + p->psa_rem_boot_addr_3); + printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); + printk("psa_int_req_no: %d\n", p->psa_int_req_no); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); + printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); + printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); + printk("psa_comp_number: %d, ", p->psa_comp_number); + printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); + printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", + p->psa_feature_select); + printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); + printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); + printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); + printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]); + printk("psa_nwid_select: %d\n", p->psa_nwid_select); + printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select); + printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_encryption_key[0], + p->psa_encryption_key[1], + p->psa_encryption_key[2], + p->psa_encryption_key[3], + p->psa_encryption_key[4], + p->psa_encryption_key[5], + p->psa_encryption_key[6], + p->psa_encryption_key[7]); + printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); + printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", + p->psa_call_code[0]); + printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_call_code[0], + p->psa_call_code[1], + p->psa_call_code[2], + p->psa_call_code[3], + p->psa_call_code[4], + p->psa_call_code[5], + p->psa_call_code[6], + p->psa_call_code[7]); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "psa_reserved[]: %02X:%02X\n", + p->psa_reserved[0], + p->psa_reserved[1]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); + printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); + printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); +} /* wv_psa_show */ +#endif /* DEBUG_PSA_SHOW */ + +#ifdef DEBUG_MMC_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the Modem Management Controller. + * This function need to be completed... + */ +static void +wv_mmc_show(struct net_device * dev) +{ + unsigned int base = dev->base_addr; + net_local * lp = netdev_priv(dev); + mmr_t m; + + /* Basic check */ + if(hasr_read(base) & HASR_NO_CLK) + { + printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n", + dev->name); + return; + } + + spin_lock_irqsave(&lp->spinlock, flags); + + /* Read the mmc */ + mmc_out(base, mmwoff(0, mmw_freeze), 1); + mmc_read(base, 0, (u_char *)&m, sizeof(m)); + mmc_out(base, mmwoff(0, mmw_freeze), 0); + + /* Don't forget to update statistics */ + lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; + + spin_unlock_irqrestore(&lp->spinlock, flags); + + printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused0[0], + m.mmr_unused0[1], + m.mmr_unused0[2], + m.mmr_unused0[3], + m.mmr_unused0[4], + m.mmr_unused0[5], + m.mmr_unused0[6], + m.mmr_unused0[7]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n", + m.mmr_des_avail, m.mmr_des_status); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused1[0], + m.mmr_unused1[1], + m.mmr_unused1[2], + m.mmr_unused1[3], + m.mmr_unused1[4]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", + m.mmr_dce_status, + (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"", + (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? + "loop test indicated," : "", + (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "", + (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? + "jabber timer expired," : ""); + printk(KERN_DEBUG "Dsp ID: %02X\n", + m.mmr_dsp_id); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", + m.mmr_unused2[0], + m.mmr_unused2[1]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", + (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, + (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); + printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", + m.mmr_thr_pre_set & MMR_THR_PRE_SET, + (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below"); + printk(KERN_DEBUG "signal_lvl: %d [%s], ", + m.mmr_signal_lvl & MMR_SIGNAL_LVL, + (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg"); + printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL, + (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update"); + printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, + (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0"); +#ifdef DEBUG_SHOW_UNUSED + printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); +#endif /* DEBUG_SHOW_UNUSED */ +} /* wv_mmc_show */ +#endif /* DEBUG_MMC_SHOW */ + +#ifdef DEBUG_I82593_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the i82593's receive unit. + */ +static void +wv_ru_show(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + + printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n"); + printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop); + /* + * Not implemented yet... + */ + printk("\n"); +} /* wv_ru_show */ +#endif /* DEBUG_I82593_SHOW */ + +#ifdef DEBUG_DEVICE_SHOW +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver. + */ +static void +wv_dev_show(struct net_device * dev) +{ + printk(KERN_DEBUG "dev:"); + printk(" state=%lX,", dev->state); + printk(" trans_start=%ld,", dev->trans_start); + printk(" flags=0x%x,", dev->flags); + printk("\n"); +} /* wv_dev_show */ + +/*------------------------------------------------------------------*/ +/* + * Print the formatted status of the WaveLAN PCMCIA device driver's + * private information. + */ +static void +wv_local_show(struct net_device * dev) +{ + net_local *lp = netdev_priv(dev); + + printk(KERN_DEBUG "local:"); + /* + * Not implemented yet... + */ + printk("\n"); +} /* wv_local_show */ +#endif /* DEBUG_DEVICE_SHOW */ + +#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) +/*------------------------------------------------------------------*/ +/* + * Dump packet header (and content if necessary) on the screen + */ +static void +wv_packet_info(u_char * p, /* Packet to dump */ + int length, /* Length of the packet */ + char * msg1, /* Name of the device */ + char * msg2) /* Name of the function */ +{ + int i; + int maxi; + + printk(KERN_DEBUG "%s: %s(): dest %pM, length %d\n", + msg1, msg2, p, length); + printk(KERN_DEBUG "%s: %s(): src %pM, type 0x%02X%02X\n", + msg1, msg2, &p[6], p[12], p[13]); + +#ifdef DEBUG_PACKET_DUMP + + printk(KERN_DEBUG "data=\""); + + if((maxi = length) > DEBUG_PACKET_DUMP) + maxi = DEBUG_PACKET_DUMP; + for(i = 14; i < maxi; i++) + if(p[i] >= ' ' && p[i] <= '~') + printk(" %c", p[i]); + else + printk("%02X", p[i]); + if(maxi < length) + printk(".."); + printk("\"\n"); + printk(KERN_DEBUG "\n"); +#endif /* DEBUG_PACKET_DUMP */ +} +#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ + +/*------------------------------------------------------------------*/ +/* + * This is the information which is displayed by the driver at startup + * There is a lot of flag to configure it at your will... + */ +static void +wv_init_info(struct net_device * dev) +{ + unsigned int base = dev->base_addr; + psa_t psa; + + /* Read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + +#ifdef DEBUG_PSA_SHOW + wv_psa_show(&psa); +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82593_SHOW + wv_ru_show(dev); +#endif + +#ifdef DEBUG_BASIC_SHOW + /* Now, let's go for the basic stuff */ + printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr %pM", + dev->name, base, dev->irq, dev->dev_addr); + + /* Print current network id */ + if(psa.psa_nwid_select) + printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]); + else + printk(", nwid off"); + + /* If 2.00 card */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + unsigned short freq; + + /* Ask the EEprom to read the frequency from the first area */ + fee_read(base, 0x00 /* 1st area - frequency... */, + &freq, 1); + + /* Print frequency */ + printk(", 2.00, %ld", (freq >> 6) + 2400L); + + /* Hack !!! */ + if(freq & 0x20) + printk(".5"); + } + else + { + printk(", PCMCIA, "); + switch (psa.psa_subband) + { + case PSA_SUBBAND_915: + printk("915"); + break; + case PSA_SUBBAND_2425: + printk("2425"); + break; + case PSA_SUBBAND_2460: + printk("2460"); + break; + case PSA_SUBBAND_2484: + printk("2484"); + break; + case PSA_SUBBAND_2430_5: + printk("2430.5"); + break; + default: + printk("unknown"); + } + } + + printk(" MHz\n"); +#endif /* DEBUG_BASIC_SHOW */ + +#ifdef DEBUG_VERSION_SHOW + /* Print version information */ + printk(KERN_NOTICE "%s", version); +#endif +} /* wv_init_info */ + +/********************* IOCTL, STATS & RECONFIG *********************/ +/* + * We found here routines that are called by Linux on differents + * occasions after the configuration and not for transmitting data + * These may be called when the user use ifconfig, /proc/net/dev + * or wireless extensions + */ + + +/*------------------------------------------------------------------*/ +/* + * Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. + */ + +static void +wavelan_set_multicast_list(struct net_device * dev) +{ + net_local * lp = netdev_priv(dev); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name); +#endif + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", + dev->name, dev->flags, dev->mc_count); +#endif + + if(dev->flags & IFF_PROMISC) + { + /* + * Enable promiscuous mode: receive all packets. + */ + if(!lp->promiscuous) + { + lp->promiscuous = 1; + lp->allmulticast = 0; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + } + } + else + /* If all multicast addresses + * or too much multicast addresses for the hardware filter */ + if((dev->flags & IFF_ALLMULTI) || + (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES)) + { + /* + * Disable promiscuous mode, but active the all multicast mode + */ + if(!lp->allmulticast) + { + lp->promiscuous = 0; + lp->allmulticast = 1; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + } + } + else + /* If there is some multicast addresses to send */ + if(dev->mc_list != (struct dev_mc_list *) NULL) + { + /* + * Disable promiscuous mode, but receive all packets + * in multicast list + */ +#ifdef MULTICAST_AVOID + if(lp->promiscuous || lp->allmulticast || + (dev->mc_count != lp->mc_count)) +#endif + { + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = dev->mc_count; + + wv_82593_reconfig(dev); + } + } + else + { + /* + * Switch to normal mode: disable promiscuous mode and + * clear the multicast list. + */ + if(lp->promiscuous || lp->mc_count == 0) + { + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = 0; + + wv_82593_reconfig(dev); + } + } +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This function doesn't exist... + * (Note : it was a nice way to test the reconfigure stuff...) + */ +#ifdef SET_MAC_ADDRESS +static int +wavelan_set_mac_address(struct net_device * dev, + void * addr) +{ + struct sockaddr * mac = addr; + + /* Copy the address */ + memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); + + /* Reconfig the beast */ + wv_82593_reconfig(dev); + + return 0; +} +#endif /* SET_MAC_ADDRESS */ + + +/*------------------------------------------------------------------*/ +/* + * Frequency setting (for hardware able of it) + * It's a bit complicated and you don't really want to look into it... + */ +static int +wv_set_frequency(u_long base, /* i/o port of the card */ + iw_freq * frequency) +{ + const int BAND_NUM = 10; /* Number of bands */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ +#ifdef DEBUG_IOCTL_INFO + int i; +#endif + + /* Setting by frequency */ + /* Theoritically, you may set any frequency between + * the two limits with a 0.5 MHz precision. In practice, + * I don't want you to have trouble with local + * regulations... */ + if((frequency->e == 1) && + (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8)) + { + freq = ((frequency->m / 10000) - 24000L) / 5; + } + + /* Setting by channel (same as wfreqsel) */ + /* Warning : each channel is 22MHz wide, so some of the channels + * will interfere... */ + if((frequency->e == 0) && + (frequency->m >= 0) && (frequency->m < BAND_NUM)) + { + /* Get frequency offset. */ + freq = channel_bands[frequency->m] >> 1; + } + + /* Verify if the frequency is allowed */ + if(freq != 0L) + { + u_short table[10]; /* Authorized frequency table */ + + /* Read the frequency table */ + fee_read(base, 0x71 /* frequency table */, + table, 10); + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Frequency table :"); + for(i = 0; i < 10; i++) + { + printk(" %04X", + table[i]); + } + printk("\n"); +#endif + + /* Look in the table if the frequency is allowed */ + if(!(table[9 - ((freq - 24) / 16)] & + (1 << ((freq - 24) % 16)))) + return -EINVAL; /* not allowed */ + } + else + return -EINVAL; + + /* If we get a usable frequency */ + if(freq != 0L) + { + unsigned short area[16]; + unsigned short dac[2]; + unsigned short area_verify[16]; + unsigned short dac_verify[2]; + /* Corresponding gain (in the power adjust value table) + * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8 + * & WCIN062D.DOC, page 6.2.9 */ + unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; + int power_band = 0; /* Selected band */ + unsigned short power_adjust; /* Correct value */ + + /* Search for the gain */ + power_band = 0; + while((freq > power_limit[power_band]) && + (power_limit[++power_band] != 0)) + ; + + /* Read the first area */ + fee_read(base, 0x00, + area, 16); + + /* Read the DAC */ + fee_read(base, 0x60, + dac, 2); + + /* Read the new power adjust value */ + fee_read(base, 0x6B - (power_band >> 1), + &power_adjust, 1); + if(power_band & 0x1) + power_adjust >>= 8; + else + power_adjust &= 0xFF; + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); + for(i = 0; i < 16; i++) + { + printk(" %04X", + area[i]); + } + printk("\n"); + + printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", + dac[0], dac[1]); +#endif + + /* Frequency offset (for info only...) */ + area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); + + /* Receiver Principle main divider coefficient */ + area[3] = (freq >> 1) + 2400L - 352L; + area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Transmitter Main divider coefficient */ + area[13] = (freq >> 1) + 2400L; + area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + + /* Others part of the area are flags, bit streams or unused... */ + + /* Set the value in the DAC */ + dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); + dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); + + /* Write the first area */ + fee_write(base, 0x00, + area, 16); + + /* Write the DAC */ + fee_write(base, 0x60, + dac, 2); + + /* We now should verify here that the EEprom writing was ok */ + + /* ReRead the first area */ + fee_read(base, 0x00, + area_verify, 16); + + /* ReRead the DAC */ + fee_read(base, 0x60, + dac_verify, 2); + + /* Compare */ + if(memcmp(area, area_verify, 16 * 2) || + memcmp(dac, dac_verify, 2 * 2)) + { +#ifdef DEBUG_IOCTL_ERROR + printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n"); +#endif + return -EOPNOTSUPP; + } + + /* We must download the frequency parameters to the + * synthetisers (from the EEprom - area 1) + * Note : as the EEprom is auto decremented, we set the end + * if the area... */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + + /* We must now download the power adjust value (gain) to + * the synthetisers (from the EEprom - area 7 - DAC) */ + mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61); + mmc_out(base, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + +#ifdef DEBUG_IOCTL_INFO + /* Verification of what we have done... */ + + printk(KERN_DEBUG "Wavelan EEprom Area 1 :"); + for(i = 0; i < 16; i++) + { + printk(" %04X", + area_verify[i]); + } + printk("\n"); + + printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n", + dac_verify[0], dac_verify[1]); +#endif + + return 0; + } + else + return -EINVAL; /* Bah, never get there... */ +} + +/*------------------------------------------------------------------*/ +/* + * Give the list of available frequencies + */ +static int +wv_frequency_list(u_long base, /* i/o port of the card */ + iw_freq * list, /* List of frequency to fill */ + int max) /* Maximum number of frequencies */ +{ + u_short table[10]; /* Authorized frequency table */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ + int i; /* index in the table */ + const int BAND_NUM = 10; /* Number of bands */ + int c = 0; /* Channel number */ + + /* Read the frequency table */ + fee_read(base, 0x71 /* frequency table */, + table, 10); + + /* Look all frequencies */ + i = 0; + for(freq = 0; freq < 150; freq++) + /* Look in the table if the frequency is allowed */ + if(table[9 - (freq / 16)] & (1 << (freq % 16))) + { + /* Compute approximate channel number */ + while((((channel_bands[c] >> 1) - 24) < freq) && + (c < BAND_NUM)) + c++; + list[i].i = c; /* Set the list index */ + + /* put in the list */ + list[i].m = (((freq + 24) * 5) + 24000L) * 10000; + list[i++].e = 1; + + /* Check number */ + if(i >= max) + return(i); + } + + return(i); +} + +#ifdef IW_WIRELESS_SPY +/*------------------------------------------------------------------*/ +/* + * Gather wireless spy statistics : for each packet, compare the source + * address with out list, and if match, get the stats... + * Sorry, but this function really need wireless extensions... + */ +static inline void +wl_spy_gather(struct net_device * dev, + u_char * mac, /* MAC address */ + u_char * stats) /* Statistics to gather */ +{ + struct iw_quality wstats; + + wstats.qual = stats[2] & MMR_SGNL_QUAL; + wstats.level = stats[0] & MMR_SIGNAL_LVL; + wstats.noise = stats[1] & MMR_SILENCE_LVL; + wstats.updated = 0x7; + + /* Update spy records */ + wireless_spy_update(dev, mac, &wstats); +} +#endif /* IW_WIRELESS_SPY */ + +#ifdef HISTOGRAM +/*------------------------------------------------------------------*/ +/* + * This function calculate an histogram on the signal level. + * As the noise is quite constant, it's like doing it on the SNR. + * We have defined a set of interval (lp->his_range), and each time + * the level goes in that interval, we increment the count (lp->his_sum). + * With this histogram you may detect if one wavelan is really weak, + * or you may also calculate the mean and standard deviation of the level... + */ +static inline void +wl_his_gather(struct net_device * dev, + u_char * stats) /* Statistics to gather */ +{ + net_local * lp = netdev_priv(dev); + u_char level = stats[0] & MMR_SIGNAL_LVL; + int i; + + /* Find the correct interval */ + i = 0; + while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++])) + ; + + /* Increment interval counter */ + (lp->his_sum[i])++; +} +#endif /* HISTOGRAM */ + +static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strncpy(info->driver, "wavelan_cs", sizeof(info->driver)-1); +} + +static const struct ethtool_ops ops = { + .get_drvinfo = wl_get_drvinfo +}; + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get protocol name + */ +static int wavelan_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + strcpy(wrqu->name, "WaveLAN"); + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set NWID + */ +static int wavelan_set_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned int base = dev->base_addr; + net_local *lp = netdev_priv(dev); + psa_t psa; + mm_t m; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set NWID in WaveLAN. */ + if (!wrqu->nwid.disabled) { + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; + psa.psa_nwid_select = 0x01; + psa_write(dev, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + + /* Set NWID in mmc. */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(base, + (char *) &m.w.mmw_netw_id_l - + (char *) &m, + (unsigned char *) &m.w.mmw_netw_id_l, 2); + mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); + } else { + /* Disable NWID in the psa. */ + psa.psa_nwid_select = 0x00; + psa_write(dev, + (char *) &psa.psa_nwid_select - + (char *) &psa, + (unsigned char *) &psa.psa_nwid_select, + 1); + + /* Disable NWID in the mmc (no filtering). */ + mmc_out(base, mmwoff(0, mmw_loopt_sel), + MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get NWID + */ +static int wavelan_get_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = netdev_priv(dev); + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Read the NWID. */ + psa_read(dev, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrqu->nwid.disabled = !(psa.psa_nwid_select); + wrqu->nwid.fixed = 1; /* Superfluous */ + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set frequency + */ +static int wavelan_set_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned int base = dev->base_addr; + net_local *lp = netdev_priv(dev); + unsigned long flags; + int ret; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(base, &(wrqu->freq)); + else + ret = -EOPNOTSUPP; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get frequency + */ +static int wavelan_get_freq(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned int base = dev->base_addr; + net_local *lp = netdev_priv(dev); + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). + * Does it work for everybody, especially old cards? */ + if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(base, 0x00, &freq, 1); + wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrqu->freq.e = 1; + } else { + psa_read(dev, + (char *) &psa.psa_subband - (char *) &psa, + (unsigned char *) &psa.psa_subband, 1); + + if (psa.psa_subband <= 4) { + wrqu->freq.m = fixed_bands[psa.psa_subband]; + wrqu->freq.e = (psa.psa_subband != 0); + } else + ret = -EOPNOTSUPP; + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set level threshold + */ +static int wavelan_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned int base = dev->base_addr; + net_local *lp = netdev_priv(dev); + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Set the level threshold. */ + /* We should complain loudly if wrqu->sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; + psa_write(dev, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_thr_pre_set), + psa.psa_thr_pre_set); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get level threshold + */ +static int wavelan_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = netdev_priv(dev); + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Read the level threshold. */ + psa_read(dev, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; + wrqu->sens.fixed = 1; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set encryption key + */ +static int wavelan_set_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned int base = dev->base_addr; + net_local *lp = netdev_priv(dev); + unsigned long flags; + psa_t psa; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if capable of encryption */ + if (!mmc_encr(base)) { + ret = -EOPNOTSUPP; + } + + /* Check the size of the key */ + if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) { + ret = -EINVAL; + } + + if(!ret) { + /* Basic checking... */ + if (wrqu->encoding.length == 8) { + /* Copy the key in the driver */ + memcpy(psa.psa_encryption_key, extra, + wrqu->encoding.length); + psa.psa_encryption_select = 1; + + psa_write(dev, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 8 + 1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); + mmc_write(base, mmwoff(0, mmw_encr_key), + (unsigned char *) &psa. + psa_encryption_key, 8); + } + + /* disable encryption */ + if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { + psa.psa_encryption_select = 0; + psa_write(dev, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1); + + mmc_out(base, mmwoff(0, mmw_encr_enable), 0); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev); + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get encryption key + */ +static int wavelan_get_encode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned int base = dev->base_addr; + net_local *lp = netdev_priv(dev); + psa_t psa; + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if encryption is available */ + if (!mmc_encr(base)) { + ret = -EOPNOTSUPP; + } else { + /* Read the encryption key */ + psa_read(dev, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1 + 8); + + /* encryption is enabled ? */ + if (psa.psa_encryption_select) + wrqu->encoding.flags = IW_ENCODE_ENABLED; + else + wrqu->encoding.flags = IW_ENCODE_DISABLED; + wrqu->encoding.flags |= mmc_encr(base); + + /* Copy the key to the user buffer */ + wrqu->encoding.length = 8; + memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length); + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +#ifdef WAVELAN_ROAMING_EXT +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set ESSID (domain) + */ +static int wavelan_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = netdev_priv(dev); + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check if disable */ + if(wrqu->data.flags == 0) + lp->filter_domains = 0; + else { + char essid[IW_ESSID_MAX_SIZE + 1]; + char * endp; + + /* Terminate the string */ + memcpy(essid, extra, wrqu->data.length); + essid[IW_ESSID_MAX_SIZE] = '\0'; + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "SetEssid : ``%s''\n", essid); +#endif /* DEBUG_IOCTL_INFO */ + + /* Convert to a number (note : Wavelan specific) */ + lp->domain_id = simple_strtoul(essid, &endp, 16); + /* Has it worked ? */ + if(endp > essid) + lp->filter_domains = 1; + else { + lp->filter_domains = 0; + ret = -EINVAL; + } + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get ESSID (domain) + */ +static int wavelan_get_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = netdev_priv(dev); + + /* Is the domain ID active ? */ + wrqu->data.flags = lp->filter_domains; + + /* Copy Domain ID into a string (Wavelan specific) */ + /* Sound crazy, be we can't have a snprintf in the kernel !!! */ + sprintf(extra, "%lX", lp->domain_id); + extra[IW_ESSID_MAX_SIZE] = '\0'; + + /* Set the length */ + wrqu->data.length = strlen(extra); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set AP address + */ +static int wavelan_set_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "Set AP to : %pM\n", wrqu->ap_addr.sa_data); +#endif /* DEBUG_IOCTL_INFO */ + + return -EOPNOTSUPP; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get AP address + */ +static int wavelan_get_wap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + /* Should get the real McCoy instead of own Ethernet address */ + memcpy(wrqu->ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); + wrqu->ap_addr.sa_family = ARPHRD_ETHER; + + return -EOPNOTSUPP; +} +#endif /* WAVELAN_ROAMING_EXT */ + +#ifdef WAVELAN_ROAMING +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set mode + */ +static int wavelan_set_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = netdev_priv(dev); + unsigned long flags; + int ret = 0; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Check mode */ + switch(wrqu->mode) { + case IW_MODE_ADHOC: + if(do_roaming) { + wv_roam_cleanup(dev); + do_roaming = 0; + } + break; + case IW_MODE_INFRA: + if(!do_roaming) { + wv_roam_init(dev); + do_roaming = 1; + } + break; + default: + ret = -EINVAL; + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get mode + */ +static int wavelan_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + if(do_roaming) + wrqu->mode = IW_MODE_INFRA; + else + wrqu->mode = IW_MODE_ADHOC; + + return 0; +} +#endif /* WAVELAN_ROAMING */ + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get range info + */ +static int wavelan_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned int base = dev->base_addr; + net_local *lp = netdev_priv(dev); + struct iw_range *range = (struct iw_range *) extra; + unsigned long flags; + int ret = 0; + + /* Set the length (very important for backward compatibility) */ + wrqu->data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know about to zero */ + memset(range, 0, sizeof(struct iw_range)); + + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 9; + + /* Set information in the range struct. */ + range->throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ + range->min_nwid = 0x0000; + range->max_nwid = 0xFFFF; + + range->sensitivity = 0x3F; + range->max_qual.qual = MMR_SGNL_QUAL; + range->max_qual.level = MMR_SIGNAL_LVL; + range->max_qual.noise = MMR_SILENCE_LVL; + range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ + /* Need to get better values for those two */ + range->avg_qual.level = 30; + range->avg_qual.noise = 8; + + range->num_bitrates = 1; + range->bitrate[0] = 2000000; /* 2 Mb/s */ + + /* Event capability (kernel + driver) */ + range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) | + IW_EVENT_CAPA_MASK(0x8B04) | + IW_EVENT_CAPA_MASK(0x8B06)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + range->num_channels = 10; + range->num_frequency = wv_frequency_list(base, range->freq, + IW_MAX_FREQUENCIES); + } else + range->num_channels = range->num_frequency = 0; + + /* Encryption supported ? */ + if (mmc_encr(base)) { + range->encoding_size[0] = 8; /* DES = 64 bits key */ + range->num_encoding_sizes = 1; + range->max_encoding_tokens = 1; /* Only one key possible */ + } else { + range->num_encoding_sizes = 0; + range->max_encoding_tokens = 0; + } + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set quality threshold + */ +static int wavelan_set_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned int base = dev->base_addr; + net_local *lp = netdev_priv(dev); + psa_t psa; + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa.psa_quality_thr = *(extra) & 0x0F; + psa_write(dev, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); + mmc_out(base, mmwoff(0, mmw_quality_thr), + psa.psa_quality_thr); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get quality threshold + */ +static int wavelan_get_qthr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = netdev_priv(dev); + psa_t psa; + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + psa_read(dev, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + *(extra) = psa.psa_quality_thr & 0x0F; + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} + +#ifdef WAVELAN_ROAMING +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set roaming + */ +static int wavelan_set_roam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = netdev_priv(dev); + unsigned long flags; + + /* Disable interrupts and save flags. */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Note : should check if user == root */ + if(do_roaming && (*extra)==0) + wv_roam_cleanup(dev); + else if(do_roaming==0 && (*extra)!=0) + wv_roam_init(dev); + + do_roaming = (*extra); + + /* Enable interrupts and restore flags. */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get quality threshold + */ +static int wavelan_get_roam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + *(extra) = do_roaming; + + return 0; +} +#endif /* WAVELAN_ROAMING */ + +#ifdef HISTOGRAM +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : set histogram + */ +static int wavelan_set_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = netdev_priv(dev); + + /* Check the number of intervals. */ + if (wrqu->data.length > 16) { + return(-E2BIG); + } + + /* Disable histo while we copy the addresses. + * As we don't disable interrupts, we need to do this */ + lp->his_number = 0; + + /* Are there ranges to copy? */ + if (wrqu->data.length > 0) { + /* Copy interval ranges to the driver */ + memcpy(lp->his_range, extra, wrqu->data.length); + + { + int i; + printk(KERN_DEBUG "Histo :"); + for(i = 0; i < wrqu->data.length; i++) + printk(" %d", lp->his_range[i]); + printk("\n"); + } + + /* Reset result structure. */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); + } + + /* Now we can set the number of ranges */ + lp->his_number = wrqu->data.length; + + return(0); +} + +/*------------------------------------------------------------------*/ +/* + * Wireless Private Handler : get histogram + */ +static int wavelan_get_histo(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + net_local *lp = netdev_priv(dev); + + /* Set the number of intervals. */ + wrqu->data.length = lp->his_number; + + /* Give back the distribution statistics */ + if(lp->his_number > 0) + memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number); + + return(0); +} +#endif /* HISTOGRAM */ + +/*------------------------------------------------------------------*/ +/* + * Structures to export the Wireless Handlers + */ + +static const struct iw_priv_args wavelan_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, + { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, + { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setroam" }, + { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" }, + { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, + { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, +}; + +static const iw_handler wavelan_handler[] = +{ + NULL, /* SIOCSIWNAME */ + wavelan_get_name, /* SIOCGIWNAME */ + wavelan_set_nwid, /* SIOCSIWNWID */ + wavelan_get_nwid, /* SIOCGIWNWID */ + wavelan_set_freq, /* SIOCSIWFREQ */ + wavelan_get_freq, /* SIOCGIWFREQ */ +#ifdef WAVELAN_ROAMING + wavelan_set_mode, /* SIOCSIWMODE */ + wavelan_get_mode, /* SIOCGIWMODE */ +#else /* WAVELAN_ROAMING */ + NULL, /* SIOCSIWMODE */ + NULL, /* SIOCGIWMODE */ +#endif /* WAVELAN_ROAMING */ + wavelan_set_sens, /* SIOCSIWSENS */ + wavelan_get_sens, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + wavelan_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ +#ifdef WAVELAN_ROAMING_EXT + wavelan_set_wap, /* SIOCSIWAP */ + wavelan_get_wap, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + wavelan_set_essid, /* SIOCSIWESSID */ + wavelan_get_essid, /* SIOCGIWESSID */ +#else /* WAVELAN_ROAMING_EXT */ + NULL, /* SIOCSIWAP */ + NULL, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWESSID */ + NULL, /* SIOCGIWESSID */ +#endif /* WAVELAN_ROAMING_EXT */ + NULL, /* SIOCSIWNICKN */ + NULL, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWRATE */ + NULL, /* SIOCGIWRATE */ + NULL, /* SIOCSIWRTS */ + NULL, /* SIOCGIWRTS */ + NULL, /* SIOCSIWFRAG */ + NULL, /* SIOCGIWFRAG */ + NULL, /* SIOCSIWTXPOW */ + NULL, /* SIOCGIWTXPOW */ + NULL, /* SIOCSIWRETRY */ + NULL, /* SIOCGIWRETRY */ + wavelan_set_encode, /* SIOCSIWENCODE */ + wavelan_get_encode, /* SIOCGIWENCODE */ +}; + +static const iw_handler wavelan_private_handler[] = +{ + wavelan_set_qthr, /* SIOCIWFIRSTPRIV */ + wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */ +#ifdef WAVELAN_ROAMING + wavelan_set_roam, /* SIOCIWFIRSTPRIV + 2 */ + wavelan_get_roam, /* SIOCIWFIRSTPRIV + 3 */ +#else /* WAVELAN_ROAMING */ + NULL, /* SIOCIWFIRSTPRIV + 2 */ + NULL, /* SIOCIWFIRSTPRIV + 3 */ +#endif /* WAVELAN_ROAMING */ +#ifdef HISTOGRAM + wavelan_set_histo, /* SIOCIWFIRSTPRIV + 4 */ + wavelan_get_histo, /* SIOCIWFIRSTPRIV + 5 */ +#endif /* HISTOGRAM */ +}; + +static const struct iw_handler_def wavelan_handler_def = +{ + .num_standard = ARRAY_SIZE(wavelan_handler), + .num_private = ARRAY_SIZE(wavelan_private_handler), + .num_private_args = ARRAY_SIZE(wavelan_private_args), + .standard = wavelan_handler, + .private = wavelan_private_handler, + .private_args = wavelan_private_args, + .get_wireless_stats = wavelan_get_wireless_stats, +}; + +/*------------------------------------------------------------------*/ +/* + * Get wireless statistics + * Called by /proc/net/wireless... + */ +static iw_stats * +wavelan_get_wireless_stats(struct net_device * dev) +{ + unsigned int base = dev->base_addr; + net_local * lp = netdev_priv(dev); + mmr_t m; + iw_stats * wstats; + unsigned long flags; + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); +#endif + + /* Disable interrupts & save flags */ + spin_lock_irqsave(&lp->spinlock, flags); + + wstats = &lp->wstats; + + /* Get data from the mmc */ + mmc_out(base, mmwoff(0, mmw_freeze), 1); + + mmc_read(base, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); + mmc_read(base, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2); + mmc_read(base, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4); + + mmc_out(base, mmwoff(0, mmw_freeze), 0); + + /* Copy data to wireless stuff */ + wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; + wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; + wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; + wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; + wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | + ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | + ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); + wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; + wstats->discard.code = 0L; + wstats->discard.misc = 0L; + + /* ReEnable interrupts & restore flags */ + spin_unlock_irqrestore(&lp->spinlock, flags); + +#ifdef DEBUG_IOCTL_TRACE + printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); +#endif + return &lp->wstats; +} + +/************************* PACKET RECEPTION *************************/ +/* + * This part deal with receiving the packets. + * The interrupt handler get an interrupt when a packet has been + * successfully received and called this part... + */ + +/*------------------------------------------------------------------*/ +/* + * Calculate the starting address of the frame pointed to by the receive + * frame pointer and verify that the frame seem correct + * (called by wv_packet_rcv()) + */ +static int +wv_start_of_frame(struct net_device * dev, + int rfp, /* end of frame */ + int wrap) /* start of buffer */ +{ + unsigned int base = dev->base_addr; + int rp; + int len; + + rp = (rfp - 5 + RX_SIZE) % RX_SIZE; + outb(rp & 0xff, PIORL(base)); + outb(((rp >> 8) & PIORH_MASK), PIORH(base)); + len = inb(PIOP(base)); + len |= inb(PIOP(base)) << 8; + + /* Sanity checks on size */ + /* Frame too big */ + if(len > MAXDATAZ + 100) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: Received frame too large, rfp %d len 0x%x\n", + dev->name, rfp, len); +#endif + return(-1); + } + + /* Frame too short */ + if(len < 7) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: Received null frame, rfp %d len 0x%x\n", + dev->name, rfp, len); +#endif + return(-1); + } + + /* Wrap around buffer */ + if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE)) /* magic formula ! */ + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n", + dev->name, wrap, rfp, len); +#endif + return(-1); + } + + return((rp - len + RX_SIZE) % RX_SIZE); +} /* wv_start_of_frame */ + +/*------------------------------------------------------------------*/ +/* + * This routine does the actual copy of data (including the ethernet + * header structure) from the WaveLAN card to an sk_buff chain that + * will be passed up to the network interface layer. NOTE: We + * currently don't handle trailer protocols (neither does the rest of + * the network interface), so if that is needed, it will (at least in + * part) be added here. The contents of the receive ring buffer are + * copied to a message chain that is then passed to the kernel. + * + * Note: if any errors occur, the packet is "dropped on the floor" + * (called by wv_packet_rcv()) + */ +static void +wv_packet_read(struct net_device * dev, + int fd_p, + int sksize) +{ + net_local * lp = netdev_priv(dev); + struct sk_buff * skb; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", + dev->name, fd_p, sksize); +#endif + + /* Allocate some buffer for the new packet */ + if((skb = dev_alloc_skb(sksize+2)) == (struct sk_buff *) NULL) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n", + dev->name, sksize); +#endif + dev->stats.rx_dropped++; + /* + * Not only do we want to return here, but we also need to drop the + * packet on the floor to clear the interrupt. + */ + return; + } + + skb_reserve(skb, 2); + fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize); + skb->protocol = eth_type_trans(skb, dev); + +#ifdef DEBUG_RX_INFO + wv_packet_info(skb_mac_header(skb), sksize, dev->name, "wv_packet_read"); +#endif /* DEBUG_RX_INFO */ + + /* Statistics gathering & stuff associated. + * It seem a bit messy with all the define, but it's really simple... */ + if( +#ifdef IW_WIRELESS_SPY + (lp->spy_data.spy_number > 0) || +#endif /* IW_WIRELESS_SPY */ +#ifdef HISTOGRAM + (lp->his_number > 0) || +#endif /* HISTOGRAM */ +#ifdef WAVELAN_ROAMING + (do_roaming) || +#endif /* WAVELAN_ROAMING */ + 0) + { + u_char stats[3]; /* Signal level, Noise level, Signal quality */ + + /* read signal level, silence level and signal quality bytes */ + fd_p = read_ringbuf(dev, (fd_p + 4) % RX_SIZE + RX_BASE, + stats, 3); +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", + dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F); +#endif + +#ifdef WAVELAN_ROAMING + if(do_roaming) + if(WAVELAN_BEACON(skb->data)) + wl_roam_gather(dev, skb->data, stats); +#endif /* WAVELAN_ROAMING */ + +#ifdef WIRELESS_SPY + wl_spy_gather(dev, skb_mac_header(skb) + WAVELAN_ADDR_SIZE, stats); +#endif /* WIRELESS_SPY */ +#ifdef HISTOGRAM + wl_his_gather(dev, stats); +#endif /* HISTOGRAM */ + } + + /* + * Hand the packet to the Network Module + */ + netif_rx(skb); + + /* Keep stats up to date */ + dev->stats.rx_packets++; + dev->stats.rx_bytes += sksize; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); +#endif + return; +} + +/*------------------------------------------------------------------*/ +/* + * This routine is called by the interrupt handler to initiate a + * packet transfer from the card to the network interface layer above + * this driver. This routine checks if a buffer has been successfully + * received by the WaveLAN card. If so, the routine wv_packet_read is + * called to do the actual transfer of the card's data including the + * ethernet header into a packet consisting of an sk_buff chain. + * (called by wavelan_interrupt()) + * Note : the spinlock is already grabbed for us and irq are disabled. + */ +static void +wv_packet_rcv(struct net_device * dev) +{ + unsigned int base = dev->base_addr; + net_local * lp = netdev_priv(dev); + int newrfp; + int rp; + int len; + int f_start; + int status; + int i593_rfp; + int stat_ptr; + u_char c[4]; + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_rcv()\n", dev->name); +#endif + + /* Get the new receive frame pointer from the i82593 chip */ + outb(CR0_STATUS_2 | OP0_NOP, LCCR(base)); + i593_rfp = inb(LCSR(base)); + i593_rfp |= inb(LCSR(base)) << 8; + i593_rfp %= RX_SIZE; + + /* Get the new receive frame pointer from the WaveLAN card. + * It is 3 bytes more than the increment of the i82593 receive + * frame pointer, for each packet. This is because it includes the + * 3 roaming bytes added by the mmc. + */ + newrfp = inb(RPLL(base)); + newrfp |= inb(RPLH(base)) << 8; + newrfp %= RX_SIZE; + +#ifdef DEBUG_RX_INFO + printk(KERN_DEBUG "%s: wv_packet_rcv(): i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + +#ifdef DEBUG_RX_ERROR + /* If no new frame pointer... */ + if(lp->overrunning || newrfp == lp->rfp) + printk(KERN_INFO "%s: wv_packet_rcv(): no new frame: i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + dev->name, i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + + /* Read all frames (packets) received */ + while(newrfp != lp->rfp) + { + /* A frame is composed of the packet, followed by a status word, + * the length of the frame (word) and the mmc info (SNR & qual). + * It's because the length is at the end that we can only scan + * frames backward. */ + + /* Find the first frame by skipping backwards over the frames */ + rp = newrfp; /* End of last frame */ + while(((f_start = wv_start_of_frame(dev, rp, newrfp)) != lp->rfp) && + (f_start != -1)) + rp = f_start; + + /* If we had a problem */ + if(f_start == -1) + { +#ifdef DEBUG_RX_ERROR + printk(KERN_INFO "wavelan_cs: cannot find start of frame "); + printk(" i593_rfp %d stop %d newrfp %d lp->rfp %d\n", + i593_rfp, lp->stop, newrfp, lp->rfp); +#endif + lp->rfp = rp; /* Get to the last usable frame */ + continue; + } + + /* f_start point to the beggining of the first frame received + * and rp to the beggining of the next one */ + + /* Read status & length of the frame */ + stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE; + stat_ptr = read_ringbuf(dev, stat_ptr, c, 4); + status = c[0] | (c[1] << 8); + len = c[2] | (c[3] << 8); + + /* Check status */ + if((status & RX_RCV_OK) != RX_RCV_OK) + { + dev->stats.rx_errors++; + if(status & RX_NO_SFD) + dev->stats.rx_frame_errors++; + if(status & RX_CRC_ERR) + dev->stats.rx_crc_errors++; + if(status & RX_OVRRUN) + dev->stats.rx_over_errors++; + +#ifdef DEBUG_RX_FAIL + printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n", + dev->name, status); +#endif + } + else + /* Read the packet and transmit to Linux */ + wv_packet_read(dev, f_start, len - 2); + + /* One frame has been processed, skip it */ + lp->rfp = rp; + } + + /* + * Update the frame stop register, but set it to less than + * the full 8K to allow space for 3 bytes of signal strength + * per packet. + */ + lp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; + outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); + outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); + outb(OP1_SWIT_TO_PORT_0, LCCR(base)); + +#ifdef DEBUG_RX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_rcv()\n", dev->name); +#endif +} + +/*********************** PACKET TRANSMISSION ***********************/ +/* + * This part deal with sending packet through the wavelan + * We copy the packet to the send buffer and then issue the send + * command to the i82593. The result of this operation will be + * checked in wavelan_interrupt() + */ + +/*------------------------------------------------------------------*/ +/* + * This routine fills in the appropriate registers and memory + * locations on the WaveLAN card and starts the card off on + * the transmit. + * (called in wavelan_packet_xmit()) + */ +static void +wv_packet_write(struct net_device * dev, + void * buf, + short length) +{ + net_local * lp = netdev_priv(dev); + unsigned int base = dev->base_addr; + unsigned long flags; + int clen = length; + register u_short xmtdata_base = TX_BASE; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); +#endif + + spin_lock_irqsave(&lp->spinlock, flags); + + /* Write the length of data buffer followed by the buffer */ + outb(xmtdata_base & 0xff, PIORL(base)); + outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(clen & 0xff, PIOP(base)); /* lsb */ + outb(clen >> 8, PIOP(base)); /* msb */ + + /* Send the data */ + outsb(PIOP(base), buf, clen); + + /* Indicate end of transmit chain */ + outb(OP0_NOP, PIOP(base)); + /* josullvn@cs.cmu.edu: need to send a second NOP for alignment... */ + outb(OP0_NOP, PIOP(base)); + + /* Reset the transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + /* Send the transmit command */ + wv_82593_cmd(dev, "wv_packet_write(): transmit", + OP0_TRANSMIT, SR0_NO_RESULT); + + /* Make sure the watchdog will keep quiet for a while */ + dev->trans_start = jiffies; + + /* Keep stats up to date */ + dev->stats.tx_bytes += length; + + spin_unlock_irqrestore(&lp->spinlock, flags); + +#ifdef DEBUG_TX_INFO + wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); +#endif /* DEBUG_TX_INFO */ + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * This routine is called when we want to send a packet (NET3 callback) + * In this routine, we check if the harware is ready to accept + * the packet. We also prevent reentrance. Then, we call the function + * to send the packet... + */ +static netdev_tx_t +wavelan_packet_xmit(struct sk_buff * skb, + struct net_device * dev) +{ + net_local * lp = netdev_priv(dev); + unsigned long flags; + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, + (unsigned) skb); +#endif + + /* + * Block a timer-based transmit from overlapping a previous transmit. + * In other words, prevent reentering this routine. + */ + netif_stop_queue(dev); + + /* If somebody has asked to reconfigure the controller, + * we can do it now */ + if(lp->reconfig_82593) + { + spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */ + wv_82593_config(dev); + spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */ + /* Note : the configure procedure was totally synchronous, + * so the Tx buffer is now free */ + } + + /* Check if we need some padding */ + /* Note : on wireless the propagation time is in the order of 1us, + * and we don't have the Ethernet specific requirement of beeing + * able to detect collisions, therefore in theory we don't really + * need to pad. Jean II */ + if (skb_padto(skb, ETH_ZLEN)) + return NETDEV_TX_OK; + + wv_packet_write(dev, skb->data, skb->len); + + dev_kfree_skb(skb); + +#ifdef DEBUG_TX_TRACE + printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); +#endif + return NETDEV_TX_OK; +} + +/********************** HARDWARE CONFIGURATION **********************/ +/* + * This part do the real job of starting and configuring the hardware. + */ + +/*------------------------------------------------------------------*/ +/* + * Routine to initialize the Modem Management Controller. + * (called by wv_hw_config()) + */ +static int +wv_mmc_init(struct net_device * dev) +{ + unsigned int base = dev->base_addr; + psa_t psa; + mmw_t m; + int configured; + int i; /* Loop counter */ + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); +#endif + + /* Read the parameter storage area */ + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + + /* + * Check the first three octets of the MAC addr for the manufacturer's code. + * Note: If you get the error message below, you've got a + * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on + * how to configure your card... + */ + for (i = 0; i < ARRAY_SIZE(MAC_ADDRESSES); i++) + if ((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) && + (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) && + (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2])) + break; + + /* If we have not found it... */ + if (i == ARRAY_SIZE(MAC_ADDRESSES)) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n", + dev->name, psa.psa_univ_mac_addr[0], + psa.psa_univ_mac_addr[1], psa.psa_univ_mac_addr[2]); +#endif + return FALSE; + } + + /* Get the MAC address */ + memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE); + +#ifdef USE_PSA_CONFIG + configured = psa.psa_conf_status & 1; +#else + configured = 0; +#endif + + /* Is the PSA is not configured */ + if(!configured) + { + /* User will be able to configure NWID after (with iwconfig) */ + psa.psa_nwid[0] = 0; + psa.psa_nwid[1] = 0; + + /* As NWID is not set : no NWID checking */ + psa.psa_nwid_select = 0; + + /* Disable encryption */ + psa.psa_encryption_select = 0; + + /* Set to standard values + * 0x04 for AT, + * 0x01 for MCA, + * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) + */ + if (psa.psa_comp_number & 1) + psa.psa_thr_pre_set = 0x01; + else + psa.psa_thr_pre_set = 0x04; + psa.psa_quality_thr = 0x03; + + /* It is configured */ + psa.psa_conf_status |= 1; + +#ifdef USE_PSA_CONFIG + /* Write the psa */ + psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, + (unsigned char *)psa.psa_nwid, 4); + psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, + (unsigned char *)&psa.psa_thr_pre_set, 1); + psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa, + (unsigned char *)&psa.psa_quality_thr, 1); + psa_write(dev, (char *)&psa.psa_conf_status - (char *)&psa, + (unsigned char *)&psa.psa_conf_status, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev); +#endif /* USE_PSA_CONFIG */ + } + + /* Zero the mmc structure */ + memset(&m, 0x00, sizeof(m)); + + /* Copy PSA info to the mmc */ + m.mmw_netw_id_l = psa.psa_nwid[1]; + m.mmw_netw_id_h = psa.psa_nwid[0]; + + if(psa.psa_nwid_select & 1) + m.mmw_loopt_sel = 0x00; + else + m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; + + memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, + sizeof(m.mmw_encr_key)); + + if(psa.psa_encryption_select) + m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; + else + m.mmw_encr_enable = 0; + + m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; + m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; + + /* + * Set default modem control parameters. + * See NCR document 407-0024326 Rev. A. + */ + m.mmw_jabber_enable = 0x01; + m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; + m.mmw_ifs = 0x20; + m.mmw_mod_delay = 0x04; + m.mmw_jam_time = 0x38; + + m.mmw_des_io_invert = 0; + m.mmw_freeze = 0; + m.mmw_decay_prm = 0; + m.mmw_decay_updat_prm = 0; + + /* Write all info to mmc */ + mmc_write(base, 0, (u_char *)&m, sizeof(m)); + + /* The following code start the modem of the 2.00 frequency + * selectable cards at power on. It's not strictly needed for the + * following boots... + * The original patch was by Joe Finney for the PCMCIA driver, but + * I've cleaned it a bit and add documentation. + * Thanks to Loeke Brederveld from Lucent for the info. + */ + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) + * (does it work for everybody ? - especially old cards...) */ + /* Note : WFREQSEL verify that it is able to read from EEprom + * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID + * is 0xA (Xilinx version) or 0xB (Ariadne version). + * My test is more crude but do work... */ + if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + { + /* We must download the frequency parameters to the + * synthetisers (from the EEprom - area 1) + * Note : as the EEprom is auto decremented, we set the end + * if the area... */ + m.mmw_fee_addr = 0x0F; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, + (unsigned char *)&m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished */ + fee_wait(base, 100, 100); + +#ifdef DEBUG_CONFIG_INFO + /* The frequency was in the last word downloaded... */ + mmc_read(base, (char *)&m.mmw_fee_data_l - (char *)&m, + (unsigned char *)&m.mmw_fee_data_l, 2); + + /* Print some info for the user */ + printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n", + dev->name, + ((m.mmw_fee_data_h << 4) | + (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L); +#endif + + /* We must now download the power adjust value (gain) to + * the synthetisers (from the EEprom - area 7 - DAC) */ + m.mmw_fee_addr = 0x61; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m, + (unsigned char *)&m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished */ + } /* if 2.00 card */ + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * Routine to gracefully turn off reception, and wait for any commands + * to complete. + * (called in wv_ru_start() and wavelan_close() and wavelan_event()) + */ +static int +wv_ru_stop(struct net_device * dev) +{ + unsigned int base = dev->base_addr; + net_local * lp = netdev_priv(dev); + unsigned long flags; + int status; + int spin; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); +#endif + + spin_lock_irqsave(&lp->spinlock, flags); + + /* First, send the LAN controller a stop receive command */ + wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", + OP0_STOP_RCV, SR0_NO_RESULT); + + /* Then, spin until the receive unit goes idle */ + spin = 300; + do + { + udelay(10); + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + } + while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0)); + + /* Now, spin until the chip finishes executing its current command */ + do + { + udelay(10); + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + } + while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); + + spin_unlock_irqrestore(&lp->spinlock, flags); + + /* If there was a problem */ + if(spin <= 0) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n", + dev->name); +#endif + return FALSE; + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_ru_stop()\n", dev->name); +#endif + return TRUE; +} /* wv_ru_stop */ + +/*------------------------------------------------------------------*/ +/* + * This routine starts the receive unit running. First, it checks if + * the card is actually ready. Then the card is instructed to receive + * packets again. + * (called in wv_hw_reset() & wavelan_open()) + */ +static int +wv_ru_start(struct net_device * dev) +{ + unsigned int base = dev->base_addr; + net_local * lp = netdev_priv(dev); + unsigned long flags; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); +#endif + + /* + * We need to start from a quiescent state. To do so, we could check + * if the card is already running, but instead we just try to shut + * it down. First, we disable reception (in case it was already enabled). + */ + if(!wv_ru_stop(dev)) + return FALSE; + + spin_lock_irqsave(&lp->spinlock, flags); + + /* Now we know that no command is being executed. */ + + /* Set the receive frame pointer and stop pointer */ + lp->rfp = 0; + outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base)); + + /* Reset ring management. This sets the receive frame pointer to 1 */ + outb(OP1_RESET_RING_MNGMT, LCCR(base)); + +#if 0 + /* XXX the i82593 manual page 6-4 seems to indicate that the stop register + should be set as below */ + /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/ +#elif 0 + /* but I set it 0 instead */ + lp->stop = 0; +#else + /* but I set it to 3 bytes per packet less than 8K */ + lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; +#endif + outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base)); + outb(OP1_INT_ENABLE, LCCR(base)); + outb(OP1_SWIT_TO_PORT_0, LCCR(base)); + + /* Reset receive DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write_slow(base, HACR_DEFAULT); + + /* Receive DMA on channel 1 */ + wv_82593_cmd(dev, "wv_ru_start(): rcv-enable", + CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT); + +#ifdef DEBUG_I82593_SHOW + { + int status; + int opri; + int spin = 10000; + + /* spin until the chip starts receiving */ + do + { + outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); + status = inb(LCSR(base)); + if(spin-- <= 0) + break; + } + while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) && + ((status & SR3_RCV_STATE_MASK) != SR3_RCV_READY)); + printk(KERN_DEBUG "rcv status is 0x%x [i:%d]\n", + (status & SR3_RCV_STATE_MASK), i); + } +#endif + + spin_unlock_irqrestore(&lp->spinlock, flags); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * This routine does a standard config of the WaveLAN controller (i82593). + * In the ISA driver, this is integrated in wavelan_hardware_reset() + * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) + */ +static int +wv_82593_config(struct net_device * dev) +{ + unsigned int base = dev->base_addr; + net_local * lp = netdev_priv(dev); + struct i82593_conf_block cfblk; + int ret = TRUE; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name); +#endif + + /* Create & fill i82593 config block + * + * Now conform to Wavelan document WCIN085B + */ + memset(&cfblk, 0x00, sizeof(struct i82593_conf_block)); + cfblk.d6mod = FALSE; /* Run in i82593 advanced mode */ + cfblk.fifo_limit = 5; /* = 56 B rx and 40 B tx fifo thresholds */ + cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */ + cfblk.fifo_32 = 1; + cfblk.throttle_enb = FALSE; + cfblk.contin = TRUE; /* enable continuous mode */ + cfblk.cntrxint = FALSE; /* enable continuous mode receive interrupts */ + cfblk.addr_len = WAVELAN_ADDR_SIZE; + cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */ + cfblk.preamb_len = 0; /* 2 bytes preamble (SFD) */ + cfblk.loopback = FALSE; + cfblk.lin_prio = 0; /* conform to 802.3 backoff algorithm */ + cfblk.exp_prio = 5; /* conform to 802.3 backoff algorithm */ + cfblk.bof_met = 1; /* conform to 802.3 backoff algorithm */ + cfblk.ifrm_spc = 0x20 >> 4; /* 32 bit times interframe spacing */ + cfblk.slottim_low = 0x20 >> 5; /* 32 bit times slot time */ + cfblk.slottim_hi = 0x0; + cfblk.max_retr = 15; + cfblk.prmisc = ((lp->promiscuous) ? TRUE: FALSE); /* Promiscuous mode */ + cfblk.bc_dis = FALSE; /* Enable broadcast reception */ + cfblk.crs_1 = TRUE; /* Transmit without carrier sense */ + cfblk.nocrc_ins = FALSE; /* i82593 generates CRC */ + cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */ + cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */ + cfblk.cs_filter = 0; /* CS is recognized immediately */ + cfblk.crs_src = FALSE; /* External carrier sense */ + cfblk.cd_filter = 0; /* CD is recognized immediately */ + cfblk.min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length 64 bytes */ + cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */ + cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */ + cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */ + cfblk.artx = TRUE; /* Disable automatic retransmission */ + cfblk.sarec = TRUE; /* Disable source addr trig of CD */ + cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */ + cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */ + cfblk.lbpkpol = TRUE; /* Loopback pin active high */ + cfblk.fdx = FALSE; /* Disable full duplex operation */ + cfblk.dummy_6 = 0x3f; /* all ones */ + cfblk.mult_ia = FALSE; /* No multiple individual addresses */ + cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */ + cfblk.dummy_1 = TRUE; /* set to 1 */ + cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */ +#ifdef MULTICAST_ALL + cfblk.mc_all = (lp->allmulticast ? TRUE: FALSE); /* Allow all multicasts */ +#else + cfblk.mc_all = FALSE; /* No multicast all mode */ +#endif + cfblk.rcv_mon = 0; /* Monitor mode disabled */ + cfblk.frag_acpt = TRUE; /* Do not accept fragments */ + cfblk.tstrttrs = FALSE; /* No start transmission threshold */ + cfblk.fretx = TRUE; /* FIFO automatic retransmission */ + cfblk.syncrqs = FALSE; /* Synchronous DRQ deassertion... */ + cfblk.sttlen = TRUE; /* 6 byte status registers */ + cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */ + cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */ + cfblk.rbuf_size = RX_SIZE>>11; /* Set receive buffer size */ + cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */ + +#ifdef DEBUG_I82593_SHOW + print_hex_dump(KERN_DEBUG, "wavelan_cs: config block: ", DUMP_PREFIX_NONE, + 16, 1, &cfblk, sizeof(struct i82593_conf_block), false); +#endif + + /* Copy the config block to the i82593 */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(sizeof(struct i82593_conf_block) & 0xff, PIOP(base)); /* lsb */ + outb(sizeof(struct i82593_conf_block) >> 8, PIOP(base)); /* msb */ + outsb(PIOP(base), (char *) &cfblk, sizeof(struct i82593_conf_block)); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): configure", + OP0_CONFIGURE, SR0_CONFIGURE_DONE)) + ret = FALSE; + + /* Initialize adapter's ethernet MAC address */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(WAVELAN_ADDR_SIZE, PIOP(base)); /* byte count lsb */ + outb(0, PIOP(base)); /* byte count msb */ + outsb(PIOP(base), &dev->dev_addr[0], WAVELAN_ADDR_SIZE); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup", + OP0_IA_SETUP, SR0_IA_SETUP_DONE)) + ret = FALSE; + +#ifdef WAVELAN_ROAMING + /* If roaming is enabled, join the "Beacon Request" multicast group... */ + /* But only if it's not in there already! */ + if(do_roaming) + dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1); +#endif /* WAVELAN_ROAMING */ + + /* If any multicast address to set */ + if(lp->mc_count) + { + struct dev_mc_list * dmi; + int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n", + dev->name, lp->mc_count); + for(dmi=dev->mc_list; dmi; dmi=dmi->next) + printk(KERN_DEBUG " %pM\n", dmi->dmi_addr); +#endif + + /* Initialize adapter's ethernet multicast addresses */ + outb(TX_BASE & 0xff, PIORL(base)); + outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); + outb(addrs_len & 0xff, PIOP(base)); /* byte count lsb */ + outb((addrs_len >> 8), PIOP(base)); /* byte count msb */ + for(dmi=dev->mc_list; dmi; dmi=dmi->next) + outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen); + + /* reset transmit DMA pointer */ + hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET); + hacr_write(base, HACR_DEFAULT); + if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup", + OP0_MC_SETUP, SR0_MC_SETUP_DONE)) + ret = FALSE; + lp->mc_count = dev->mc_count; /* remember to avoid repeated reset */ + } + + /* Job done, clear the flag */ + lp->reconfig_82593 = FALSE; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name); +#endif + return(ret); +} + +/*------------------------------------------------------------------*/ +/* + * Read the Access Configuration Register, perform a software reset, + * and then re-enable the card's software. + * + * If I understand correctly : reset the pcmcia interface of the + * wavelan. + * (called by wv_config()) + */ +static int +wv_pcmcia_reset(struct net_device * dev) +{ + int i; + conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; + struct pcmcia_device * link = ((net_local *)netdev_priv(dev))->link; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name); +#endif + + i = pcmcia_access_configuration_register(link, ®); + if (i != 0) + { + cs_error(link, AccessConfigurationRegister, i); + return FALSE; + } + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n", + dev->name, (u_int) reg.Value); +#endif + + reg.Action = CS_WRITE; + reg.Value = reg.Value | COR_SW_RESET; + i = pcmcia_access_configuration_register(link, ®); + if (i != 0) + { + cs_error(link, AccessConfigurationRegister, i); + return FALSE; + } + + reg.Action = CS_WRITE; + reg.Value = COR_LEVEL_IRQ | COR_CONFIG; + i = pcmcia_access_configuration_register(link, ®); + if (i != 0) + { + cs_error(link, AccessConfigurationRegister, i); + return FALSE; + } + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * wavelan_hw_config() is called after a CARD_INSERTION event is + * received, to configure the wavelan hardware. + * Note that the reception will be enabled in wavelan->open(), so the + * device is configured but idle... + * Performs the following actions: + * 1. A pcmcia software reset (using wv_pcmcia_reset()) + * 2. A power reset (reset DMA) + * 3. Reset the LAN controller + * 4. Initialize the radio modem (using wv_mmc_init) + * 5. Configure LAN controller (using wv_82593_config) + * 6. Perform a diagnostic on the LAN controller + * (called by wavelan_event() & wv_hw_reset()) + */ +static int +wv_hw_config(struct net_device * dev) +{ + net_local * lp = netdev_priv(dev); + unsigned int base = dev->base_addr; + unsigned long flags; + int ret = FALSE; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name); +#endif + + /* compile-time check the sizes of structures */ + BUILD_BUG_ON(sizeof(psa_t) != PSA_SIZE); + BUILD_BUG_ON(sizeof(mmw_t) != MMW_SIZE); + BUILD_BUG_ON(sizeof(mmr_t) != MMR_SIZE); + + /* Reset the pcmcia interface */ + if(wv_pcmcia_reset(dev) == FALSE) + return FALSE; + + /* Disable interrupts */ + spin_lock_irqsave(&lp->spinlock, flags); + + /* Disguised goto ;-) */ + do + { + /* Power UP the module + reset the modem + reset host adapter + * (in fact, reset DMA channels) */ + hacr_write_slow(base, HACR_RESET); + hacr_write(base, HACR_DEFAULT); + + /* Check if the module has been powered up... */ + if(hasr_read(base) & HASR_NO_CLK) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n", + dev->name); +#endif + break; + } + + /* initialize the modem */ + if(wv_mmc_init(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n", + dev->name); +#endif + break; + } + + /* reset the LAN controller (i82593) */ + outb(OP0_RESET, LCCR(base)); + mdelay(1); /* A bit crude ! */ + + /* Initialize the LAN controller */ + if(wv_82593_config(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", + dev->name); +#endif + break; + } + + /* Diagnostic */ + if(wv_diag(dev) == FALSE) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n", + dev->name); +#endif + break; + } + + /* + * insert code for loopback test here + */ + + /* The device is now configured */ + lp->configured = 1; + ret = TRUE; + } + while(0); + + /* Re-enable interrupts */ + spin_unlock_irqrestore(&lp->spinlock, flags); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); +#endif + return(ret); +} + +/*------------------------------------------------------------------*/ +/* + * Totally reset the wavelan and restart it. + * Performs the following actions: + * 1. Call wv_hw_config() + * 2. Start the LAN controller's receive unit + * (called by wavelan_event(), wavelan_watchdog() and wavelan_open()) + */ +static void +wv_hw_reset(struct net_device * dev) +{ + net_local * lp = netdev_priv(dev); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name); +#endif + + lp->nresets++; + lp->configured = 0; + + /* Call wv_hw_config() for most of the reset & init stuff */ + if(wv_hw_config(dev) == FALSE) + return; + + /* start receive unit */ + wv_ru_start(dev); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); +#endif +} + +/*------------------------------------------------------------------*/ +/* + * wv_pcmcia_config() is called after a CARD_INSERTION event is + * received, to configure the PCMCIA socket, and to make the ethernet + * device available to the system. + * (called by wavelan_event()) + */ +static int +wv_pcmcia_config(struct pcmcia_device * link) +{ + struct net_device * dev = (struct net_device *) link->priv; + int i; + win_req_t req; + memreq_t mem; + net_local * lp = netdev_priv(dev); + + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link); +#endif + + do + { + i = pcmcia_request_io(link, &link->io); + if (i != 0) + { + cs_error(link, RequestIO, i); + break; + } + + /* + * Now allocate an interrupt line. Note that this does not + * actually assign a handler to the interrupt. + */ + i = pcmcia_request_irq(link, &link->irq); + if (i != 0) + { + cs_error(link, RequestIRQ, i); + break; + } + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping. + */ + link->conf.ConfigIndex = 1; + i = pcmcia_request_configuration(link, &link->conf); + if (i != 0) + { + cs_error(link, RequestConfiguration, i); + break; + } + + /* + * Allocate a small memory window. Note that the struct pcmcia_device + * structure provides space for one window handle -- if your + * device needs several windows, you'll need to keep track of + * the handles in your private data structure, link->priv. + */ + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + req.Base = req.Size = 0; + req.AccessSpeed = mem_speed; + i = pcmcia_request_window(&link, &req, &link->win); + if (i != 0) + { + cs_error(link, RequestWindow, i); + break; + } + + lp->mem = ioremap(req.Base, req.Size); + dev->mem_start = (u_long)lp->mem; + dev->mem_end = dev->mem_start + req.Size; + + mem.CardOffset = 0; mem.Page = 0; + i = pcmcia_map_mem_page(link->win, &mem); + if (i != 0) + { + cs_error(link, MapMemPage, i); + break; + } + + /* Feed device with this info... */ + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + netif_start_queue(dev); + +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART %p IRQ %d IOPORT 0x%x\n", + lp->mem, dev->irq, (u_int) dev->base_addr); +#endif + + SET_NETDEV_DEV(dev, &handle_to_dev(link)); + i = register_netdev(dev); + if(i != 0) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_INFO "wv_pcmcia_config(): register_netdev() failed\n"); +#endif + break; + } + } + while(0); /* Humm... Disguised goto !!! */ + + /* If any step failed, release any partially configured state */ + if(i != 0) + { + wv_pcmcia_release(link); + return FALSE; + } + + strcpy(((net_local *) netdev_priv(dev))->node.dev_name, dev->name); + link->dev_node = &((net_local *) netdev_priv(dev))->node; + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "<-wv_pcmcia_config()\n"); +#endif + return TRUE; +} + +/*------------------------------------------------------------------*/ +/* + * After a card is removed, wv_pcmcia_release() will unregister the net + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ +static void +wv_pcmcia_release(struct pcmcia_device *link) +{ + struct net_device * dev = (struct net_device *) link->priv; + net_local * lp = netdev_priv(dev); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); +#endif + + iounmap(lp->mem); + pcmcia_disable_device(link); + +#ifdef DEBUG_CONFIG_TRACE + printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); +#endif +} + +/************************ INTERRUPT HANDLING ************************/ + +/* + * This function is the interrupt handler for the WaveLAN card. This + * routine will be called whenever: + * 1. A packet is received. + * 2. A packet has successfully been transferred and the unit is + * ready to transmit another packet. + * 3. A command has completed execution. + */ +static irqreturn_t +wavelan_interrupt(int irq, + void * dev_id) +{ + struct net_device * dev = dev_id; + net_local * lp; + unsigned int base; + int status0; + u_int tx_status; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); +#endif + + lp = netdev_priv(dev); + base = dev->base_addr; + +#ifdef DEBUG_INTERRUPT_INFO + /* Check state of our spinlock (it should be cleared) */ + if(spin_is_locked(&lp->spinlock)) + printk(KERN_DEBUG + "%s: wavelan_interrupt(): spinlock is already locked !!!\n", + dev->name); +#endif + + /* Prevent reentrancy. We need to do that because we may have + * multiple interrupt handler running concurently. + * It is safe because interrupts are disabled before aquiring + * the spinlock. */ + spin_lock(&lp->spinlock); + + /* Treat all pending interrupts */ + while(1) + { + /* ---------------- INTERRUPT CHECKING ---------------- */ + /* + * Look for the interrupt and verify the validity + */ + outb(CR0_STATUS_0 | OP0_NOP, LCCR(base)); + status0 = inb(LCSR(base)); + +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "status0 0x%x [%s => 0x%x]", status0, + (status0&SR0_INTERRUPT)?"int":"no int",status0&~SR0_INTERRUPT); + if(status0&SR0_INTERRUPT) + { + printk(" [%s => %d]\n", (status0 & SR0_CHNL) ? "chnl" : + ((status0 & SR0_EXECUTION) ? "cmd" : + ((status0 & SR0_RECEPTION) ? "recv" : "unknown")), + (status0 & SR0_EVENT_MASK)); + } + else + printk("\n"); +#endif + + /* Return if no actual interrupt from i82593 (normal exit) */ + if(!(status0 & SR0_INTERRUPT)) + break; + + /* If interrupt is both Rx and Tx or none... + * This code in fact is there to catch the spurious interrupt + * when you remove the wavelan pcmcia card from the socket */ + if(((status0 & SR0_BOTH_RX_TX) == SR0_BOTH_RX_TX) || + ((status0 & SR0_BOTH_RX_TX) == 0x0)) + { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_INFO "%s: wv_interrupt(): bogus interrupt (or from dead card) : %X\n", + dev->name, status0); +#endif + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + break; + } + + /* ----------------- RECEIVING PACKET ----------------- */ + /* + * When the wavelan signal the reception of a new packet, + * we call wv_packet_rcv() to copy if from the buffer and + * send it to NET3 + */ + if(status0 & SR0_RECEPTION) + { +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "%s: wv_interrupt(): receive\n", dev->name); +#endif + + if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n", + dev->name); +#endif + dev->stats.rx_over_errors++; + lp->overrunning = 1; + } + + /* Get the packet */ + wv_packet_rcv(dev); + lp->overrunning = 0; + + /* Acknowledge the interrupt */ + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); + continue; + } + + /* ---------------- COMMAND COMPLETION ---------------- */ + /* + * Interrupts issued when the i82593 has completed a command. + * Most likely : transmission done + */ + + /* If a transmission has been done */ + if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || + (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE || + (status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) + { +#ifdef DEBUG_TX_ERROR + if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) + printk(KERN_INFO "%s: wv_interrupt(): packet transmitted without CRC.\n", + dev->name); +#endif + + /* Get transmission status */ + tx_status = inb(LCSR(base)); + tx_status |= (inb(LCSR(base)) << 8); +#ifdef DEBUG_INTERRUPT_INFO + printk(KERN_DEBUG "%s: wv_interrupt(): transmission done\n", + dev->name); + { + u_int rcv_bytes; + u_char status3; + rcv_bytes = inb(LCSR(base)); + rcv_bytes |= (inb(LCSR(base)) << 8); + status3 = inb(LCSR(base)); + printk(KERN_DEBUG "tx_status 0x%02x rcv_bytes 0x%02x status3 0x%x\n", + tx_status, rcv_bytes, (u_int) status3); + } +#endif + /* Check for possible errors */ + if((tx_status & TX_OK) != TX_OK) + { + dev->stats.tx_errors++; + + if(tx_status & TX_FRTL) + { +#ifdef DEBUG_TX_ERROR + printk(KERN_INFO "%s: wv_interrupt(): frame too long\n", + dev->name); +#endif + } + if(tx_status & TX_UND_RUN) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n", + dev->name); +#endif + dev->stats.tx_aborted_errors++; + } + if(tx_status & TX_LOST_CTS) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name); +#endif + dev->stats.tx_carrier_errors++; + } + if(tx_status & TX_LOST_CRS) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n", + dev->name); +#endif + dev->stats.tx_carrier_errors++; + } + if(tx_status & TX_HRT_BEAT) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name); +#endif + dev->stats.tx_heartbeat_errors++; + } + if(tx_status & TX_DEFER) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): channel jammed\n", + dev->name); +#endif + } + /* Ignore late collisions since they're more likely to happen + * here (the WaveLAN design prevents the LAN controller from + * receiving while it is transmitting). We take action only when + * the maximum retransmit attempts is exceeded. + */ + if(tx_status & TX_COLL) + { + if(tx_status & TX_MAX_COL) + { +#ifdef DEBUG_TX_FAIL + printk(KERN_DEBUG "%s: wv_interrupt(): channel congestion\n", + dev->name); +#endif + if(!(tx_status & TX_NCOL_MASK)) + { + dev->stats.collisions += 0x10; + } + } + } + } /* if(!(tx_status & TX_OK)) */ + + dev->stats.collisions += (tx_status & TX_NCOL_MASK); + dev->stats.tx_packets++; + + netif_wake_queue(dev); + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ + } + else /* if interrupt = transmit done or retransmit done */ + { +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "wavelan_cs: unknown interrupt, status0 = %02x\n", + status0); +#endif + outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ + } + } /* while(1) */ + + spin_unlock(&lp->spinlock); + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); +#endif + + /* We always return IRQ_HANDLED, because we will receive empty + * interrupts under normal operations. Anyway, it doesn't matter + * as we are dealing with an ISA interrupt that can't be shared. + * + * Explanation : under heavy receive, the following happens : + * ->wavelan_interrupt() + * (status0 & SR0_INTERRUPT) != 0 + * ->wv_packet_rcv() + * (status0 & SR0_INTERRUPT) != 0 + * ->wv_packet_rcv() + * (status0 & SR0_INTERRUPT) == 0 // i.e. no more event + * <-wavelan_interrupt() + * ->wavelan_interrupt() + * (status0 & SR0_INTERRUPT) == 0 // i.e. empty interrupt + * <-wavelan_interrupt() + * Jean II */ + return IRQ_HANDLED; +} /* wv_interrupt */ + +/*------------------------------------------------------------------*/ +/* + * Watchdog: when we start a transmission, a timer is set for us in the + * kernel. If the transmission completes, this timer is disabled. If + * the timer expires, we are called and we try to unlock the hardware. + * + * Note : This watchdog is move clever than the one in the ISA driver, + * because it try to abort the current command before reseting + * everything... + * On the other hand, it's a bit simpler, because we don't have to + * deal with the multiple Tx buffers... + */ +static void +wavelan_watchdog(struct net_device * dev) +{ + net_local * lp = netdev_priv(dev); + unsigned int base = dev->base_addr; + unsigned long flags; + int aborted = FALSE; + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); +#endif + +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", + dev->name); +#endif + + spin_lock_irqsave(&lp->spinlock, flags); + + /* Ask to abort the current command */ + outb(OP0_ABORT, LCCR(base)); + + /* Wait for the end of the command (a bit hackish) */ + if(wv_82593_cmd(dev, "wavelan_watchdog(): abort", + OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED)) + aborted = TRUE; + + /* Release spinlock here so that wv_hw_reset() can grab it */ + spin_unlock_irqrestore(&lp->spinlock, flags); + + /* Check if we were successful in aborting it */ + if(!aborted) + { + /* It seem that it wasn't enough */ +#ifdef DEBUG_INTERRUPT_ERROR + printk(KERN_INFO "%s: wavelan_watchdog: abort failed, trying reset\n", + dev->name); +#endif + wv_hw_reset(dev); + } + +#ifdef DEBUG_PSA_SHOW + { + psa_t psa; + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + wv_psa_show(&psa); + } +#endif +#ifdef DEBUG_MMC_SHOW + wv_mmc_show(dev); +#endif +#ifdef DEBUG_I82593_SHOW + wv_ru_show(dev); +#endif + + /* We are no more waiting for something... */ + netif_wake_queue(dev); + +#ifdef DEBUG_INTERRUPT_TRACE + printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); +#endif +} + +/********************* CONFIGURATION CALLBACKS *********************/ +/* + * Here are the functions called by the pcmcia package (cardmgr) and + * linux networking (NET3) for initialization, configuration and + * deinstallations of the Wavelan Pcmcia Hardware. + */ + +/*------------------------------------------------------------------*/ +/* + * Configure and start up the WaveLAN PCMCIA adaptor. + * Called by NET3 when it "open" the device. + */ +static int +wavelan_open(struct net_device * dev) +{ + net_local * lp = netdev_priv(dev); + struct pcmcia_device * link = lp->link; + unsigned int base = dev->base_addr; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* Check if the modem is powered up (wavelan_close() power it down */ + if(hasr_read(base) & HASR_NO_CLK) + { + /* Power up (power up time is 250us) */ + hacr_write(base, HACR_DEFAULT); + + /* Check if the module has been powered up... */ + if(hasr_read(base) & HASR_NO_CLK) + { +#ifdef DEBUG_CONFIG_ERRORS + printk(KERN_WARNING "%s: wavelan_open(): modem not connected\n", + dev->name); +#endif + return FALSE; + } + } + + /* Start reception and declare the driver ready */ + if(!lp->configured) + return FALSE; + if(!wv_ru_start(dev)) + wv_hw_reset(dev); /* If problem : reset */ + netif_start_queue(dev); + + /* Mark the device as used */ + link->open++; + +#ifdef WAVELAN_ROAMING + if(do_roaming) + wv_roam_init(dev); +#endif /* WAVELAN_ROAMING */ + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); +#endif + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * Shutdown the WaveLAN PCMCIA adaptor. + * Called by NET3 when it "close" the device. + */ +static int +wavelan_close(struct net_device * dev) +{ + struct pcmcia_device * link = ((net_local *)netdev_priv(dev))->link; + unsigned int base = dev->base_addr; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, + (unsigned int) dev); +#endif + + /* If the device isn't open, then nothing to do */ + if(!link->open) + { +#ifdef DEBUG_CONFIG_INFO + printk(KERN_DEBUG "%s: wavelan_close(): device not open\n", dev->name); +#endif + return 0; + } + +#ifdef WAVELAN_ROAMING + /* Cleanup of roaming stuff... */ + if(do_roaming) + wv_roam_cleanup(dev); +#endif /* WAVELAN_ROAMING */ + + link->open--; + + /* If the card is still present */ + if(netif_running(dev)) + { + netif_stop_queue(dev); + + /* Stop receiving new messages and wait end of transmission */ + wv_ru_stop(dev); + + /* Power down the module */ + hacr_write(base, HACR_DEFAULT & (~HACR_PWR_STAT)); + } + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); +#endif + return 0; +} + +static const struct net_device_ops wavelan_netdev_ops = { + .ndo_open = wavelan_open, + .ndo_stop = wavelan_close, + .ndo_start_xmit = wavelan_packet_xmit, + .ndo_set_multicast_list = wavelan_set_multicast_list, +#ifdef SET_MAC_ADDRESS + .ndo_set_mac_address = wavelan_set_mac_address, +#endif + .ndo_tx_timeout = wavelan_watchdog, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + +/*------------------------------------------------------------------*/ +/* + * wavelan_attach() creates an "instance" of the driver, allocating + * local data structures for one device (one interface). The device + * is registered with Card Services. + * + * The dev_link structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a + * card insertion event. + */ +static int +wavelan_probe(struct pcmcia_device *p_dev) +{ + struct net_device * dev; /* Interface generic data */ + net_local * lp; /* Interface specific data */ + int ret; + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "-> wavelan_attach()\n"); +#endif + + /* The io structure describes IO port mapping */ + p_dev->io.NumPorts1 = 8; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = 3; + + /* Interrupt setup */ + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; + p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; + p_dev->irq.Handler = wavelan_interrupt; + + /* General socket configuration */ + p_dev->conf.Attributes = CONF_ENABLE_IRQ; + p_dev->conf.IntType = INT_MEMORY_AND_IO; + + /* Allocate the generic data structure */ + dev = alloc_etherdev(sizeof(net_local)); + if (!dev) + return -ENOMEM; + + p_dev->priv = p_dev->irq.Instance = dev; + + lp = netdev_priv(dev); + + /* Init specific data */ + lp->configured = 0; + lp->reconfig_82593 = FALSE; + lp->nresets = 0; + /* Multicast stuff */ + lp->promiscuous = 0; + lp->allmulticast = 0; + lp->mc_count = 0; + + /* Init spinlock */ + spin_lock_init(&lp->spinlock); + + /* back links */ + lp->dev = dev; + + /* wavelan NET3 callbacks */ + dev->netdev_ops = &wavelan_netdev_ops; + dev->watchdog_timeo = WATCHDOG_JIFFIES; + SET_ETHTOOL_OPS(dev, &ops); + + dev->wireless_handlers = &wavelan_handler_def; + lp->wireless_data.spy_data = &lp->spy_data; + dev->wireless_data = &lp->wireless_data; + + /* Other specific data */ + dev->mtu = WAVELAN_MTU; + + ret = wv_pcmcia_config(p_dev); + if (ret) + return ret; + + ret = wv_hw_config(dev); + if (ret) { + dev->irq = 0; + pcmcia_disable_device(p_dev); + return ret; + } + + wv_init_info(dev); + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<- wavelan_attach()\n"); +#endif + + return 0; +} + +/*------------------------------------------------------------------*/ +/* + * This deletes a driver "instance". The device is de-registered with + * Card Services. If it has been released, all local data structures + * are freed. Otherwise, the structures will be freed when the device + * is released. + */ +static void +wavelan_detach(struct pcmcia_device *link) +{ +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link); +#endif + + /* Some others haven't done their job : give them another chance */ + wv_pcmcia_release(link); + + /* Free pieces */ + if(link->priv) + { + struct net_device * dev = (struct net_device *) link->priv; + + /* Remove ourselves from the kernel list of ethernet devices */ + /* Warning : can't be called from interrupt, timer or wavelan_close() */ + if (link->dev_node) + unregister_netdev(dev); + link->dev_node = NULL; + ((net_local *)netdev_priv(dev))->link = NULL; + ((net_local *)netdev_priv(dev))->dev = NULL; + free_netdev(dev); + } + +#ifdef DEBUG_CALLBACK_TRACE + printk(KERN_DEBUG "<- wavelan_detach()\n"); +#endif +} + +static int wavelan_suspend(struct pcmcia_device *link) +{ + struct net_device * dev = (struct net_device *) link->priv; + + /* NB: wavelan_close will be called, but too late, so we are + * obliged to close nicely the wavelan here. David, could you + * close the device before suspending them ? And, by the way, + * could you, on resume, add a "route add -net ..." after the + * ifconfig up ? Thanks... */ + + /* Stop receiving new messages and wait end of transmission */ + wv_ru_stop(dev); + + if (link->open) + netif_device_detach(dev); + + /* Power down the module */ + hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT)); + + return 0; +} + +static int wavelan_resume(struct pcmcia_device *link) +{ + struct net_device * dev = (struct net_device *) link->priv; + + if (link->open) { + wv_hw_reset(dev); + netif_device_attach(dev); + } + + return 0; +} + + +static struct pcmcia_device_id wavelan_ids[] = { + PCMCIA_DEVICE_PROD_ID12("AT&T","WaveLAN/PCMCIA", 0xe7c5affd, 0x1bc50975), + PCMCIA_DEVICE_PROD_ID12("Digital", "RoamAbout/DS", 0x9999ab35, 0x00d05e06), + PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/PCMCIA", 0x23eb9949, 0x1bc50975), + PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/PCMCIA", 0x24358cd4, 0x1bc50975), + PCMCIA_DEVICE_NULL, +}; +MODULE_DEVICE_TABLE(pcmcia, wavelan_ids); + +static struct pcmcia_driver wavelan_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "wavelan_cs", + }, + .probe = wavelan_probe, + .remove = wavelan_detach, + .id_table = wavelan_ids, + .suspend = wavelan_suspend, + .resume = wavelan_resume, +}; + +static int __init +init_wavelan_cs(void) +{ + return pcmcia_register_driver(&wavelan_driver); +} + +static void __exit +exit_wavelan_cs(void) +{ + pcmcia_unregister_driver(&wavelan_driver); +} + +module_init(init_wavelan_cs); +module_exit(exit_wavelan_cs); diff --git a/drivers/staging/wavelan/wavelan_cs.h b/drivers/staging/wavelan/wavelan_cs.h new file mode 100644 index 000000000000..2e4bfe4147c6 --- /dev/null +++ b/drivers/staging/wavelan/wavelan_cs.h @@ -0,0 +1,386 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganization and extension of the driver. + * Original copyright follow. See wavelan_cs.h for details. + * + * This file contain the declarations of the Wavelan hardware. Note that + * the Pcmcia Wavelan include a i82593 controller (see definitions in + * file i82593.h). + * + * The main difference between the pcmcia hardware and the ISA one is + * the Ethernet Controller (i82593 instead of i82586). The i82593 allow + * only one send buffer. The PSA (Parameter Storage Area : EEprom for + * permanent storage of various info) is memory mapped, but not the + * MMI (Modem Management Interface). + */ + +/* + * Definitions for the AT&T GIS (formerly NCR) WaveLAN PCMCIA card: + * An Ethernet-like radio transceiver controlled by an Intel 82593 + * coprocessor. + * + * + **************************************************************************** + * Copyright 1995 + * Anthony D. Joseph + * Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this program + * for any purpose and without fee is hereby granted, provided + * that this copyright and permission notice appear on all copies + * and supporting documentation, the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * program without specific prior permission, and notice be given + * in supporting documentation that copying and distribution is + * by permission of M.I.T. M.I.T. makes no representations about + * the suitability of this software for any purpose. It is pro- + * vided "as is" without express or implied warranty. + **************************************************************************** + * + * + * Credits: + * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht for + * providing extremely useful information about WaveLAN PCMCIA hardware + * + * This driver is based upon several other drivers, in particular: + * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter + * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter + * Anders Klemets' PCMCIA WaveLAN adapter driver + * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter + */ + +#ifndef _WAVELAN_CS_H +#define _WAVELAN_CS_H + +/************************** MAGIC NUMBERS ***************************/ + +/* The detection of the wavelan card is made by reading the MAC address + * from the card and checking it. If you have a non AT&T product (OEM, + * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this + * part to accommodate your hardware... + */ +static const unsigned char MAC_ADDRESSES[][3] = +{ + { 0x08, 0x00, 0x0E }, /* AT&T Wavelan (standard) & DEC RoamAbout */ + { 0x08, 0x00, 0x6A }, /* AT&T Wavelan (alternate) */ + { 0x00, 0x00, 0xE1 }, /* Hitachi Wavelan */ + { 0x00, 0x60, 0x1D } /* Lucent Wavelan (another one) */ + /* Add your card here and send me the patch ! */ +}; + +/* + * Constants used to convert channels to frequencies + */ + +/* Frequency available in the 2.0 modem, in units of 250 kHz + * (as read in the offset register of the dac area). + * Used to map channel numbers used by `wfreqsel' to frequencies + */ +static const short channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, + 0xD0, 0xF0, 0xF8, 0x150 }; + +/* Frequencies of the 1.0 modem (fixed frequencies). + * Use to map the PSA `subband' to a frequency + * Note : all frequencies apart from the first one need to be multiplied by 10 + */ +static const int fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; + + +/*************************** PC INTERFACE ****************************/ + +/* WaveLAN host interface definitions */ + +#define LCCR(base) (base) /* LAN Controller Command Register */ +#define LCSR(base) (base) /* LAN Controller Status Register */ +#define HACR(base) (base+0x1) /* Host Adapter Command Register */ +#define HASR(base) (base+0x1) /* Host Adapter Status Register */ +#define PIORL(base) (base+0x2) /* Program I/O Register Low */ +#define RPLL(base) (base+0x2) /* Receive Pointer Latched Low */ +#define PIORH(base) (base+0x3) /* Program I/O Register High */ +#define RPLH(base) (base+0x3) /* Receive Pointer Latched High */ +#define PIOP(base) (base+0x4) /* Program I/O Port */ +#define MMR(base) (base+0x6) /* MMI Address Register */ +#define MMD(base) (base+0x7) /* MMI Data Register */ + +/* Host Adaptor Command Register bit definitions */ + +#define HACR_LOF (1 << 3) /* Lock Out Flag, toggle every 250ms */ +#define HACR_PWR_STAT (1 << 4) /* Power State, 1=active, 0=sleep */ +#define HACR_TX_DMA_RESET (1 << 5) /* Reset transmit DMA ptr on high */ +#define HACR_RX_DMA_RESET (1 << 6) /* Reset receive DMA ptr on high */ +#define HACR_ROM_WEN (1 << 7) /* EEPROM write enabled when true */ + +#define HACR_RESET (HACR_TX_DMA_RESET | HACR_RX_DMA_RESET) +#define HACR_DEFAULT (HACR_PWR_STAT) + +/* Host Adapter Status Register bit definitions */ + +#define HASR_MMI_BUSY (1 << 2) /* MMI is busy when true */ +#define HASR_LOF (1 << 3) /* Lock out flag status */ +#define HASR_NO_CLK (1 << 4) /* active when modem not connected */ + +/* Miscellaneous bit definitions */ + +#define PIORH_SEL_TX (1 << 5) /* PIOR points to 0=rx/1=tx buffer */ +#define MMR_MMI_WR (1 << 0) /* Next MMI cycle is 0=read, 1=write */ +#define PIORH_MASK 0x1f /* only low 5 bits are significant */ +#define RPLH_MASK 0x1f /* only low 5 bits are significant */ +#define MMI_ADDR_MASK 0x7e /* Bits 1-6 of MMR are significant */ + +/* Attribute Memory map */ + +#define CIS_ADDR 0x0000 /* Card Information Status Register */ +#define PSA_ADDR 0x0e00 /* Parameter Storage Area address */ +#define EEPROM_ADDR 0x1000 /* EEPROM address (unused ?) */ +#define COR_ADDR 0x4000 /* Configuration Option Register */ + +/* Configuration Option Register bit definitions */ + +#define COR_CONFIG (1 << 0) /* Config Index, 0 when unconfigured */ +#define COR_SW_RESET (1 << 7) /* Software Reset on true */ +#define COR_LEVEL_IRQ (1 << 6) /* Level IRQ */ + +/* Local Memory map */ + +#define RX_BASE 0x0000 /* Receive memory, 8 kB */ +#define TX_BASE 0x2000 /* Transmit memory, 2 kB */ +#define UNUSED_BASE 0x2800 /* Unused, 22 kB */ +#define RX_SIZE (TX_BASE-RX_BASE) /* Size of receive area */ +#define RX_SIZE_SHIFT 6 /* Bits to shift in stop register */ + +#define TRUE 1 +#define FALSE 0 + +#define MOD_ENAL 1 +#define MOD_PROM 2 + +/* Size of a MAC address */ +#define WAVELAN_ADDR_SIZE 6 + +/* Maximum size of Wavelan packet */ +#define WAVELAN_MTU 1500 + +#define MAXDATAZ (6 + 6 + 2 + WAVELAN_MTU) + +/********************** PARAMETER STORAGE AREA **********************/ + +/* + * Parameter Storage Area (PSA). + */ +typedef struct psa_t psa_t; +struct psa_t +{ + /* For the PCMCIA Adapter, locations 0x00-0x0F are unused and fixed at 00 */ + unsigned char psa_io_base_addr_1; /* [0x00] Base address 1 ??? */ + unsigned char psa_io_base_addr_2; /* [0x01] Base address 2 */ + unsigned char psa_io_base_addr_3; /* [0x02] Base address 3 */ + unsigned char psa_io_base_addr_4; /* [0x03] Base address 4 */ + unsigned char psa_rem_boot_addr_1; /* [0x04] Remote Boot Address 1 */ + unsigned char psa_rem_boot_addr_2; /* [0x05] Remote Boot Address 2 */ + unsigned char psa_rem_boot_addr_3; /* [0x06] Remote Boot Address 3 */ + unsigned char psa_holi_params; /* [0x07] HOst Lan Interface (HOLI) Parameters */ + unsigned char psa_int_req_no; /* [0x08] Interrupt Request Line */ + unsigned char psa_unused0[7]; /* [0x09-0x0F] unused */ + + unsigned char psa_univ_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x10-0x15] Universal (factory) MAC Address */ + unsigned char psa_local_mac_addr[WAVELAN_ADDR_SIZE]; /* [0x16-1B] Local MAC Address */ + unsigned char psa_univ_local_sel; /* [0x1C] Universal Local Selection */ +#define PSA_UNIVERSAL 0 /* Universal (factory) */ +#define PSA_LOCAL 1 /* Local */ + unsigned char psa_comp_number; /* [0x1D] Compatability Number: */ +#define PSA_COMP_PC_AT_915 0 /* PC-AT 915 MHz */ +#define PSA_COMP_PC_MC_915 1 /* PC-MC 915 MHz */ +#define PSA_COMP_PC_AT_2400 2 /* PC-AT 2.4 GHz */ +#define PSA_COMP_PC_MC_2400 3 /* PC-MC 2.4 GHz */ +#define PSA_COMP_PCMCIA_915 4 /* PCMCIA 915 MHz or 2.0 */ + unsigned char psa_thr_pre_set; /* [0x1E] Modem Threshold Preset */ + unsigned char psa_feature_select; /* [0x1F] Call code required (1=on) */ +#define PSA_FEATURE_CALL_CODE 0x01 /* Call code required (Japan) */ + unsigned char psa_subband; /* [0x20] Subband */ +#define PSA_SUBBAND_915 0 /* 915 MHz or 2.0 */ +#define PSA_SUBBAND_2425 1 /* 2425 MHz */ +#define PSA_SUBBAND_2460 2 /* 2460 MHz */ +#define PSA_SUBBAND_2484 3 /* 2484 MHz */ +#define PSA_SUBBAND_2430_5 4 /* 2430.5 MHz */ + unsigned char psa_quality_thr; /* [0x21] Modem Quality Threshold */ + unsigned char psa_mod_delay; /* [0x22] Modem Delay ??? (reserved) */ + unsigned char psa_nwid[2]; /* [0x23-0x24] Network ID */ + unsigned char psa_nwid_select; /* [0x25] Network ID Select On Off */ + unsigned char psa_encryption_select; /* [0x26] Encryption On Off */ + unsigned char psa_encryption_key[8]; /* [0x27-0x2E] Encryption Key */ + unsigned char psa_databus_width; /* [0x2F] AT bus width select 8/16 */ + unsigned char psa_call_code[8]; /* [0x30-0x37] (Japan) Call Code */ + unsigned char psa_nwid_prefix[2]; /* [0x38-0x39] Roaming domain */ + unsigned char psa_reserved[2]; /* [0x3A-0x3B] Reserved - fixed 00 */ + unsigned char psa_conf_status; /* [0x3C] Conf Status, bit 0=1:config*/ + unsigned char psa_crc[2]; /* [0x3D] CRC-16 over PSA */ + unsigned char psa_crc_status; /* [0x3F] CRC Valid Flag */ +}; + +/* Size for structure checking (if padding is correct) */ +#define PSA_SIZE 64 + +/* Calculate offset of a field in the above structure + * Warning : only even addresses are used */ +#define psaoff(p,f) ((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL)) + +/******************** MODEM MANAGEMENT INTERFACE ********************/ + +/* + * Modem Management Controller (MMC) write structure. + */ +typedef struct mmw_t mmw_t; +struct mmw_t +{ + unsigned char mmw_encr_key[8]; /* encryption key */ + unsigned char mmw_encr_enable; /* enable/disable encryption */ +#define MMW_ENCR_ENABLE_MODE 0x02 /* Mode of security option */ +#define MMW_ENCR_ENABLE_EN 0x01 /* Enable security option */ + unsigned char mmw_unused0[1]; /* unused */ + unsigned char mmw_des_io_invert; /* Encryption option */ +#define MMW_DES_IO_INVERT_RES 0x0F /* Reserved */ +#define MMW_DES_IO_INVERT_CTRL 0xF0 /* Control ??? (set to 0) */ + unsigned char mmw_unused1[5]; /* unused */ + unsigned char mmw_loopt_sel; /* looptest selection */ +#define MMW_LOOPT_SEL_DIS_NWID 0x40 /* disable NWID filtering */ +#define MMW_LOOPT_SEL_INT 0x20 /* activate Attention Request */ +#define MMW_LOOPT_SEL_LS 0x10 /* looptest w/o collision avoidance */ +#define MMW_LOOPT_SEL_LT3A 0x08 /* looptest 3a */ +#define MMW_LOOPT_SEL_LT3B 0x04 /* looptest 3b */ +#define MMW_LOOPT_SEL_LT3C 0x02 /* looptest 3c */ +#define MMW_LOOPT_SEL_LT3D 0x01 /* looptest 3d */ + unsigned char mmw_jabber_enable; /* jabber timer enable */ + /* Abort transmissions > 200 ms */ + unsigned char mmw_freeze; /* freeze / unfreeeze signal level */ + /* 0 : signal level & qual updated for every new message, 1 : frozen */ + unsigned char mmw_anten_sel; /* antenna selection */ +#define MMW_ANTEN_SEL_SEL 0x01 /* direct antenna selection */ +#define MMW_ANTEN_SEL_ALG_EN 0x02 /* antenna selection algo. enable */ + unsigned char mmw_ifs; /* inter frame spacing */ + /* min time between transmission in bit periods (.5 us) - bit 0 ignored */ + unsigned char mmw_mod_delay; /* modem delay (synchro) */ + unsigned char mmw_jam_time; /* jamming time (after collision) */ + unsigned char mmw_unused2[1]; /* unused */ + unsigned char mmw_thr_pre_set; /* level threshold preset */ + /* Discard all packet with signal < this value (4) */ + unsigned char mmw_decay_prm; /* decay parameters */ + unsigned char mmw_decay_updat_prm; /* decay update parameterz */ + unsigned char mmw_quality_thr; /* quality (z-quotient) threshold */ + /* Discard all packet with quality < this value (3) */ + unsigned char mmw_netw_id_l; /* NWID low order byte */ + unsigned char mmw_netw_id_h; /* NWID high order byte */ + /* Network ID or Domain : create virtual net on the air */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmw_mode_select; /* for analog tests (set to 0) */ + unsigned char mmw_unused3[1]; /* unused */ + unsigned char mmw_fee_ctrl; /* frequency eeprom control */ +#define MMW_FEE_CTRL_PRE 0x10 /* Enable protected instructions */ +#define MMW_FEE_CTRL_DWLD 0x08 /* Download eeprom to mmc */ +#define MMW_FEE_CTRL_CMD 0x07 /* EEprom commands : */ +#define MMW_FEE_CTRL_READ 0x06 /* Read */ +#define MMW_FEE_CTRL_WREN 0x04 /* Write enable */ +#define MMW_FEE_CTRL_WRITE 0x05 /* Write data to address */ +#define MMW_FEE_CTRL_WRALL 0x04 /* Write data to all addresses */ +#define MMW_FEE_CTRL_WDS 0x04 /* Write disable */ +#define MMW_FEE_CTRL_PRREAD 0x16 /* Read addr from protect register */ +#define MMW_FEE_CTRL_PREN 0x14 /* Protect register enable */ +#define MMW_FEE_CTRL_PRCLEAR 0x17 /* Unprotect all registers */ +#define MMW_FEE_CTRL_PRWRITE 0x15 /* Write addr in protect register */ +#define MMW_FEE_CTRL_PRDS 0x14 /* Protect register disable */ + /* Never issue this command (PRDS) : it's irreversible !!! */ + + unsigned char mmw_fee_addr; /* EEprom address */ +#define MMW_FEE_ADDR_CHANNEL 0xF0 /* Select the channel */ +#define MMW_FEE_ADDR_OFFSET 0x0F /* Offset in channel data */ +#define MMW_FEE_ADDR_EN 0xC0 /* FEE_CTRL enable operations */ +#define MMW_FEE_ADDR_DS 0x00 /* FEE_CTRL disable operations */ +#define MMW_FEE_ADDR_ALL 0x40 /* FEE_CTRL all operations */ +#define MMW_FEE_ADDR_CLEAR 0xFF /* FEE_CTRL clear operations */ + + unsigned char mmw_fee_data_l; /* Write data to EEprom */ + unsigned char mmw_fee_data_h; /* high octet */ + unsigned char mmw_ext_ant; /* Setting for external antenna */ +#define MMW_EXT_ANT_EXTANT 0x01 /* Select external antenna */ +#define MMW_EXT_ANT_POL 0x02 /* Polarity of the antenna */ +#define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ +#define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ +#define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ +} __attribute__((packed)); + +/* Size for structure checking (if padding is correct) */ +#define MMW_SIZE 37 + +/* Calculate offset of a field in the above structure */ +#define mmwoff(p,f) (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0) + + +/* + * Modem Management Controller (MMC) read structure. + */ +typedef struct mmr_t mmr_t; +struct mmr_t +{ + unsigned char mmr_unused0[8]; /* unused */ + unsigned char mmr_des_status; /* encryption status */ + unsigned char mmr_des_avail; /* encryption available (0x55 read) */ +#define MMR_DES_AVAIL_DES 0x55 /* DES available */ +#define MMR_DES_AVAIL_AES 0x33 /* AES (AT&T) available */ + unsigned char mmr_des_io_invert; /* des I/O invert register */ + unsigned char mmr_unused1[5]; /* unused */ + unsigned char mmr_dce_status; /* DCE status */ +#define MMR_DCE_STATUS_RX_BUSY 0x01 /* receiver busy */ +#define MMR_DCE_STATUS_LOOPT_IND 0x02 /* loop test indicated */ +#define MMR_DCE_STATUS_TX_BUSY 0x04 /* transmitter on */ +#define MMR_DCE_STATUS_JBR_EXPIRED 0x08 /* jabber timer expired */ +#define MMR_DCE_STATUS 0x0F /* mask to get the bits */ + unsigned char mmr_dsp_id; /* DSP id (AA = Daedalus rev A) */ + unsigned char mmr_unused2[2]; /* unused */ + unsigned char mmr_correct_nwid_l; /* # of correct NWID's rxd (low) */ + unsigned char mmr_correct_nwid_h; /* # of correct NWID's rxd (high) */ + /* Warning : Read high order octet first !!! */ + unsigned char mmr_wrong_nwid_l; /* # of wrong NWID's rxd (low) */ + unsigned char mmr_wrong_nwid_h; /* # of wrong NWID's rxd (high) */ + unsigned char mmr_thr_pre_set; /* level threshold preset */ +#define MMR_THR_PRE_SET 0x3F /* level threshold preset */ +#define MMR_THR_PRE_SET_CUR 0x80 /* Current signal above it */ + unsigned char mmr_signal_lvl; /* signal level */ +#define MMR_SIGNAL_LVL 0x3F /* signal level */ +#define MMR_SIGNAL_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_silence_lvl; /* silence level (noise) */ +#define MMR_SILENCE_LVL 0x3F /* silence level */ +#define MMR_SILENCE_LVL_VALID 0x80 /* Updated since last read */ + unsigned char mmr_sgnl_qual; /* signal quality */ +#define MMR_SGNL_QUAL 0x0F /* signal quality */ +#define MMR_SGNL_QUAL_ANT 0x80 /* current antenna used */ + unsigned char mmr_netw_id_l; /* NWID low order byte ??? */ + unsigned char mmr_unused3[3]; /* unused */ + + /* 2.0 Hardware extension - frequency selection support */ + unsigned char mmr_fee_status; /* Status of frequency eeprom */ +#define MMR_FEE_STATUS_ID 0xF0 /* Modem revision id */ +#define MMR_FEE_STATUS_DWLD 0x08 /* Download in progress */ +#define MMR_FEE_STATUS_BUSY 0x04 /* EEprom busy */ + unsigned char mmr_unused4[1]; /* unused */ + unsigned char mmr_fee_data_l; /* Read data from eeprom (low) */ + unsigned char mmr_fee_data_h; /* Read data from eeprom (high) */ +}; + +/* Size for structure checking (if padding is correct) */ +#define MMR_SIZE 36 + +/* Calculate offset of a field in the above structure */ +#define mmroff(p,f) (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0) + + +/* Make the two above structures one */ +typedef union mm_t +{ + struct mmw_t w; /* Write to the mmc */ + struct mmr_t r; /* Read from the mmc */ +} mm_t; + +#endif /* _WAVELAN_CS_H */ diff --git a/drivers/staging/wavelan/wavelan_cs.p.h b/drivers/staging/wavelan/wavelan_cs.p.h new file mode 100644 index 000000000000..81d91531c4f9 --- /dev/null +++ b/drivers/staging/wavelan/wavelan_cs.p.h @@ -0,0 +1,766 @@ +/* + * Wavelan Pcmcia driver + * + * Jean II - HPLB '96 + * + * Reorganisation and extension of the driver. + * + * This file contain all definition and declarations necessary for the + * wavelan pcmcia driver. This file is a private header, so it should + * be included only on wavelan_cs.c !!! + */ + +#ifndef WAVELAN_CS_P_H +#define WAVELAN_CS_P_H + +/************************** DOCUMENTATION **************************/ +/* + * This driver provide a Linux interface to the Wavelan Pcmcia hardware + * The Wavelan is a product of Lucent (http://www.wavelan.com/). + * This division was formerly part of NCR and then AT&T. + * Wavelan are also distributed by DEC (RoamAbout DS)... + * + * To know how to use this driver, read the PCMCIA HOWTO. + * If you want to exploit the many other fonctionalities, look comments + * in the code... + * + * This driver is the result of the effort of many peoples (see below). + */ + +/* ------------------------ SPECIFIC NOTES ------------------------ */ +/* + * Web page + * -------- + * I try to maintain a web page with the Wireless LAN Howto at : + * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + * + * SMP + * --- + * We now are SMP compliant (I eventually fixed the remaining bugs). + * The driver has been tested on a dual P6-150 and survived my usual + * set of torture tests. + * Anyway, I spent enough time chasing interrupt re-entrancy during + * errors or reconfigure, and I designed the locked/unlocked sections + * of the driver with great care, and with the recent addition of + * the spinlock (thanks to the new API), we should be quite close to + * the truth. + * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), + * but better safe than sorry (especially at 2 Mb/s ;-). + * + * I have also looked into disabling only our interrupt on the card + * (via HACR) instead of all interrupts in the processor (via cli), + * so that other driver are not impacted, and it look like it's + * possible, but it's very tricky to do right (full of races). As + * the gain would be mostly for SMP systems, it can wait... + * + * Debugging and options + * --------------------- + * You will find below a set of '#define" allowing a very fine control + * on the driver behaviour and the debug messages printed. + * The main options are : + * o WAVELAN_ROAMING, for the experimental roaming support. + * o SET_PSA_CRC, to have your card correctly recognised by + * an access point and the Point-to-Point diagnostic tool. + * o USE_PSA_CONFIG, to read configuration from the PSA (EEprom) + * (otherwise we always start afresh with some defaults) + * + * wavelan_cs.o is darn too big + * ------------------------- + * That's true ! There is a very simple way to reduce the driver + * object by 33% (yes !). Comment out the following line : + * #include + * Other compile options can also reduce the size of it... + * + * MAC address and hardware detection : + * ---------------------------------- + * The detection code of the wavelan chech that the first 3 + * octets of the MAC address fit the company code. This type of + * detection work well for AT&T cards (because the AT&T code is + * hardcoded in wavelan_cs.h), but of course will fail for other + * manufacturer. + * + * If you are sure that your card is derived from the wavelan, + * here is the way to configure it : + * 1) Get your MAC address + * a) With your card utilities (wfreqsel, instconf, ...) + * b) With the driver : + * o compile the kernel with DEBUG_CONFIG_INFO enabled + * o Boot and look the card messages + * 2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan_cs.h) + * 3) Compile & verify + * 4) Send me the MAC code - I will include it in the next version... + * + */ + +/* --------------------- WIRELESS EXTENSIONS --------------------- */ +/* + * This driver is the first one to support "wireless extensions". + * This set of extensions provide you some way to control the wireless + * caracteristics of the hardware in a standard way and support for + * applications for taking advantage of it (like Mobile IP). + * + * It might be a good idea as well to fetch the wireless tools to + * configure the device and play a bit. + */ + +/* ---------------------------- FILES ---------------------------- */ +/* + * wavelan_cs.c : The actual code for the driver - C functions + * + * wavelan_cs.p.h : Private header : local types / vars for the driver + * + * wavelan_cs.h : Description of the hardware interface & structs + * + * i82593.h : Description if the Ethernet controller + */ + +/* --------------------------- HISTORY --------------------------- */ +/* + * The history of the Wavelan drivers is as complicated as history of + * the Wavelan itself (NCR -> AT&T -> Lucent). + * + * All started with Anders Klemets , + * writing a Wavelan ISA driver for the MACH microkernel. Girish + * Welling had also worked on it. + * Keith Moore modify this for the Pcmcia hardware. + * + * Robert Morris port these two drivers to BSDI + * and add specific Pcmcia support (there is currently no equivalent + * of the PCMCIA package under BSD...). + * + * Jim Binkley port both BSDI drivers to FreeBSD. + * + * Bruce Janson port the BSDI ISA driver to Linux. + * + * Anthony D. Joseph started modify Bruce driver + * (with help of the BSDI PCMCIA driver) for PCMCIA. + * Yunzhou Li finished is work. + * Joe Finney patched the driver to start + * correctly 2.00 cards (2.4 GHz with frequency selection). + * David Hinds integrated the whole in his + * Pcmcia package (+ bug corrections). + * + * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some + * patchs to the Pcmcia driver. After, I added code in the ISA driver + * for Wireless Extensions and full support of frequency selection + * cards. Now, I'm doing the same to the Pcmcia driver + some + * reorganisation. + * Loeke Brederveld from Lucent has given me + * much needed informations on the Wavelan hardware. + */ + +/* By the way : for the copyright & legal stuff : + * Almost everybody wrote code under GNU or BSD license (or alike), + * and want that their original copyright remain somewhere in the + * code (for myself, I go with the GPL). + * Nobody want to take responsibility for anything, except the fame... + */ + +/* --------------------------- CREDITS --------------------------- */ +/* + * Credits: + * Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht and + * Loeke Brederveld of Lucent for providing extremely useful + * information about WaveLAN PCMCIA hardware + * + * This driver is based upon several other drivers, in particular: + * David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter + * Bruce Janson's Linux driver for the AT-bus WaveLAN adapter + * Anders Klemets' PCMCIA WaveLAN adapter driver + * Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter + * + * Additional Credits: + * + * This software was originally developed under Linux 1.2.3 + * (Slackware 2.0 distribution). + * And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+) + * with an HP OmniBook 4000 and then a 5500. + * + * It is based on other device drivers and information either written + * or supplied by: + * James Ashton (jaa101@syseng.anu.edu.au), + * Ajay Bakre (bakre@paul.rutgers.edu), + * Donald Becker (becker@super.org), + * Jim Binkley , + * Loeke Brederveld , + * Allan Creighton (allanc@cs.su.oz.au), + * Brent Elphick , + * Joe Finney , + * Matthew Geier (matthew@cs.su.oz.au), + * Remo di Giovanni (remo@cs.su.oz.au), + * Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM), + * David Hinds , + * Jan Hoogendoorn (c/o marteijn@lucent.com), + * Bruce Janson , + * Anthony D. Joseph , + * Anders Klemets (klemets@paul.rutgers.edu), + * Yunzhou Li , + * Marc Meertens (mmeertens@lucent.com), + * Keith Moore, + * Robert Morris (rtm@das.harvard.edu), + * Ian Parkin (ian@cs.su.oz.au), + * John Rosenberg (johnr@cs.su.oz.au), + * George Rossi (george@phm.gov.au), + * Arthur Scott (arthur@cs.su.oz.au), + * Stanislav Sinyagin + * Peter Storey, + * Jean Tourrilhes , + * Girish Welling (welling@paul.rutgers.edu) + * Clark Woodworth + * Yongguang Zhang ... + */ + +/* ------------------------- IMPROVEMENTS ------------------------- */ +/* + * I proudly present : + * + * Changes made in 2.8.22 : + * ---------------------- + * - improved wv_set_multicast_list + * - catch spurious interrupt + * - correct release of the device + * + * Changes mades in release : + * ------------------------ + * - Reorganisation of the code, function name change + * - Creation of private header (wavelan_cs.h) + * - Reorganised debug messages + * - More comments, history, ... + * - Configure earlier (in "insert" instead of "open") + * and do things only once + * - mmc_init : configure the PSA if not done + * - mmc_init : 2.00 detection better code for 2.00 init + * - better info at startup + * - Correct a HUGE bug (volatile & uncalibrated busy loop) + * in wv_82593_cmd => config speedup + * - Stop receiving & power down on close (and power up on open) + * use "ifconfig down" & "ifconfig up ; route add -net ..." + * - Send packets : add watchdog instead of pooling + * - Receive : check frame wrap around & try to recover some frames + * - wavelan_set_multicast_list : avoid reset + * - add wireless extensions (ioctl & get_wireless_stats) + * get/set nwid/frequency on fly, info for /proc/net/wireless + * - Suppress useless stuff from lp (net_local), but add link + * - More inlines + * - Lot of others minor details & cleanups + * + * Changes made in second release : + * ------------------------------ + * - Optimise wv_85893_reconfig stuff, fix potential problems + * - Change error values for ioctl + * - Non blocking wv_ru_stop() + call wv_reset() in case of problems + * - Remove development printk from wavelan_watchdog() + * - Remove of the watchdog to wavelan_close instead of wavelan_release + * fix potential problems... + * - Start debugging suspend stuff (but it's still a bit weird) + * - Debug & optimize dump header/packet in Rx & Tx (debug) + * - Use "readb" and "writeb" to be kernel 2.1 compliant + * - Better handling of bogus interrupts + * - Wireless extension : SETSPY and GETSPY + * - Remove old stuff (stats - for those needing it, just ask me...) + * - Make wireless extensions optional + * + * Changes made in third release : + * ----------------------------- + * - cleanups & typos + * - modif wireless ext (spy -> only one pointer) + * - new private ioctl to set/get quality & level threshold + * - Init : correct default value of level threshold for pcmcia + * - kill watchdog in hw_reset + * - more 2.1 support (copy_to/from_user instead of memcpy_to/fromfs) + * - Add message level (debug stuff in /var/adm/debug & errors not + * displayed at console and still in /var/adm/messages) + * + * Changes made in fourth release : + * ------------------------------ + * - multicast support (yes !) thanks to Yongguang Zhang. + * + * Changes made in fifth release (2.9.0) : + * ------------------------------------- + * - Revisited multicast code (it was mostly wrong). + * - protect code in wv_82593_reconfig with dev->tbusy (oups !) + * + * Changes made in sixth release (2.9.1a) : + * -------------------------------------- + * - Change the detection code for multi manufacturer code support + * - Correct bug (hang kernel) in init when we were "rejecting" a card + * + * Changes made in seventh release (2.9.1b) : + * ---------------------------------------- + * - Update to wireless extensions changes + * - Silly bug in card initial configuration (psa_conf_status) + * + * Changes made in eigth release : + * ----------------------------- + * - Small bug in debug code (probably not the last one...) + * - 1.2.13 support (thanks to Clark Woodworth) + * + * Changes made for release in 2.9.2b : + * ---------------------------------- + * - Level threshold is now a standard wireless extension (version 4 !) + * - modules parameters types for kernel > 2.1.17 + * - updated man page + * - Others cleanup from David Hinds + * + * Changes made for release in 2.9.5 : + * --------------------------------- + * - byte count stats (courtesy of David Hinds) + * - Remove dev_tint stuff (courtesy of David Hinds) + * - Others cleanup from David Hinds + * - Encryption setting from Brent Elphick (thanks a lot !) + * - 'base' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin) + * + * Changes made for release in 2.9.6 : + * --------------------------------- + * - fix bug : no longuer disable watchdog in case of bogus interrupt + * - increase timeout in config code for picky hardware + * - mask unused bits in status (Wireless Extensions) + * + * Changes integrated by Justin Seger & David Hinds : + * ----------------------------------------------------------------- + * - Roaming "hack" from Joe Finney + * - PSA CRC code from Bob Gray + * - Better initialisation of the i82593 controller + * from Joseph K. O'Sullivan + * + * Changes made for release in 3.0.10 : + * ---------------------------------- + * - Fix eject "hang" of the driver under 2.2.X : + * o create wv_flush_stale_links() + * o Rename wavelan_release to wv_pcmcia_release & move up + * o move unregister_netdev to wavelan_detach() + * o wavelan_release() no longer call wavelan_detach() + * o Suppress "release" timer + * o Other cleanups & fixes + * - New MAC address in the probe + * - Reorg PSA_CRC code (endian neutral & cleaner) + * - Correct initialisation of the i82593 from Lucent manual + * - Put back the watchdog, with larger timeout + * - TRANSMIT_NO_CRC is a "normal" error, so recover from it + * from Derrick J Brashear + * - Better handling of TX and RX normal failure conditions + * - #ifdef out all the roaming code + * - Add ESSID & "AP current address" ioctl stubs + * - General cleanup of the code + * + * Changes made for release in 3.0.13 : + * ---------------------------------- + * - Re-enable compilation of roaming code by default, but with + * do_roaming = 0 + * - Nuke `nwid=nwid^ntohs(beacon->domain_id)' in wl_roam_gather + * at the demand of John Carol Langford + * - Introduced WAVELAN_ROAMING_EXT for incomplete ESSID stuff. + * + * Changes made for release in 3.0.15 : + * ---------------------------------- + * - Change e-mail and web page addresses + * - Watchdog timer is now correctly expressed in HZ, not in jiffies + * - Add channel number to the list of frequencies in range + * - Add the (short) list of bit-rates in range + * - Developp a new sensitivity... (sens.value & sens.fixed) + * + * Changes made for release in 3.1.2 : + * --------------------------------- + * - Fix check for root permission (break instead of exit) + * - New nwid & encoding setting (Wireless Extension 9) + * + * Changes made for release in 3.1.12 : + * ---------------------------------- + * - reworked wv_82593_cmd to avoid using the IRQ handler and doing + * ugly things with interrupts. + * - Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog + * - Update to new network API (softnet - 2.3.43) : + * o replace dev->tbusy (David + me) + * o replace dev->tstart (David + me) + * o remove dev->interrupt (David) + * o add SMP locking via spinlock in splxx (me) + * o add spinlock in interrupt handler (me) + * o use kernel watchdog instead of ours (me) + * o verify that all the changes make sense and work (me) + * - Re-sync kernel/pcmcia versions (not much actually) + * - A few other cleanups (David & me)... + * + * Changes made for release in 3.1.22 : + * ---------------------------------- + * - Check that SMP works, remove annoying log message + * + * Changes made for release in 3.1.24 : + * ---------------------------------- + * - Fix unfrequent card lockup when watchdog was reseting the hardware : + * o control first busy loop in wv_82593_cmd() + * o Extend spinlock protection in wv_hw_config() + * + * Changes made for release in 3.1.33 : + * ---------------------------------- + * - Optional use new driver API for Wireless Extensions : + * o got rid of wavelan_ioctl() + * o use a bunch of iw_handler instead + * + * Changes made for release in 3.2.1 : + * --------------------------------- + * - Set dev->trans_start to avoid filling the logs + * (and generating useless abort commands) + * - Avoid deadlocks in mmc_out()/mmc_in() + * + * Wishes & dreams: + * ---------------- + * - Cleanup and integrate the roaming code + * (std debug, set DomainID, decay avg and co...) + */ + +/***************************** INCLUDES *****************************/ + +/* Linux headers that we need */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include /* Wireless extensions */ +#include /* New driver API */ + +/* Pcmcia headers that we need */ +#include +#include +#include +#include +#include + +/* Wavelan declarations */ +#include "i82593.h" /* Definitions for the Intel chip */ + +#include "wavelan_cs.h" /* Others bits of the hardware */ + +/************************** DRIVER OPTIONS **************************/ +/* + * `#define' or `#undef' the following constant to change the behaviour + * of the driver... + */ +#define WAVELAN_ROAMING /* Include experimental roaming code */ +#undef WAVELAN_ROAMING_EXT /* Enable roaming wireless extensions */ +#undef SET_PSA_CRC /* Set the CRC in PSA (slower) */ +#define USE_PSA_CONFIG /* Use info from the PSA */ +#undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */ +#define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ +#undef SET_MAC_ADDRESS /* Experimental */ + +/* Warning : these stuff will slow down the driver... */ +#define WIRELESS_SPY /* Enable spying addresses */ +#undef HISTOGRAM /* Enable histogram of sig level... */ + +/****************************** DEBUG ******************************/ + +#undef DEBUG_MODULE_TRACE /* Module insertion/removal */ +#undef DEBUG_CALLBACK_TRACE /* Calls made by Linux */ +#undef DEBUG_INTERRUPT_TRACE /* Calls to handler */ +#undef DEBUG_INTERRUPT_INFO /* type of interrupt & so on */ +#define DEBUG_INTERRUPT_ERROR /* problems */ +#undef DEBUG_CONFIG_TRACE /* Trace the config functions */ +#undef DEBUG_CONFIG_INFO /* What's going on... */ +#define DEBUG_CONFIG_ERRORS /* Errors on configuration */ +#undef DEBUG_TX_TRACE /* Transmission calls */ +#undef DEBUG_TX_INFO /* Header of the transmitted packet */ +#undef DEBUG_TX_FAIL /* Normal failure conditions */ +#define DEBUG_TX_ERROR /* Unexpected conditions */ +#undef DEBUG_RX_TRACE /* Transmission calls */ +#undef DEBUG_RX_INFO /* Header of the transmitted packet */ +#undef DEBUG_RX_FAIL /* Normal failure conditions */ +#define DEBUG_RX_ERROR /* Unexpected conditions */ +#undef DEBUG_PACKET_DUMP /* Dump packet on the screen */ +#undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ +#undef DEBUG_IOCTL_INFO /* Various debug info */ +#define DEBUG_IOCTL_ERROR /* What's going wrong */ +#define DEBUG_BASIC_SHOW /* Show basic startup info */ +#undef DEBUG_VERSION_SHOW /* Print version info */ +#undef DEBUG_PSA_SHOW /* Dump psa to screen */ +#undef DEBUG_MMC_SHOW /* Dump mmc to screen */ +#undef DEBUG_SHOW_UNUSED /* Show also unused fields */ +#undef DEBUG_I82593_SHOW /* Show i82593 status */ +#undef DEBUG_DEVICE_SHOW /* Show device parameters */ + +/************************ CONSTANTS & MACROS ************************/ + +#ifdef DEBUG_VERSION_SHOW +static const char *version = "wavelan_cs.c : v24 (SMP + wireless extensions) 11/1/02\n"; +#endif + +/* Watchdog temporisation */ +#define WATCHDOG_JIFFIES (256*HZ/100) + +/* Fix a bug in some old wireless extension definitions */ +#ifndef IW_ESSID_MAX_SIZE +#define IW_ESSID_MAX_SIZE 32 +#endif + +/* ------------------------ PRIVATE IOCTL ------------------------ */ + +#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ +#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ +#define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */ +#define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */ + +#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 4 /* Set histogram ranges */ +#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 5 /* Get histogram values */ + +/*************************** WaveLAN Roaming **************************/ +#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ + +#define WAVELAN_ROAMING_DEBUG 0 /* 1 = Trace of handover decisions */ + /* 2 = Info on each beacon rcvd... */ +#define MAX_WAVEPOINTS 7 /* Max visible at one time */ +#define WAVEPOINT_HISTORY 5 /* SNR sample history slow search */ +#define WAVEPOINT_FAST_HISTORY 2 /* SNR sample history fast search */ +#define SEARCH_THRESH_LOW 10 /* SNR to enter cell search */ +#define SEARCH_THRESH_HIGH 13 /* SNR to leave cell search */ +#define WAVELAN_ROAMING_DELTA 1 /* Hysteresis value (+/- SNR) */ +#define CELL_TIMEOUT 2*HZ /* in jiffies */ + +#define FAST_CELL_SEARCH 1 /* Boolean values... */ +#define NWID_PROMISC 1 /* for code clarity. */ + +typedef struct wavepoint_beacon +{ + unsigned char dsap, /* Unused */ + ssap, /* Unused */ + ctrl, /* Unused */ + O,U,I, /* Unused */ + spec_id1, /* Unused */ + spec_id2, /* Unused */ + pdu_type, /* Unused */ + seq; /* WavePoint beacon sequence number */ + __be16 domain_id, /* WavePoint Domain ID */ + nwid; /* WavePoint NWID */ +} wavepoint_beacon; + +typedef struct wavepoint_history +{ + unsigned short nwid; /* WavePoint's NWID */ + int average_slow; /* SNR running average */ + int average_fast; /* SNR running average */ + unsigned char sigqual[WAVEPOINT_HISTORY]; /* Ringbuffer of recent SNR's */ + unsigned char qualptr; /* Index into ringbuffer */ + unsigned char last_seq; /* Last seq. no seen for WavePoint */ + struct wavepoint_history *next; /* Next WavePoint in table */ + struct wavepoint_history *prev; /* Previous WavePoint in table */ + unsigned long last_seen; /* Time of last beacon recvd, jiffies */ +} wavepoint_history; + +struct wavepoint_table +{ + wavepoint_history *head; /* Start of ringbuffer */ + int num_wavepoints; /* No. of WavePoints visible */ + unsigned char locked; /* Table lock */ +}; + +#endif /* WAVELAN_ROAMING */ + +/****************************** TYPES ******************************/ + +/* Shortcuts */ +typedef struct iw_statistics iw_stats; +typedef struct iw_quality iw_qual; +typedef struct iw_freq iw_freq; +typedef struct net_local net_local; +typedef struct timer_list timer_list; + +/* Basic types */ +typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ + +/* + * Static specific data for the interface. + * + * For each network interface, Linux keep data in two structure. "device" + * keep the generic data (same format for everybody) and "net_local" keep + * the additional specific data. + */ +struct net_local +{ + dev_node_t node; /* ???? What is this stuff ???? */ + struct net_device * dev; /* Reverse link... */ + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ + struct pcmcia_device * link; /* pcmcia structure */ + int nresets; /* Number of hw resets */ + u_char configured; /* If it is configured */ + u_char reconfig_82593; /* Need to reconfigure the controller */ + u_char promiscuous; /* Promiscuous mode */ + u_char allmulticast; /* All Multicast mode */ + int mc_count; /* Number of multicast addresses */ + + int stop; /* Current i82593 Stop Hit Register */ + int rfp; /* Last DMA machine receive pointer */ + int overrunning; /* Receiver overrun flag */ + + iw_stats wstats; /* Wireless specific stats */ + + struct iw_spy_data spy_data; + struct iw_public_data wireless_data; + +#ifdef HISTOGRAM + int his_number; /* Number of intervals */ + u_char his_range[16]; /* Boundaries of interval ]n-1; n] */ + u_long his_sum[16]; /* Sum in interval */ +#endif /* HISTOGRAM */ +#ifdef WAVELAN_ROAMING + u_long domain_id; /* Domain ID we lock on for roaming */ + int filter_domains; /* Check Domain ID of beacon found */ + struct wavepoint_table wavepoint_table; /* Table of visible WavePoints*/ + wavepoint_history * curr_point; /* Current wavepoint */ + int cell_search; /* Searching for new cell? */ + struct timer_list cell_timer; /* Garbage collection */ +#endif /* WAVELAN_ROAMING */ + void __iomem *mem; +}; + +/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ +static inline u_char /* data */ + hasr_read(u_long); /* Read the host interface : base address */ +static void + hacr_write(u_long, /* Write to host interface : base address */ + u_char), /* data */ + hacr_write_slow(u_long, + u_char); +static void + psa_read(struct net_device *, /* Read the Parameter Storage Area */ + int, /* offset in PSA */ + u_char *, /* buffer to fill */ + int), /* size to read */ + psa_write(struct net_device *, /* Write to the PSA */ + int, /* Offset in psa */ + u_char *, /* Buffer in memory */ + int); /* Length of buffer */ +static void + mmc_out(u_long, /* Write 1 byte to the Modem Manag Control */ + u_short, + u_char), + mmc_write(u_long, /* Write n bytes to the MMC */ + u_char, + u_char *, + int); +static u_char /* Read 1 byte from the MMC */ + mmc_in(u_long, + u_short); +static void + mmc_read(u_long, /* Read n bytes from the MMC */ + u_char, + u_char *, + int), + fee_wait(u_long, /* Wait for frequency EEprom : base address */ + int, /* Base delay to wait for */ + int); /* Number of time to wait */ +static void + fee_read(u_long, /* Read the frequency EEprom : base address */ + u_short, /* destination offset */ + u_short *, /* data buffer */ + int); /* number of registers */ +/* ---------------------- I82593 SUBROUTINES ----------------------- */ +static int + wv_82593_cmd(struct net_device *, /* synchronously send a command to i82593 */ + char *, + int, + int); +static inline int + wv_diag(struct net_device *); /* Diagnostique the i82593 */ +static int + read_ringbuf(struct net_device *, /* Read a receive buffer */ + int, + char *, + int); +static void + wv_82593_reconfig(struct net_device *); /* Reconfigure the controller */ +/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ +static void + wv_init_info(struct net_device *); /* display startup info */ +/* ------------------- IOCTL, STATS & RECONFIG ------------------- */ +static iw_stats * + wavelan_get_wireless_stats(struct net_device *); +/* ----------------------- PACKET RECEPTION ----------------------- */ +static int + wv_start_of_frame(struct net_device *, /* Seek beggining of current frame */ + int, /* end of frame */ + int); /* start of buffer */ +static void + wv_packet_read(struct net_device *, /* Read a packet from a frame */ + int, + int), + wv_packet_rcv(struct net_device *); /* Read all packets waiting */ +/* --------------------- PACKET TRANSMISSION --------------------- */ +static void + wv_packet_write(struct net_device *, /* Write a packet to the Tx buffer */ + void *, + short); +static netdev_tx_t + wavelan_packet_xmit(struct sk_buff *, /* Send a packet */ + struct net_device *); +/* -------------------- HARDWARE CONFIGURATION -------------------- */ +static int + wv_mmc_init(struct net_device *); /* Initialize the modem */ +static int + wv_ru_stop(struct net_device *), /* Stop the i82593 receiver unit */ + wv_ru_start(struct net_device *); /* Start the i82593 receiver unit */ +static int + wv_82593_config(struct net_device *); /* Configure the i82593 */ +static int + wv_pcmcia_reset(struct net_device *); /* Reset the pcmcia interface */ +static int + wv_hw_config(struct net_device *); /* Reset & configure the whole hardware */ +static void + wv_hw_reset(struct net_device *); /* Same, + start receiver unit */ +static int + wv_pcmcia_config(struct pcmcia_device *); /* Configure the pcmcia interface */ +static void + wv_pcmcia_release(struct pcmcia_device *);/* Remove a device */ +/* ---------------------- INTERRUPT HANDLING ---------------------- */ +static irqreturn_t + wavelan_interrupt(int, /* Interrupt handler */ + void *); +static void + wavelan_watchdog(struct net_device *); /* Transmission watchdog */ +/* ------------------- CONFIGURATION CALLBACKS ------------------- */ +static int + wavelan_open(struct net_device *), /* Open the device */ + wavelan_close(struct net_device *); /* Close the device */ +static void + wavelan_detach(struct pcmcia_device *p_dev); /* Destroy a removed device */ + +/**************************** VARIABLES ****************************/ + +/* + * Parameters that can be set with 'insmod' + * The exact syntax is 'insmod wavelan_cs.o =' + */ + +/* Shared memory speed, in ns */ +static int mem_speed = 0; + +/* New module interface */ +module_param(mem_speed, int, 0); + +#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ +/* Enable roaming mode ? No ! Please keep this to 0 */ +static int do_roaming = 0; +module_param(do_roaming, bool, 0); +#endif /* WAVELAN_ROAMING */ + +MODULE_LICENSE("GPL"); + +#endif /* WAVELAN_CS_P_H */ + -- cgit v1.2.3 From 4b5783549730da21d88b41dce9a2b738afa44abc Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 28 Oct 2009 16:16:38 -0400 Subject: netwave: move driver to staging Move the netwave driver to drivers/staging. This is another pre-802.11 driver that has seen virtually no non-API-fixup activity in years, and for which no active hardware is likely to still exist. This driver represents unnecessary ongoing maintenance for no clear benefit. This patch brought to you by the "hacking" session at the 2009 Kernel Summit in Tokyo, Japan... Acked-by: Greg Kroah-Hartman Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 13 - drivers/net/wireless/Makefile | 3 - drivers/net/wireless/netwave_cs.c | 1389 ---------------------------------- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/netwave/Kconfig | 11 + drivers/staging/netwave/Makefile | 1 + drivers/staging/netwave/netwave_cs.c | 1389 ++++++++++++++++++++++++++++++++++ 8 files changed, 1404 insertions(+), 1405 deletions(-) delete mode 100644 drivers/net/wireless/netwave_cs.c create mode 100644 drivers/staging/netwave/Kconfig create mode 100644 drivers/staging/netwave/Makefile create mode 100644 drivers/staging/netwave/netwave_cs.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index f94188f05a02..bf0eb4e774b4 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -25,19 +25,6 @@ menuconfig WLAN_PRE80211 This option does not affect the kernel build, it only lets you choose drivers. -config PCMCIA_NETWAVE - tristate "Xircom Netwave AirSurfer Pcmcia wireless support" - depends on PCMCIA && WLAN_PRE80211 - select WIRELESS_EXT - select WEXT_PRIV - help - Say Y here if you intend to attach this type of PCMCIA (PC-card) - wireless Ethernet networking card to your computer. - - To compile this driver as a module, choose M here: the module will be - called netwave_cs. If unsure, say N. - - menuconfig WLAN_80211 bool "Wireless LAN (IEEE 802.11)" depends on NETDEVICES diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index f4a7c8ae27ea..5d4ce4d2b32b 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -5,9 +5,6 @@ obj-$(CONFIG_IPW2100) += ipw2x00/ obj-$(CONFIG_IPW2200) += ipw2x00/ -# Obsolete cards -obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o - obj-$(CONFIG_HERMES) += orinoco/ obj-$(CONFIG_AIRO) += airo.o diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c deleted file mode 100644 index 9498b46c99a4..000000000000 --- a/drivers/net/wireless/netwave_cs.c +++ /dev/null @@ -1,1389 +0,0 @@ -/********************************************************************* - * - * Filename: netwave_cs.c - * Version: 0.4.1 - * Description: Netwave AirSurfer Wireless LAN PC Card driver - * Status: Experimental. - * Authors: John Markus Bjørndalen - * Dag Brattli - * David Hinds - * Created at: A long time ago! - * Modified at: Mon Nov 10 11:54:37 1997 - * Modified by: Dag Brattli - * - * Copyright (c) 1997 University of Tromsø, Norway - * - * Revision History: - * - * 08-Nov-97 15:14:47 John Markus Bjørndalen - * - Fixed some bugs in netwave_rx and cleaned it up a bit. - * (One of the bugs would have destroyed packets when receiving - * multiple packets per interrupt). - * - Cleaned up parts of newave_hw_xmit. - * - A few general cleanups. - * 24-Oct-97 13:17:36 Dag Brattli - * - Fixed netwave_rx receive function (got updated docs) - * Others: - * - Changed name from xircnw to netwave, take a look at - * http://www.netwave-wireless.com - * - Some reorganizing of the code - * - Removed possible race condition between interrupt handler and transmit - * function - * - Started to add wireless extensions, but still needs some coding - * - Added watchdog for better handling of transmission timeouts - * (hopefully this works better) - ********************************************************************/ - -/* To have statistics (just packets sent) define this */ -#undef NETWAVE_STATS - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define NETWAVE_REGOFF 0x8000 -/* The Netwave IO registers, offsets to iobase */ -#define NETWAVE_REG_COR 0x0 -#define NETWAVE_REG_CCSR 0x2 -#define NETWAVE_REG_ASR 0x4 -#define NETWAVE_REG_IMR 0xa -#define NETWAVE_REG_PMR 0xc -#define NETWAVE_REG_IOLOW 0x6 -#define NETWAVE_REG_IOHI 0x7 -#define NETWAVE_REG_IOCONTROL 0x8 -#define NETWAVE_REG_DATA 0xf -/* The Netwave Extended IO registers, offsets to RamBase */ -#define NETWAVE_EREG_ASCC 0x114 -#define NETWAVE_EREG_RSER 0x120 -#define NETWAVE_EREG_RSERW 0x124 -#define NETWAVE_EREG_TSER 0x130 -#define NETWAVE_EREG_TSERW 0x134 -#define NETWAVE_EREG_CB 0x100 -#define NETWAVE_EREG_SPCQ 0x154 -#define NETWAVE_EREG_SPU 0x155 -#define NETWAVE_EREG_LIF 0x14e -#define NETWAVE_EREG_ISPLQ 0x156 -#define NETWAVE_EREG_HHC 0x158 -#define NETWAVE_EREG_NI 0x16e -#define NETWAVE_EREG_MHS 0x16b -#define NETWAVE_EREG_TDP 0x140 -#define NETWAVE_EREG_RDP 0x150 -#define NETWAVE_EREG_PA 0x160 -#define NETWAVE_EREG_EC 0x180 -#define NETWAVE_EREG_CRBP 0x17a -#define NETWAVE_EREG_ARW 0x166 - -/* - * Commands used in the extended command buffer - * NETWAVE_EREG_CB (0x100-0x10F) - */ -#define NETWAVE_CMD_NOP 0x00 -#define NETWAVE_CMD_SRC 0x01 -#define NETWAVE_CMD_STC 0x02 -#define NETWAVE_CMD_AMA 0x03 -#define NETWAVE_CMD_DMA 0x04 -#define NETWAVE_CMD_SAMA 0x05 -#define NETWAVE_CMD_ER 0x06 -#define NETWAVE_CMD_DR 0x07 -#define NETWAVE_CMD_TL 0x08 -#define NETWAVE_CMD_SRP 0x09 -#define NETWAVE_CMD_SSK 0x0a -#define NETWAVE_CMD_SMD 0x0b -#define NETWAVE_CMD_SAPD 0x0c -#define NETWAVE_CMD_SSS 0x11 -/* End of Command marker */ -#define NETWAVE_CMD_EOC 0x00 - -/* ASR register bits */ -#define NETWAVE_ASR_RXRDY 0x80 -#define NETWAVE_ASR_TXBA 0x01 - -#define TX_TIMEOUT ((32*HZ)/100) - -static const unsigned int imrConfRFU1 = 0x10; /* RFU interrupt mask, keep high */ -static const unsigned int imrConfIENA = 0x02; /* Interrupt enable */ - -static const unsigned int corConfIENA = 0x01; /* Interrupt enable */ -static const unsigned int corConfLVLREQ = 0x40; /* Keep high */ - -static const unsigned int rxConfRxEna = 0x80; /* Receive Enable */ -static const unsigned int rxConfMAC = 0x20; /* MAC host receive mode*/ -static const unsigned int rxConfPro = 0x10; /* Promiscuous */ -static const unsigned int rxConfAMP = 0x08; /* Accept Multicast Packets */ -static const unsigned int rxConfBcast = 0x04; /* Accept Broadcast Packets */ - -static const unsigned int txConfTxEna = 0x80; /* Transmit Enable */ -static const unsigned int txConfMAC = 0x20; /* Host sends MAC mode */ -static const unsigned int txConfEUD = 0x10; /* Enable Uni-Data packets */ -static const unsigned int txConfKey = 0x02; /* Scramble data packets */ -static const unsigned int txConfLoop = 0x01; /* Loopback mode */ - -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n"; -#else -#define DEBUG(n, args...) -#endif - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -/* Choose the domain, default is 0x100 */ -static u_int domain = 0x100; - -/* Scramble key, range from 0x0 to 0xffff. - * 0x0 is no scrambling. - */ -static u_int scramble_key = 0x0; - -/* Shared memory speed, in ns. The documentation states that - * the card should not be read faster than every 400ns. - * This timing should be provided by the HBA. If it becomes a - * problem, try setting mem_speed to 400. - */ -static int mem_speed; - -module_param(domain, int, 0); -module_param(scramble_key, int, 0); -module_param(mem_speed, int, 0); - -/*====================================================================*/ - -/* PCMCIA (Card Services) related functions */ -static void netwave_release(struct pcmcia_device *link); /* Card removal */ -static int netwave_pcmcia_config(struct pcmcia_device *arg); /* Runs after card - insertion */ -static void netwave_detach(struct pcmcia_device *p_dev); /* Destroy instance */ - -/* Hardware configuration */ -static void netwave_doreset(unsigned int iobase, u_char __iomem *ramBase); -static void netwave_reset(struct net_device *dev); - -/* Misc device stuff */ -static int netwave_open(struct net_device *dev); /* Open the device */ -static int netwave_close(struct net_device *dev); /* Close the device */ - -/* Packet transmission and Packet reception */ -static netdev_tx_t netwave_start_xmit( struct sk_buff *skb, - struct net_device *dev); -static int netwave_rx( struct net_device *dev); - -/* Interrupt routines */ -static irqreturn_t netwave_interrupt(int irq, void *dev_id); -static void netwave_watchdog(struct net_device *); - -/* Wireless extensions */ -static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev); - -static void set_multicast_list(struct net_device *dev); - -/* - A struct pcmcia_device structure has fields for most things that are needed - to keep track of a socket, but there will usually be some device - specific information that also needs to be kept track of. The - 'priv' pointer in a struct pcmcia_device structure can be used to point to - a device-specific private data structure, like this. - - A driver needs to provide a dev_node_t structure for each device - on a card. In some cases, there is only one device per card (for - example, ethernet cards, modems). In other cases, there may be - many actual or logical devices (SCSI adapters, memory cards with - multiple partitions). The dev_node_t structures need to be kept - in a linked list starting at the 'dev' field of a struct pcmcia_device - structure. We allocate them in the card's private data structure, - because they generally can't be allocated dynamically. -*/ - -static const struct iw_handler_def netwave_handler_def; - -#define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */ - -#define MAX_ESA 10 - -typedef struct net_addr { - u_char addr48[6]; -} net_addr; - -struct site_survey { - u_short length; - u_char struct_revision; - u_char roaming_state; - - u_char sp_existsFlag; - u_char sp_link_quality; - u_char sp_max_link_quality; - u_char linkQualityGoodFairBoundary; - u_char linkQualityFairPoorBoundary; - u_char sp_utilization; - u_char sp_goodness; - u_char sp_hotheadcount; - u_char roaming_condition; - - net_addr sp; - u_char numAPs; - net_addr nearByAccessPoints[MAX_ESA]; -}; - -typedef struct netwave_private { - struct pcmcia_device *p_dev; - spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ - dev_node_t node; - u_char __iomem *ramBase; - int timeoutCounter; - int lastExec; - struct timer_list watchdog; /* To avoid blocking state */ - struct site_survey nss; - struct iw_statistics iw_stats; /* Wireless stats */ -} netwave_private; - -/* - * The Netwave card is little-endian, so won't work for big endian - * systems. - */ -static inline unsigned short get_uint16(u_char __iomem *staddr) -{ - return readw(staddr); /* Return only 16 bits */ -} - -static inline short get_int16(u_char __iomem * staddr) -{ - return readw(staddr); -} - -/* - * Wait until the WOC (Write Operation Complete) bit in the - * ASR (Adapter Status Register) is asserted. - * This should have aborted if it takes too long time. - */ -static inline void wait_WOC(unsigned int iobase) -{ - /* Spin lock */ - while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ; -} - -static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase, - unsigned int iobase) { - u_short resultBuffer; - - /* if time since last snapshot is > 1 sec. (100 jiffies?) then take - * new snapshot, else return cached data. This is the recommended rate. - */ - if ( jiffies - priv->lastExec > 100) { - /* Take site survey snapshot */ - /*printk( KERN_DEBUG "Taking new snapshot. %ld\n", jiffies - - priv->lastExec); */ - wait_WOC(iobase); - writeb(NETWAVE_CMD_SSS, ramBase + NETWAVE_EREG_CB + 0); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); - wait_WOC(iobase); - - /* Get result and copy to cach */ - resultBuffer = readw(ramBase + NETWAVE_EREG_CRBP); - copy_from_pc( &priv->nss, ramBase+resultBuffer, - sizeof(struct site_survey)); - } -} - -/* - * Function netwave_get_wireless_stats (dev) - * - * Wireless extensions statistics - * - */ -static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev) -{ - unsigned long flags; - unsigned int iobase = dev->base_addr; - netwave_private *priv = netdev_priv(dev); - u_char __iomem *ramBase = priv->ramBase; - struct iw_statistics* wstats; - - wstats = &priv->iw_stats; - - spin_lock_irqsave(&priv->spinlock, flags); - - netwave_snapshot( priv, ramBase, iobase); - - wstats->status = priv->nss.roaming_state; - wstats->qual.qual = readb( ramBase + NETWAVE_EREG_SPCQ); - wstats->qual.level = readb( ramBase + NETWAVE_EREG_ISPLQ); - wstats->qual.noise = readb( ramBase + NETWAVE_EREG_SPU) & 0x3f; - wstats->discard.nwid = 0L; - wstats->discard.code = 0L; - wstats->discard.misc = 0L; - - spin_unlock_irqrestore(&priv->spinlock, flags); - - return &priv->iw_stats; -} - -static const struct net_device_ops netwave_netdev_ops = { - .ndo_open = netwave_open, - .ndo_stop = netwave_close, - .ndo_start_xmit = netwave_start_xmit, - .ndo_set_multicast_list = set_multicast_list, - .ndo_tx_timeout = netwave_watchdog, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -/* - * Function netwave_attach (void) - * - * Creates an "instance" of the driver, allocating local data - * structures for one device. The device is registered with Card - * Services. - * - * The dev_link structure is initialized, but we don't actually - * configure the card at this point -- we wait until we receive a - * card insertion event. - */ -static int netwave_probe(struct pcmcia_device *link) -{ - struct net_device *dev; - netwave_private *priv; - - DEBUG(0, "netwave_attach()\n"); - - /* Initialize the struct pcmcia_device structure */ - dev = alloc_etherdev(sizeof(netwave_private)); - if (!dev) - return -ENOMEM; - priv = netdev_priv(dev); - priv->p_dev = link; - link->priv = dev; - - /* The io structure describes IO port mapping */ - link->io.NumPorts1 = 16; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - /* link->io.NumPorts2 = 16; - link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; */ - link->io.IOAddrLines = 5; - - /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.Handler = &netwave_interrupt; - - /* General socket configuration */ - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 1; - - /* Netwave private struct init. link/dev/node already taken care of, - * other stuff zero'd - Jean II */ - spin_lock_init(&priv->spinlock); - - /* Netwave specific entries in the device structure */ - dev->netdev_ops = &netwave_netdev_ops; - /* wireless extensions */ - dev->wireless_handlers = &netwave_handler_def; - - dev->watchdog_timeo = TX_TIMEOUT; - - link->irq.Instance = dev; - - return netwave_pcmcia_config( link); -} /* netwave_attach */ - -/* - * Function netwave_detach (link) - * - * This deletes a driver "instance". The device is de-registered - * with Card Services. If it has been released, all local data - * structures are freed. Otherwise, the structures will be freed - * when the device is released. - */ -static void netwave_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - DEBUG(0, "netwave_detach(0x%p)\n", link); - - netwave_release(link); - - if (link->dev_node) - unregister_netdev(dev); - - free_netdev(dev); -} /* netwave_detach */ - -/* - * Wireless Handler : get protocol name - */ -static int netwave_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - strcpy(wrqu->name, "Netwave"); - return 0; -} - -/* - * Wireless Handler : set Network ID - */ -static int netwave_set_nwid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long flags; - unsigned int iobase = dev->base_addr; - netwave_private *priv = netdev_priv(dev); - u_char __iomem *ramBase = priv->ramBase; - - /* Disable interrupts & save flags */ - spin_lock_irqsave(&priv->spinlock, flags); - - if(!wrqu->nwid.disabled) { - domain = wrqu->nwid.value; - printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", - (domain >> 8) & 0x01, domain & 0xff); - wait_WOC(iobase); - writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); - writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); - writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); - } - - /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore(&priv->spinlock, flags); - - return 0; -} - -/* - * Wireless Handler : get Network ID - */ -static int netwave_get_nwid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - wrqu->nwid.value = domain; - wrqu->nwid.disabled = 0; - wrqu->nwid.fixed = 1; - return 0; -} - -/* - * Wireless Handler : set scramble key - */ -static int netwave_set_scramble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *key) -{ - unsigned long flags; - unsigned int iobase = dev->base_addr; - netwave_private *priv = netdev_priv(dev); - u_char __iomem *ramBase = priv->ramBase; - - /* Disable interrupts & save flags */ - spin_lock_irqsave(&priv->spinlock, flags); - - scramble_key = (key[0] << 8) | key[1]; - wait_WOC(iobase); - writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); - writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); - writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); - - /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore(&priv->spinlock, flags); - - return 0; -} - -/* - * Wireless Handler : get scramble key - */ -static int netwave_get_scramble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *key) -{ - key[1] = scramble_key & 0xff; - key[0] = (scramble_key>>8) & 0xff; - wrqu->encoding.flags = IW_ENCODE_ENABLED; - wrqu->encoding.length = 2; - return 0; -} - -/* - * Wireless Handler : get mode - */ -static int netwave_get_mode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - if(domain & 0x100) - wrqu->mode = IW_MODE_INFRA; - else - wrqu->mode = IW_MODE_ADHOC; - - return 0; -} - -/* - * Wireless Handler : get range info - */ -static int netwave_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct iw_range *range = (struct iw_range *) extra; - int ret = 0; - - /* Set the length (very important for backward compatibility) */ - wrqu->data.length = sizeof(struct iw_range); - - /* Set all the info we don't care or don't know about to zero */ - memset(range, 0, sizeof(struct iw_range)); - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 9; /* Nothing for us in v10 and v11 */ - - /* Set information in the range struct */ - range->throughput = 450 * 1000; /* don't argue on this ! */ - range->min_nwid = 0x0000; - range->max_nwid = 0x01FF; - - range->num_channels = range->num_frequency = 0; - - range->sensitivity = 0x3F; - range->max_qual.qual = 255; - range->max_qual.level = 255; - range->max_qual.noise = 0; - - range->num_bitrates = 1; - range->bitrate[0] = 1000000; /* 1 Mb/s */ - - range->encoding_size[0] = 2; /* 16 bits scrambling */ - range->num_encoding_sizes = 1; - range->max_encoding_tokens = 1; /* Only one key possible */ - - return ret; -} - -/* - * Wireless Private Handler : get snapshot - */ -static int netwave_get_snap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - unsigned long flags; - unsigned int iobase = dev->base_addr; - netwave_private *priv = netdev_priv(dev); - u_char __iomem *ramBase = priv->ramBase; - - /* Disable interrupts & save flags */ - spin_lock_irqsave(&priv->spinlock, flags); - - /* Take snapshot of environment */ - netwave_snapshot( priv, ramBase, iobase); - wrqu->data.length = priv->nss.length; - memcpy(extra, (u_char *) &priv->nss, sizeof( struct site_survey)); - - priv->lastExec = jiffies; - - /* ReEnable interrupts & restore flags */ - spin_unlock_irqrestore(&priv->spinlock, flags); - - return(0); -} - -/* - * Structures to export the Wireless Handlers - * This is the stuff that are treated the wireless extensions (iwconfig) - */ - -static const struct iw_priv_args netwave_private_args[] = { -/*{ cmd, set_args, get_args, name } */ - { SIOCGIPSNAP, 0, - IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof(struct site_survey), - "getsitesurvey" }, -}; - -static const iw_handler netwave_handler[] = -{ - NULL, /* SIOCSIWNAME */ - netwave_get_name, /* SIOCGIWNAME */ - netwave_set_nwid, /* SIOCSIWNWID */ - netwave_get_nwid, /* SIOCGIWNWID */ - NULL, /* SIOCSIWFREQ */ - NULL, /* SIOCGIWFREQ */ - NULL, /* SIOCSIWMODE */ - netwave_get_mode, /* SIOCGIWMODE */ - NULL, /* SIOCSIWSENS */ - NULL, /* SIOCGIWSENS */ - NULL, /* SIOCSIWRANGE */ - netwave_get_range, /* SIOCGIWRANGE */ - NULL, /* SIOCSIWPRIV */ - NULL, /* SIOCGIWPRIV */ - NULL, /* SIOCSIWSTATS */ - NULL, /* SIOCGIWSTATS */ - NULL, /* SIOCSIWSPY */ - NULL, /* SIOCGIWSPY */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - NULL, /* SIOCSIWAP */ - NULL, /* SIOCGIWAP */ - NULL, /* -- hole -- */ - NULL, /* SIOCGIWAPLIST */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - NULL, /* SIOCSIWESSID */ - NULL, /* SIOCGIWESSID */ - NULL, /* SIOCSIWNICKN */ - NULL, /* SIOCGIWNICKN */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - NULL, /* SIOCSIWRATE */ - NULL, /* SIOCGIWRATE */ - NULL, /* SIOCSIWRTS */ - NULL, /* SIOCGIWRTS */ - NULL, /* SIOCSIWFRAG */ - NULL, /* SIOCGIWFRAG */ - NULL, /* SIOCSIWTXPOW */ - NULL, /* SIOCGIWTXPOW */ - NULL, /* SIOCSIWRETRY */ - NULL, /* SIOCGIWRETRY */ - netwave_set_scramble, /* SIOCSIWENCODE */ - netwave_get_scramble, /* SIOCGIWENCODE */ -}; - -static const iw_handler netwave_private_handler[] = -{ - NULL, /* SIOCIWFIRSTPRIV */ - netwave_get_snap, /* SIOCIWFIRSTPRIV + 1 */ -}; - -static const struct iw_handler_def netwave_handler_def = -{ - .num_standard = ARRAY_SIZE(netwave_handler), - .num_private = ARRAY_SIZE(netwave_private_handler), - .num_private_args = ARRAY_SIZE(netwave_private_args), - .standard = (iw_handler *) netwave_handler, - .private = (iw_handler *) netwave_private_handler, - .private_args = (struct iw_priv_args *) netwave_private_args, - .get_wireless_stats = netwave_get_wireless_stats, -}; - -/* - * Function netwave_pcmcia_config (link) - * - * netwave_pcmcia_config() is scheduled to run after a CARD_INSERTION - * event is received, to configure the PCMCIA socket, and to make the - * device available to the system. - * - */ - -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - -static int netwave_pcmcia_config(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - netwave_private *priv = netdev_priv(dev); - int i, j, last_ret, last_fn; - win_req_t req; - memreq_t mem; - u_char __iomem *ramBase = NULL; - - DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); - - /* - * Try allocating IO ports. This tries a few fixed addresses. - * If you want, you can also read the card's config table to - * pick addresses -- see the serial driver for an example. - */ - for (i = j = 0x0; j < 0x400; j += 0x20) { - link->io.BasePort1 = j ^ 0x300; - i = pcmcia_request_io(link, &link->io); - if (i == 0) - break; - } - if (i != 0) { - cs_error(link, RequestIO, i); - goto failed; - } - - /* - * Now allocate an interrupt line. Note that this does not - * actually assign a handler to the interrupt. - */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - - /* - * This actually configures the PCMCIA socket -- setting up - * the I/O windows and the interrupt mapping. - */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); - - /* - * Allocate a 32K memory window. Note that the struct pcmcia_device - * structure provides space for one window handle -- if your - * device needs several windows, you'll need to keep track of - * the handles in your private data structure, dev->priv. - */ - DEBUG(1, "Setting mem speed of %d\n", mem_speed); - - req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE; - req.Base = 0; req.Size = 0x8000; - req.AccessSpeed = mem_speed; - CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win)); - mem.CardOffset = 0x20000; mem.Page = 0; - CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); - - /* Store base address of the common window frame */ - ramBase = ioremap(req.Base, 0x8000); - priv->ramBase = ramBase; - - dev->irq = link->irq.AssignedIRQ; - dev->base_addr = link->io.BasePort1; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); - - if (register_netdev(dev) != 0) { - printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n"); - goto failed; - } - - strcpy(priv->node.dev_name, dev->name); - link->dev_node = &priv->node; - - /* Reset card before reading physical address */ - netwave_doreset(dev->base_addr, ramBase); - - /* Read the ethernet address and fill in the Netwave registers. */ - for (i = 0; i < 6; i++) - dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i); - - printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx, " - "id %c%c, hw_addr %pM\n", - dev->name, dev->base_addr, dev->irq, - (u_long) ramBase, - (int) readb(ramBase+NETWAVE_EREG_NI), - (int) readb(ramBase+NETWAVE_EREG_NI+1), - dev->dev_addr); - - /* get revision words */ - printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", - get_uint16(ramBase + NETWAVE_EREG_ARW), - get_uint16(ramBase + NETWAVE_EREG_ARW+2)); - return 0; - -cs_failed: - cs_error(link, last_fn, last_ret); -failed: - netwave_release(link); - return -ENODEV; -} /* netwave_pcmcia_config */ - -/* - * Function netwave_release (arg) - * - * After a card is removed, netwave_release() will unregister the net - * device, and release the PCMCIA configuration. If the device is - * still open, this will be postponed until it is closed. - */ -static void netwave_release(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - netwave_private *priv = netdev_priv(dev); - - DEBUG(0, "netwave_release(0x%p)\n", link); - - pcmcia_disable_device(link); - if (link->win) - iounmap(priv->ramBase); -} - -static int netwave_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int netwave_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - if (link->open) { - netwave_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - - -/* - * Function netwave_doreset (ioBase, ramBase) - * - * Proper hardware reset of the card. - */ -static void netwave_doreset(unsigned int ioBase, u_char __iomem *ramBase) -{ - /* Reset card */ - wait_WOC(ioBase); - outb(0x80, ioBase + NETWAVE_REG_PMR); - writeb(0x08, ramBase + NETWAVE_EREG_ASCC); /* Bit 3 is WOC */ - outb(0x0, ioBase + NETWAVE_REG_PMR); /* release reset */ -} - -/* - * Function netwave_reset (dev) - * - * Reset and restore all of the netwave registers - */ -static void netwave_reset(struct net_device *dev) { - /* u_char state; */ - netwave_private *priv = netdev_priv(dev); - u_char __iomem *ramBase = priv->ramBase; - unsigned int iobase = dev->base_addr; - - DEBUG(0, "netwave_reset: Done with hardware reset\n"); - - priv->timeoutCounter = 0; - - /* Reset card */ - netwave_doreset(iobase, ramBase); - printk(KERN_DEBUG "netwave_reset: Done with hardware reset\n"); - - /* Write a NOP to check the card */ - wait_WOC(iobase); - writeb(NETWAVE_CMD_NOP, ramBase + NETWAVE_EREG_CB + 0); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); - - /* Set receive conf */ - wait_WOC(iobase); - writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0); - writeb(rxConfRxEna + rxConfBcast, ramBase + NETWAVE_EREG_CB + 1); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); - - /* Set transmit conf */ - wait_WOC(iobase); - writeb(NETWAVE_CMD_STC, ramBase + NETWAVE_EREG_CB + 0); - writeb(txConfTxEna, ramBase + NETWAVE_EREG_CB + 1); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); - - /* Now set the MU Domain */ - printk(KERN_DEBUG "Setting domain to 0x%x%02x\n", (domain >> 8) & 0x01, domain & 0xff); - wait_WOC(iobase); - writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); - writeb(domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); - writeb((domain>>8) & 0x01, ramBase + NETWAVE_EREG_CB + 2); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); - - /* Set scramble key */ - printk(KERN_DEBUG "Setting scramble key to 0x%x\n", scramble_key); - wait_WOC(iobase); - writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); - writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); - writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); - - /* Enable interrupts, bit 4 high to keep unused - * source from interrupting us, bit 2 high to - * set interrupt enable, 567 to enable TxDN, - * RxErr and RxRdy - */ - wait_WOC(iobase); - outb(imrConfIENA+imrConfRFU1, iobase + NETWAVE_REG_IMR); - - /* Hent 4 bytes fra 0x170. Skal vaere 0a,29,88,36 - * waitWOC - * skriv 80 til d000:3688 - * sjekk om det ble 80 - */ - - /* Enable Receiver */ - wait_WOC(iobase); - writeb(NETWAVE_CMD_ER, ramBase + NETWAVE_EREG_CB + 0); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); - - /* Set the IENA bit in COR */ - wait_WOC(iobase); - outb(corConfIENA + corConfLVLREQ, iobase + NETWAVE_REG_COR); -} - -/* - * Function netwave_hw_xmit (data, len, dev) - */ -static int netwave_hw_xmit(unsigned char* data, int len, - struct net_device* dev) { - unsigned long flags; - unsigned int TxFreeList, - curBuff, - MaxData, - DataOffset; - int tmpcount; - - netwave_private *priv = netdev_priv(dev); - u_char __iomem * ramBase = priv->ramBase; - unsigned int iobase = dev->base_addr; - - /* Disable interrupts & save flags */ - spin_lock_irqsave(&priv->spinlock, flags); - - /* Check if there are transmit buffers available */ - wait_WOC(iobase); - if ((inb(iobase+NETWAVE_REG_ASR) & NETWAVE_ASR_TXBA) == 0) { - /* No buffers available */ - printk(KERN_DEBUG "netwave_hw_xmit: %s - no xmit buffers available.\n", - dev->name); - spin_unlock_irqrestore(&priv->spinlock, flags); - return 1; - } - - dev->stats.tx_bytes += len; - - DEBUG(3, "Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n", - readb(ramBase + NETWAVE_EREG_SPCQ), - readb(ramBase + NETWAVE_EREG_SPU), - readb(ramBase + NETWAVE_EREG_LIF), - readb(ramBase + NETWAVE_EREG_ISPLQ)); - - /* Now try to insert it into the adapters free memory */ - wait_WOC(iobase); - TxFreeList = get_uint16(ramBase + NETWAVE_EREG_TDP); - MaxData = get_uint16(ramBase + NETWAVE_EREG_TDP+2); - DataOffset = get_uint16(ramBase + NETWAVE_EREG_TDP+4); - - DEBUG(3, "TxFreeList %x, MaxData %x, DataOffset %x\n", - TxFreeList, MaxData, DataOffset); - - /* Copy packet to the adapter fragment buffers */ - curBuff = TxFreeList; - tmpcount = 0; - while (tmpcount < len) { - int tmplen = len - tmpcount; - copy_to_pc(ramBase + curBuff + DataOffset, data + tmpcount, - (tmplen < MaxData) ? tmplen : MaxData); - tmpcount += MaxData; - - /* Advance to next buffer */ - curBuff = get_uint16(ramBase + curBuff); - } - - /* Now issue transmit list */ - wait_WOC(iobase); - writeb(NETWAVE_CMD_TL, ramBase + NETWAVE_EREG_CB + 0); - writeb(len & 0xff, ramBase + NETWAVE_EREG_CB + 1); - writeb((len>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); - - spin_unlock_irqrestore(&priv->spinlock, flags); - return 0; -} - -static netdev_tx_t netwave_start_xmit(struct sk_buff *skb, - struct net_device *dev) { - /* This flag indicate that the hardware can't perform a transmission. - * Theoritically, NET3 check it before sending a packet to the driver, - * but in fact it never do that and pool continuously. - * As the watchdog will abort too long transmissions, we are quite safe... - */ - - netif_stop_queue(dev); - - { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char* buf = skb->data; - - if (netwave_hw_xmit( buf, length, dev) == 1) { - /* Some error, let's make them call us another time? */ - netif_start_queue(dev); - } - dev->trans_start = jiffies; - } - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} /* netwave_start_xmit */ - -/* - * Function netwave_interrupt (irq, dev_id) - * - * This function is the interrupt handler for the Netwave card. This - * routine will be called whenever: - * 1. A packet is received. - * 2. A packet has successfully been transferred and the unit is - * ready to transmit another packet. - * 3. A command has completed execution. - */ -static irqreturn_t netwave_interrupt(int irq, void* dev_id) -{ - unsigned int iobase; - u_char __iomem *ramBase; - struct net_device *dev = (struct net_device *)dev_id; - struct netwave_private *priv = netdev_priv(dev); - struct pcmcia_device *link = priv->p_dev; - int i; - - if (!netif_device_present(dev)) - return IRQ_NONE; - - iobase = dev->base_addr; - ramBase = priv->ramBase; - - /* Now find what caused the interrupt, check while interrupts ready */ - for (i = 0; i < 10; i++) { - u_char status; - - wait_WOC(iobase); - if (!(inb(iobase+NETWAVE_REG_CCSR) & 0x02)) - break; /* None of the interrupt sources asserted (normal exit) */ - - status = inb(iobase + NETWAVE_REG_ASR); - - if (!pcmcia_dev_present(link)) { - DEBUG(1, "netwave_interrupt: Interrupt with status 0x%x " - "from removed or suspended card!\n", status); - break; - } - - /* RxRdy */ - if (status & 0x80) { - netwave_rx(dev); - /* wait_WOC(iobase); */ - /* RxRdy cannot be reset directly by the host */ - } - /* RxErr */ - if (status & 0x40) { - u_char rser; - - rser = readb(ramBase + NETWAVE_EREG_RSER); - - if (rser & 0x04) { - ++dev->stats.rx_dropped; - ++dev->stats.rx_crc_errors; - } - if (rser & 0x02) - ++dev->stats.rx_frame_errors; - - /* Clear the RxErr bit in RSER. RSER+4 is the - * write part. Also clear the RxCRC (0x04) and - * RxBig (0x02) bits if present */ - wait_WOC(iobase); - writeb(0x40 | (rser & 0x06), ramBase + NETWAVE_EREG_RSER + 4); - - /* Write bit 6 high to ASCC to clear RxErr in ASR, - * WOC must be set first! - */ - wait_WOC(iobase); - writeb(0x40, ramBase + NETWAVE_EREG_ASCC); - - /* Remember to count up dev->stats on error packets */ - ++dev->stats.rx_errors; - } - /* TxDN */ - if (status & 0x20) { - int txStatus; - - txStatus = readb(ramBase + NETWAVE_EREG_TSER); - DEBUG(3, "Transmit done. TSER = %x id %x\n", - txStatus, readb(ramBase + NETWAVE_EREG_TSER + 1)); - - if (txStatus & 0x20) { - /* Transmitting was okay, clear bits */ - wait_WOC(iobase); - writeb(0x2f, ramBase + NETWAVE_EREG_TSER + 4); - ++dev->stats.tx_packets; - } - - if (txStatus & 0xd0) { - if (txStatus & 0x80) { - ++dev->stats.collisions; /* Because of /proc/net/dev*/ - /* ++dev->stats.tx_aborted_errors; */ - /* printk("Collision. %ld\n", jiffies - dev->trans_start); */ - } - if (txStatus & 0x40) - ++dev->stats.tx_carrier_errors; - /* 0x80 TxGU Transmit giveup - nine times and no luck - * 0x40 TxNOAP No access point. Discarded packet. - * 0x10 TxErr Transmit error. Always set when - * TxGU and TxNOAP is set. (Those are the only ones - * to set TxErr). - */ - DEBUG(3, "netwave_interrupt: TxDN with error status %x\n", - txStatus); - - /* Clear out TxGU, TxNOAP, TxErr and TxTrys */ - wait_WOC(iobase); - writeb(0xdf & txStatus, ramBase+NETWAVE_EREG_TSER+4); - ++dev->stats.tx_errors; - } - DEBUG(3, "New status is TSER %x ASR %x\n", - readb(ramBase + NETWAVE_EREG_TSER), - inb(iobase + NETWAVE_REG_ASR)); - - netif_wake_queue(dev); - } - /* TxBA, this would trigger on all error packets received */ - /* if (status & 0x01) { - DEBUG(4, "Transmit buffers available, %x\n", status); - } - */ - } - /* Handled if we looped at least one time - Jean II */ - return IRQ_RETVAL(i); -} /* netwave_interrupt */ - -/* - * Function netwave_watchdog (a) - * - * Watchdog : when we start a transmission, we set a timer in the - * kernel. If the transmission complete, this timer is disabled. If - * it expire, we reset the card. - * - */ -static void netwave_watchdog(struct net_device *dev) { - - DEBUG(1, "%s: netwave_watchdog: watchdog timer expired\n", dev->name); - netwave_reset(dev); - dev->trans_start = jiffies; - netif_wake_queue(dev); -} /* netwave_watchdog */ - -static int netwave_rx(struct net_device *dev) -{ - netwave_private *priv = netdev_priv(dev); - u_char __iomem *ramBase = priv->ramBase; - unsigned int iobase = dev->base_addr; - u_char rxStatus; - struct sk_buff *skb = NULL; - unsigned int curBuffer, - rcvList; - int rcvLen; - int tmpcount = 0; - int dataCount, dataOffset; - int i; - u_char *ptr; - - DEBUG(3, "xinw_rx: Receiving ... \n"); - - /* Receive max 10 packets for now. */ - for (i = 0; i < 10; i++) { - /* Any packets? */ - wait_WOC(iobase); - rxStatus = readb(ramBase + NETWAVE_EREG_RSER); - if ( !( rxStatus & 0x80)) /* No more packets */ - break; - - /* Check if multicast/broadcast or other */ - /* multicast = (rxStatus & 0x20); */ - - /* The receive list pointer and length of the packet */ - wait_WOC(iobase); - rcvLen = get_int16( ramBase + NETWAVE_EREG_RDP); - rcvList = get_uint16( ramBase + NETWAVE_EREG_RDP + 2); - - if (rcvLen < 0) { - printk(KERN_DEBUG "netwave_rx: Receive packet with len %d\n", - rcvLen); - return 0; - } - - skb = dev_alloc_skb(rcvLen+5); - if (skb == NULL) { - DEBUG(1, "netwave_rx: Could not allocate an sk_buff of " - "length %d\n", rcvLen); - ++dev->stats.rx_dropped; - /* Tell the adapter to skip the packet */ - wait_WOC(iobase); - writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); - return 0; - } - - skb_reserve( skb, 2); /* Align IP on 16 byte */ - skb_put( skb, rcvLen); - - /* Copy packet fragments to the skb data area */ - ptr = (u_char*) skb->data; - curBuffer = rcvList; - tmpcount = 0; - while ( tmpcount < rcvLen) { - /* Get length and offset of current buffer */ - dataCount = get_uint16( ramBase+curBuffer+2); - dataOffset = get_uint16( ramBase+curBuffer+4); - - copy_from_pc( ptr + tmpcount, - ramBase+curBuffer+dataOffset, dataCount); - - tmpcount += dataCount; - - /* Point to next buffer */ - curBuffer = get_uint16(ramBase + curBuffer); - } - - skb->protocol = eth_type_trans(skb,dev); - /* Queue packet for network layer */ - netif_rx(skb); - - dev->stats.rx_packets++; - dev->stats.rx_bytes += rcvLen; - - /* Got the packet, tell the adapter to skip it */ - wait_WOC(iobase); - writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); - DEBUG(3, "Packet reception ok\n"); - } - return 0; -} - -static int netwave_open(struct net_device *dev) { - netwave_private *priv = netdev_priv(dev); - struct pcmcia_device *link = priv->p_dev; - - DEBUG(1, "netwave_open: starting.\n"); - - if (!pcmcia_dev_present(link)) - return -ENODEV; - - link->open++; - - netif_start_queue(dev); - netwave_reset(dev); - - return 0; -} - -static int netwave_close(struct net_device *dev) { - netwave_private *priv = netdev_priv(dev); - struct pcmcia_device *link = priv->p_dev; - - DEBUG(1, "netwave_close: finishing.\n"); - - link->open--; - netif_stop_queue(dev); - - return 0; -} - -static struct pcmcia_device_id netwave_ids[] = { - PCMCIA_DEVICE_PROD_ID12("Xircom", "CreditCard Netwave", 0x2e3ee845, 0x54e28a28), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, netwave_ids); - -static struct pcmcia_driver netwave_driver = { - .owner = THIS_MODULE, - .drv = { - .name = "netwave_cs", - }, - .probe = netwave_probe, - .remove = netwave_detach, - .id_table = netwave_ids, - .suspend = netwave_suspend, - .resume = netwave_resume, -}; - -static int __init init_netwave_cs(void) -{ - return pcmcia_register_driver(&netwave_driver); -} - -static void __exit exit_netwave_cs(void) -{ - pcmcia_unregister_driver(&netwave_driver); -} - -module_init(init_netwave_cs); -module_exit(exit_netwave_cs); - -/* Set or clear the multicast filter for this adaptor. - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. - */ -static void set_multicast_list(struct net_device *dev) -{ - unsigned int iobase = dev->base_addr; - netwave_private *priv = netdev_priv(dev); - u_char __iomem * ramBase = priv->ramBase; - u_char rcvMode = 0; - -#ifdef PCMCIA_DEBUG - if (pc_debug > 2) { - static int old; - if (old != dev->mc_count) { - old = dev->mc_count; - DEBUG(0, "%s: setting Rx mode to %d addresses.\n", - dev->name, dev->mc_count); - } - } -#endif - - if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { - /* Multicast Mode */ - rcvMode = rxConfRxEna + rxConfAMP + rxConfBcast; - } else if (dev->flags & IFF_PROMISC) { - /* Promiscous mode */ - rcvMode = rxConfRxEna + rxConfPro + rxConfAMP + rxConfBcast; - } else { - /* Normal mode */ - rcvMode = rxConfRxEna + rxConfBcast; - } - - /* printk("netwave set_multicast_list: rcvMode to %x\n", rcvMode);*/ - /* Now set receive mode */ - wait_WOC(iobase); - writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0); - writeb(rcvMode, ramBase + NETWAVE_EREG_CB + 1); - writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); -} -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index c1082f20534c..4e3873bfd010 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -137,5 +137,7 @@ source "drivers/staging/arlan/Kconfig" source "drivers/staging/wavelan/Kconfig" +source "drivers/staging/netwave/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 7bccdd3e7fab..fb1d7851b563 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -51,3 +51,4 @@ obj-$(CONFIG_STRIP) += strip/ obj-$(CONFIG_ARLAN) += arlan/ obj-$(CONFIG_WAVELAN) += wavelan/ obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan/ +obj-$(CONFIG_PCMCIA_NETWAVE) += netwave/ diff --git a/drivers/staging/netwave/Kconfig b/drivers/staging/netwave/Kconfig new file mode 100644 index 000000000000..c0c996c0550a --- /dev/null +++ b/drivers/staging/netwave/Kconfig @@ -0,0 +1,11 @@ +config PCMCIA_NETWAVE + tristate "Xircom Netwave AirSurfer Pcmcia wireless support" + depends on PCMCIA + select WIRELESS_EXT + select WEXT_PRIV + help + Say Y here if you intend to attach this type of PCMCIA (PC-card) + wireless Ethernet networking card to your computer. + + To compile this driver as a module, choose M here: the module will be + called netwave_cs. If unsure, say N. diff --git a/drivers/staging/netwave/Makefile b/drivers/staging/netwave/Makefile new file mode 100644 index 000000000000..2ab89de59b9b --- /dev/null +++ b/drivers/staging/netwave/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o diff --git a/drivers/staging/netwave/netwave_cs.c b/drivers/staging/netwave/netwave_cs.c new file mode 100644 index 000000000000..9498b46c99a4 --- /dev/null +++ b/drivers/staging/netwave/netwave_cs.c @@ -0,0 +1,1389 @@ +/********************************************************************* + * + * Filename: netwave_cs.c + * Version: 0.4.1 + * Description: Netwave AirSurfer Wireless LAN PC Card driver + * Status: Experimental. + * Authors: John Markus Bjørndalen + * Dag Brattli + * David Hinds + * Created at: A long time ago! + * Modified at: Mon Nov 10 11:54:37 1997 + * Modified by: Dag Brattli + * + * Copyright (c) 1997 University of Tromsø, Norway + * + * Revision History: + * + * 08-Nov-97 15:14:47 John Markus Bjørndalen + * - Fixed some bugs in netwave_rx and cleaned it up a bit. + * (One of the bugs would have destroyed packets when receiving + * multiple packets per interrupt). + * - Cleaned up parts of newave_hw_xmit. + * - A few general cleanups. + * 24-Oct-97 13:17:36 Dag Brattli + * - Fixed netwave_rx receive function (got updated docs) + * Others: + * - Changed name from xircnw to netwave, take a look at + * http://www.netwave-wireless.com + * - Some reorganizing of the code + * - Removed possible race condition between interrupt handler and transmit + * function + * - Started to add wireless extensions, but still needs some coding + * - Added watchdog for better handling of transmission timeouts + * (hopefully this works better) + ********************************************************************/ + +/* To have statistics (just packets sent) define this */ +#undef NETWAVE_STATS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define NETWAVE_REGOFF 0x8000 +/* The Netwave IO registers, offsets to iobase */ +#define NETWAVE_REG_COR 0x0 +#define NETWAVE_REG_CCSR 0x2 +#define NETWAVE_REG_ASR 0x4 +#define NETWAVE_REG_IMR 0xa +#define NETWAVE_REG_PMR 0xc +#define NETWAVE_REG_IOLOW 0x6 +#define NETWAVE_REG_IOHI 0x7 +#define NETWAVE_REG_IOCONTROL 0x8 +#define NETWAVE_REG_DATA 0xf +/* The Netwave Extended IO registers, offsets to RamBase */ +#define NETWAVE_EREG_ASCC 0x114 +#define NETWAVE_EREG_RSER 0x120 +#define NETWAVE_EREG_RSERW 0x124 +#define NETWAVE_EREG_TSER 0x130 +#define NETWAVE_EREG_TSERW 0x134 +#define NETWAVE_EREG_CB 0x100 +#define NETWAVE_EREG_SPCQ 0x154 +#define NETWAVE_EREG_SPU 0x155 +#define NETWAVE_EREG_LIF 0x14e +#define NETWAVE_EREG_ISPLQ 0x156 +#define NETWAVE_EREG_HHC 0x158 +#define NETWAVE_EREG_NI 0x16e +#define NETWAVE_EREG_MHS 0x16b +#define NETWAVE_EREG_TDP 0x140 +#define NETWAVE_EREG_RDP 0x150 +#define NETWAVE_EREG_PA 0x160 +#define NETWAVE_EREG_EC 0x180 +#define NETWAVE_EREG_CRBP 0x17a +#define NETWAVE_EREG_ARW 0x166 + +/* + * Commands used in the extended command buffer + * NETWAVE_EREG_CB (0x100-0x10F) + */ +#define NETWAVE_CMD_NOP 0x00 +#define NETWAVE_CMD_SRC 0x01 +#define NETWAVE_CMD_STC 0x02 +#define NETWAVE_CMD_AMA 0x03 +#define NETWAVE_CMD_DMA 0x04 +#define NETWAVE_CMD_SAMA 0x05 +#define NETWAVE_CMD_ER 0x06 +#define NETWAVE_CMD_DR 0x07 +#define NETWAVE_CMD_TL 0x08 +#define NETWAVE_CMD_SRP 0x09 +#define NETWAVE_CMD_SSK 0x0a +#define NETWAVE_CMD_SMD 0x0b +#define NETWAVE_CMD_SAPD 0x0c +#define NETWAVE_CMD_SSS 0x11 +/* End of Command marker */ +#define NETWAVE_CMD_EOC 0x00 + +/* ASR register bits */ +#define NETWAVE_ASR_RXRDY 0x80 +#define NETWAVE_ASR_TXBA 0x01 + +#define TX_TIMEOUT ((32*HZ)/100) + +static const unsigned int imrConfRFU1 = 0x10; /* RFU interrupt mask, keep high */ +static const unsigned int imrConfIENA = 0x02; /* Interrupt enable */ + +static const unsigned int corConfIENA = 0x01; /* Interrupt enable */ +static const unsigned int corConfLVLREQ = 0x40; /* Keep high */ + +static const unsigned int rxConfRxEna = 0x80; /* Receive Enable */ +static const unsigned int rxConfMAC = 0x20; /* MAC host receive mode*/ +static const unsigned int rxConfPro = 0x10; /* Promiscuous */ +static const unsigned int rxConfAMP = 0x08; /* Accept Multicast Packets */ +static const unsigned int rxConfBcast = 0x04; /* Accept Broadcast Packets */ + +static const unsigned int txConfTxEna = 0x80; /* Transmit Enable */ +static const unsigned int txConfMAC = 0x20; /* Host sends MAC mode */ +static const unsigned int txConfEUD = 0x10; /* Enable Uni-Data packets */ +static const unsigned int txConfKey = 0x02; /* Scramble data packets */ +static const unsigned int txConfLoop = 0x01; /* Loopback mode */ + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +module_param(pc_debug, int, 0); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Choose the domain, default is 0x100 */ +static u_int domain = 0x100; + +/* Scramble key, range from 0x0 to 0xffff. + * 0x0 is no scrambling. + */ +static u_int scramble_key = 0x0; + +/* Shared memory speed, in ns. The documentation states that + * the card should not be read faster than every 400ns. + * This timing should be provided by the HBA. If it becomes a + * problem, try setting mem_speed to 400. + */ +static int mem_speed; + +module_param(domain, int, 0); +module_param(scramble_key, int, 0); +module_param(mem_speed, int, 0); + +/*====================================================================*/ + +/* PCMCIA (Card Services) related functions */ +static void netwave_release(struct pcmcia_device *link); /* Card removal */ +static int netwave_pcmcia_config(struct pcmcia_device *arg); /* Runs after card + insertion */ +static void netwave_detach(struct pcmcia_device *p_dev); /* Destroy instance */ + +/* Hardware configuration */ +static void netwave_doreset(unsigned int iobase, u_char __iomem *ramBase); +static void netwave_reset(struct net_device *dev); + +/* Misc device stuff */ +static int netwave_open(struct net_device *dev); /* Open the device */ +static int netwave_close(struct net_device *dev); /* Close the device */ + +/* Packet transmission and Packet reception */ +static netdev_tx_t netwave_start_xmit( struct sk_buff *skb, + struct net_device *dev); +static int netwave_rx( struct net_device *dev); + +/* Interrupt routines */ +static irqreturn_t netwave_interrupt(int irq, void *dev_id); +static void netwave_watchdog(struct net_device *); + +/* Wireless extensions */ +static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev); + +static void set_multicast_list(struct net_device *dev); + +/* + A struct pcmcia_device structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a struct pcmcia_device structure can be used to point to + a device-specific private data structure, like this. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a struct pcmcia_device + structure. We allocate them in the card's private data structure, + because they generally can't be allocated dynamically. +*/ + +static const struct iw_handler_def netwave_handler_def; + +#define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */ + +#define MAX_ESA 10 + +typedef struct net_addr { + u_char addr48[6]; +} net_addr; + +struct site_survey { + u_short length; + u_char struct_revision; + u_char roaming_state; + + u_char sp_existsFlag; + u_char sp_link_quality; + u_char sp_max_link_quality; + u_char linkQualityGoodFairBoundary; + u_char linkQualityFairPoorBoundary; + u_char sp_utilization; + u_char sp_goodness; + u_char sp_hotheadcount; + u_char roaming_condition; + + net_addr sp; + u_char numAPs; + net_addr nearByAccessPoints[MAX_ESA]; +}; + +typedef struct netwave_private { + struct pcmcia_device *p_dev; + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ + dev_node_t node; + u_char __iomem *ramBase; + int timeoutCounter; + int lastExec; + struct timer_list watchdog; /* To avoid blocking state */ + struct site_survey nss; + struct iw_statistics iw_stats; /* Wireless stats */ +} netwave_private; + +/* + * The Netwave card is little-endian, so won't work for big endian + * systems. + */ +static inline unsigned short get_uint16(u_char __iomem *staddr) +{ + return readw(staddr); /* Return only 16 bits */ +} + +static inline short get_int16(u_char __iomem * staddr) +{ + return readw(staddr); +} + +/* + * Wait until the WOC (Write Operation Complete) bit in the + * ASR (Adapter Status Register) is asserted. + * This should have aborted if it takes too long time. + */ +static inline void wait_WOC(unsigned int iobase) +{ + /* Spin lock */ + while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ; +} + +static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase, + unsigned int iobase) { + u_short resultBuffer; + + /* if time since last snapshot is > 1 sec. (100 jiffies?) then take + * new snapshot, else return cached data. This is the recommended rate. + */ + if ( jiffies - priv->lastExec > 100) { + /* Take site survey snapshot */ + /*printk( KERN_DEBUG "Taking new snapshot. %ld\n", jiffies - + priv->lastExec); */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_SSS, ramBase + NETWAVE_EREG_CB + 0); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); + wait_WOC(iobase); + + /* Get result and copy to cach */ + resultBuffer = readw(ramBase + NETWAVE_EREG_CRBP); + copy_from_pc( &priv->nss, ramBase+resultBuffer, + sizeof(struct site_survey)); + } +} + +/* + * Function netwave_get_wireless_stats (dev) + * + * Wireless extensions statistics + * + */ +static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev) +{ + unsigned long flags; + unsigned int iobase = dev->base_addr; + netwave_private *priv = netdev_priv(dev); + u_char __iomem *ramBase = priv->ramBase; + struct iw_statistics* wstats; + + wstats = &priv->iw_stats; + + spin_lock_irqsave(&priv->spinlock, flags); + + netwave_snapshot( priv, ramBase, iobase); + + wstats->status = priv->nss.roaming_state; + wstats->qual.qual = readb( ramBase + NETWAVE_EREG_SPCQ); + wstats->qual.level = readb( ramBase + NETWAVE_EREG_ISPLQ); + wstats->qual.noise = readb( ramBase + NETWAVE_EREG_SPU) & 0x3f; + wstats->discard.nwid = 0L; + wstats->discard.code = 0L; + wstats->discard.misc = 0L; + + spin_unlock_irqrestore(&priv->spinlock, flags); + + return &priv->iw_stats; +} + +static const struct net_device_ops netwave_netdev_ops = { + .ndo_open = netwave_open, + .ndo_stop = netwave_close, + .ndo_start_xmit = netwave_start_xmit, + .ndo_set_multicast_list = set_multicast_list, + .ndo_tx_timeout = netwave_watchdog, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + +/* + * Function netwave_attach (void) + * + * Creates an "instance" of the driver, allocating local data + * structures for one device. The device is registered with Card + * Services. + * + * The dev_link structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a + * card insertion event. + */ +static int netwave_probe(struct pcmcia_device *link) +{ + struct net_device *dev; + netwave_private *priv; + + DEBUG(0, "netwave_attach()\n"); + + /* Initialize the struct pcmcia_device structure */ + dev = alloc_etherdev(sizeof(netwave_private)); + if (!dev) + return -ENOMEM; + priv = netdev_priv(dev); + priv->p_dev = link; + link->priv = dev; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 16; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + /* link->io.NumPorts2 = 16; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; */ + link->io.IOAddrLines = 5; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Handler = &netwave_interrupt; + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + + /* Netwave private struct init. link/dev/node already taken care of, + * other stuff zero'd - Jean II */ + spin_lock_init(&priv->spinlock); + + /* Netwave specific entries in the device structure */ + dev->netdev_ops = &netwave_netdev_ops; + /* wireless extensions */ + dev->wireless_handlers = &netwave_handler_def; + + dev->watchdog_timeo = TX_TIMEOUT; + + link->irq.Instance = dev; + + return netwave_pcmcia_config( link); +} /* netwave_attach */ + +/* + * Function netwave_detach (link) + * + * This deletes a driver "instance". The device is de-registered + * with Card Services. If it has been released, all local data + * structures are freed. Otherwise, the structures will be freed + * when the device is released. + */ +static void netwave_detach(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + + DEBUG(0, "netwave_detach(0x%p)\n", link); + + netwave_release(link); + + if (link->dev_node) + unregister_netdev(dev); + + free_netdev(dev); +} /* netwave_detach */ + +/* + * Wireless Handler : get protocol name + */ +static int netwave_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + strcpy(wrqu->name, "Netwave"); + return 0; +} + +/* + * Wireless Handler : set Network ID + */ +static int netwave_set_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long flags; + unsigned int iobase = dev->base_addr; + netwave_private *priv = netdev_priv(dev); + u_char __iomem *ramBase = priv->ramBase; + + /* Disable interrupts & save flags */ + spin_lock_irqsave(&priv->spinlock, flags); + + if(!wrqu->nwid.disabled) { + domain = wrqu->nwid.value; + printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", + (domain >> 8) & 0x01, domain & 0xff); + wait_WOC(iobase); + writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); + writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + } + + /* ReEnable interrupts & restore flags */ + spin_unlock_irqrestore(&priv->spinlock, flags); + + return 0; +} + +/* + * Wireless Handler : get Network ID + */ +static int netwave_get_nwid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + wrqu->nwid.value = domain; + wrqu->nwid.disabled = 0; + wrqu->nwid.fixed = 1; + return 0; +} + +/* + * Wireless Handler : set scramble key + */ +static int netwave_set_scramble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *key) +{ + unsigned long flags; + unsigned int iobase = dev->base_addr; + netwave_private *priv = netdev_priv(dev); + u_char __iomem *ramBase = priv->ramBase; + + /* Disable interrupts & save flags */ + spin_lock_irqsave(&priv->spinlock, flags); + + scramble_key = (key[0] << 8) | key[1]; + wait_WOC(iobase); + writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); + writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + + /* ReEnable interrupts & restore flags */ + spin_unlock_irqrestore(&priv->spinlock, flags); + + return 0; +} + +/* + * Wireless Handler : get scramble key + */ +static int netwave_get_scramble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *key) +{ + key[1] = scramble_key & 0xff; + key[0] = (scramble_key>>8) & 0xff; + wrqu->encoding.flags = IW_ENCODE_ENABLED; + wrqu->encoding.length = 2; + return 0; +} + +/* + * Wireless Handler : get mode + */ +static int netwave_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + if(domain & 0x100) + wrqu->mode = IW_MODE_INFRA; + else + wrqu->mode = IW_MODE_ADHOC; + + return 0; +} + +/* + * Wireless Handler : get range info + */ +static int netwave_get_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_range *range = (struct iw_range *) extra; + int ret = 0; + + /* Set the length (very important for backward compatibility) */ + wrqu->data.length = sizeof(struct iw_range); + + /* Set all the info we don't care or don't know about to zero */ + memset(range, 0, sizeof(struct iw_range)); + + /* Set the Wireless Extension versions */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 9; /* Nothing for us in v10 and v11 */ + + /* Set information in the range struct */ + range->throughput = 450 * 1000; /* don't argue on this ! */ + range->min_nwid = 0x0000; + range->max_nwid = 0x01FF; + + range->num_channels = range->num_frequency = 0; + + range->sensitivity = 0x3F; + range->max_qual.qual = 255; + range->max_qual.level = 255; + range->max_qual.noise = 0; + + range->num_bitrates = 1; + range->bitrate[0] = 1000000; /* 1 Mb/s */ + + range->encoding_size[0] = 2; /* 16 bits scrambling */ + range->num_encoding_sizes = 1; + range->max_encoding_tokens = 1; /* Only one key possible */ + + return ret; +} + +/* + * Wireless Private Handler : get snapshot + */ +static int netwave_get_snap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + unsigned long flags; + unsigned int iobase = dev->base_addr; + netwave_private *priv = netdev_priv(dev); + u_char __iomem *ramBase = priv->ramBase; + + /* Disable interrupts & save flags */ + spin_lock_irqsave(&priv->spinlock, flags); + + /* Take snapshot of environment */ + netwave_snapshot( priv, ramBase, iobase); + wrqu->data.length = priv->nss.length; + memcpy(extra, (u_char *) &priv->nss, sizeof( struct site_survey)); + + priv->lastExec = jiffies; + + /* ReEnable interrupts & restore flags */ + spin_unlock_irqrestore(&priv->spinlock, flags); + + return(0); +} + +/* + * Structures to export the Wireless Handlers + * This is the stuff that are treated the wireless extensions (iwconfig) + */ + +static const struct iw_priv_args netwave_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { SIOCGIPSNAP, 0, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof(struct site_survey), + "getsitesurvey" }, +}; + +static const iw_handler netwave_handler[] = +{ + NULL, /* SIOCSIWNAME */ + netwave_get_name, /* SIOCGIWNAME */ + netwave_set_nwid, /* SIOCSIWNWID */ + netwave_get_nwid, /* SIOCGIWNWID */ + NULL, /* SIOCSIWFREQ */ + NULL, /* SIOCGIWFREQ */ + NULL, /* SIOCSIWMODE */ + netwave_get_mode, /* SIOCGIWMODE */ + NULL, /* SIOCSIWSENS */ + NULL, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + netwave_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ + NULL, /* SIOCSIWSPY */ + NULL, /* SIOCGIWSPY */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWAP */ + NULL, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWESSID */ + NULL, /* SIOCGIWESSID */ + NULL, /* SIOCSIWNICKN */ + NULL, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + NULL, /* SIOCSIWRATE */ + NULL, /* SIOCGIWRATE */ + NULL, /* SIOCSIWRTS */ + NULL, /* SIOCGIWRTS */ + NULL, /* SIOCSIWFRAG */ + NULL, /* SIOCGIWFRAG */ + NULL, /* SIOCSIWTXPOW */ + NULL, /* SIOCGIWTXPOW */ + NULL, /* SIOCSIWRETRY */ + NULL, /* SIOCGIWRETRY */ + netwave_set_scramble, /* SIOCSIWENCODE */ + netwave_get_scramble, /* SIOCGIWENCODE */ +}; + +static const iw_handler netwave_private_handler[] = +{ + NULL, /* SIOCIWFIRSTPRIV */ + netwave_get_snap, /* SIOCIWFIRSTPRIV + 1 */ +}; + +static const struct iw_handler_def netwave_handler_def = +{ + .num_standard = ARRAY_SIZE(netwave_handler), + .num_private = ARRAY_SIZE(netwave_private_handler), + .num_private_args = ARRAY_SIZE(netwave_private_args), + .standard = (iw_handler *) netwave_handler, + .private = (iw_handler *) netwave_private_handler, + .private_args = (struct iw_priv_args *) netwave_private_args, + .get_wireless_stats = netwave_get_wireless_stats, +}; + +/* + * Function netwave_pcmcia_config (link) + * + * netwave_pcmcia_config() is scheduled to run after a CARD_INSERTION + * event is received, to configure the PCMCIA socket, and to make the + * device available to the system. + * + */ + +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) + +static int netwave_pcmcia_config(struct pcmcia_device *link) { + struct net_device *dev = link->priv; + netwave_private *priv = netdev_priv(dev); + int i, j, last_ret, last_fn; + win_req_t req; + memreq_t mem; + u_char __iomem *ramBase = NULL; + + DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); + + /* + * Try allocating IO ports. This tries a few fixed addresses. + * If you want, you can also read the card's config table to + * pick addresses -- see the serial driver for an example. + */ + for (i = j = 0x0; j < 0x400; j += 0x20) { + link->io.BasePort1 = j ^ 0x300; + i = pcmcia_request_io(link, &link->io); + if (i == 0) + break; + } + if (i != 0) { + cs_error(link, RequestIO, i); + goto failed; + } + + /* + * Now allocate an interrupt line. Note that this does not + * actually assign a handler to the interrupt. + */ + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping. + */ + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + + /* + * Allocate a 32K memory window. Note that the struct pcmcia_device + * structure provides space for one window handle -- if your + * device needs several windows, you'll need to keep track of + * the handles in your private data structure, dev->priv. + */ + DEBUG(1, "Setting mem speed of %d\n", mem_speed); + + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE; + req.Base = 0; req.Size = 0x8000; + req.AccessSpeed = mem_speed; + CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win)); + mem.CardOffset = 0x20000; mem.Page = 0; + CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); + + /* Store base address of the common window frame */ + ramBase = ioremap(req.Base, 0x8000); + priv->ramBase = ramBase; + + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); + + if (register_netdev(dev) != 0) { + printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n"); + goto failed; + } + + strcpy(priv->node.dev_name, dev->name); + link->dev_node = &priv->node; + + /* Reset card before reading physical address */ + netwave_doreset(dev->base_addr, ramBase); + + /* Read the ethernet address and fill in the Netwave registers. */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i); + + printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx, " + "id %c%c, hw_addr %pM\n", + dev->name, dev->base_addr, dev->irq, + (u_long) ramBase, + (int) readb(ramBase+NETWAVE_EREG_NI), + (int) readb(ramBase+NETWAVE_EREG_NI+1), + dev->dev_addr); + + /* get revision words */ + printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", + get_uint16(ramBase + NETWAVE_EREG_ARW), + get_uint16(ramBase + NETWAVE_EREG_ARW+2)); + return 0; + +cs_failed: + cs_error(link, last_fn, last_ret); +failed: + netwave_release(link); + return -ENODEV; +} /* netwave_pcmcia_config */ + +/* + * Function netwave_release (arg) + * + * After a card is removed, netwave_release() will unregister the net + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ +static void netwave_release(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + netwave_private *priv = netdev_priv(dev); + + DEBUG(0, "netwave_release(0x%p)\n", link); + + pcmcia_disable_device(link); + if (link->win) + iounmap(priv->ramBase); +} + +static int netwave_suspend(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + + if (link->open) + netif_device_detach(dev); + + return 0; +} + +static int netwave_resume(struct pcmcia_device *link) +{ + struct net_device *dev = link->priv; + + if (link->open) { + netwave_reset(dev); + netif_device_attach(dev); + } + + return 0; +} + + +/* + * Function netwave_doreset (ioBase, ramBase) + * + * Proper hardware reset of the card. + */ +static void netwave_doreset(unsigned int ioBase, u_char __iomem *ramBase) +{ + /* Reset card */ + wait_WOC(ioBase); + outb(0x80, ioBase + NETWAVE_REG_PMR); + writeb(0x08, ramBase + NETWAVE_EREG_ASCC); /* Bit 3 is WOC */ + outb(0x0, ioBase + NETWAVE_REG_PMR); /* release reset */ +} + +/* + * Function netwave_reset (dev) + * + * Reset and restore all of the netwave registers + */ +static void netwave_reset(struct net_device *dev) { + /* u_char state; */ + netwave_private *priv = netdev_priv(dev); + u_char __iomem *ramBase = priv->ramBase; + unsigned int iobase = dev->base_addr; + + DEBUG(0, "netwave_reset: Done with hardware reset\n"); + + priv->timeoutCounter = 0; + + /* Reset card */ + netwave_doreset(iobase, ramBase); + printk(KERN_DEBUG "netwave_reset: Done with hardware reset\n"); + + /* Write a NOP to check the card */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_NOP, ramBase + NETWAVE_EREG_CB + 0); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); + + /* Set receive conf */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0); + writeb(rxConfRxEna + rxConfBcast, ramBase + NETWAVE_EREG_CB + 1); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); + + /* Set transmit conf */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_STC, ramBase + NETWAVE_EREG_CB + 0); + writeb(txConfTxEna, ramBase + NETWAVE_EREG_CB + 1); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); + + /* Now set the MU Domain */ + printk(KERN_DEBUG "Setting domain to 0x%x%02x\n", (domain >> 8) & 0x01, domain & 0xff); + wait_WOC(iobase); + writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0); + writeb(domain & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((domain>>8) & 0x01, ramBase + NETWAVE_EREG_CB + 2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + + /* Set scramble key */ + printk(KERN_DEBUG "Setting scramble key to 0x%x\n", scramble_key); + wait_WOC(iobase); + writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0); + writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + + /* Enable interrupts, bit 4 high to keep unused + * source from interrupting us, bit 2 high to + * set interrupt enable, 567 to enable TxDN, + * RxErr and RxRdy + */ + wait_WOC(iobase); + outb(imrConfIENA+imrConfRFU1, iobase + NETWAVE_REG_IMR); + + /* Hent 4 bytes fra 0x170. Skal vaere 0a,29,88,36 + * waitWOC + * skriv 80 til d000:3688 + * sjekk om det ble 80 + */ + + /* Enable Receiver */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_ER, ramBase + NETWAVE_EREG_CB + 0); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); + + /* Set the IENA bit in COR */ + wait_WOC(iobase); + outb(corConfIENA + corConfLVLREQ, iobase + NETWAVE_REG_COR); +} + +/* + * Function netwave_hw_xmit (data, len, dev) + */ +static int netwave_hw_xmit(unsigned char* data, int len, + struct net_device* dev) { + unsigned long flags; + unsigned int TxFreeList, + curBuff, + MaxData, + DataOffset; + int tmpcount; + + netwave_private *priv = netdev_priv(dev); + u_char __iomem * ramBase = priv->ramBase; + unsigned int iobase = dev->base_addr; + + /* Disable interrupts & save flags */ + spin_lock_irqsave(&priv->spinlock, flags); + + /* Check if there are transmit buffers available */ + wait_WOC(iobase); + if ((inb(iobase+NETWAVE_REG_ASR) & NETWAVE_ASR_TXBA) == 0) { + /* No buffers available */ + printk(KERN_DEBUG "netwave_hw_xmit: %s - no xmit buffers available.\n", + dev->name); + spin_unlock_irqrestore(&priv->spinlock, flags); + return 1; + } + + dev->stats.tx_bytes += len; + + DEBUG(3, "Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n", + readb(ramBase + NETWAVE_EREG_SPCQ), + readb(ramBase + NETWAVE_EREG_SPU), + readb(ramBase + NETWAVE_EREG_LIF), + readb(ramBase + NETWAVE_EREG_ISPLQ)); + + /* Now try to insert it into the adapters free memory */ + wait_WOC(iobase); + TxFreeList = get_uint16(ramBase + NETWAVE_EREG_TDP); + MaxData = get_uint16(ramBase + NETWAVE_EREG_TDP+2); + DataOffset = get_uint16(ramBase + NETWAVE_EREG_TDP+4); + + DEBUG(3, "TxFreeList %x, MaxData %x, DataOffset %x\n", + TxFreeList, MaxData, DataOffset); + + /* Copy packet to the adapter fragment buffers */ + curBuff = TxFreeList; + tmpcount = 0; + while (tmpcount < len) { + int tmplen = len - tmpcount; + copy_to_pc(ramBase + curBuff + DataOffset, data + tmpcount, + (tmplen < MaxData) ? tmplen : MaxData); + tmpcount += MaxData; + + /* Advance to next buffer */ + curBuff = get_uint16(ramBase + curBuff); + } + + /* Now issue transmit list */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_TL, ramBase + NETWAVE_EREG_CB + 0); + writeb(len & 0xff, ramBase + NETWAVE_EREG_CB + 1); + writeb((len>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3); + + spin_unlock_irqrestore(&priv->spinlock, flags); + return 0; +} + +static netdev_tx_t netwave_start_xmit(struct sk_buff *skb, + struct net_device *dev) { + /* This flag indicate that the hardware can't perform a transmission. + * Theoritically, NET3 check it before sending a packet to the driver, + * but in fact it never do that and pool continuously. + * As the watchdog will abort too long transmissions, we are quite safe... + */ + + netif_stop_queue(dev); + + { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char* buf = skb->data; + + if (netwave_hw_xmit( buf, length, dev) == 1) { + /* Some error, let's make them call us another time? */ + netif_start_queue(dev); + } + dev->trans_start = jiffies; + } + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} /* netwave_start_xmit */ + +/* + * Function netwave_interrupt (irq, dev_id) + * + * This function is the interrupt handler for the Netwave card. This + * routine will be called whenever: + * 1. A packet is received. + * 2. A packet has successfully been transferred and the unit is + * ready to transmit another packet. + * 3. A command has completed execution. + */ +static irqreturn_t netwave_interrupt(int irq, void* dev_id) +{ + unsigned int iobase; + u_char __iomem *ramBase; + struct net_device *dev = (struct net_device *)dev_id; + struct netwave_private *priv = netdev_priv(dev); + struct pcmcia_device *link = priv->p_dev; + int i; + + if (!netif_device_present(dev)) + return IRQ_NONE; + + iobase = dev->base_addr; + ramBase = priv->ramBase; + + /* Now find what caused the interrupt, check while interrupts ready */ + for (i = 0; i < 10; i++) { + u_char status; + + wait_WOC(iobase); + if (!(inb(iobase+NETWAVE_REG_CCSR) & 0x02)) + break; /* None of the interrupt sources asserted (normal exit) */ + + status = inb(iobase + NETWAVE_REG_ASR); + + if (!pcmcia_dev_present(link)) { + DEBUG(1, "netwave_interrupt: Interrupt with status 0x%x " + "from removed or suspended card!\n", status); + break; + } + + /* RxRdy */ + if (status & 0x80) { + netwave_rx(dev); + /* wait_WOC(iobase); */ + /* RxRdy cannot be reset directly by the host */ + } + /* RxErr */ + if (status & 0x40) { + u_char rser; + + rser = readb(ramBase + NETWAVE_EREG_RSER); + + if (rser & 0x04) { + ++dev->stats.rx_dropped; + ++dev->stats.rx_crc_errors; + } + if (rser & 0x02) + ++dev->stats.rx_frame_errors; + + /* Clear the RxErr bit in RSER. RSER+4 is the + * write part. Also clear the RxCRC (0x04) and + * RxBig (0x02) bits if present */ + wait_WOC(iobase); + writeb(0x40 | (rser & 0x06), ramBase + NETWAVE_EREG_RSER + 4); + + /* Write bit 6 high to ASCC to clear RxErr in ASR, + * WOC must be set first! + */ + wait_WOC(iobase); + writeb(0x40, ramBase + NETWAVE_EREG_ASCC); + + /* Remember to count up dev->stats on error packets */ + ++dev->stats.rx_errors; + } + /* TxDN */ + if (status & 0x20) { + int txStatus; + + txStatus = readb(ramBase + NETWAVE_EREG_TSER); + DEBUG(3, "Transmit done. TSER = %x id %x\n", + txStatus, readb(ramBase + NETWAVE_EREG_TSER + 1)); + + if (txStatus & 0x20) { + /* Transmitting was okay, clear bits */ + wait_WOC(iobase); + writeb(0x2f, ramBase + NETWAVE_EREG_TSER + 4); + ++dev->stats.tx_packets; + } + + if (txStatus & 0xd0) { + if (txStatus & 0x80) { + ++dev->stats.collisions; /* Because of /proc/net/dev*/ + /* ++dev->stats.tx_aborted_errors; */ + /* printk("Collision. %ld\n", jiffies - dev->trans_start); */ + } + if (txStatus & 0x40) + ++dev->stats.tx_carrier_errors; + /* 0x80 TxGU Transmit giveup - nine times and no luck + * 0x40 TxNOAP No access point. Discarded packet. + * 0x10 TxErr Transmit error. Always set when + * TxGU and TxNOAP is set. (Those are the only ones + * to set TxErr). + */ + DEBUG(3, "netwave_interrupt: TxDN with error status %x\n", + txStatus); + + /* Clear out TxGU, TxNOAP, TxErr and TxTrys */ + wait_WOC(iobase); + writeb(0xdf & txStatus, ramBase+NETWAVE_EREG_TSER+4); + ++dev->stats.tx_errors; + } + DEBUG(3, "New status is TSER %x ASR %x\n", + readb(ramBase + NETWAVE_EREG_TSER), + inb(iobase + NETWAVE_REG_ASR)); + + netif_wake_queue(dev); + } + /* TxBA, this would trigger on all error packets received */ + /* if (status & 0x01) { + DEBUG(4, "Transmit buffers available, %x\n", status); + } + */ + } + /* Handled if we looped at least one time - Jean II */ + return IRQ_RETVAL(i); +} /* netwave_interrupt */ + +/* + * Function netwave_watchdog (a) + * + * Watchdog : when we start a transmission, we set a timer in the + * kernel. If the transmission complete, this timer is disabled. If + * it expire, we reset the card. + * + */ +static void netwave_watchdog(struct net_device *dev) { + + DEBUG(1, "%s: netwave_watchdog: watchdog timer expired\n", dev->name); + netwave_reset(dev); + dev->trans_start = jiffies; + netif_wake_queue(dev); +} /* netwave_watchdog */ + +static int netwave_rx(struct net_device *dev) +{ + netwave_private *priv = netdev_priv(dev); + u_char __iomem *ramBase = priv->ramBase; + unsigned int iobase = dev->base_addr; + u_char rxStatus; + struct sk_buff *skb = NULL; + unsigned int curBuffer, + rcvList; + int rcvLen; + int tmpcount = 0; + int dataCount, dataOffset; + int i; + u_char *ptr; + + DEBUG(3, "xinw_rx: Receiving ... \n"); + + /* Receive max 10 packets for now. */ + for (i = 0; i < 10; i++) { + /* Any packets? */ + wait_WOC(iobase); + rxStatus = readb(ramBase + NETWAVE_EREG_RSER); + if ( !( rxStatus & 0x80)) /* No more packets */ + break; + + /* Check if multicast/broadcast or other */ + /* multicast = (rxStatus & 0x20); */ + + /* The receive list pointer and length of the packet */ + wait_WOC(iobase); + rcvLen = get_int16( ramBase + NETWAVE_EREG_RDP); + rcvList = get_uint16( ramBase + NETWAVE_EREG_RDP + 2); + + if (rcvLen < 0) { + printk(KERN_DEBUG "netwave_rx: Receive packet with len %d\n", + rcvLen); + return 0; + } + + skb = dev_alloc_skb(rcvLen+5); + if (skb == NULL) { + DEBUG(1, "netwave_rx: Could not allocate an sk_buff of " + "length %d\n", rcvLen); + ++dev->stats.rx_dropped; + /* Tell the adapter to skip the packet */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); + return 0; + } + + skb_reserve( skb, 2); /* Align IP on 16 byte */ + skb_put( skb, rcvLen); + + /* Copy packet fragments to the skb data area */ + ptr = (u_char*) skb->data; + curBuffer = rcvList; + tmpcount = 0; + while ( tmpcount < rcvLen) { + /* Get length and offset of current buffer */ + dataCount = get_uint16( ramBase+curBuffer+2); + dataOffset = get_uint16( ramBase+curBuffer+4); + + copy_from_pc( ptr + tmpcount, + ramBase+curBuffer+dataOffset, dataCount); + + tmpcount += dataCount; + + /* Point to next buffer */ + curBuffer = get_uint16(ramBase + curBuffer); + } + + skb->protocol = eth_type_trans(skb,dev); + /* Queue packet for network layer */ + netif_rx(skb); + + dev->stats.rx_packets++; + dev->stats.rx_bytes += rcvLen; + + /* Got the packet, tell the adapter to skip it */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); + DEBUG(3, "Packet reception ok\n"); + } + return 0; +} + +static int netwave_open(struct net_device *dev) { + netwave_private *priv = netdev_priv(dev); + struct pcmcia_device *link = priv->p_dev; + + DEBUG(1, "netwave_open: starting.\n"); + + if (!pcmcia_dev_present(link)) + return -ENODEV; + + link->open++; + + netif_start_queue(dev); + netwave_reset(dev); + + return 0; +} + +static int netwave_close(struct net_device *dev) { + netwave_private *priv = netdev_priv(dev); + struct pcmcia_device *link = priv->p_dev; + + DEBUG(1, "netwave_close: finishing.\n"); + + link->open--; + netif_stop_queue(dev); + + return 0; +} + +static struct pcmcia_device_id netwave_ids[] = { + PCMCIA_DEVICE_PROD_ID12("Xircom", "CreditCard Netwave", 0x2e3ee845, 0x54e28a28), + PCMCIA_DEVICE_NULL, +}; +MODULE_DEVICE_TABLE(pcmcia, netwave_ids); + +static struct pcmcia_driver netwave_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "netwave_cs", + }, + .probe = netwave_probe, + .remove = netwave_detach, + .id_table = netwave_ids, + .suspend = netwave_suspend, + .resume = netwave_resume, +}; + +static int __init init_netwave_cs(void) +{ + return pcmcia_register_driver(&netwave_driver); +} + +static void __exit exit_netwave_cs(void) +{ + pcmcia_unregister_driver(&netwave_driver); +} + +module_init(init_netwave_cs); +module_exit(exit_netwave_cs); + +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. + */ +static void set_multicast_list(struct net_device *dev) +{ + unsigned int iobase = dev->base_addr; + netwave_private *priv = netdev_priv(dev); + u_char __iomem * ramBase = priv->ramBase; + u_char rcvMode = 0; + +#ifdef PCMCIA_DEBUG + if (pc_debug > 2) { + static int old; + if (old != dev->mc_count) { + old = dev->mc_count; + DEBUG(0, "%s: setting Rx mode to %d addresses.\n", + dev->name, dev->mc_count); + } + } +#endif + + if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { + /* Multicast Mode */ + rcvMode = rxConfRxEna + rxConfAMP + rxConfBcast; + } else if (dev->flags & IFF_PROMISC) { + /* Promiscous mode */ + rcvMode = rxConfRxEna + rxConfPro + rxConfAMP + rxConfBcast; + } else { + /* Normal mode */ + rcvMode = rxConfRxEna + rxConfBcast; + } + + /* printk("netwave set_multicast_list: rcvMode to %x\n", rcvMode);*/ + /* Now set receive mode */ + wait_WOC(iobase); + writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0); + writeb(rcvMode, ramBase + NETWAVE_EREG_CB + 1); + writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2); +} +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 133d7c6a504c672011ebc24b26e05b15f7410c07 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 28 Oct 2009 16:29:30 -0400 Subject: wireless: remove WLAN_80211 and WLAN_PRE80211 from Kconfig With the WLAN_PRE80211 drivers moved to drivers/staging, this distinction becomes unnecessary. Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 48 ++++++++++--------------------- drivers/net/wireless/ath/Kconfig | 1 - drivers/net/wireless/ath/ar9170/Kconfig | 2 +- drivers/net/wireless/ath/ath5k/Kconfig | 2 +- drivers/net/wireless/ath/ath9k/Kconfig | 2 +- drivers/net/wireless/b43/Kconfig | 2 +- drivers/net/wireless/b43legacy/Kconfig | 2 +- drivers/net/wireless/hostap/Kconfig | 1 - drivers/net/wireless/ipw2x00/Kconfig | 6 ++-- drivers/net/wireless/iwlwifi/Kconfig | 2 +- drivers/net/wireless/iwmc3200wifi/Kconfig | 2 +- drivers/net/wireless/libertas/Kconfig | 2 +- drivers/net/wireless/orinoco/Kconfig | 2 +- drivers/net/wireless/p54/Kconfig | 2 +- drivers/net/wireless/rt2x00/Kconfig | 2 +- drivers/net/wireless/wl12xx/Kconfig | 2 +- drivers/net/wireless/zd1211rw/Kconfig | 2 +- 17 files changed, 31 insertions(+), 51 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index bf0eb4e774b4..674a08b07884 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -16,27 +16,9 @@ menuconfig WLAN if WLAN -menuconfig WLAN_PRE80211 - bool "Wireless LAN (pre-802.11)" - depends on NETDEVICES - ---help--- - Say Y if you have any pre-802.11 wireless LAN hardware. - - This option does not affect the kernel build, it only - lets you choose drivers. - -menuconfig WLAN_80211 - bool "Wireless LAN (IEEE 802.11)" - depends on NETDEVICES - ---help--- - Say Y if you have any 802.11 wireless LAN hardware. - - This option does not affect the kernel build, it only - lets you choose drivers. - config PCMCIA_RAYCS tristate "Aviator/Raytheon 2.4GHz wireless support" - depends on PCMCIA && WLAN_80211 + depends on PCMCIA select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV @@ -51,7 +33,7 @@ config PCMCIA_RAYCS config LIBERTAS_THINFIRM tristate "Marvell 8xxx Libertas WLAN driver support with thin firmware" - depends on WLAN_80211 && MAC80211 + depends on MAC80211 select FW_LOADER ---help--- A library for Marvell Libertas 8xxx devices using thinfirm. @@ -64,7 +46,7 @@ config LIBERTAS_THINFIRM_USB config AIRO tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" - depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN) + depends on ISA_DMA_API && (PCI || BROKEN) select WIRELESS_EXT select CRYPTO select WEXT_SPY @@ -84,7 +66,7 @@ config AIRO config ATMEL tristate "Atmel at76c50x chipset 802.11b support" - depends on (PCI || PCMCIA) && WLAN_80211 + depends on (PCI || PCMCIA) select WIRELESS_EXT select WEXT_PRIV select FW_LOADER @@ -119,7 +101,7 @@ config PCMCIA_ATMEL config AT76C50X_USB tristate "Atmel at76c503/at76c505/at76c505a USB cards" - depends on MAC80211 && WLAN_80211 && USB + depends on MAC80211 && USB select FW_LOADER ---help--- Enable support for USB Wireless devices using Atmel at76c503, @@ -127,7 +109,7 @@ config AT76C50X_USB config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" - depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211 + depends on PCMCIA && (BROKEN || !M32R) select WIRELESS_EXT select CRYPTO select CRYPTO_AES @@ -147,7 +129,7 @@ config AIRO_CS config PCMCIA_WL3501 tristate "Planet WL3501 PCMCIA cards" - depends on EXPERIMENTAL && PCMCIA && WLAN_80211 + depends on EXPERIMENTAL && PCMCIA select WIRELESS_EXT select WEXT_SPY help @@ -157,7 +139,7 @@ config PCMCIA_WL3501 config PRISM54 tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' - depends on PCI && EXPERIMENTAL && WLAN_80211 + depends on PCI && EXPERIMENTAL select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV @@ -181,7 +163,7 @@ config PRISM54 config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" - depends on USB && WLAN_80211 + depends on USB select WIRELESS_EXT select WEXT_PRIV select FW_LOADER @@ -200,7 +182,7 @@ config USB_ZD1201 config USB_NET_RNDIS_WLAN tristate "Wireless RNDIS USB support" - depends on USB && WLAN_80211 && EXPERIMENTAL + depends on USB && EXPERIMENTAL depends on CFG80211 select USB_USBNET select USB_NET_CDCETHER @@ -228,7 +210,7 @@ config USB_NET_RNDIS_WLAN config RTL8180 tristate "Realtek 8180/8185 PCI support" - depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && PCI && EXPERIMENTAL select EEPROM_93CX6 ---help--- This is a driver for RTL8180 and RTL8185 based cards. @@ -284,7 +266,7 @@ config RTL8180 config RTL8187 tristate "Realtek 8187 and 8187B USB support" - depends on MAC80211 && USB && WLAN_80211 + depends on MAC80211 && USB select EEPROM_93CX6 ---help--- This is a driver for RTL8187 and RTL8187B based cards. @@ -313,7 +295,7 @@ config RTL8187_LEDS config ADM8211 tristate "ADMtek ADM8211 support" - depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && PCI && EXPERIMENTAL select CRC32 select EEPROM_93CX6 ---help--- @@ -340,7 +322,7 @@ config ADM8211 config MAC80211_HWSIM tristate "Simulated radio testing tool for mac80211" - depends on MAC80211 && WLAN_80211 + depends on MAC80211 ---help--- This driver is a developer testing tool that can be used to test IEEE 802.11 networking stack (mac80211) functionality. This is not @@ -353,7 +335,7 @@ config MAC80211_HWSIM config MWL8K tristate "Marvell 88W8xxx PCI/PCIe Wireless support" - depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && PCI && EXPERIMENTAL ---help--- This driver supports Marvell TOPDOG 802.11 wireless cards. diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 6ce86cb37654..4e7a7fd695c8 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,6 +1,5 @@ menuconfig ATH_COMMON tristate "Atheros Wireless Cards" - depends on WLAN_80211 depends on CFG80211 ---help--- This will enable the support for the Atheros wireless drivers. diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig index 05918f1e685a..d7a4799d20fb 100644 --- a/drivers/net/wireless/ath/ar9170/Kconfig +++ b/drivers/net/wireless/ath/ar9170/Kconfig @@ -1,6 +1,6 @@ config AR9170_USB tristate "Atheros AR9170 802.11n USB support" - depends on USB && MAC80211 && WLAN_80211 + depends on USB && MAC80211 select FW_LOADER help This is a driver for the Atheros "otus" 802.11n USB devices. diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index 06d006675d7d..eb83b7b4d0e3 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -1,6 +1,6 @@ config ATH5K tristate "Atheros 5xxx wireless cards support" - depends on PCI && MAC80211 && WLAN_80211 + depends on PCI && MAC80211 select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 99ce066392a7..b735fb399fb1 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -3,7 +3,7 @@ config ATH9K_HW config ATH9K tristate "Atheros 802.11n wireless cards support" - depends on PCI && MAC80211 && WLAN_80211 + depends on PCI && MAC80211 select ATH9K_HW select MAC80211_LEDS select LEDS_CLASS diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 54ea61c15d8b..64c12e1bced3 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -1,6 +1,6 @@ config B43 tristate "Broadcom 43xx wireless support (mac80211 stack)" - depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA + depends on SSB_POSSIBLE && MAC80211 && HAS_DMA select SSB select FW_LOADER ---help--- diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index 94a463478053..1ffa28835c58 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -1,6 +1,6 @@ config B43LEGACY tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)" - depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA + depends on SSB_POSSIBLE && MAC80211 && HAS_DMA select SSB select FW_LOADER ---help--- diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig index 08f1e989653d..287d82728bc3 100644 --- a/drivers/net/wireless/hostap/Kconfig +++ b/drivers/net/wireless/hostap/Kconfig @@ -1,6 +1,5 @@ config HOSTAP tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" - depends on WLAN_80211 select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index 59ec9eec5024..2715b101aded 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -4,7 +4,7 @@ config IPW2100 tristate "Intel PRO/Wireless 2100 Network Connection" - depends on PCI && WLAN_80211 && CFG80211 + depends on PCI && CFG80211 select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV @@ -65,7 +65,7 @@ config IPW2100_DEBUG config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && WLAN_80211 && CFG80211 && CFG80211_WEXT + depends on PCI && CFG80211 && CFG80211_WEXT select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV @@ -154,7 +154,7 @@ config IPW2200_DEBUG config LIBIPW tristate - depends on PCI && WLAN_80211 && CFG80211 + depends on PCI && CFG80211 select WIRELESS_EXT select WEXT_SPY select CRYPTO diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index c82c97be7bfa..b16b06c2031f 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -1,6 +1,6 @@ config IWLWIFI tristate "Intel Wireless Wifi" - depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on PCI && MAC80211 && EXPERIMENTAL select FW_LOADER config IWLWIFI_SPECTRUM_MEASUREMENT diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig index 9606b3100fde..b9d34a766964 100644 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -1,6 +1,6 @@ config IWM tristate "Intel Wireless Multicomm 3200 WiFi driver" - depends on MMC && WLAN_80211 && EXPERIMENTAL + depends on MMC && EXPERIMENTAL depends on CFG80211 select FW_LOADER select IWMC3200TOP diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig index 8f8d75b61ea9..30aa9d48d67e 100644 --- a/drivers/net/wireless/libertas/Kconfig +++ b/drivers/net/wireless/libertas/Kconfig @@ -1,6 +1,6 @@ config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" - depends on WLAN_80211 && CFG80211 + depends on CFG80211 select WIRELESS_EXT select WEXT_SPY select LIB80211 diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig index dce652054afd..e2a2c18920aa 100644 --- a/drivers/net/wireless/orinoco/Kconfig +++ b/drivers/net/wireless/orinoco/Kconfig @@ -1,6 +1,6 @@ config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" - depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 + depends on (PPC_PMAC || PCI || PCMCIA) depends on CFG80211 && CFG80211_WEXT select WIRELESS_EXT select WEXT_SPY diff --git a/drivers/net/wireless/p54/Kconfig b/drivers/net/wireless/p54/Kconfig index b45d6a4ed1e8..b0342a520bf1 100644 --- a/drivers/net/wireless/p54/Kconfig +++ b/drivers/net/wireless/p54/Kconfig @@ -1,6 +1,6 @@ config P54_COMMON tristate "Softmac Prism54 support" - depends on MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && EXPERIMENTAL select FW_LOADER ---help--- This is common code for isl38xx/stlc45xx based modules. diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 390c0c7b3ac2..a6796a130486 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -1,6 +1,6 @@ menuconfig RT2X00 tristate "Ralink driver support" - depends on MAC80211 && WLAN_80211 + depends on MAC80211 ---help--- This will enable the support for the Ralink drivers, developed in the rt2x00 project . diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 88060e117541..33de7fa4f882 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -1,6 +1,6 @@ menuconfig WL12XX tristate "TI wl12xx driver support" - depends on MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && EXPERIMENTAL ---help--- This will enable TI wl12xx driver support. The drivers make use of the mac80211 stack. diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig index 74b31eafe72d..5f809695f71a 100644 --- a/drivers/net/wireless/zd1211rw/Kconfig +++ b/drivers/net/wireless/zd1211rw/Kconfig @@ -1,6 +1,6 @@ config ZD1211RW tristate "ZyDAS ZD1211/ZD1211B USB-wireless support" - depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on USB && MAC80211 && EXPERIMENTAL select FW_LOADER ---help--- This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless -- cgit v1.2.3 From 0cab6559f878f328906949c5c20cbbc411cddeb7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:32 -0400 Subject: ath9k_hw: modify the rf control register for ar9271 revision 1.0 Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 58167d861dc6..68db16690abf 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -1112,6 +1112,10 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); + + if (AR_SREV_9271_10(ah)) + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, pModal->thresh62); REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, -- cgit v1.2.3 From 8564328d85f69121744d8337124857a2e726239b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:33 -0400 Subject: ath9k_hw: update register initialization/reset values for ar9271 This update the register initialization/reset values (aka initvals) for ar9271 based on the last recommended values on 2009-06-04 by our systems engineering team. The changes account for: * Supporting ar9271 1.0 and ar9271 1.1 together, the difference is bb_spectral_scan_ena, for 1.0 we'll set this to 0x1. * Ensuring we get the correct noise floor values -115 ~ -118 when we enable bb_enable_ant_div_lnadiv=0 and mc_tx_def_ant_sel=1. Previous to this we would get noise floor values in the range -50 ~ -80. To fix settings for the registers: - bb_ch1_xatten1_db - bb_ch1_xatten2_db - bb_ch1_xatten1_margin - bb_ch1_xatten2_margin - bb_ch1_gain_force - bb_ch1_xatten2_hyst_margin - bb_ch1_xatten1_hyst_margin - bb_ch1_max_oc_gain * 0x8120[2] mc_mic_new_location_enable is changed to 0x1. The MAC team suggest to set this value. * 0x9910[0] bb_spectral_scan_ena is changed to 0x0. For ar9271 1.1 we don't need to enable this bit. Cc: Stephen Chen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 15 +++++++++++---- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/initvals.h | 29 +++++++++++++++++------------ 3 files changed, 29 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2fbadbee1aa2..7cee89b81fce 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -662,10 +662,13 @@ static void ath9k_hw_init_cal_settings(struct ath_hw *ah) static void ath9k_hw_init_mode_regs(struct ath_hw *ah) { if (AR_SREV_9271(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271_1_0, - ARRAY_SIZE(ar9271Modes_9271_1_0), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271_1_0, - ARRAY_SIZE(ar9271Common_9271_1_0), 2); + INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271, + ARRAY_SIZE(ar9271Modes_9271), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271, + ARRAY_SIZE(ar9271Common_9271), 2); + INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only, + ar9271Modes_9271_1_0_only, + ARRAY_SIZE(ar9271Modes_9271_1_0_only), 6); return; } @@ -1492,6 +1495,10 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites); + if (AR_SREV_9271_10(ah)) + REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only, + modesIndex, regWrites); + if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) { REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 33a5aec1856d..48b6c71144a7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -596,6 +596,7 @@ struct ath_hw { struct ar5416IniArray iniModesAdditional; struct ar5416IniArray iniModesRxGain; struct ar5416IniArray iniModesTxGain; + struct ar5416IniArray iniModes_9271_1_0_only; struct ar5416IniArray iniCckfirNormal; struct ar5416IniArray iniCckfirJapan2484; diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index 3ee6658d809b..8a3bf3ab998d 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h @@ -6379,8 +6379,8 @@ static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = { }; -/* AR9271 initialization values automaticaly created: 03/23/09 */ -static const u_int32_t ar9271Modes_9271_1_0[][6] = { +/* AR9271 initialization values automaticaly created: 06/04/09 */ +static const u_int32_t ar9271Modes_9271[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, @@ -6390,8 +6390,8 @@ static const u_int32_t ar9271Modes_9271_1_0[][6] = { { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e }, + { 0x00009828, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001 }, { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, @@ -6405,6 +6405,7 @@ static const u_int32_t ar9271Modes_9271_1_0[][6] = { { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009910, 0x30002310, 0x30002310, 0x30002310, 0x30002310, 0x30002310 }, { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, @@ -6415,7 +6416,7 @@ static const u_int32_t ar9271Modes_9271_1_0[][6] = { { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 }, + { 0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f }, { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, @@ -6704,7 +6705,7 @@ static const u_int32_t ar9271Modes_9271_1_0[][6] = { { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, }; -static const u_int32_t ar9271Common_9271_1_0[][2] = { +static const u_int32_t ar9271Common_9271[][2] = { { 0x0000000c, 0x00000000 }, { 0x00000030, 0x00020045 }, { 0x00000034, 0x00000005 }, @@ -6800,7 +6801,7 @@ static const u_int32_t ar9271Common_9271_1_0[][2] = { { 0x0000803c, 0x00000000 }, { 0x00008048, 0x00000000 }, { 0x00008054, 0x00000000 }, - { 0x00008058, 0x02000000 }, + { 0x00008058, 0x00000000 }, { 0x0000805c, 0x000fc78f }, { 0x00008060, 0x0000000f }, { 0x00008064, 0x00000000 }, @@ -6831,7 +6832,7 @@ static const u_int32_t ar9271Common_9271_1_0[][2] = { { 0x00008110, 0x00000168 }, { 0x00008118, 0x000100aa }, { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04814 }, + { 0x00008120, 0x08f04810 }, { 0x00008124, 0x00000000 }, { 0x00008128, 0x00000000 }, { 0x0000812c, 0x00000000 }, @@ -6878,7 +6879,7 @@ static const u_int32_t ar9271Common_9271_1_0[][2] = { { 0x00008258, 0x00000000 }, { 0x0000825c, 0x400000ff }, { 0x00008260, 0x00080922 }, - { 0x00008264, 0xa8a00010 }, + { 0x00008264, 0x88a00010 }, { 0x00008270, 0x00000000 }, { 0x00008274, 0x40000000 }, { 0x00008278, 0x003e4180 }, @@ -6910,7 +6911,7 @@ static const u_int32_t ar9271Common_9271_1_0[][2] = { { 0x00007814, 0x924934a8 }, { 0x0000781c, 0x00000000 }, { 0x00007820, 0x00000c04 }, - { 0x00007824, 0x00d86bff }, + { 0x00007824, 0x00d8abff }, { 0x00007828, 0x66964300 }, { 0x0000782c, 0x8db6d961 }, { 0x00007830, 0x8db6d96c }, @@ -6944,7 +6945,6 @@ static const u_int32_t ar9271Common_9271_1_0[][2] = { { 0x00009904, 0x00000000 }, { 0x00009908, 0x00000000 }, { 0x0000990c, 0x00000000 }, - { 0x00009910, 0x30002310 }, { 0x0000991c, 0x10000fff }, { 0x00009920, 0x04900000 }, { 0x00009928, 0x00000001 }, @@ -6958,7 +6958,7 @@ static const u_int32_t ar9271Common_9271_1_0[][2] = { { 0x00009954, 0x5f3ca3de }, { 0x00009958, 0x0108ecff }, { 0x00009968, 0x000003ce }, - { 0x00009970, 0x192bb515 }, + { 0x00009970, 0x192bb514 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, { 0x0000997c, 0x00000000 }, @@ -7045,3 +7045,8 @@ static const u_int32_t ar9271Common_9271_1_0[][2] = { { 0x0000d380, 0x7f3c7bba }, { 0x0000d384, 0xf3307ff0 }, }; + +static const u_int32_t ar9271Modes_9271_1_0_only[][6] = { + { 0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311 }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, +}; -- cgit v1.2.3 From c75724d1747230abdd37d0594ac5277b867befd4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:34 -0400 Subject: ath9k_hw: change the way we initialize the pll for ar9271 We adjust the core clock for ar9271 to 117 MHz; this also requires us to adjust the baud divider based on the targetted baud rate. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/reg.h | 3 +++ 2 files changed, 39 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7cee89b81fce..be9c0b691885 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1040,6 +1040,22 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); } +static void ath9k_hw_change_target_baud(struct ath_hw *ah, u32 freq, u32 baud) +{ + u32 lcr; + u32 baud_divider = freq * 1000 * 1000 / 16 / baud; + + lcr = REG_READ(ah , 0x5100c); + lcr |= 0x80; + + REG_WRITE(ah, 0x5100c, lcr); + REG_WRITE(ah, 0x51004, (baud_divider >> 8)); + REG_WRITE(ah, 0x51000, (baud_divider & 0xff)); + + lcr &= ~0x80; + REG_WRITE(ah, 0x5100c, lcr); +} + static void ath9k_hw_init_pll(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -1103,6 +1119,26 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, } REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); + /* Switch the core clock for ar9271 to 117Mhz */ + if (AR_SREV_9271(ah)) { + if ((pll == 0x142c) || (pll == 0x2850) ) { + udelay(500); + /* set CLKOBS to output AHB clock */ + REG_WRITE(ah, 0x7020, 0xe); + /* + * 0x304: 117Mhz, ahb_ratio: 1x1 + * 0x306: 40Mhz, ahb_ratio: 1x1 + */ + REG_WRITE(ah, 0x50040, 0x304); + /* + * makes adjustments for the baud dividor to keep the + * targetted baud rate based on the used core clock. + */ + ath9k_hw_change_target_baud(ah, AR9271_CORE_CLOCK, + AR9271_TARGET_BAUD_RATE); + } + } + udelay(RTC_PLL_SETTLE_DELAY); REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index ceed0095efac..061e12ce0b24 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1704,4 +1704,7 @@ enum { #define AR_KEYTABLE_MAC0(_n) (AR_KEYTABLE(_n) + 24) #define AR_KEYTABLE_MAC1(_n) (AR_KEYTABLE(_n) + 28) +#define AR9271_CORE_CLOCK 117 /* clock to 117Mhz */ +#define AR9271_TARGET_BAUD_RATE 19200 /* 115200 */ + #endif -- cgit v1.2.3 From 131d1d036ac7e7c8ad063581b57ba3bb5f7c881d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:35 -0400 Subject: ath9k_hw: start documenting 802.11n RF anlong front ends Document what we can about the RF analog front ends (radios) of Atheros 802.11n devices. What should be clearer now is the what we do for old pre AR5416 and AR5418 MAC based devices in comparison to the modern sigle-chip 802.11n solutions. All devices after AR9280 are single chip and require less programming -- the RF registers no longer need to be initialized as they all have the RF analog front end embedded together with the MAC/BB; this includes the AR9271. Older devices such as the ones with the AR5416 MACs (PCI) or AR5418 MACs (PCI-E) have an external 2.4 GHz AR2133 radio or a dual band 2.4 GHz / 5 GHz AR5133 radio. These external radios require additional programming of the RF registers. Clarify which parts are for what devices and which code is shared. This patch has no functional changes. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.h | 9 ++ drivers/net/wireless/ath/ath9k/phy.c | 166 +++++++++++++++++++++++++++++++++-- 2 files changed, 170 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 48b6c71144a7..007b41426b27 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -148,6 +148,15 @@ enum wireless_mode { ATH9K_MODE_MAX, }; +/** + * ath9k_ant_setting - transmit antenna settings + * + * Configures the antenna setting to use for transmit. + * + * @ATH9K_ANT_VARIABLE: this means transmit on all active antennas + * @ATH9K_ANT_FIXED_A: this means transmit on the first antenna only + * @ATH9K_ANT_FIXED_B: this means transmit on the second antenna only + */ enum ath9k_ant_setting { ATH9K_ANT_VARIABLE = 0, ATH9K_ANT_FIXED_A, diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 72a17c43a5a0..9e515033b878 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -14,8 +14,44 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/** + * DOC: Programming Atheros 802.11n analog front end radios + * + * AR5416 MAC based PCI devices and AR518 MAC based PCI-Express + * devices have either an external AR2133 analog front end radio for single + * band 2.4 GHz communication or an AR5133 analog front end radio for dual + * band 2.4 GHz / 5 GHz communication. + * + * All devices after the AR5416 and AR5418 family starting with the AR9280 + * have their analog front radios, MAC/BB and host PCIe/USB interface embedded + * into a single-chip and require less programming. + * + * The following single-chips exist with a respective embedded radio: + * + * AR9280 - 11n dual-band 2x2 MIMO for PCIe + * AR9281 - 11n single-band 1x2 MIMO for PCIe + * AR9285 - 11n single-band 1x1 for PCIe + * AR9287 - 11n single-band 2x2 MIMO for PCIe + * + * AR9220 - 11n dual-band 2x2 MIMO for PCI + * AR9223 - 11n single-band 2x2 MIMO for PCI + * + * AR9287 - 11n single-band 1x1 MIMO for USB + */ + #include "hw.h" +/** + * ath9k_hw_write_regs - ?? + * + * @ah: atheros hardware structure + * @modesIndex: + * @freqIndex: + * @regWrites: + * + * Used for both the chipsets with an external AR2133/AR5133 radios and + * single-chip devices. + */ void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, int regWrites) @@ -23,6 +59,15 @@ ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); } +/** + * ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios + * @ah: atheros hardware stucture + * @chan: + * + * For the external AR2133/AR5133 radios, takes the MHz channel value and set + * the channel value. Assumes writes enabled to analog bus and bank6 register + * cache in ah->analogBank6Data. + */ bool ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -97,6 +142,27 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) return true; } +/** + * ath9k_hw_ar9280_set_channel - set channel on single-chip device + * @ah: atheros hardware structure + * @chan: + * + * This is the function to change channel on single-chip devices, that is + * all devices after ar9280. + * + * This function takes the channel value in MHz and sets + * hardware channel value. Assumes writes have been enabled to analog bus. + * + * Actual Expression, + * + * For 2GHz channel, + * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17) + * (freq_ref = 40MHz) + * + * For 5GHz channel, + * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10) + * (freq_ref = 40MHz/(24>>amodeRefSel)) + */ void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -111,7 +177,7 @@ void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL); reg32 &= 0xc0000000; - if (freq < 4800) { + if (freq < 4800) { /* 2 GHz, fractional mode */ u32 txctl; int regWrites = 0; @@ -122,6 +188,7 @@ void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, if (AR_SREV_9287_11_OR_LATER(ah)) { if (freq == 2484) { + /* Enable channel spreading for channel 14 */ REG_WRITE_ARRAY(&ah->iniCckfirJapan2484, 1, regWrites); } else { @@ -155,10 +222,15 @@ void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, case 1: default: aModeRefSel = 0; + /* + * Enable 2G (fractional) mode for channels + * which are 5MHz spaced. + */ fracMode = 1; refDivA = 1; channelSel = (freq * 0x8000) / 15; + /* RefDivA setting */ REG_RMW_FIELD(ah, AR_AN_SYNTH9, AR_AN_SYNTH9_REFDIVA, refDivA); @@ -182,6 +254,17 @@ void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, ah->curchan_rad_index = -1; } +/** + * ath9k_phy_modify_rx_buffer() - perform analog swizzling of parameters + * @rfbuf: + * @reg32: + * @numBits: + * @firstBit: + * @column: + * + * Performs analog "swizzling" of parameters into their location. + * Used on external AR2133/AR5133 radios. + */ static void ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, u32 numBits, u32 firstBit, @@ -209,6 +292,18 @@ ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, } } +/* * + * ath9k_hw_set_rf_regs - programs rf registers based on EEPROM + * @ah: atheros hardware structure + * @chan: + * @modesIndex: + * + * Used for the external AR2133/AR5133 radios. + * + * Reads the EEPROM header info from the device structure and programs + * all rf registers. This routine requires access to the analog + * rf device. This is not required for single-chip devices. + */ bool ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, u16 modesIndex) @@ -218,17 +313,27 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, u32 ob2GHz = 0, db2GHz = 0; int regWrites = 0; + /* + * Software does not need to program bank data + * for single chip devices, that is AR9280 or anything + * after that. + */ if (AR_SREV_9280_10_OR_LATER(ah)) return true; + /* Setup rf parameters */ eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); + /* Setup Bank 0 Write */ RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); + /* Setup Bank 1 Write */ RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); + /* Setup Bank 2 Write */ RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); + /* Setup Bank 6 Write */ RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, modesIndex); { @@ -239,6 +344,7 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, } } + /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ if (eepMinorRev >= 2) { if (IS_CHAN_2GHZ(chan)) { ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2); @@ -257,8 +363,10 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, } } + /* Setup Bank 7 Setup */ RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); + /* Write Analog registers */ REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, regWrites); REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data, @@ -275,6 +383,11 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, return true; } +/** + * ath9k_hw_rf_free - Free memory for analog bank scratch buffers + * @ah: atheros hardware struture + * For the external AR2133/AR5133 radios. + */ void ath9k_hw_rf_free(struct ath_hw *ah) { @@ -295,6 +408,13 @@ ath9k_hw_rf_free(struct ath_hw *ah) #undef ATH_FREE_BANK } +/** + * ath9k_hw_init_rf - initialize external radio structures + * @ah: atheros hardware structure + * @status: + * + * Only required for older devices with external AR2133/AR5133 radios. + */ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) { struct ath_common *common = ath9k_hw_common(ah); @@ -360,6 +480,33 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) return true; } +/** + * ath9k_hw_decrease_chain_power() + * + * @ah: atheros hardware structure + * @chan: + * + * Only used on the AR5416 and AR5418 with the external AR2133/AR5133 radios. + * + * Sets a chain internal RF path to the lowest output power. Any + * further writes to bank6 after this setting will override these + * changes. Thus this function must be the last function in the + * sequence to modify bank 6. + * + * This function must be called after ar5416SetRfRegs() which is + * called from ath9k_hw_process_ini() due to swizzling of bank 6. + * Depends on ah->analogBank6Data being initialized by + * ath9k_hw_set_rf_regs() + * + * Additional additive reduction in power - + * change chain's switch table so chain's tx state is actually the rx + * state value. May produce different results in 2GHz/5GHz as well as + * board to board but in general should be a reduction. + * + * Activated by #ifdef ALTER_SWITCH. Not tried yet. If so, must be + * called after ah->eep_ops->set_board_values() due to RMW of + * PHY_SWITCH_CHAIN_0. + */ void ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -371,26 +518,35 @@ ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) case ATH9K_ANT_FIXED_A: bank6SelMask = (ah->config.antenna_switch_swap & ANTSWAP_AB) ? - REDUCE_CHAIN_0 : REDUCE_CHAIN_1; + REDUCE_CHAIN_0 : /* swapped, reduce chain 0 */ + REDUCE_CHAIN_1; /* normal, select chain 1/2 to reduce */ break; case ATH9K_ANT_FIXED_B: bank6SelMask = (ah->config.antenna_switch_swap & ANTSWAP_AB) ? - REDUCE_CHAIN_1 : REDUCE_CHAIN_0; + REDUCE_CHAIN_1 : /* swapped, reduce chain 1/2 */ + REDUCE_CHAIN_0; /* normal, select chain 0 to reduce */ break; case ATH9K_ANT_VARIABLE: - return; + return; /* do not change anything */ break; default: - return; + return; /* do not change anything */ break; } for (i = 0; i < ah->iniBank6.ia_rows; i++) bank6Temp[i] = ah->analogBank6Data[i]; + /* Write Bank 5 to switch Bank 6 write to selected chain only */ REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask); + /* + * Modify Bank6 selected chain to use lowest amplification. + * Modifies the parameters to a value of 1. + * Depends on existing bank 6 values to be cached in + * ah->analogBank6Data + */ ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0); ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0); ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0); -- cgit v1.2.3 From b67b4397cfbfca8f5c4fff2a36e00d81ef6a28c2 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:36 -0400 Subject: ath9k_hw: bail out early on ath9k_hw_init_rf() We a huge branch for old hardware and nothing for newer hardware. Instead of doing this just bail out early for newer hardware. This patch has no functional changes. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/phy.c | 109 ++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 54 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 9e515033b878..bd4fb076cb08 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -419,62 +419,63 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) { struct ath_common *common = ath9k_hw_common(ah); - if (!AR_SREV_9280_10_OR_LATER(ah)) { - ah->analogBank0Data = - kzalloc((sizeof(u32) * - ah->iniBank0.ia_rows), GFP_KERNEL); - ah->analogBank1Data = - kzalloc((sizeof(u32) * - ah->iniBank1.ia_rows), GFP_KERNEL); - ah->analogBank2Data = - kzalloc((sizeof(u32) * - ah->iniBank2.ia_rows), GFP_KERNEL); - ah->analogBank3Data = - kzalloc((sizeof(u32) * - ah->iniBank3.ia_rows), GFP_KERNEL); - ah->analogBank6Data = - kzalloc((sizeof(u32) * - ah->iniBank6.ia_rows), GFP_KERNEL); - ah->analogBank6TPCData = - kzalloc((sizeof(u32) * - ah->iniBank6TPC.ia_rows), GFP_KERNEL); - ah->analogBank7Data = - kzalloc((sizeof(u32) * - ah->iniBank7.ia_rows), GFP_KERNEL); - - if (ah->analogBank0Data == NULL - || ah->analogBank1Data == NULL - || ah->analogBank2Data == NULL - || ah->analogBank3Data == NULL - || ah->analogBank6Data == NULL - || ah->analogBank6TPCData == NULL - || ah->analogBank7Data == NULL) { - ath_print(common, ATH_DBG_FATAL, - "Cannot allocate RF banks\n"); - *status = -ENOMEM; - return false; - } + if (AR_SREV_9280_10_OR_LATER(ah)) + return true; - ah->addac5416_21 = - kzalloc((sizeof(u32) * - ah->iniAddac.ia_rows * - ah->iniAddac.ia_columns), GFP_KERNEL); - if (ah->addac5416_21 == NULL) { - ath_print(common, ATH_DBG_FATAL, - "Cannot allocate addac5416_21\n"); - *status = -ENOMEM; - return false; - } + ah->analogBank0Data = + kzalloc((sizeof(u32) * + ah->iniBank0.ia_rows), GFP_KERNEL); + ah->analogBank1Data = + kzalloc((sizeof(u32) * + ah->iniBank1.ia_rows), GFP_KERNEL); + ah->analogBank2Data = + kzalloc((sizeof(u32) * + ah->iniBank2.ia_rows), GFP_KERNEL); + ah->analogBank3Data = + kzalloc((sizeof(u32) * + ah->iniBank3.ia_rows), GFP_KERNEL); + ah->analogBank6Data = + kzalloc((sizeof(u32) * + ah->iniBank6.ia_rows), GFP_KERNEL); + ah->analogBank6TPCData = + kzalloc((sizeof(u32) * + ah->iniBank6TPC.ia_rows), GFP_KERNEL); + ah->analogBank7Data = + kzalloc((sizeof(u32) * + ah->iniBank7.ia_rows), GFP_KERNEL); + + if (ah->analogBank0Data == NULL + || ah->analogBank1Data == NULL + || ah->analogBank2Data == NULL + || ah->analogBank3Data == NULL + || ah->analogBank6Data == NULL + || ah->analogBank6TPCData == NULL + || ah->analogBank7Data == NULL) { + ath_print(common, ATH_DBG_FATAL, + "Cannot allocate RF banks\n"); + *status = -ENOMEM; + return false; + } - ah->bank6Temp = - kzalloc((sizeof(u32) * - ah->iniBank6.ia_rows), GFP_KERNEL); - if (ah->bank6Temp == NULL) { - ath_print(common, ATH_DBG_FATAL, - "Cannot allocate bank6Temp\n"); - *status = -ENOMEM; - return false; - } + ah->addac5416_21 = + kzalloc((sizeof(u32) * + ah->iniAddac.ia_rows * + ah->iniAddac.ia_columns), GFP_KERNEL); + if (ah->addac5416_21 == NULL) { + ath_print(common, ATH_DBG_FATAL, + "Cannot allocate addac5416_21\n"); + *status = -ENOMEM; + return false; + } + + ah->bank6Temp = + kzalloc((sizeof(u32) * + ah->iniBank6.ia_rows), GFP_KERNEL); + if (ah->bank6Temp == NULL) { + ath_print(common, ATH_DBG_FATAL, + "Cannot allocate bank6Temp\n"); + *status = -ENOMEM; + return false; } return true; -- cgit v1.2.3 From 574d6b122d37549bc2817a4939d238f3d8b41da4 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:37 -0400 Subject: ath9k_hw: simplify rf attach and rename to ath9k_hw_rf_alloc_ext_banks() ath9k_hw_rfattach() was just calling a helper and this helper was doing nothing for single-chip devices, and for non single-chip devices it is just allocating memory for banks to program the RF registers at a later time. Simplify this by having the hw initialization call the rf bank allocation directly for external radios. Also, propagate an -ENOMEM properly now upon failure. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 27 +++++++++------------------ drivers/net/wireless/ath/ath9k/phy.c | 19 +++++++------------ drivers/net/wireless/ath/ath9k/phy.h | 3 +-- 3 files changed, 17 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index be9c0b691885..2e2516e1cd4a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -454,21 +454,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->power_mode = ATH9K_PM_UNDEFINED; } -static int ath9k_hw_rfattach(struct ath_hw *ah) -{ - bool rfStatus = false; - int ecode = 0; - - rfStatus = ath9k_hw_init_rf(ah, &ecode); - if (!rfStatus) { - ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, - "RF setup failed, status: %u\n", ecode); - return ecode; - } - - return 0; -} - static int ath9k_hw_rf_claim(struct ath_hw *ah) { u32 val; @@ -585,9 +570,15 @@ static int ath9k_hw_post_init(struct ath_hw *ah) ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah)); - ecode = ath9k_hw_rfattach(ah); - if (ecode != 0) - return ecode; + if (!AR_SREV_9280_10_OR_LATER(ah)) { + ecode = ath9k_hw_rf_alloc_ext_banks(ah); + if (ecode) { + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "Failed allocating banks for " + "external radio\n"); + return ecode; + } + } if (!AR_SREV_9100(ah)) { ath9k_hw_ani_setup(ah); diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index bd4fb076cb08..f3136b2dfb75 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -409,18 +409,16 @@ ath9k_hw_rf_free(struct ath_hw *ah) } /** - * ath9k_hw_init_rf - initialize external radio structures + * ath9k_hw_rf_alloc_ext_banks - allocates banks for external radio programming * @ah: atheros hardware structure - * @status: * * Only required for older devices with external AR2133/AR5133 radios. */ -bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) +int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - if (AR_SREV_9280_10_OR_LATER(ah)) - return true; + BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); ah->analogBank0Data = kzalloc((sizeof(u32) * @@ -453,8 +451,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) || ah->analogBank7Data == NULL) { ath_print(common, ATH_DBG_FATAL, "Cannot allocate RF banks\n"); - *status = -ENOMEM; - return false; + return -ENOMEM; } ah->addac5416_21 = @@ -464,8 +461,7 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) if (ah->addac5416_21 == NULL) { ath_print(common, ATH_DBG_FATAL, "Cannot allocate addac5416_21\n"); - *status = -ENOMEM; - return false; + return -ENOMEM; } ah->bank6Temp = @@ -474,11 +470,10 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) if (ah->bank6Temp == NULL) { ath_print(common, ATH_DBG_FATAL, "Cannot allocate bank6Temp\n"); - *status = -ENOMEM; - return false; + return -ENOMEM; } - return true; + return 0; } /** diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index b64bc69d7bbb..0bbbfbcfe3f4 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -29,8 +29,7 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah, u16 modesIndex); void ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan); -bool ath9k_hw_init_rf(struct ath_hw *ah, - int *status); +int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah); #define AR_PHY_BASE 0x9800 #define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) -- cgit v1.2.3 From 431ba3c6dce0256eafde43af221504f99a2fcc0a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:38 -0400 Subject: ath9k_hw: simplify ath9k_hw_rf_alloc_ext_banks() This is calling an allocation and checking for it, simplify this process in a macro. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/phy.c | 72 ++++++++++-------------------------- 1 file changed, 20 insertions(+), 52 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index f3136b2dfb75..923ea0b45174 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -416,64 +416,32 @@ ath9k_hw_rf_free(struct ath_hw *ah) */ int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah) { +#define ATH_ALLOC_BANK(bank, size) do { \ + bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \ + if (!bank) { \ + ath_print(common, ATH_DBG_FATAL, \ + "Cannot allocate RF banks\n"); \ + return -ENOMEM; \ + } \ + } while (0); + struct ath_common *common = ath9k_hw_common(ah); BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); - ah->analogBank0Data = - kzalloc((sizeof(u32) * - ah->iniBank0.ia_rows), GFP_KERNEL); - ah->analogBank1Data = - kzalloc((sizeof(u32) * - ah->iniBank1.ia_rows), GFP_KERNEL); - ah->analogBank2Data = - kzalloc((sizeof(u32) * - ah->iniBank2.ia_rows), GFP_KERNEL); - ah->analogBank3Data = - kzalloc((sizeof(u32) * - ah->iniBank3.ia_rows), GFP_KERNEL); - ah->analogBank6Data = - kzalloc((sizeof(u32) * - ah->iniBank6.ia_rows), GFP_KERNEL); - ah->analogBank6TPCData = - kzalloc((sizeof(u32) * - ah->iniBank6TPC.ia_rows), GFP_KERNEL); - ah->analogBank7Data = - kzalloc((sizeof(u32) * - ah->iniBank7.ia_rows), GFP_KERNEL); - - if (ah->analogBank0Data == NULL - || ah->analogBank1Data == NULL - || ah->analogBank2Data == NULL - || ah->analogBank3Data == NULL - || ah->analogBank6Data == NULL - || ah->analogBank6TPCData == NULL - || ah->analogBank7Data == NULL) { - ath_print(common, ATH_DBG_FATAL, - "Cannot allocate RF banks\n"); - return -ENOMEM; - } - - ah->addac5416_21 = - kzalloc((sizeof(u32) * - ah->iniAddac.ia_rows * - ah->iniAddac.ia_columns), GFP_KERNEL); - if (ah->addac5416_21 == NULL) { - ath_print(common, ATH_DBG_FATAL, - "Cannot allocate addac5416_21\n"); - return -ENOMEM; - } - - ah->bank6Temp = - kzalloc((sizeof(u32) * - ah->iniBank6.ia_rows), GFP_KERNEL); - if (ah->bank6Temp == NULL) { - ath_print(common, ATH_DBG_FATAL, - "Cannot allocate bank6Temp\n"); - return -ENOMEM; - } + ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows); + ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows); + ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows); + ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows); + ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows); + ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows); + ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows); + ATH_ALLOC_BANK(ah->addac5416_21, + ah->iniAddac.ia_rows * ah->iniAddac.ia_columns); + ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows); return 0; +#undef ATH_ALLOC_BANK } /** -- cgit v1.2.3 From dc51dd503953a8bed545d10eb89fb3340a98879b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:39 -0400 Subject: ath9k_hw: rename ath9k_hw_rf_free() to ath9k_hw_rf_free_ext_banks() This clarifies this is only required for external radios. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 3 ++- drivers/net/wireless/ath/ath9k/hw.h | 1 - drivers/net/wireless/ath/ath9k/phy.c | 9 ++++++--- drivers/net/wireless/ath/ath9k/phy.h | 2 ++ 4 files changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2e2516e1cd4a..4c3ff2e429e7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1282,7 +1282,8 @@ void ath9k_hw_detach(struct ath_hw *ah) ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); free_hw: - ath9k_hw_rf_free(ah); + if (!AR_SREV_9280_10_OR_LATER(ah)) + ath9k_hw_rf_free_ext_banks(ah); kfree(ah); ah = NULL; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 007b41426b27..7f2b5d21f2f1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -628,7 +628,6 @@ static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_detach(struct ath_hw *ah); int ath9k_hw_init(struct ath_hw *ah); -void ath9k_hw_rf_free(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); void ath9k_hw_fill_cap_info(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 923ea0b45174..d50b5ff28b38 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -384,18 +384,20 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, } /** - * ath9k_hw_rf_free - Free memory for analog bank scratch buffers + * ath9k_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers * @ah: atheros hardware struture - * For the external AR2133/AR5133 radios. + * For the external AR2133/AR5133 radios banks. */ void -ath9k_hw_rf_free(struct ath_hw *ah) +ath9k_hw_rf_free_ext_banks(struct ath_hw *ah) { #define ATH_FREE_BANK(bank) do { \ kfree(bank); \ bank = NULL; \ } while (0); + BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + ATH_FREE_BANK(ah->analogBank0Data); ATH_FREE_BANK(ah->analogBank1Data); ATH_FREE_BANK(ah->analogBank2Data); @@ -405,6 +407,7 @@ ath9k_hw_rf_free(struct ath_hw *ah) ATH_FREE_BANK(ah->analogBank7Data); ATH_FREE_BANK(ah->addac5416_21); ATH_FREE_BANK(ah->bank6Temp); + #undef ATH_FREE_BANK } diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 0bbbfbcfe3f4..477b606d09fd 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -29,6 +29,8 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah, u16 modesIndex); void ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan); + +void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah); int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah); #define AR_PHY_BASE 0x9800 -- cgit v1.2.3 From 0a3b7bac673ee9462f5defe808609746d27af50d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:40 -0400 Subject: ath9k_hw: make both analog channel change routines return int This allows us to later define a callback for both. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 24 +++++++++++++----------- drivers/net/wireless/ath/ath9k/phy.c | 14 +++++++------- drivers/net/wireless/ath/ath9k/phy.h | 7 ++----- 3 files changed, 22 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4c3ff2e429e7..d4dc1cbe00aa 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1868,6 +1868,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *channel = chan->chan; u32 synthDelay, qnum; + int r; for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { @@ -1888,14 +1889,14 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ath9k_hw_set_regs(ah, chan); - if (AR_SREV_9280_10_OR_LATER(ah)) { - ath9k_hw_ar9280_set_channel(ah, chan); - } else { - if (!(ath9k_hw_set_channel(ah, chan))) { - ath_print(common, ATH_DBG_FATAL, - "Failed to set channel\n"); - return false; - } + if (AR_SREV_9280_10_OR_LATER(ah)) + r = ath9k_hw_ar9280_set_channel(ah, chan); + else + r = ath9k_hw_set_channel(ah, chan); + if (r) { + ath_print(common, ATH_DBG_FATAL, + "Failed to set channel\n"); + return false; } ah->eep_ops->set_txpower(ah, chan, @@ -2534,10 +2535,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); if (AR_SREV_9280_10_OR_LATER(ah)) - ath9k_hw_ar9280_set_channel(ah, chan); + r = ath9k_hw_ar9280_set_channel(ah, chan); else - if (!(ath9k_hw_set_channel(ah, chan))) - return -EIO; + r = ath9k_hw_set_channel(ah, chan); + if (r) + return r; for (i = 0; i < AR_NUM_DCU; i++) REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index d50b5ff28b38..bfcb9af4ae3c 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -68,8 +68,7 @@ ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, * the channel value. Assumes writes enabled to analog bus and bank6 register * cache in ah->analogBank6Data. */ -bool -ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) +int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); u32 channelSel = 0; @@ -94,7 +93,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) } else { ath_print(common, ATH_DBG_FATAL, "Invalid channel %u MHz\n", freq); - return false; + return -EINVAL; } channelSel = (channelSel << 2) & 0xff; @@ -127,7 +126,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) } else { ath_print(common, ATH_DBG_FATAL, "Invalid channel %u MHz\n", freq); - return false; + return -EINVAL; } reg32 = @@ -139,7 +138,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) ah->curchan = chan; ah->curchan_rad_index = -1; - return true; + return 0; } /** @@ -163,8 +162,7 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10) * (freq_ref = 40MHz/(24>>amodeRefSel)) */ -void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, - struct ath9k_channel *chan) +int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) { u16 bMode, fracMode, aModeRefSel = 0; u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0; @@ -252,6 +250,8 @@ void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, ah->curchan = chan; ah->curchan_rad_index = -1; + + return 0; } /** diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 477b606d09fd..bef9b41d250f 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -17,11 +17,8 @@ #ifndef PHY_H #define PHY_H -void ath9k_hw_ar9280_set_channel(struct ath_hw *ah, - struct ath9k_channel - *chan); -bool ath9k_hw_set_channel(struct ath_hw *ah, - struct ath9k_channel *chan); +int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); +int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, int regWrites); bool ath9k_hw_set_rf_regs(struct ath_hw *ah, -- cgit v1.2.3 From e68a060b5d88a72c06ec87864d20bea3f2a40629 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:41 -0400 Subject: ath9k_hw: use a callback for frequency change This avoids a branch on every channel change. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 15 ++++++--------- drivers/net/wireless/ath/ath9k/hw.h | 4 +++- 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index d4dc1cbe00aa..f2b2f45d3a78 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -951,8 +951,11 @@ int ath9k_hw_init(struct ath_hw *ah) ath9k_hw_init_cal_settings(ah); ah->ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_10_OR_LATER(ah)) + if (AR_SREV_9280_10_OR_LATER(ah)) { ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; + ah->ath9k_hw_rf_set_freq = &ath9k_hw_ar9280_set_channel; + } else + ah->ath9k_hw_rf_set_freq = &ath9k_hw_set_channel; ath9k_hw_init_mode_regs(ah); @@ -1889,10 +1892,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, ath9k_hw_set_regs(ah, chan); - if (AR_SREV_9280_10_OR_LATER(ah)) - r = ath9k_hw_ar9280_set_channel(ah, chan); - else - r = ath9k_hw_set_channel(ah, chan); + r = ah->ath9k_hw_rf_set_freq(ah, chan); if (r) { ath_print(common, ATH_DBG_FATAL, "Failed to set channel\n"); @@ -2534,10 +2534,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); - if (AR_SREV_9280_10_OR_LATER(ah)) - r = ath9k_hw_ar9280_set_channel(ah, chan); - else - r = ath9k_hw_set_channel(ah, chan); + r = ah->ath9k_hw_rf_set_freq(ah, chan); if (r) return r; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 7f2b5d21f2f1..dcf1295f4eb4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -548,7 +548,9 @@ struct ath_hw { DONT_USE_32KHZ, } enable_32kHz_clock; - /* RF */ + /* Callback for radio frequency change */ + int (*ath9k_hw_rf_set_freq)(struct ath_hw *ah, struct ath9k_channel *chan); + /* Used to program the radio on non single-chip devices */ u32 *analogBank0Data; u32 *analogBank1Data; u32 *analogBank2Data; -- cgit v1.2.3 From e16393bbb17e828aa433be9909462f9a61e4cbdb Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:42 -0400 Subject: ath9k_hw: order phy.c code and integrate spur mitigation This reorders phy.c routines in the order in the order in which they are used and also moves the spur mitigation helpers for each type of chip into phy.c as they are RF related. This patch has no functional changes. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 453 -------------------- drivers/net/wireless/ath/ath9k/phy.c | 779 ++++++++++++++++++++++++++++------- drivers/net/wireless/ath/ath9k/phy.h | 19 +- 3 files changed, 637 insertions(+), 614 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f2b2f45d3a78..626667c3101c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -30,8 +30,6 @@ static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan); static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, struct ar5416_eeprom_def *pEepData, u32 reg, u32 value); -static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); -static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); MODULE_AUTHOR("Atheros Communications"); MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); @@ -1930,457 +1928,6 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, return true; } -static void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int freq; - int bin, cur_bin; - int bb_spur_off, spur_subchannel_sd; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, newVal; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - struct chan_centers centers; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = centers.synth_center; - - ah->config.spurmode = SPUR_ENABLE_EEPROM; - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); - - if (is2GHz) - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; - else - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; - - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - freq; - - if (IS_CHAN_HT40(chan)) { - if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { - bb_spur = cur_bb_spur; - break; - } - } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - return; - } else { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - } - - bin = bb_spur * 320; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - - newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); - - newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); - - if (IS_CHAN_HT40(chan)) { - if (bb_spur < 0) { - spur_subchannel_sd = 1; - bb_spur_off = bb_spur + 10; - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur - 10; - } - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur; - } - - if (IS_CHAN_HT40(chan)) - spur_delta_phase = - ((bb_spur * 262144) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - else - spur_delta_phase = - ((bb_spur * 524288) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; - spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; - - newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, newVal); - - newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; - REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp_v = abs(cur_vit_mask - bin); - - if (tmp_v < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); -} - -static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int bin, cur_bin; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, new; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - (chan->channel * 10); - if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) - return; - - bin = bb_spur * 32; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); - - new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, new); - - spur_delta_phase = ((bb_spur * 524288) / 100) & - AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; - spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; - - new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, new); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp_v = abs(cur_vit_mask - bin); - - if (tmp_v < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); -} - static void ath9k_enable_rfkill(struct ath_hw *ah) { REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index bfcb9af4ae3c..8e4c3bd84bc0 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -52,95 +52,12 @@ * Used for both the chipsets with an external AR2133/AR5133 radios and * single-chip devices. */ -void -ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, - int regWrites) +void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, + u32 freqIndex, int regWrites) { REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); } -/** - * ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios - * @ah: atheros hardware stucture - * @chan: - * - * For the external AR2133/AR5133 radios, takes the MHz channel value and set - * the channel value. Assumes writes enabled to analog bus and bank6 register - * cache in ah->analogBank6Data. - */ -int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) -{ - struct ath_common *common = ath9k_hw_common(ah); - u32 channelSel = 0; - u32 bModeSynth = 0; - u32 aModeRefSel = 0; - u32 reg32 = 0; - u16 freq; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = centers.synth_center; - - if (freq < 4800) { - u32 txctl; - - if (((freq - 2192) % 5) == 0) { - channelSel = ((freq - 672) * 2 - 3040) / 10; - bModeSynth = 0; - } else if (((freq - 2224) % 5) == 0) { - channelSel = ((freq - 704) * 2 - 3040) / 10; - bModeSynth = 1; - } else { - ath_print(common, ATH_DBG_FATAL, - "Invalid channel %u MHz\n", freq); - return -EINVAL; - } - - channelSel = (channelSel << 2) & 0xff; - channelSel = ath9k_hw_reverse_bits(channelSel, 8); - - txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); - if (freq == 2484) { - - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl | AR_PHY_CCK_TX_CTRL_JAPAN); - } else { - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); - } - - } else if ((freq % 20) == 0 && freq >= 5120) { - channelSel = - ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8); - aModeRefSel = ath9k_hw_reverse_bits(1, 2); - } else if ((freq % 10) == 0) { - channelSel = - ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8); - if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) - aModeRefSel = ath9k_hw_reverse_bits(2, 2); - else - aModeRefSel = ath9k_hw_reverse_bits(1, 2); - } else if ((freq % 5) == 0) { - channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8); - aModeRefSel = ath9k_hw_reverse_bits(1, 2); - } else { - ath_print(common, ATH_DBG_FATAL, - "Invalid channel %u MHz\n", freq); - return -EINVAL; - } - - reg32 = - (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | - (1 << 5) | 0x1; - - REG_WRITE(ah, AR_PHY(0x37), reg32); - - ah->curchan = chan; - ah->curchan_rad_index = -1; - - return 0; -} - /** * ath9k_hw_ar9280_set_channel - set channel on single-chip device * @ah: atheros hardware structure @@ -254,6 +171,622 @@ int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) return 0; } +/** + * ath9k_hw_9280_spur_mitigate - convert baseband spur frequency + * @ah: atheros hardware structure + * @chan: + * + * For single-chip solutions. Converts to baseband spur frequency given the + * input channel frequency and compute register settings below. + */ +void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) +{ + int bb_spur = AR_NO_SPUR; + int freq; + int bin, cur_bin; + int bb_spur_off, spur_subchannel_sd; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, newVal; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; + struct chan_centers centers; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); + + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + ah->config.spurmode = SPUR_ENABLE_EEPROM; + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); + + if (is2GHz) + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; + else + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; + + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - freq; + + if (IS_CHAN_HT40(chan)) { + if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { + bb_spur = cur_bb_spur; + break; + } + } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + return; + } else { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + } + + bin = bb_spur * 320; + + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + + newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); + + newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); + + if (IS_CHAN_HT40(chan)) { + if (bb_spur < 0) { + spur_subchannel_sd = 1; + bb_spur_off = bb_spur + 10; + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur - 10; + } + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur; + } + + if (IS_CHAN_HT40(chan)) + spur_delta_phase = + ((bb_spur * 262144) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + else + spur_delta_phase = + ((bb_spur * 524288) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; + spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; + + newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, newVal); + + newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; + REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); + + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + + /* workaround for gcc bug #37014 */ + volatile int tmp_v = abs(cur_vit_mask - bin); + + if (tmp_v < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); +} + +/* All code below is for non single-chip solutions */ + +/** + * ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios + * @ah: atheros hardware stucture + * @chan: + * + * For the external AR2133/AR5133 radios, takes the MHz channel value and set + * the channel value. Assumes writes enabled to analog bus and bank6 register + * cache in ah->analogBank6Data. + */ +int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) +{ + struct ath_common *common = ath9k_hw_common(ah); + u32 channelSel = 0; + u32 bModeSynth = 0; + u32 aModeRefSel = 0; + u32 reg32 = 0; + u16 freq; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + if (freq < 4800) { + u32 txctl; + + if (((freq - 2192) % 5) == 0) { + channelSel = ((freq - 672) * 2 - 3040) / 10; + bModeSynth = 0; + } else if (((freq - 2224) % 5) == 0) { + channelSel = ((freq - 704) * 2 - 3040) / 10; + bModeSynth = 1; + } else { + ath_print(common, ATH_DBG_FATAL, + "Invalid channel %u MHz\n", freq); + return -EINVAL; + } + + channelSel = (channelSel << 2) & 0xff; + channelSel = ath9k_hw_reverse_bits(channelSel, 8); + + txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (freq == 2484) { + + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); + } + + } else if ((freq % 20) == 0 && freq >= 5120) { + channelSel = + ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8); + aModeRefSel = ath9k_hw_reverse_bits(1, 2); + } else if ((freq % 10) == 0) { + channelSel = + ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8); + if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) + aModeRefSel = ath9k_hw_reverse_bits(2, 2); + else + aModeRefSel = ath9k_hw_reverse_bits(1, 2); + } else if ((freq % 5) == 0) { + channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8); + aModeRefSel = ath9k_hw_reverse_bits(1, 2); + } else { + ath_print(common, ATH_DBG_FATAL, + "Invalid channel %u MHz\n", freq); + return -EINVAL; + } + + reg32 = + (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | + (1 << 5) | 0x1; + + REG_WRITE(ah, AR_PHY(0x37), reg32); + + ah->curchan = chan; + ah->curchan_rad_index = -1; + + return 0; +} + +/** + * ath9k_hw_spur_mitigate - convert baseband spur frequency for external radios + * @ah: atheros hardware structure + * @chan: + * + * For non single-chip solutions. Converts to baseband spur frequency given the + * input channel frequency and compute register settings below. + */ +void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) +{ + int bb_spur = AR_NO_SPUR; + int bin, cur_bin; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, new; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); + + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - (chan->channel * 10); + if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) + return; + + bin = bb_spur * 32; + + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); + + new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, new); + + spur_delta_phase = ((bb_spur * 524288) / 100) & + AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; + spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; + + new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, new); + + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + + /* workaround for gcc bug #37014 */ + volatile int tmp_v = abs(cur_vit_mask - bin); + + if (tmp_v < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); +} + +/** + * ath9k_hw_rf_alloc_ext_banks - allocates banks for external radio programming + * @ah: atheros hardware structure + * + * Only required for older devices with external AR2133/AR5133 radios. + */ +int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah) +{ +#define ATH_ALLOC_BANK(bank, size) do { \ + bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \ + if (!bank) { \ + ath_print(common, ATH_DBG_FATAL, \ + "Cannot allocate RF banks\n"); \ + return -ENOMEM; \ + } \ + } while (0); + + struct ath_common *common = ath9k_hw_common(ah); + + BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + + ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows); + ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows); + ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows); + ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows); + ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows); + ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows); + ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows); + ATH_ALLOC_BANK(ah->addac5416_21, + ah->iniAddac.ia_rows * ah->iniAddac.ia_columns); + ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows); + + return 0; +#undef ATH_ALLOC_BANK +} + + +/** + * ath9k_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers + * @ah: atheros hardware struture + * For the external AR2133/AR5133 radios banks. + */ +void +ath9k_hw_rf_free_ext_banks(struct ath_hw *ah) +{ +#define ATH_FREE_BANK(bank) do { \ + kfree(bank); \ + bank = NULL; \ + } while (0); + + BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + + ATH_FREE_BANK(ah->analogBank0Data); + ATH_FREE_BANK(ah->analogBank1Data); + ATH_FREE_BANK(ah->analogBank2Data); + ATH_FREE_BANK(ah->analogBank3Data); + ATH_FREE_BANK(ah->analogBank6Data); + ATH_FREE_BANK(ah->analogBank6TPCData); + ATH_FREE_BANK(ah->analogBank7Data); + ATH_FREE_BANK(ah->addac5416_21); + ATH_FREE_BANK(ah->bank6Temp); + +#undef ATH_FREE_BANK +} + /** * ath9k_phy_modify_rx_buffer() - perform analog swizzling of parameters * @rfbuf: @@ -265,10 +798,9 @@ int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) * Performs analog "swizzling" of parameters into their location. * Used on external AR2133/AR5133 radios. */ -static void -ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, - u32 numBits, u32 firstBit, - u32 column) +static void ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, + u32 numBits, u32 firstBit, + u32 column) { u32 tmp32, mask, arrayEntry, lastBit; int32_t bitPosition, bitsLeft; @@ -304,9 +836,8 @@ ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, * all rf registers. This routine requires access to the analog * rf device. This is not required for single-chip devices. */ -bool -ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, - u16 modesIndex) +bool ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, + u16 modesIndex) { u32 eepMinorRev; u32 ob5GHz = 0, db5GHz = 0; @@ -383,70 +914,6 @@ ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, return true; } -/** - * ath9k_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers - * @ah: atheros hardware struture - * For the external AR2133/AR5133 radios banks. - */ -void -ath9k_hw_rf_free_ext_banks(struct ath_hw *ah) -{ -#define ATH_FREE_BANK(bank) do { \ - kfree(bank); \ - bank = NULL; \ - } while (0); - - BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); - - ATH_FREE_BANK(ah->analogBank0Data); - ATH_FREE_BANK(ah->analogBank1Data); - ATH_FREE_BANK(ah->analogBank2Data); - ATH_FREE_BANK(ah->analogBank3Data); - ATH_FREE_BANK(ah->analogBank6Data); - ATH_FREE_BANK(ah->analogBank6TPCData); - ATH_FREE_BANK(ah->analogBank7Data); - ATH_FREE_BANK(ah->addac5416_21); - ATH_FREE_BANK(ah->bank6Temp); - -#undef ATH_FREE_BANK -} - -/** - * ath9k_hw_rf_alloc_ext_banks - allocates banks for external radio programming - * @ah: atheros hardware structure - * - * Only required for older devices with external AR2133/AR5133 radios. - */ -int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah) -{ -#define ATH_ALLOC_BANK(bank, size) do { \ - bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \ - if (!bank) { \ - ath_print(common, ATH_DBG_FATAL, \ - "Cannot allocate RF banks\n"); \ - return -ENOMEM; \ - } \ - } while (0); - - struct ath_common *common = ath9k_hw_common(ah); - - BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); - - ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows); - ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows); - ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows); - ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows); - ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows); - ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows); - ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows); - ATH_ALLOC_BANK(ah->addac5416_21, - ah->iniAddac.ia_rows * ah->iniAddac.ia_columns); - ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows); - - return 0; -#undef ATH_ALLOC_BANK -} - /** * ath9k_hw_decrease_chain_power() * diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index bef9b41d250f..ba297bef7dc5 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -17,19 +17,28 @@ #ifndef PHY_H #define PHY_H -int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); -int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); +/* Common between single chip and non single-chip solutions */ void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, int regWrites); + +/* Single chip radio settings */ +int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); +void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); + +/* Routines below are for non single-chip solutions */ +int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); +void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); + +int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah); +void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah); + bool ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, u16 modesIndex); + void ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan); -void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah); -int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah); - #define AR_PHY_BASE 0x9800 #define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) -- cgit v1.2.3 From ae478cf69e9e49a88e0fe8beaffbcba2f97b5209 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:43 -0400 Subject: ath9k_hw: make spur mitigation a callback This only differs between single-chip solutions and non single-chip solutions. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 17 ++++++----------- drivers/net/wireless/ath/ath9k/hw.h | 5 +++++ 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 626667c3101c..f73c07dfe65f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -952,8 +952,11 @@ int ath9k_hw_init(struct ath_hw *ah) if (AR_SREV_9280_10_OR_LATER(ah)) { ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; ah->ath9k_hw_rf_set_freq = &ath9k_hw_ar9280_set_channel; - } else + ah->ath9k_hw_spur_mitigate_freq = &ath9k_hw_9280_spur_mitigate; + } else { ah->ath9k_hw_rf_set_freq = &ath9k_hw_set_channel; + ah->ath9k_hw_spur_mitigate_freq = &ath9k_hw_spur_mitigate; + } ath9k_hw_init_mode_regs(ah); @@ -1917,10 +1920,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) ath9k_hw_set_delta_slope(ah, chan); - if (AR_SREV_9280_10_OR_LATER(ah)) - ath9k_hw_9280_spur_mitigate(ah, chan); - else - ath9k_hw_spur_mitigate(ah, chan); + ah->ath9k_hw_spur_mitigate_freq(ah, chan); if (!chan->oneTimeCalsDone) chan->oneTimeCalsDone = true; @@ -2053,13 +2053,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) ath9k_hw_set_delta_slope(ah, chan); - if (AR_SREV_9280_10_OR_LATER(ah)) - ath9k_hw_9280_spur_mitigate(ah, chan); - else - ath9k_hw_spur_mitigate(ah, chan); - + ah->ath9k_hw_spur_mitigate_freq(ah, chan); ah->eep_ops->set_board_values(ah, chan); - ath9k_hw_decrease_chain_power(ah, chan); REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr)); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index dcf1295f4eb4..c7b0c4d5f75a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -550,6 +550,11 @@ struct ath_hw { /* Callback for radio frequency change */ int (*ath9k_hw_rf_set_freq)(struct ath_hw *ah, struct ath9k_channel *chan); + + /* Callback for baseband spur frequency */ + void (*ath9k_hw_spur_mitigate_freq)(struct ath_hw *ah, + struct ath9k_channel *chan); + /* Used to program the radio on non single-chip devices */ u32 *analogBank0Data; u32 *analogBank1Data; -- cgit v1.2.3 From 896ff260351f736f0d9d32f4fd36257f3e75bd97 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:44 -0400 Subject: ath9k_hw: remove unused modesIndex param from ath9k_hw_write_regs() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 2 +- drivers/net/wireless/ath/ath9k/phy.c | 4 +--- drivers/net/wireless/ath/ath9k/phy.h | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f73c07dfe65f..7300db9f8117 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1525,7 +1525,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, DO_DELAY(regWrites); } - ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites); + ath9k_hw_write_regs(ah, freqIndex, regWrites); if (AR_SREV_9271_10(ah)) REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only, diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 8e4c3bd84bc0..a15532eaae19 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -45,15 +45,13 @@ * ath9k_hw_write_regs - ?? * * @ah: atheros hardware structure - * @modesIndex: * @freqIndex: * @regWrites: * * Used for both the chipsets with an external AR2133/AR5133 radios and * single-chip devices. */ -void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, - u32 freqIndex, int regWrites) +void ath9k_hw_write_regs(struct ath_hw *ah, u32 freqIndex, int regWrites) { REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); } diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index ba297bef7dc5..dc145a135dc7 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -18,8 +18,7 @@ #define PHY_H /* Common between single chip and non single-chip solutions */ -void ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, - u32 freqIndex, int regWrites); +void ath9k_hw_write_regs(struct ath_hw *ah, u32 freqIndex, int regWrites); /* Single chip radio settings */ int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); -- cgit v1.2.3 From a77658286105c8be3741305c5dcf4c319746817f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:45 -0400 Subject: ath9k_hw: Fix and complete force bias for AR5416 Force bias is a fix for usage of AR5416 radios on the 2.4 GHz band for orientation sensitivity. This was only partially implemented with the ath9k_hw_decrease_chain_power() but first -- this was being called for all chipsets which is not correct and second -- it was missing the actual orientation code. We now ensure to only enable force bias only for AR5416 and BUG_ON() on other chipsets. Although ath9k_hw_decrease_chain_power() was enabled for newer chipsets I suspect that it never ran unless the EEPROM had ATH9K_ANT_FIXED_A or ATH9K_ANT_FIXED_B for antenna diversity. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 4 ++- drivers/net/wireless/ath/ath9k/phy.c | 70 ++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7300db9f8117..111ff049f75d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2055,7 +2055,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ah->ath9k_hw_spur_mitigate_freq(ah, chan); ah->eep_ops->set_board_values(ah, chan); - ath9k_hw_decrease_chain_power(ah, chan); + + if (AR_SREV_5416(ah)) + ath9k_hw_decrease_chain_power(ah, chan); REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr)); REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4) diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index a15532eaae19..df55e28a6560 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -41,6 +41,10 @@ #include "hw.h" +static void ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, + u32 numBits, u32 firstBit, + u32 column); + /** * ath9k_hw_write_regs - ?? * @@ -429,6 +433,67 @@ void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) /* All code below is for non single-chip solutions */ +/* + * Fix on 2.4 GHz band for orientation sensitivity issue by increasing + * rf_pwd_icsyndiv. + * + * Theoretical Rules: + * if 2 GHz band + * if forceBiasAuto + * if synth_freq < 2412 + * bias = 0 + * else if 2412 <= synth_freq <= 2422 + * bias = 1 + * else // synth_freq > 2422 + * bias = 2 + * else if forceBias > 0 + * bias = forceBias & 7 + * else + * no change, use value from ini file + * else + * no change, invalid band + * + * 1st Mod: + * 2422 also uses value of 2 + * + * + * 2nd Mod: + * Less than 2412 uses value of 0, 2412 and above uses value of 2 + */ +static void ath9k_hw_force_bias(struct ath_hw *ah, u16 synth_freq) +{ + struct ath_common *common = ath9k_hw_common(ah); + u32 tmp_reg; + int reg_writes = 0; + u32 new_bias = 0; + + if (!AR_SREV_5416(ah) || synth_freq >= 3000) { + return; + } + + BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + + if (synth_freq < 2412) + new_bias = 0; + else if (synth_freq < 2422) + new_bias = 1; + else + new_bias = 2; + + /* pre-reverse this field */ + tmp_reg = ath9k_hw_reverse_bits(new_bias, 3); + + ath_print(common, ATH_DBG_CONFIG, + "Force rf_pwd_icsyndiv to %1d on %4d\n", + new_bias, synth_freq); + + /* swizzle rf_pwd_icsyndiv */ + ath9k_phy_modify_rx_buffer(ah->analogBank6Data, tmp_reg, 3, 181, 3); + + /* write Bank 6 with new params */ + REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes); +} + /** * ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios * @ah: atheros hardware stucture @@ -499,6 +564,9 @@ int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) return -EINVAL; } + ath9k_hw_force_bias(ah, freq); + ath9k_hw_decrease_chain_power(ah, chan); + reg32 = (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | (1 << 5) | 0x1; @@ -946,6 +1014,8 @@ ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) u32 bank6SelMask; u32 *bank6Temp = ah->bank6Temp; + BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + switch (ah->config.diversity_control) { case ATH9K_ANT_FIXED_A: bank6SelMask = -- cgit v1.2.3 From ddcd4c08188dc512ceb08bcc3f4f830c2dbfb5ce Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 19 Oct 2009 02:33:46 -0400 Subject: ath9k_hw: make ath9k_phy_modify_rx_buffer() static To do this we reorder callers in order in which they are called. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/phy.c | 256 +++++++++++++++++------------------ 1 file changed, 126 insertions(+), 130 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index df55e28a6560..13ab4d7eb7aa 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -41,10 +41,6 @@ #include "hw.h" -static void ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, - u32 numBits, u32 firstBit, - u32 column); - /** * ath9k_hw_write_regs - ?? * @@ -433,6 +429,43 @@ void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) /* All code below is for non single-chip solutions */ +/** + * ath9k_phy_modify_rx_buffer() - perform analog swizzling of parameters + * @rfbuf: + * @reg32: + * @numBits: + * @firstBit: + * @column: + * + * Performs analog "swizzling" of parameters into their location. + * Used on external AR2133/AR5133 radios. + */ +static void ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, + u32 numBits, u32 firstBit, + u32 column) +{ + u32 tmp32, mask, arrayEntry, lastBit; + int32_t bitPosition, bitsLeft; + + tmp32 = ath9k_hw_reverse_bits(reg32, numBits); + arrayEntry = (firstBit - 1) / 8; + bitPosition = (firstBit - 1) % 8; + bitsLeft = numBits; + while (bitsLeft > 0) { + lastBit = (bitPosition + bitsLeft > 8) ? + 8 : bitPosition + bitsLeft; + mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) << + (column * 8); + rfBuf[arrayEntry] &= ~mask; + rfBuf[arrayEntry] |= ((tmp32 << bitPosition) << + (column * 8)) & mask; + bitsLeft -= 8 - bitPosition; + tmp32 = tmp32 >> (8 - bitPosition); + bitPosition = 0; + arrayEntry++; + } +} + /* * Fix on 2.4 GHz band for orientation sensitivity issue by increasing * rf_pwd_icsyndiv. @@ -494,6 +527,95 @@ static void ath9k_hw_force_bias(struct ath_hw *ah, u16 synth_freq) REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes); } +/** + * ath9k_hw_decrease_chain_power() + * + * @ah: atheros hardware structure + * @chan: + * + * Only used on the AR5416 and AR5418 with the external AR2133/AR5133 radios. + * + * Sets a chain internal RF path to the lowest output power. Any + * further writes to bank6 after this setting will override these + * changes. Thus this function must be the last function in the + * sequence to modify bank 6. + * + * This function must be called after ar5416SetRfRegs() which is + * called from ath9k_hw_process_ini() due to swizzling of bank 6. + * Depends on ah->analogBank6Data being initialized by + * ath9k_hw_set_rf_regs() + * + * Additional additive reduction in power - + * change chain's switch table so chain's tx state is actually the rx + * state value. May produce different results in 2GHz/5GHz as well as + * board to board but in general should be a reduction. + * + * Activated by #ifdef ALTER_SWITCH. Not tried yet. If so, must be + * called after ah->eep_ops->set_board_values() due to RMW of + * PHY_SWITCH_CHAIN_0. + */ +void ath9k_hw_decrease_chain_power(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + int i, regWrites = 0; + u32 bank6SelMask; + u32 *bank6Temp = ah->bank6Temp; + + BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + + switch (ah->config.diversity_control) { + case ATH9K_ANT_FIXED_A: + bank6SelMask = + (ah->config.antenna_switch_swap & ANTSWAP_AB) ? + REDUCE_CHAIN_0 : /* swapped, reduce chain 0 */ + REDUCE_CHAIN_1; /* normal, select chain 1/2 to reduce */ + break; + case ATH9K_ANT_FIXED_B: + bank6SelMask = + (ah->config.antenna_switch_swap & ANTSWAP_AB) ? + REDUCE_CHAIN_1 : /* swapped, reduce chain 1/2 */ + REDUCE_CHAIN_0; /* normal, select chain 0 to reduce */ + break; + case ATH9K_ANT_VARIABLE: + return; /* do not change anything */ + break; + default: + return; /* do not change anything */ + break; + } + + for (i = 0; i < ah->iniBank6.ia_rows; i++) + bank6Temp[i] = ah->analogBank6Data[i]; + + /* Write Bank 5 to switch Bank 6 write to selected chain only */ + REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask); + + /* + * Modify Bank6 selected chain to use lowest amplification. + * Modifies the parameters to a value of 1. + * Depends on existing bank 6 values to be cached in + * ah->analogBank6Data + */ + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0); + ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0); + + REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites); + + REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053); +#ifdef ALTER_SWITCH + REG_WRITE(ah, PHY_SWITCH_CHAIN_0, + (REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38) + | ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38)); +#endif +} + /** * ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios * @ah: atheros hardware stucture @@ -853,43 +975,6 @@ ath9k_hw_rf_free_ext_banks(struct ath_hw *ah) #undef ATH_FREE_BANK } -/** - * ath9k_phy_modify_rx_buffer() - perform analog swizzling of parameters - * @rfbuf: - * @reg32: - * @numBits: - * @firstBit: - * @column: - * - * Performs analog "swizzling" of parameters into their location. - * Used on external AR2133/AR5133 radios. - */ -static void ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, - u32 numBits, u32 firstBit, - u32 column) -{ - u32 tmp32, mask, arrayEntry, lastBit; - int32_t bitPosition, bitsLeft; - - tmp32 = ath9k_hw_reverse_bits(reg32, numBits); - arrayEntry = (firstBit - 1) / 8; - bitPosition = (firstBit - 1) % 8; - bitsLeft = numBits; - while (bitsLeft > 0) { - lastBit = (bitPosition + bitsLeft > 8) ? - 8 : bitPosition + bitsLeft; - mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) << - (column * 8); - rfBuf[arrayEntry] &= ~mask; - rfBuf[arrayEntry] |= ((tmp32 << bitPosition) << - (column * 8)) & mask; - bitsLeft -= 8 - bitPosition; - tmp32 = tmp32 >> (8 - bitPosition); - bitPosition = 0; - arrayEntry++; - } -} - /* * * ath9k_hw_set_rf_regs - programs rf registers based on EEPROM * @ah: atheros hardware structure @@ -979,92 +1064,3 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, return true; } - -/** - * ath9k_hw_decrease_chain_power() - * - * @ah: atheros hardware structure - * @chan: - * - * Only used on the AR5416 and AR5418 with the external AR2133/AR5133 radios. - * - * Sets a chain internal RF path to the lowest output power. Any - * further writes to bank6 after this setting will override these - * changes. Thus this function must be the last function in the - * sequence to modify bank 6. - * - * This function must be called after ar5416SetRfRegs() which is - * called from ath9k_hw_process_ini() due to swizzling of bank 6. - * Depends on ah->analogBank6Data being initialized by - * ath9k_hw_set_rf_regs() - * - * Additional additive reduction in power - - * change chain's switch table so chain's tx state is actually the rx - * state value. May produce different results in 2GHz/5GHz as well as - * board to board but in general should be a reduction. - * - * Activated by #ifdef ALTER_SWITCH. Not tried yet. If so, must be - * called after ah->eep_ops->set_board_values() due to RMW of - * PHY_SWITCH_CHAIN_0. - */ -void -ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) -{ - int i, regWrites = 0; - u32 bank6SelMask; - u32 *bank6Temp = ah->bank6Temp; - - BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); - - switch (ah->config.diversity_control) { - case ATH9K_ANT_FIXED_A: - bank6SelMask = - (ah->config.antenna_switch_swap & ANTSWAP_AB) ? - REDUCE_CHAIN_0 : /* swapped, reduce chain 0 */ - REDUCE_CHAIN_1; /* normal, select chain 1/2 to reduce */ - break; - case ATH9K_ANT_FIXED_B: - bank6SelMask = - (ah->config.antenna_switch_swap & ANTSWAP_AB) ? - REDUCE_CHAIN_1 : /* swapped, reduce chain 1/2 */ - REDUCE_CHAIN_0; /* normal, select chain 0 to reduce */ - break; - case ATH9K_ANT_VARIABLE: - return; /* do not change anything */ - break; - default: - return; /* do not change anything */ - break; - } - - for (i = 0; i < ah->iniBank6.ia_rows; i++) - bank6Temp[i] = ah->analogBank6Data[i]; - - /* Write Bank 5 to switch Bank 6 write to selected chain only */ - REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask); - - /* - * Modify Bank6 selected chain to use lowest amplification. - * Modifies the parameters to a value of 1. - * Depends on existing bank 6 values to be cached in - * ah->analogBank6Data - */ - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0); - - REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites); - - REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053); -#ifdef ALTER_SWITCH - REG_WRITE(ah, PHY_SWITCH_CHAIN_0, - (REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38) - | ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38)); -#endif -} -- cgit v1.2.3 From 750266646befe42ee8a3a9f9b6f692174635c5b8 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 28 Oct 2009 16:08:32 -0700 Subject: wireless: airo_cs needs WEXT_SPY airo_cs uses spy interfaces so it needs to select WEXT_SPY. ERROR: "iw_handler_set_thrspy" [drivers/net/wireless/airo.ko] undefined! ERROR: "wireless_spy_update" [drivers/net/wireless/airo.ko] undefined! ERROR: "iw_handler_get_spy" [drivers/net/wireless/airo.ko] undefined! ERROR: "iw_handler_get_thrspy" [drivers/net/wireless/airo.ko] undefined! ERROR: "iw_handler_set_spy" [drivers/net/wireless/airo.ko] undefined! Signed-off-by: Randy Dunlap Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 674a08b07884..56dd6650c97a 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -111,6 +111,7 @@ config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" depends on PCMCIA && (BROKEN || !M32R) select WIRELESS_EXT + select WEXT_SPY select CRYPTO select CRYPTO_AES ---help--- -- cgit v1.2.3 From e7d17cf4f7e1b8d06575b6db2397c99c151674b8 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 29 Oct 2009 13:20:04 +0200 Subject: wl1271: fix init loop timeout The check after the loop which checks whether the initialization timed-out was wrong. If the initialization would succeed exactly in the 20000th time (the value set for INIT_LOOP), the driver would bail out and claim that initialization failed. Reported-by: Juha Leppanen Signed-off-by: Luciano Coelho Reviewed-by: Janne Ylalehto Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index ba4a2b4f0f56..8678bea05ed5 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -380,7 +380,7 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) } } - if (loop >= INIT_LOOP) { + if (loop > INIT_LOOP) { wl1271_error("timeout waiting for the hardware to " "complete initialization"); return -EIO; -- cgit v1.2.3 From d2d8cda7fc0b7a133492e70332217a7f20757615 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 30 Oct 2009 11:58:21 -0500 Subject: b43legacy: Fix DMA TX bounce buffer copying This patch is adapted from the submission by Michael Buesch for a bounce-buffer copying problem with b43. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/dma.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index 866403415811..0a86bdf53154 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -1240,8 +1240,9 @@ struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev, } static int dma_tx_fragment(struct b43legacy_dmaring *ring, - struct sk_buff *skb) + struct sk_buff **in_skb) { + struct sk_buff *skb = *in_skb; const struct b43legacy_dma_ops *ops = ring->ops; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 *header; @@ -1305,8 +1306,14 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, } memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); + memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb)); + bounce_skb->dev = skb->dev; + skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb)); + info = IEEE80211_SKB_CB(bounce_skb); + dev_kfree_skb_any(skb); skb = bounce_skb; + *in_skb = bounce_skb; meta->skb = skb; meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { @@ -1360,8 +1367,10 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, struct sk_buff *skb) { struct b43legacy_dmaring *ring; + struct ieee80211_hdr *hdr; int err = 0; unsigned long flags; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); spin_lock_irqsave(&ring->lock, flags); @@ -1386,7 +1395,11 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev, goto out_unlock; } - err = dma_tx_fragment(ring, skb); + /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing + * into the skb data or cb now. */ + hdr = NULL; + info = NULL; + err = dma_tx_fragment(ring, &skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ -- cgit v1.2.3 From 86c34fe89e9cad9e1ba4d1a8bbf98259035f4caf Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Tue, 27 Oct 2009 16:51:40 -0700 Subject: libertas: remove internal buffers from GSPI driver This patch removes the internal command and data buffers that the GSPI driver maintained and instead relies on the Libertas core to synchronize access to the command and data ports as with the other interface drivers. This cleanup reduces the GSPI driver's memory footprint and should improve performance by removing the need to copy to these internal buffers. This also simplifies the bottom half of the interrupt handler. This is an incremental cleanup: after removing the redundant buffers, we can further improve the driver to use a threaded IRQ handler instead of maintaining its own thread. However I would like a few folks to test the buffer removal first and make sure that I'm not introducing regressions. Tested on Blackfin BF527 with DMA disabled due to an issue with the SPI host controller driver in the current bleeding-edge Blackfin kernel. I would appreciate it if someone with working DMA could test this patch and provide feedback. Signed-off-by: Andrey Yurovsky Tested-by: George Shore Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_spi.c | 136 ++------------------------------- 1 file changed, 6 insertions(+), 130 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 30d9d0ea28eb..d6a48dd3652c 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -32,12 +32,6 @@ #include "dev.h" #include "if_spi.h" -struct if_spi_packet { - struct list_head list; - u16 blen; - u8 buffer[0] __attribute__((aligned(4))); -}; - struct if_spi_card { struct spi_device *spi; struct lbs_private *priv; @@ -66,33 +60,10 @@ struct if_spi_card { struct semaphore spi_thread_terminated; u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE]; - - /* A buffer of incoming packets from libertas core. - * Since we can't sleep in hw_host_to_card, we have to buffer - * them. */ - struct list_head cmd_packet_list; - struct list_head data_packet_list; - - /* Protects cmd_packet_list and data_packet_list */ - spinlock_t buffer_lock; }; static void free_if_spi_card(struct if_spi_card *card) { - struct list_head *cursor, *next; - struct if_spi_packet *packet; - - BUG_ON(card->run_thread); - list_for_each_safe(cursor, next, &card->cmd_packet_list) { - packet = container_of(cursor, struct if_spi_packet, list); - list_del(&packet->list); - kfree(packet); - } - list_for_each_safe(cursor, next, &card->data_packet_list) { - packet = container_of(cursor, struct if_spi_packet, list); - list_del(&packet->list); - kfree(packet); - } spi_set_drvdata(card->spi, NULL); kfree(card); } @@ -774,40 +745,6 @@ out: return err; } -/* Move data or a command from the host to the card. */ -static void if_spi_h2c(struct if_spi_card *card, - struct if_spi_packet *packet, int type) -{ - int err = 0; - u16 int_type, port_reg; - - switch (type) { - case MVMS_DAT: - int_type = IF_SPI_CIC_TX_DOWNLOAD_OVER; - port_reg = IF_SPI_DATA_RDWRPORT_REG; - break; - case MVMS_CMD: - int_type = IF_SPI_CIC_CMD_DOWNLOAD_OVER; - port_reg = IF_SPI_CMD_RDWRPORT_REG; - break; - default: - lbs_pr_err("can't transfer buffer of type %d\n", type); - err = -EINVAL; - goto out; - } - - /* Write the data to the card */ - err = spu_write(card, port_reg, packet->buffer, packet->blen); - if (err) - goto out; - -out: - kfree(packet); - - if (err) - lbs_pr_err("%s: error %d\n", __func__, err); -} - /* Inform the host about a card event */ static void if_spi_e2h(struct if_spi_card *card) { @@ -837,8 +774,6 @@ static int lbs_spi_thread(void *data) int err; struct if_spi_card *card = data; u16 hiStatus; - unsigned long flags; - struct if_spi_packet *packet; while (1) { /* Wait to be woken up by one of two things. First, our ISR @@ -877,43 +812,9 @@ static int lbs_spi_thread(void *data) if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY || (card->priv->psstate != PS_STATE_FULL_POWER && (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) { - /* This means two things. First of all, - * if there was a previous command sent, the card has - * successfully received it. - * Secondly, it is now ready to download another - * command. - */ lbs_host_to_card_done(card->priv); - - /* Do we have any command packets from the host to - * send? */ - packet = NULL; - spin_lock_irqsave(&card->buffer_lock, flags); - if (!list_empty(&card->cmd_packet_list)) { - packet = (struct if_spi_packet *)(card-> - cmd_packet_list.next); - list_del(&packet->list); - } - spin_unlock_irqrestore(&card->buffer_lock, flags); - - if (packet) - if_spi_h2c(card, packet, MVMS_CMD); } - if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) { - /* Do we have any data packets from the host to - * send? */ - packet = NULL; - spin_lock_irqsave(&card->buffer_lock, flags); - if (!list_empty(&card->data_packet_list)) { - packet = (struct if_spi_packet *)(card-> - data_packet_list.next); - list_del(&packet->list); - } - spin_unlock_irqrestore(&card->buffer_lock, flags); - if (packet) - if_spi_h2c(card, packet, MVMS_DAT); - } if (hiStatus & IF_SPI_HIST_CARD_EVENT) if_spi_e2h(card); @@ -942,40 +843,18 @@ static int if_spi_host_to_card(struct lbs_private *priv, u8 type, u8 *buf, u16 nb) { int err = 0; - unsigned long flags; struct if_spi_card *card = priv->card; - struct if_spi_packet *packet; - u16 blen; lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb); - if (nb == 0) { - lbs_pr_err("%s: invalid size requested: %d\n", __func__, nb); - err = -EINVAL; - goto out; - } - blen = ALIGN(nb, 4); - packet = kzalloc(sizeof(struct if_spi_packet) + blen, GFP_ATOMIC); - if (!packet) { - err = -ENOMEM; - goto out; - } - packet->blen = blen; - memcpy(packet->buffer, buf, nb); - memset(packet->buffer + nb, 0, blen - nb); + nb = ALIGN(nb, 4); switch (type) { case MVMS_CMD: - priv->dnld_sent = DNLD_CMD_SENT; - spin_lock_irqsave(&card->buffer_lock, flags); - list_add_tail(&packet->list, &card->cmd_packet_list); - spin_unlock_irqrestore(&card->buffer_lock, flags); + err = spu_write(card, IF_SPI_CMD_RDWRPORT_REG, buf, nb); break; case MVMS_DAT: - priv->dnld_sent = DNLD_DATA_SENT; - spin_lock_irqsave(&card->buffer_lock, flags); - list_add_tail(&packet->list, &card->data_packet_list); - spin_unlock_irqrestore(&card->buffer_lock, flags); + err = spu_write(card, IF_SPI_DATA_RDWRPORT_REG, buf, nb); break; default: lbs_pr_err("can't transfer buffer of type %d", type); @@ -983,9 +862,6 @@ static int if_spi_host_to_card(struct lbs_private *priv, break; } - /* Wake up the spi thread */ - up(&card->spi_ready); -out: lbs_deb_leave_args(LBS_DEB_SPI, "err=%d", err); return err; } @@ -1062,9 +938,6 @@ static int __devinit if_spi_probe(struct spi_device *spi) sema_init(&card->spi_ready, 0); sema_init(&card->spi_thread_terminated, 0); - INIT_LIST_HEAD(&card->cmd_packet_list); - INIT_LIST_HEAD(&card->data_packet_list); - spin_lock_init(&card->buffer_lock); /* Initialize the SPI Interface Unit */ err = spu_init(card, pdata->use_dummy_writes); @@ -1141,6 +1014,9 @@ static int __devinit if_spi_probe(struct spi_device *spi) goto terminate_thread; } + /* poke the IRQ handler so that we don't miss the first interrupt */ + up(&card->spi_ready); + /* Start the card. * This will call register_netdev, and we'll start * getting interrupts... */ -- cgit v1.2.3 From 5ebeb5a676c864acf59caa166b3cc0a13b7cff93 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:04 -0700 Subject: iwlwifi: provide firmware version By setting the firmware version in wiphy it is possible to obtain this information via ethtool. Some examples, # ethtool -i wlan1 driver: iwlagn version: 2.6.32-rc5-wl-56840-g26d8540 firmware-version: 228.57.2.23 bus-info: 0000:03:00.0 # ethtool -i wlan0 driver: iwl3945 version: 2.6.32-rc5-wl-56840-g26d8540 firmware-version: 15.28.2.8 bus-info: 0000:02:00.0 Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 8 ++++++++ 2 files changed, 16 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index fa1672e99e4b..05d1070e22d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1377,6 +1377,14 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_UCODE_API(priv->ucode_ver), IWL_UCODE_SERIAL(priv->ucode_ver)); + snprintf(priv->hw->wiphy->fw_version, + sizeof(priv->hw->wiphy->fw_version), + "%u.%u.%u.%u", + IWL_UCODE_MAJOR(priv->ucode_ver), + IWL_UCODE_MINOR(priv->ucode_ver), + IWL_UCODE_API(priv->ucode_ver), + IWL_UCODE_SERIAL(priv->ucode_ver)); + if (build) IWL_DEBUG_INFO(priv, "Build %u\n", build); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index bfd7f497157f..5c80a83eb2e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2160,6 +2160,14 @@ static int iwl3945_read_ucode(struct iwl_priv *priv) IWL_UCODE_API(priv->ucode_ver), IWL_UCODE_SERIAL(priv->ucode_ver)); + snprintf(priv->hw->wiphy->fw_version, + sizeof(priv->hw->wiphy->fw_version), + "%u.%u.%u.%u", + IWL_UCODE_MAJOR(priv->ucode_ver), + IWL_UCODE_MINOR(priv->ucode_ver), + IWL_UCODE_API(priv->ucode_ver), + IWL_UCODE_SERIAL(priv->ucode_ver)); + IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", priv->ucode_ver); IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n", -- cgit v1.2.3 From 5220af0c3b44f5d6e32661e5bb49154c514dbf4f Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 30 Oct 2009 14:36:05 -0700 Subject: iwlwifi: remove unneeded locks from apm_stop() and stop_master() Since priv->reg_lock was added to keep multi-access register manipulation atomic, priv->lock protection is no longer needed. Remove this from iwl_apm_stop_master() and iwl_apm_stop(). Add warning of timeout when polling for busmaster disablement confirmation, and some comments. NOTE: This is needed to enable use of apm_ops.stop() within iwl_eeprom_init(); priv->lock does not get initialized until after this flow. See patch "remove power-wasting calls to apm_ops.init()" Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d2b56baf98fb..4808f6661160 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1353,39 +1353,39 @@ EXPORT_SYMBOL(iwl_irq_handle_error); int iwl_apm_stop_master(struct iwl_priv *priv) { - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); + int ret = 0; - /* set stop master bit */ + /* stop device's busmaster DMA activity */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, + ret = iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + if (ret) + IWL_WARN(priv, "Master Disable Timed Out, 100 usec\n"); - spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO(priv, "stop master\n"); - return 0; + return ret; } EXPORT_SYMBOL(iwl_apm_stop_master); void iwl_apm_stop(struct iwl_priv *priv) { - unsigned long flags; - IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n"); + /* Stop device's DMA activity */ iwl_apm_stop_master(priv); - spin_lock_irqsave(&priv->lock, flags); - + /* Reset the entire device */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); - /* clear "init complete" move adapter D0A* --> D0U state */ + + /* + * Clear "initialization complete" bit to move adapter from + * D0A* (powered-up Active) --> D0U* (Uninitialized) state. + */ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - spin_unlock_irqrestore(&priv->lock, flags); } EXPORT_SYMBOL(iwl_apm_stop); -- cgit v1.2.3 From 88521364cc04b67f36748983545b9fe1d4ba4a15 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 30 Oct 2009 14:36:06 -0700 Subject: iwlwifi: remove power-wasting calls to apm_ops.init() To save power, don't run apm_ops.init() until needed at "up" time. EEPROM (5000 and earlier devices) may be read without running apm_ops.init(), but OTP reads (6000 and newer devices) require a powered-up chip. Therefore, remove apm_ops.init() from the general path in XXXX_pci_probe(), and call it only if device uses OTP. Once done with OTP read, call apm_ops.stop() to reset chip and save power until "up" time comes around. NOTE: This patch depends on removal of priv->lock from iwl_apm_stop(); lock does not get initialized until later in flow. See patch "remove unneeded locks from apm_stop()". Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ------ drivers/net/wireless/iwlwifi/iwl-eeprom.c | 11 +++++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 7 ------- 3 files changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 05d1070e22d0..6daaad1e4bc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3113,12 +3113,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_iounmap; } - /* amp init */ - err = priv->cfg->ops->lib->apm_ops.init(priv); - if (err < 0) { - IWL_ERR(priv, "Failed to init APMG\n"); - goto out_iounmap; - } /***************** * 4. Read EEPROM *****************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 9429cb1c69bd..8a0709e81a9f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -533,6 +533,10 @@ int iwl_eeprom_init(struct iwl_priv *priv) goto err; } if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { + + /* OTP reads require powered-up chip */ + priv->cfg->ops->lib->apm_ops.init(priv); + ret = iwl_init_otp_access(priv); if (ret) { IWL_ERR(priv, "Failed to initialize OTP access.\n"); @@ -563,6 +567,13 @@ int iwl_eeprom_init(struct iwl_priv *priv) e[cache_addr / 2] = eeprom_data; cache_addr += sizeof(u16); } + + /* + * Now that OTP reads are complete, reset chip to save + * power until we load uCode during "up". + */ + priv->cfg->ops->lib->apm_ops.stop(priv); + } else { /* eeprom is an array of 16bit values */ for (addr = 0; addr < sz; addr += sizeof(u16)) { diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5c80a83eb2e1..23b31e6dcacd 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4000,13 +4000,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e */ spin_lock_init(&priv->reg_lock); - /* amp init */ - err = priv->cfg->ops->lib->apm_ops.init(priv); - if (err < 0) { - IWL_DEBUG_INFO(priv, "Failed to init the card\n"); - goto out_iounmap; - } - /*********************** * 4. Read EEPROM * ********************/ -- cgit v1.2.3 From a6c5c731c3f783f60ed79dcf41efa8b5b3af2f22 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 30 Oct 2009 14:36:07 -0700 Subject: iwlagn: invoke L0S workaround for 6000/1000 series Invoke workaround to avoid instability in L0->L0S->L1 transition on PCIe bus. Workaround disables L0S state so device moves directly from L0->L1. Workaround needed on all devices since and including 4965; add to 6000/1000. Describe bug and workaround better in comments. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 20 ++++++++++---------- drivers/net/wireless/iwlwifi/iwl-core.c | 8 ++++++-- 3 files changed, 18 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 3a645e485dda..1e387b9dce1e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -164,7 +164,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, @@ -190,7 +190,7 @@ struct iwl_cfg iwl1000_bg_cfg = { .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_AB, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 32466d38d1ae..2f841a8576e0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -299,7 +299,7 @@ struct iwl_cfg iwl6000h_2agn_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -329,7 +329,7 @@ struct iwl_cfg iwl6000h_2abg_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -358,7 +358,7 @@ struct iwl_cfg iwl6000h_2bg_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_HYBRID, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -390,7 +390,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -420,7 +420,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -449,7 +449,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .valid_tx_ant = ANT_BC, .valid_rx_ant = ANT_BC, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_INTERNAL, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -478,7 +478,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, @@ -508,7 +508,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .valid_tx_ant = ANT_AB, .valid_rx_ant = ANT_AB, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, @@ -537,7 +537,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -567,7 +567,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .valid_tx_ant = ANT_ABC, .valid_rx_ant = ANT_ABC, .pll_cfg_val = 0, - .set_l0s = false, + .set_l0s = true, .use_bsm = false, .pa_type = IWL_PA_SYSTEM, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 4808f6661160..addc9ad5a5c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1430,8 +1430,12 @@ int iwl_apm_init(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); /* - * HW bug W/A - costs negligible power consumption ... - * Check if BIOS (or OS) enabled L1-ASPM on this device + * HW bug W/A for instability in PCIe bus L0->L0S->L1 transition. + * Check if BIOS (or OS) enabled L1-ASPM on this device. + * If so (likely), disable L0S, so device moves directly L0->L1; + * costs negligible amount of power savings. + * If not (unlikely), enable L0S, so there is at least some + * power savings, even without L1. */ if (priv->cfg->set_l0s) { lctl = iwl_pcie_link_ctl(priv); -- cgit v1.2.3 From c72cd19fab7983e97a1a41b7158e0b9f87a7fe96 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 30 Oct 2009 14:36:08 -0700 Subject: iwlagn: Clarify FH_TX interrupt Add/clarify comments and debug messages for interrupt used only for uCode load Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6daaad1e4bc9..7751a75d4dc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1033,11 +1033,12 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } + /* This "Tx" DMA channel is used only for loading uCode */ if (inta & CSR_INT_BIT_FH_TX) { - IWL_DEBUG_ISR(priv, "Tx interrupt\n"); + IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); priv->isr_stats.tx++; handled |= CSR_INT_BIT_FH_TX; - /* FH finished to write, send event */ + /* Wake up uCode load routine, now that load is complete */ priv->ucode_write_complete = 1; wake_up_interruptible(&priv->wait_command_queue); } @@ -1234,12 +1235,13 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) iwl_leds_background(priv); } + /* This "Tx" DMA channel is used only for loading uCode */ if (inta & CSR_INT_BIT_FH_TX) { iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK); - IWL_DEBUG_ISR(priv, "Tx interrupt\n"); + IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); priv->isr_stats.tx++; handled |= CSR_INT_BIT_FH_TX; - /* FH finished to write, send event */ + /* Wake up uCode load routine, now that load is complete */ priv->ucode_write_complete = 1; wake_up_interruptible(&priv->wait_command_queue); } -- cgit v1.2.3 From c2e61da29d92df864dc5eec81d774199b02d7023 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 30 Oct 2009 14:36:09 -0700 Subject: iwlagn: update write pointers for all tx queues after wakeup Wakeup interrupt has been updating write pointers (indexes, actually) only for tx queues 0-5. This is adequate just for 3945, but inadequate for other devices, all of which have more tx queues. Now updating all tx/command queues, so device can be aware of all new tx and host commands enqueued while device was asleep. This can potentially improve data traffic bandwidth and/or latency. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7751a75d4dc9..0cb95bfd15a5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -890,6 +890,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) u32 inta, handled = 0; u32 inta_fh; unsigned long flags; + u32 i; #ifdef CONFIG_IWLWIFI_DEBUG u32 inta_mask; #endif @@ -1007,19 +1008,17 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) handled |= CSR_INT_BIT_SW_ERR; } - /* uCode wakes up after power-down sleep */ + /* + * uCode wakes up after power-down sleep. + * Tell device about any new tx or host commands enqueued, + * and about any Rx buffers made available while asleep. + */ if (inta & CSR_INT_BIT_WAKEUP) { IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - iwl_txq_update_write_ptr(priv, &priv->txq[0]); - iwl_txq_update_write_ptr(priv, &priv->txq[1]); - iwl_txq_update_write_ptr(priv, &priv->txq[2]); - iwl_txq_update_write_ptr(priv, &priv->txq[3]); - iwl_txq_update_write_ptr(priv, &priv->txq[4]); - iwl_txq_update_write_ptr(priv, &priv->txq[5]); - + for (i = 0; i < priv->hw_params.max_txq_num; i++) + iwl_txq_update_write_ptr(priv, &priv->txq[i]); priv->isr_stats.wakeup++; - handled |= CSR_INT_BIT_WAKEUP; } -- cgit v1.2.3 From c33de6256a07869b48830e3a26fb6942ea8c4f79 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:10 -0700 Subject: iwlwifi: unmap memory before use Handling responses to driver originated commands include passing the original command buffer to the caller. At this time it is possible for a callback to be invoked that is passed this command buffer and thus likely to access it. We need to make sure that the memory associated with that buffer is not DMA mapped at the time. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 8ae4c9b614e7..b46967ff3806 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1121,11 +1121,6 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, return; } - pci_unmap_single(priv->pci_dev, - pci_unmap_addr(&txq->meta[cmd_idx], mapping), - pci_unmap_len(&txq->meta[cmd_idx], len), - PCI_DMA_BIDIRECTIONAL); - for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { @@ -1173,6 +1168,11 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index]; + pci_unmap_single(priv->pci_dev, + pci_unmap_addr(meta, mapping), + pci_unmap_len(meta, len), + PCI_DMA_BIDIRECTIONAL); + /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { meta->source->reply_page = (unsigned long)rxb_addr(rxb); -- cgit v1.2.3 From 89f186a8b64a4c90a219cfd94c26de5cfea54b84 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:11 -0700 Subject: iwlwifi: move iwl_[un]init_drv to iwlagn Since iwlagn is the only user of these functions, move it to this module. This results in a bit more code moving than just these functions since the functions only used by them are also moved and we need to export the symbols previously available to them directly. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 90 +++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-calib.c | 1 + drivers/net/wireless/iwlwifi/iwl-core.c | 93 -------------------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 - drivers/net/wireless/iwlwifi/iwl-scan.c | 1 + 5 files changed, 92 insertions(+), 95 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0cb95bfd15a5..2814565fa3b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2972,6 +2972,96 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) del_timer_sync(&priv->statistics_periodic); } +static void iwl_init_hw_rates(struct iwl_priv *priv, + struct ieee80211_rate *rates) +{ + int i; + + for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) { + rates[i].bitrate = iwl_rates[i].ieee * 5; + rates[i].hw_value = i; /* Rate scaling will work on indexes */ + rates[i].hw_value_short = i; + rates[i].flags = 0; + if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) { + /* + * If CCK != 1M then set short preamble rate flag. + */ + rates[i].flags |= + (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ? + 0 : IEEE80211_RATE_SHORT_PREAMBLE; + } + } +} + +static int iwl_init_drv(struct iwl_priv *priv) +{ + int ret; + + priv->ibss_beacon = NULL; + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->sta_lock); + spin_lock_init(&priv->hcmd_lock); + + INIT_LIST_HEAD(&priv->free_frames); + + mutex_init(&priv->mutex); + + /* Clear the driver's (not device's) station table */ + iwl_clear_stations_table(priv); + + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->band = IEEE80211_BAND_2GHZ; + + priv->iw_mode = NL80211_IFTYPE_STATION; + + /* Choose which receivers/antennas to use */ + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv); + + iwl_init_scan_params(priv); + + iwl_reset_qos(priv); + + priv->qos_data.qos_active = 0; + priv->qos_data.qos_cap.val = 0; + + priv->rates_mask = IWL_RATES_MASK; + /* Set the tx_power_user_lmt to the lowest power level + * this value will get overwritten by channel max power avg + * from eeprom */ + priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MIN; + + ret = iwl_init_channel_map(priv); + if (ret) { + IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); + goto err; + } + + ret = iwlcore_init_geos(priv); + if (ret) { + IWL_ERR(priv, "initializing geos failed: %d\n", ret); + goto err_free_channel_map; + } + iwl_init_hw_rates(priv, priv->ieee_rates); + + return 0; + +err_free_channel_map: + iwl_free_channel_map(priv); +err: + return ret; +} + +static void iwl_uninit_drv(struct iwl_priv *priv) +{ + iwl_calib_free_results(priv); + iwlcore_free_geos(priv); + iwl_free_channel_map(priv); + kfree(priv->scan); +} + static struct attribute *iwl_sysfs_entries[] = { &dev_attr_flags.attr, &dev_attr_filter_flags.attr, diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 1f801eb9fbff..d994de7438d8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -132,6 +132,7 @@ void iwl_calib_free_results(struct iwl_priv *priv) priv->calib_results[i].buf_len = 0; } } +EXPORT_SYMBOL(iwl_calib_free_results); /***************************************************************************** * RUNTIME calibrations framework diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index addc9ad5a5c6..256c9a49fa3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -451,28 +451,6 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, } } -static void iwlcore_init_hw_rates(struct iwl_priv *priv, - struct ieee80211_rate *rates) -{ - int i; - - for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) { - rates[i].bitrate = iwl_rates[i].ieee * 5; - rates[i].hw_value = i; /* Rate scaling will work on indexes */ - rates[i].hw_value_short = i; - rates[i].flags = 0; - if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) { - /* - * If CCK != 1M then set short preamble rate flag. - */ - rates[i].flags |= - (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ? - 0 : IEEE80211_RATE_SHORT_PREAMBLE; - } - } -} - - /** * iwlcore_init_geos - Initialize mac80211's geo/channel info based from eeprom */ @@ -1571,68 +1549,6 @@ int iwl_set_hw_params(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_set_hw_params); -int iwl_init_drv(struct iwl_priv *priv) -{ - int ret; - - priv->ibss_beacon = NULL; - - spin_lock_init(&priv->lock); - spin_lock_init(&priv->sta_lock); - spin_lock_init(&priv->hcmd_lock); - - INIT_LIST_HEAD(&priv->free_frames); - - mutex_init(&priv->mutex); - - /* Clear the driver's (not device's) station table */ - iwl_clear_stations_table(priv); - - priv->ieee_channels = NULL; - priv->ieee_rates = NULL; - priv->band = IEEE80211_BAND_2GHZ; - - priv->iw_mode = NL80211_IFTYPE_STATION; - - /* Choose which receivers/antennas to use */ - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv); - - iwl_init_scan_params(priv); - - iwl_reset_qos(priv); - - priv->qos_data.qos_active = 0; - priv->qos_data.qos_cap.val = 0; - - priv->rates_mask = IWL_RATES_MASK; - /* Set the tx_power_user_lmt to the lowest power level - * this value will get overwritten by channel max power avg - * from eeprom */ - priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MIN; - - ret = iwl_init_channel_map(priv); - if (ret) { - IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); - goto err; - } - - ret = iwlcore_init_geos(priv); - if (ret) { - IWL_ERR(priv, "initializing geos failed: %d\n", ret); - goto err_free_channel_map; - } - iwlcore_init_hw_rates(priv, priv->ieee_rates); - - return 0; - -err_free_channel_map: - iwl_free_channel_map(priv); -err: - return ret; -} -EXPORT_SYMBOL(iwl_init_drv); - int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret = 0; @@ -1680,15 +1596,6 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) } EXPORT_SYMBOL(iwl_set_tx_power); -void iwl_uninit_drv(struct iwl_priv *priv) -{ - iwl_calib_free_results(priv); - iwlcore_free_geos(priv); - iwl_free_channel_map(priv); - kfree(priv->scan); -} -EXPORT_SYMBOL(iwl_uninit_drv); - #define ICT_COUNT (PAGE_SIZE/sizeof(u32)) /* Free dram table */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b875dcfca2d6..ddf0998fb752 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -316,8 +316,6 @@ void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast); int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); -int iwl_init_drv(struct iwl_priv *priv); -void iwl_uninit_drv(struct iwl_priv *priv); bool iwl_is_monitor_mode(struct iwl_priv *priv); void iwl_post_associate(struct iwl_priv *priv); void iwl_bss_info_changed(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 4fca65a2fe9c..1eb0d0bf1fe4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -401,6 +401,7 @@ void iwl_init_scan_params(struct iwl_priv *priv) if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; } +EXPORT_SYMBOL(iwl_init_scan_params); static int iwl_scan_initiate(struct iwl_priv *priv) { -- cgit v1.2.3 From 9a9ca65fbfa1cd14a6c016b793d61492f9f613d0 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:12 -0700 Subject: iwlwifi: split adding broadcast station from others In preparation for some station management changes we split the addition of a broadcast station from the other stations. Later we will rely on mac80211 to direct all management (addition/removal) of all stations except the broadcast station. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++--- drivers/net/wireless/iwlwifi/iwl-sta.c | 62 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-sta.h | 1 + 3 files changed, 65 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2814565fa3b4..4a13f7e21d63 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -190,11 +190,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) priv->start_calib = 0; /* Add the broadcast address so we can send broadcast frames */ - if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) == - IWL_INVALID_STATION) { - IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n"); - return -EIO; - } + iwl_add_bcast_station(priv); /* If we have set the ASSOC_MSK and we are in BSS mode then * add the IWL_AP_ID to the station rate table */ @@ -2524,7 +2520,7 @@ void iwl_config_ap(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); iwl_activate_qos(priv, 1); spin_unlock_irqrestore(&priv->lock, flags); - iwl_rxon_add_station(priv, iwl_bcast_addr, 0); + iwl_add_bcast_station(priv); } iwl_send_beacon_cmd(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index dc74c16d36a8..ce1ceac19c7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1029,6 +1029,68 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) } EXPORT_SYMBOL(iwl_rxon_add_station); +/** + * iwl_sta_init_bcast_lq - Initialize a bcast station's hardware rate table + * + * NOTE: Run REPLY_ADD_STA command to set up station table entry, before + * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, + * which requires station table entry to exist). + */ +static void iwl_sta_init_bcast_lq(struct iwl_priv *priv) +{ + int i, r; + struct iwl_link_quality_cmd link_cmd = { + .reserved1 = 0, + }; + u32 rate_flags; + + /* Set up the rate scaling to start at selected rate, fall back + * all the way down to 1M in IEEE order, and then spin on 1M */ + if (priv->band == IEEE80211_BAND_5GHZ) + r = IWL_RATE_6M_INDEX; + else + r = IWL_RATE_1M_INDEX; + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + rate_flags = 0; + if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) + rate_flags |= RATE_MCS_CCK_MSK; + + rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << + RATE_MCS_ANT_POS; + + link_cmd.rs_table[i].rate_n_flags = + iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); + r = iwl_get_prev_ieee_rate(r); + } + + link_cmd.general_params.single_stream_ant_msk = + first_antenna(priv->hw_params.valid_tx_ant); + link_cmd.general_params.dual_stream_ant_msk = 3; + link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + link_cmd.agg_params.agg_time_limit = + cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); + + /* Update the rate scaling for control frame Tx to AP */ + link_cmd.sta_id = priv->hw_params.bcast_sta_id; + + iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, + sizeof(link_cmd), &link_cmd, NULL); +} + + +/** + * iwl_add_bcast_station - add broadcast station into station table. + */ +void iwl_add_bcast_station(struct iwl_priv *priv) +{ + iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL); + + /* Set up default rate scaling table in device's station table */ + iwl_sta_init_bcast_lq(priv); +} +EXPORT_SYMBOL(iwl_add_bcast_station); + /** * iwl_get_sta_id - Find station's index within station table * diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 6deebade6361..1c382de80d49 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -52,6 +52,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv, const u8 *addr, u32 iv32, u16 *phase1key); int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); +void iwl_add_bcast_station(struct iwl_priv *priv); int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); void iwl_clear_stations_table(struct iwl_priv *priv); int iwl_get_free_ucode_key_index(struct iwl_priv *priv); -- cgit v1.2.3 From 62a94926183374d8414ab2ec633d9fe9530644ec Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:13 -0700 Subject: iwl3945: store station rate scale information in mac80211 station structure Currently the rate scale information is pointed to from the mac80211 station structure but since that is the only member we might as well make it part of the structure. Also move the rate scaling initialization to the init function, no need to do it when we allocate the structure. This fits with how mac80211 deals with rate scaling information (it always calls init after allocation) and makes it easier for us to later call initialization directly. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 99 ++++++++---------------------- drivers/net/wireless/iwlwifi/iwl-3945.h | 35 ++++++++++- 2 files changed, 60 insertions(+), 74 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index cbb0585083a9..819a81bbb1b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -42,38 +42,6 @@ #define RS_NAME "iwl-3945-rs" -struct iwl3945_rate_scale_data { - u64 data; - s32 success_counter; - s32 success_ratio; - s32 counter; - s32 average_tpt; - unsigned long stamp; -}; - -struct iwl3945_rs_sta { - spinlock_t lock; - struct iwl_priv *priv; - s32 *expected_tpt; - unsigned long last_partial_flush; - unsigned long last_flush; - u32 flush_time; - u32 last_tx_packets; - u32 tx_packets; - u8 tgg; - u8 flush_pending; - u8 start_rate; - u8 ibss_sta_added; - struct timer_list rate_scale_flush; - struct iwl3945_rate_scale_data win[IWL_RATE_COUNT_3945]; -#ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *rs_sta_dbgfs_stats_table_file; -#endif - - /* used to be in sta_info */ - int last_txrate_idx; -}; - static s32 iwl3945_expected_tpt_g[IWL_RATE_COUNT_3945] = { 7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202 }; @@ -370,6 +338,28 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, IWL_DEBUG_RATE(priv, "enter\n"); + spin_lock_init(&rs_sta->lock); + + rs_sta->priv = priv; + + rs_sta->start_rate = IWL_RATE_INVALID; + + /* default to just 802.11b */ + rs_sta->expected_tpt = iwl3945_expected_tpt_b; + + rs_sta->last_partial_flush = jiffies; + rs_sta->last_flush = jiffies; + rs_sta->flush_time = IWL_RATE_FLUSH; + rs_sta->last_tx_packets = 0; + rs_sta->ibss_sta_added = 0; + + init_timer(&rs_sta->rate_scale_flush); + rs_sta->rate_scale_flush.data = (unsigned long)rs_sta; + rs_sta->rate_scale_flush.function = &iwl3945_bg_rate_scale_flush; + + for (i = 0; i < IWL_RATE_COUNT_3945; i++) + iwl3945_clear_window(&rs_sta->win[i]); + /* TODO: what is a good starting rate for STA? About middle? Maybe not * the lowest or the highest rate.. Could consider using RSSI from * previous packets? Need to have IEEE 802.1X auth succeed immediately @@ -409,45 +399,11 @@ static void *rs_alloc_sta(void *iwl_priv, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl3945_rs_sta *rs_sta; struct iwl3945_sta_priv *psta = (void *) sta->drv_priv; - struct iwl_priv *priv = iwl_priv; - int i; - - /* - * XXX: If it's using sta->drv_priv anyway, it might - * as well just put all the information there. - */ + struct iwl_priv *priv __maybe_unused = iwl_priv; IWL_DEBUG_RATE(priv, "enter\n"); - rs_sta = kzalloc(sizeof(struct iwl3945_rs_sta), gfp); - if (!rs_sta) { - IWL_DEBUG_RATE(priv, "leave: ENOMEM\n"); - return NULL; - } - - psta->rs_sta = rs_sta; - - spin_lock_init(&rs_sta->lock); - - rs_sta->priv = priv; - - rs_sta->start_rate = IWL_RATE_INVALID; - - /* default to just 802.11b */ - rs_sta->expected_tpt = iwl3945_expected_tpt_b; - - rs_sta->last_partial_flush = jiffies; - rs_sta->last_flush = jiffies; - rs_sta->flush_time = IWL_RATE_FLUSH; - rs_sta->last_tx_packets = 0; - rs_sta->ibss_sta_added = 0; - - init_timer(&rs_sta->rate_scale_flush); - rs_sta->rate_scale_flush.data = (unsigned long)rs_sta; - rs_sta->rate_scale_flush.function = &iwl3945_bg_rate_scale_flush; - - for (i = 0; i < IWL_RATE_COUNT_3945; i++) - iwl3945_clear_window(&rs_sta->win[i]); + rs_sta = &psta->rs_sta; IWL_DEBUG_RATE(priv, "leave\n"); @@ -458,14 +414,11 @@ static void rs_free_sta(void *iwl_priv, struct ieee80211_sta *sta, void *priv_sta) { struct iwl3945_sta_priv *psta = (void *) sta->drv_priv; - struct iwl3945_rs_sta *rs_sta = priv_sta; + struct iwl3945_rs_sta *rs_sta = &psta->rs_sta; struct iwl_priv *priv __maybe_unused = rs_sta->priv; - psta->rs_sta = NULL; - IWL_DEBUG_RATE(priv, "enter\n"); del_timer_sync(&rs_sta->rate_scale_flush); - kfree(rs_sta); IWL_DEBUG_RATE(priv, "leave\n"); } @@ -967,7 +920,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) } psta = (void *) sta->drv_priv; - rs_sta = psta->rs_sta; + rs_sta = &psta->rs_sta; spin_lock_irqsave(&rs_sta->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index ebb999a51b58..2b0d65c5780a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -74,8 +74,41 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; /* Module parameters accessible from iwl-*.c */ extern struct iwl_mod_params iwl3945_mod_params; +struct iwl3945_rate_scale_data { + u64 data; + s32 success_counter; + s32 success_ratio; + s32 counter; + s32 average_tpt; + unsigned long stamp; +}; + +struct iwl3945_rs_sta { + spinlock_t lock; + struct iwl_priv *priv; + s32 *expected_tpt; + unsigned long last_partial_flush; + unsigned long last_flush; + u32 flush_time; + u32 last_tx_packets; + u32 tx_packets; + u8 tgg; + u8 flush_pending; + u8 start_rate; + u8 ibss_sta_added; + struct timer_list rate_scale_flush; + struct iwl3945_rate_scale_data win[IWL_RATE_COUNT_3945]; +#ifdef CONFIG_MAC80211_DEBUGFS + struct dentry *rs_sta_dbgfs_stats_table_file; +#endif + + /* used to be in sta_info */ + int last_txrate_idx; +}; + + struct iwl3945_sta_priv { - struct iwl3945_rs_sta *rs_sta; + struct iwl3945_rs_sta rs_sta; }; enum iwl3945_antenna { -- cgit v1.2.3 From 5ad13f8ce76814b37842c15301287efd607c6d26 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:14 -0700 Subject: iwlagn: move rate scale initialization to init function This fits better in how the callbacks operate (alloc does allocation and init does initialization). This also helps if we later want to do our own initialization without relying on the mac80211 allocation. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 27d4ece4d467..43edd8fd4405 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2477,19 +2477,12 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta; struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv; struct iwl_priv *priv; - int i, j; priv = (struct iwl_priv *)priv_rate; IWL_DEBUG_RATE(priv, "create station rate scale window\n"); lq_sta = &sta_priv->lq_sta; - lq_sta->lq.sta_id = 0xff; - - for (j = 0; j < LQ_SIZE; j++) - for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); - return lq_sta; } @@ -2502,6 +2495,12 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct iwl_lq_sta *lq_sta = priv_sta; + lq_sta->lq.sta_id = 0xff; + + for (j = 0; j < LQ_SIZE; j++) + for (i = 0; i < IWL_RATE_COUNT; i++) + rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); + lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->supp_rates[sband->band]; for (j = 0; j < LQ_SIZE; j++) -- cgit v1.2.3 From f2f21b4928489e1cf6c289d2f429e75c6dee61b5 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 30 Oct 2009 14:36:15 -0700 Subject: iwlwifi: print warning when sending host command fails More information than the "-EIO" return code will be useful here. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index b46967ff3806..05e75109d842 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -979,7 +979,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) !(cmd->flags & CMD_SIZE_HUGE)); if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { - IWL_DEBUG_INFO(priv, "Not sending command - RF/CT KILL\n"); + IWL_WARN(priv, "Not sending command - %s KILL\n", + iwl_is_rfkill(priv) ? "RF" : "CT"); return -EIO; } -- cgit v1.2.3 From fe1bcbfda77bf6fa3bbad8bf26b9e9ab23fbe345 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 30 Oct 2009 14:36:16 -0700 Subject: iwlwifi: coex API data structure Add data structure define for COEX_MEDIUM_NOTIFICATION and COEX_EVENT_CMD host commands. COEX_MEDIUM_NOTIFICATION is notification from uCode to host to indicate medium changes. COEX_EVENT_CMD is from host to uCode for coex event request. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 69 +++++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 + 2 files changed, 68 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 954bad60355d..43dd6af00892 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3503,30 +3503,42 @@ struct iwl_led_cmd { } __attribute__ ((packed)); /* - * Coexistence WIFI/WIMAX Command - * COEX_PRIORITY_TABLE_CMD = 0x5a - * + * station priority table entries + * also used as potential "events" value for both + * COEX_MEDIUM_NOTIFICATION and COEX_EVENT_CMD */ enum { + /* un-association part */ COEX_UNASSOC_IDLE = 0, COEX_UNASSOC_MANUAL_SCAN = 1, COEX_UNASSOC_AUTO_SCAN = 2, + /* calibration */ COEX_CALIBRATION = 3, COEX_PERIODIC_CALIBRATION = 4, + /* connection */ COEX_CONNECTION_ESTAB = 5, + /* association part */ COEX_ASSOCIATED_IDLE = 6, COEX_ASSOC_MANUAL_SCAN = 7, COEX_ASSOC_AUTO_SCAN = 8, COEX_ASSOC_ACTIVE_LEVEL = 9, + /* RF ON/OFF */ COEX_RF_ON = 10, COEX_RF_OFF = 11, COEX_STAND_ALONE_DEBUG = 12, + /* IPAN */ COEX_IPAN_ASSOC_LEVEL = 13, + /* reserved */ COEX_RSRVD1 = 14, COEX_RSRVD2 = 15, COEX_NUM_OF_EVENTS = 16 }; +/* + * Coexistence WIFI/WIMAX Command + * COEX_PRIORITY_TABLE_CMD = 0x5a + * + */ struct iwl_wimax_coex_event_entry { u8 request_prio; u8 win_medium_prio; @@ -3551,6 +3563,55 @@ struct iwl_wimax_coex_cmd { struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS]; } __attribute__ ((packed)); +/* + * Coexistence MEDIUM NOTIFICATION + * COEX_MEDIUM_NOTIFICATION = 0x5b + * + * notification from uCode to host to indicate medium changes + * + */ +/* + * status field + * bit 0 - 2: medium status + * bit 3: medium change indication + * bit 4 - 31: reserved + */ +/* status option values, (0 - 2 bits) */ +#define COEX_MEDIUM_BUSY (0x0) /* radio belongs to WiMAX */ +#define COEX_MEDIUM_ACTIVE (0x1) /* radio belongs to WiFi */ +#define COEX_MEDIUM_PRE_RELEASE (0x2) /* received radio release */ +#define COEX_MEDIUM_MSK (0x7) + +/* send notification status (1 bit) */ +#define COEX_MEDIUM_CHANGED (0x8) +#define COEX_MEDIUM_CHANGED_MSK (0x8) +#define COEX_MEDIUM_SHIFT (3) + +struct iwl_coex_medium_notification { + __le32 status; + __le32 events; +} __attribute__ ((packed)); + +/* + * Coexistence EVENT Command + * COEX_EVENT_CMD = 0x5c + * + * send from host to uCode for coex event request. + */ +/* flags options */ +#define COEX_EVENT_REQUEST_MSK (0x1) + +struct iwl_coex_event_cmd { + u8 flags; + u8 event; + __le16 reserved; +} __attribute__ ((packed)); + +struct iwl_coex_event_resp { + __le32 status; +} __attribute__ ((packed)); + + /****************************************************************************** * (13) * Union of all expected notifications/responses: @@ -3587,6 +3648,8 @@ struct iwl_rx_packet { struct iwl_notif_statistics stats; struct iwl_compressed_ba_resp compressed_ba; struct iwl_missed_beacon_notif missed_beacon; + struct iwl_coex_medium_notification coex_medium_notif; + struct iwl_coex_event_resp coex_event; __le32 status; u8 raw[0]; } u; diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index f2a60dc4109f..905645d15a9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -55,6 +55,8 @@ const char *get_cmd_string(u8 cmd) IWL_CMD(REPLY_LEDS_CMD); IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); IWL_CMD(COEX_PRIORITY_TABLE_CMD); + IWL_CMD(COEX_MEDIUM_NOTIFICATION); + IWL_CMD(COEX_EVENT_CMD); IWL_CMD(RADAR_NOTIFICATION); IWL_CMD(REPLY_QUIET_CMD); IWL_CMD(REPLY_CHANNEL_SWITCH); -- cgit v1.2.3 From 3f3e0376bb14ac7bfd8ac3e9824b2ad04d945e18 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 30 Oct 2009 14:36:17 -0700 Subject: iwlwifi: add SM PS support for 6x50 series Spatial Multiplexing Power Save was disabled to achieve better throughput while in power save mode by activating all the rx chains all the time. By doing so, the device power consumption is high. Enable static/dynamic spatial multiplexing power save if device support it, which can lower the power consumption without impact throughput. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-agn.c | 4 +++ drivers/net/wireless/iwlwifi/iwl-core.c | 48 ++++++++++++++++++++++++++------- drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl-sta.c | 5 ++++ 6 files changed, 52 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 2f841a8576e0..a4a8b5e2f411 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -490,6 +490,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .support_sm_ps = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -579,6 +580,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .support_sm_ps = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4a13f7e21d63..b5fe8f87aa7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3011,6 +3011,10 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->band = IEEE80211_BAND_2GHZ; priv->iw_mode = NL80211_IFTYPE_STATION; + if (priv->cfg->support_sm_ps) + priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DYNAMIC; + else + priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 256c9a49fa3b..c4ff381e440e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -414,8 +414,12 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, if (priv->cfg->ht_greenfield_support) ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & - (WLAN_HT_CAP_SM_PS_DISABLED << 2)); + if (priv->cfg->support_sm_ps) + ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & + (WLAN_HT_CAP_SM_PS_DYNAMIC << 2)); + else + ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & + (WLAN_HT_CAP_SM_PS_DISABLED << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; if (priv->hw_params.ht40_channel & BIT(band)) { @@ -963,17 +967,35 @@ static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) } /* - * When we are in power saving, there's no difference between - * using multiple chains or just a single chain, but due to the - * lack of SM PS we lose a lot of throughput if we use just a - * single chain. - * - * Therefore, use the active count here (which will use multiple - * chains unless connected to a legacy AP). + * When we are in power saving mode, unless device support spatial + * multiplexing power save, use the active count for rx chain count. */ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) { - return active_cnt; + int idle_cnt = active_cnt; + bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); + + if (priv->cfg->support_sm_ps) { + /* # Rx chains when idling and maybe trying to save power */ + switch (priv->current_ht_config.sm_ps) { + case WLAN_HT_CAP_SM_PS_STATIC: + case WLAN_HT_CAP_SM_PS_DYNAMIC: + idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : + IWL_NUM_IDLE_CHAINS_SINGLE; + break; + case WLAN_HT_CAP_SM_PS_DISABLED: + idle_cnt = (is_cam) ? active_cnt : + IWL_NUM_IDLE_CHAINS_SINGLE; + break; + case WLAN_HT_CAP_SM_PS_INVALID: + default: + IWL_ERR(priv, "invalid sm_ps mode %d\n", + priv->current_ht_config.sm_ps); + WARN_ON(1); + break; + } + } + return idle_cnt; } /* up to 4 chains */ @@ -2257,6 +2279,12 @@ static void iwl_ht_conf(struct iwl_priv *priv, >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; maxstreams += 1; + ht_conf->sm_ps = + (u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS) + >> 2); + IWL_DEBUG_MAC80211(priv, "sm_ps: 0x%x\n", + ht_conf->sm_ps); + if ((ht_cap->mcs.rx_mask[1] == 0) && (ht_cap->mcs.rx_mask[2] == 0)) ht_conf->single_chain_sufficient = true; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ddf0998fb752..d2e47dab38d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -228,6 +228,7 @@ struct iwl_mod_params { * @chain_noise_num_beacons: number of beacons used to compute chain noise * @adv_thermal_throttle: support advance thermal throttle * @support_ct_kill_exit: support ct kill exit condition + * @support_sm_ps: support spatial multiplexing power save * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -283,6 +284,7 @@ struct iwl_cfg { const bool supports_idle; bool adv_thermal_throttle; bool support_ct_kill_exit; + bool support_sm_ps; }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e7ce67387662..cb2642c18da4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -517,6 +517,7 @@ struct iwl_ht_config { bool is_ht; bool is_40mhz; bool single_chain_sufficient; + u8 sm_ps; /* BSS related data */ u8 extension_chan_offset; u8 ht_protection; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index ce1ceac19c7d..74cc8dbe9359 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -182,6 +182,11 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, goto done; mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; + IWL_DEBUG_ASSOC(priv, "spatial multiplexing power save mode: %s\n", + (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? + "static" : + (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? + "dynamic" : "disabled"); sta_flags = priv->stations[index].sta.station_flags; -- cgit v1.2.3 From 1933ac4d9377ed44caba45abe1531ec1bc14bb63 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 30 Oct 2009 14:36:18 -0700 Subject: iwlwifi: add wimax/wifi coexist support for 6x50 series For 6x50 series, it is wimax/wifi combo device, so driver need to enable the wimax/wifi co-exist function and send the coexist event priority table to uCode for operation. The priority table will be used by uCode to determine what is the proper action it should take when co-exist with WiMAX. For example, when WiFi runs a scan, it must own radio exclusively, therefore will disconnect WiMAX if WiMAX is connected. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 12 +--- drivers/net/wireless/iwlwifi/iwl-6000.c | 3 + drivers/net/wireless/iwlwifi/iwl-commands.h | 92 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 59 ++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-core.h | 3 + 5 files changed, 158 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d256fecc6cda..910217f0ad8a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -591,16 +591,6 @@ static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); } -static int iwl5000_send_wimax_coex(struct iwl_priv *priv) -{ - struct iwl_wimax_coex_cmd coex_cmd; - - memset(&coex_cmd, 0, sizeof(coex_cmd)); - - return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD, - sizeof(coex_cmd), &coex_cmd); -} - int iwl5000_alive_notify(struct iwl_priv *priv) { u32 a; @@ -681,7 +671,7 @@ int iwl5000_alive_notify(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); - iwl5000_send_wimax_coex(priv); + iwl_send_wimax_coex(priv); iwl5000_set_Xtal_calib(priv); iwl_send_calib_results(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index a4a8b5e2f411..70e117f8d0c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -491,6 +491,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .adv_thermal_throttle = true, .support_ct_kill_exit = true, .support_sm_ps = true, + .support_wimax_coexist = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -520,6 +521,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .support_wimax_coexist = true, }; struct iwl_cfg iwl6000_3agn_cfg = { @@ -581,6 +583,7 @@ struct iwl_cfg iwl6050_3agn_cfg = { .adv_thermal_throttle = true, .support_ct_kill_exit = true, .support_sm_ps = true, + .support_wimax_coexist = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 43dd6af00892..b62c90ec9e1e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3507,6 +3507,98 @@ struct iwl_led_cmd { * also used as potential "events" value for both * COEX_MEDIUM_NOTIFICATION and COEX_EVENT_CMD */ + +/* + * COEX events entry flag masks + * RP - Requested Priority + * WP - Win Medium Priority: priority assigned when the contention has been won + */ +#define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG (0x1) +#define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG (0x2) +#define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG (0x4) + +#define COEX_CU_UNASSOC_IDLE_RP 4 +#define COEX_CU_UNASSOC_MANUAL_SCAN_RP 4 +#define COEX_CU_UNASSOC_AUTO_SCAN_RP 4 +#define COEX_CU_CALIBRATION_RP 4 +#define COEX_CU_PERIODIC_CALIBRATION_RP 4 +#define COEX_CU_CONNECTION_ESTAB_RP 4 +#define COEX_CU_ASSOCIATED_IDLE_RP 4 +#define COEX_CU_ASSOC_MANUAL_SCAN_RP 4 +#define COEX_CU_ASSOC_AUTO_SCAN_RP 4 +#define COEX_CU_ASSOC_ACTIVE_LEVEL_RP 4 +#define COEX_CU_RF_ON_RP 6 +#define COEX_CU_RF_OFF_RP 4 +#define COEX_CU_STAND_ALONE_DEBUG_RP 6 +#define COEX_CU_IPAN_ASSOC_LEVEL_RP 4 +#define COEX_CU_RSRVD1_RP 4 +#define COEX_CU_RSRVD2_RP 4 + +#define COEX_CU_UNASSOC_IDLE_WP 3 +#define COEX_CU_UNASSOC_MANUAL_SCAN_WP 3 +#define COEX_CU_UNASSOC_AUTO_SCAN_WP 3 +#define COEX_CU_CALIBRATION_WP 3 +#define COEX_CU_PERIODIC_CALIBRATION_WP 3 +#define COEX_CU_CONNECTION_ESTAB_WP 3 +#define COEX_CU_ASSOCIATED_IDLE_WP 3 +#define COEX_CU_ASSOC_MANUAL_SCAN_WP 3 +#define COEX_CU_ASSOC_AUTO_SCAN_WP 3 +#define COEX_CU_ASSOC_ACTIVE_LEVEL_WP 3 +#define COEX_CU_RF_ON_WP 3 +#define COEX_CU_RF_OFF_WP 3 +#define COEX_CU_STAND_ALONE_DEBUG_WP 6 +#define COEX_CU_IPAN_ASSOC_LEVEL_WP 3 +#define COEX_CU_RSRVD1_WP 3 +#define COEX_CU_RSRVD2_WP 3 + +#define COEX_UNASSOC_IDLE_FLAGS 0 +#define COEX_UNASSOC_MANUAL_SCAN_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_UNASSOC_AUTO_SCAN_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_CALIBRATION_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_PERIODIC_CALIBRATION_FLAGS 0 +/* + * COEX_CONNECTION_ESTAB: + * we need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network. + */ +#define COEX_CONNECTION_ESTAB_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG) +#define COEX_ASSOCIATED_IDLE_FLAGS 0 +#define COEX_ASSOC_MANUAL_SCAN_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_ASSOC_AUTO_SCAN_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_ASSOC_ACTIVE_LEVEL_FLAGS 0 +#define COEX_RF_ON_FLAGS 0 +#define COEX_RF_OFF_FLAGS 0 +#define COEX_STAND_ALONE_DEBUG_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG) +#define COEX_IPAN_ASSOC_LEVEL_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG) +#define COEX_RSRVD1_FLAGS 0 +#define COEX_RSRVD2_FLAGS 0 +/* + * COEX_CU_RF_ON is the event wrapping all radio ownership. + * We need DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network. + */ +#define COEX_CU_RF_ON_FLAGS \ + (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_FLG | \ + COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_FLG | \ + COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_FLG) + + enum { /* un-association part */ COEX_UNASSOC_IDLE = 0, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c4ff381e440e..7373b2f50aca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -46,6 +46,37 @@ MODULE_VERSION(IWLWIFI_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); +static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { + {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP, + 0, COEX_UNASSOC_IDLE_FLAGS}, + {COEX_CU_UNASSOC_MANUAL_SCAN_RP, COEX_CU_UNASSOC_MANUAL_SCAN_WP, + 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, + {COEX_CU_UNASSOC_AUTO_SCAN_RP, COEX_CU_UNASSOC_AUTO_SCAN_WP, + 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, + {COEX_CU_CALIBRATION_RP, COEX_CU_CALIBRATION_WP, + 0, COEX_CALIBRATION_FLAGS}, + {COEX_CU_PERIODIC_CALIBRATION_RP, COEX_CU_PERIODIC_CALIBRATION_WP, + 0, COEX_PERIODIC_CALIBRATION_FLAGS}, + {COEX_CU_CONNECTION_ESTAB_RP, COEX_CU_CONNECTION_ESTAB_WP, + 0, COEX_CONNECTION_ESTAB_FLAGS}, + {COEX_CU_ASSOCIATED_IDLE_RP, COEX_CU_ASSOCIATED_IDLE_WP, + 0, COEX_ASSOCIATED_IDLE_FLAGS}, + {COEX_CU_ASSOC_MANUAL_SCAN_RP, COEX_CU_ASSOC_MANUAL_SCAN_WP, + 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, + {COEX_CU_ASSOC_AUTO_SCAN_RP, COEX_CU_ASSOC_AUTO_SCAN_WP, + 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, + {COEX_CU_ASSOC_ACTIVE_LEVEL_RP, COEX_CU_ASSOC_ACTIVE_LEVEL_WP, + 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, + {COEX_CU_RF_ON_RP, COEX_CU_RF_ON_WP, 0, COEX_CU_RF_ON_FLAGS}, + {COEX_CU_RF_OFF_RP, COEX_CU_RF_OFF_WP, 0, COEX_RF_OFF_FLAGS}, + {COEX_CU_STAND_ALONE_DEBUG_RP, COEX_CU_STAND_ALONE_DEBUG_WP, + 0, COEX_STAND_ALONE_DEBUG_FLAGS}, + {COEX_CU_IPAN_ASSOC_LEVEL_RP, COEX_CU_IPAN_ASSOC_LEVEL_WP, + 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, + {COEX_CU_RSRVD1_RP, COEX_CU_RSRVD1_WP, 0, COEX_RSRVD1_FLAGS}, + {COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS} +}; + #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ IWL_RATE_SISO_##s##M_PLCP, \ @@ -2865,6 +2896,34 @@ void iwl_free_txq_mem(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_free_txq_mem); +int iwl_send_wimax_coex(struct iwl_priv *priv) +{ + struct iwl_wimax_coex_cmd uninitialized_var(coex_cmd); + + if (priv->cfg->support_wimax_coexist) { + /* UnMask wake up src at associated sleep */ + coex_cmd.flags |= COEX_FLAGS_ASSOC_WA_UNMASK_MSK; + + /* UnMask wake up src at unassociated sleep */ + coex_cmd.flags |= COEX_FLAGS_UNASSOC_WA_UNMASK_MSK; + memcpy(coex_cmd.sta_prio, cu_priorities, + sizeof(struct iwl_wimax_coex_event_entry) * + COEX_NUM_OF_EVENTS); + + /* enabling the coexistence feature */ + coex_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK; + + /* enabling the priorities tables */ + coex_cmd.flags |= COEX_FLAGS_STA_TABLE_VALID_MSK; + } else { + /* coexistence is disabled */ + memset(&coex_cmd, 0, sizeof(coex_cmd)); + } + return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD, + sizeof(coex_cmd), &coex_cmd); +} +EXPORT_SYMBOL(iwl_send_wimax_coex); + #ifdef CONFIG_IWLWIFI_DEBUGFS #define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index d2e47dab38d4..9574d8f33537 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -229,6 +229,7 @@ struct iwl_mod_params { * @adv_thermal_throttle: support advance thermal throttle * @support_ct_kill_exit: support ct kill exit condition * @support_sm_ps: support spatial multiplexing power save + * @support_wimax_coexist: support wimax/wifi co-exist * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the @@ -285,6 +286,7 @@ struct iwl_cfg { bool adv_thermal_throttle; bool support_ct_kill_exit; bool support_sm_ps; + const bool support_wimax_coexist; }; /*************************** @@ -340,6 +342,7 @@ int iwl_alloc_txq_mem(struct iwl_priv *priv); void iwl_free_txq_mem(struct iwl_priv *priv); void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags); +int iwl_send_wimax_coex(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_alloc_traffic_mem(struct iwl_priv *priv); void iwl_free_traffic_mem(struct iwl_priv *priv); -- cgit v1.2.3 From 93a59d7527147e3656664aa3179f8d19de256081 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 31 Oct 2009 22:59:27 +0100 Subject: p54: disable channels with incomplete calibration data sets James Grossmann [1] reported that p54 spews out confusing messages instead of preventing the mayhem from happening. the reason is that "p54: generate channel list dynamically" is not perfect. It didn't discard incomplete channel data sets and therefore p54 advertised to support them as well. [1]: http://marc.info/?l=linux-wireless&m=125699830215890 Cc: Larry Finger Reported-by: James Grossmann Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/eeprom.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 0efe67deedee..8e3818f6832e 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -126,7 +126,7 @@ static int p54_generate_band(struct ieee80211_hw *dev, int ret = -ENOMEM; if ((!list->entries) || (!list->band_channel_num[band])) - return 0; + return -EINVAL; tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); if (!tmp) @@ -158,6 +158,7 @@ static int p54_generate_band(struct ieee80211_hw *dev, (list->channels[i].data & CHAN_HAS_CURVE ? "" : " [curve data]"), list->channels[i].index, list->channels[i].freq); + continue; } tmp->channels[j].band = list->channels[i].band; @@ -165,7 +166,16 @@ static int p54_generate_band(struct ieee80211_hw *dev, j++; } - tmp->n_channels = list->band_channel_num[band]; + if (j == 0) { + printk(KERN_ERR "%s: Disabling totally damaged %s band.\n", + wiphy_name(dev->wiphy), (band == IEEE80211_BAND_2GHZ) ? + "2 GHz" : "5 GHz"); + + ret = -ENODATA; + goto err_out; + } + + tmp->n_channels = j; old = priv->band_table[band]; priv->band_table[band] = tmp; if (old) { @@ -228,13 +238,13 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; struct p54_channel_list *list; unsigned int i, j, max_channel_num; - int ret = -ENOMEM; + int ret = 0; u16 freq; if ((priv->iq_autocal_len != priv->curve_data->entries) || (priv->iq_autocal_len != priv->output_limit->entries)) - printk(KERN_ERR "%s: EEPROM is damaged... you may not be able" - "to use all channels with this device.\n", + printk(KERN_ERR "%s: Unsupported or damaged EEPROM detected. " + "You may not be able to use all channels.\n", wiphy_name(dev->wiphy)); max_channel_num = max_t(unsigned int, priv->output_limit->entries, @@ -243,8 +253,10 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev) priv->curve_data->entries); list = kzalloc(sizeof(*list), GFP_KERNEL); - if (!list) + if (!list) { + ret = -ENOMEM; goto free; + } list->max_entries = max_channel_num; list->channels = kzalloc(sizeof(struct p54_channel_entry) * @@ -282,13 +294,8 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev) p54_compare_channels, NULL); for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) { - if (list->band_channel_num[i]) { - ret = p54_generate_band(dev, list, i); - if (ret) - goto free; - + if (p54_generate_band(dev, list, i) == 0) j++; - } } if (j == 0) { /* no useable band available. */ -- cgit v1.2.3 From 70541839dd2eacb521fa4f8515ab696599b36ea3 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 1 Nov 2009 11:30:48 +0200 Subject: mac80211_hwsim: Check idle state on TX Track the idle state for hwsim radios and reject TX if mac80211 is trying to transmit something when the radio is supposed to be idle. In addition, do not deliver frames if the receiving radio is in the idle state. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index d2b2e5e739b7..58c357eaf216 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -284,7 +284,7 @@ struct mac80211_hwsim_data { struct ieee80211_channel *channel; unsigned long beacon_int; /* in jiffies unit */ unsigned int rx_filter; - int started; + bool started, idle; struct timer_list beacon_timer; enum ps_mode { PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL @@ -402,6 +402,12 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_rx_status rx_status; + if (data->idle) { + printk(KERN_DEBUG "%s: Trying to TX when idle - reject\n", + wiphy_name(hw->wiphy)); + return false; + } + memset(&rx_status, 0, sizeof(rx_status)); /* TODO: set mactime */ rx_status.freq = data->channel->center_freq; @@ -428,7 +434,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, if (data == data2) continue; - if (!data2->started || !hwsim_ps_rx_ok(data2, skb) || + if (data2->idle || !data2->started || + !hwsim_ps_rx_ok(data2, skb) || !data->channel || !data2->channel || data->channel->center_freq != data2->channel->center_freq || !(data->group & data2->group)) @@ -571,6 +578,8 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) !!(conf->flags & IEEE80211_CONF_IDLE), !!(conf->flags & IEEE80211_CONF_PS)); + data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); + data->channel = conf->channel; if (!data->started || !data->beacon_int) del_timer(&data->beacon_timer); -- cgit v1.2.3 From 6c085227bd7168fd84976479218f81bf35b5acd7 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 1 Nov 2009 11:31:45 +0200 Subject: mac80211_hwsim: Send ACK frames on the hwsim0 interface Report successful transmissions (receiver awake and on the same channel) by generating ACK frames on the hwsim0 interface. This makes it easier to figure out from packet capture logs whether frames were delivered or not. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 58c357eaf216..fc4ec48eda12 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -365,6 +365,49 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, } +static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr) +{ + struct mac80211_hwsim_data *data = hw->priv; + struct sk_buff *skb; + struct hwsim_radiotap_hdr *hdr; + u16 flags; + struct ieee80211_hdr *hdr11; + + if (!netif_running(hwsim_mon)) + return; + + skb = dev_alloc_skb(100); + if (skb == NULL) + return; + + hdr = (struct hwsim_radiotap_hdr *) skb_put(skb, sizeof(*hdr)); + hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION; + hdr->hdr.it_pad = 0; + hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); + hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_CHANNEL)); + hdr->rt_flags = 0; + hdr->rt_rate = 0; + hdr->rt_channel = cpu_to_le16(data->channel->center_freq); + flags = IEEE80211_CHAN_2GHZ; + hdr->rt_chbitmask = cpu_to_le16(flags); + + hdr11 = (struct ieee80211_hdr *) skb_put(skb, 10); + hdr11->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | + IEEE80211_STYPE_ACK); + hdr11->duration_id = cpu_to_le16(0); + memcpy(hdr11->addr1, addr, ETH_ALEN); + + skb->dev = hwsim_mon; + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); +} + + static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, struct sk_buff *skb) { @@ -471,6 +514,10 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) } ack = mac80211_hwsim_tx_frame(hw, skb); + if (ack && skb->len >= 16) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + mac80211_hwsim_monitor_ack(hw, hdr->addr2); + } txi = IEEE80211_SKB_CB(skb); -- cgit v1.2.3 From c6317a548d839e6f518649a4e7e9aa30b55d509a Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 2 Nov 2009 20:22:08 +0200 Subject: wl1271: Remove excess null-data template settings The null-data template (nullfunc) is dependent on the BSSID of the current AP only, so it needs to be updated only when the BSSID changes. Removed excess setting of the template. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 86132bb00787..0ae506a2e90b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1067,11 +1067,11 @@ static int wl1271_op_config_interface(struct ieee80211_hw *hw, ret = wl1271_cmd_join(wl); if (ret < 0) goto out_sleep; - } - ret = wl1271_cmd_build_null_data(wl); - if (ret < 0) - goto out_sleep; + ret = wl1271_cmd_build_null_data(wl); + if (ret < 0) + goto out_sleep; + } wl->ssid_len = conf->ssid_len; if (wl->ssid_len) @@ -1137,10 +1137,6 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) wl->channel = channel; } - ret = wl1271_cmd_build_null_data(wl); - if (ret < 0) - goto out_sleep; - if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { wl1271_info("psm enabled"); @@ -1165,7 +1161,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (conf->power_level != wl->power_level) { ret = wl1271_acx_tx_power(wl, conf->power_level); if (ret < 0) - goto out; + goto out_sleep; wl->power_level = conf->power_level; } -- cgit v1.2.3 From 605351e2220bd7960a55d6d7903f87f11f419f4e Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 2 Nov 2009 20:22:09 +0200 Subject: wl1271: Increase TX power value Currently, to avoid distortions, the TX power level has been hardcoded to a low value. The value is slightly too low for good functionality, so we increase it from 7dB to 12dB. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_acx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index bf5a8680a462..5cc89bbdac7a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -141,7 +141,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power) * calibration, to avoid distortions */ /* acx->current_tx_power = power * 10; */ - acx->current_tx_power = 70; + acx->current_tx_power = 120; ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); if (ret < 0) { -- cgit v1.2.3 From 3b775b4b27818130291e7716f3ce1e24664004c9 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 2 Nov 2009 20:22:10 +0200 Subject: wl1271: Check result code of commands Check the result code of all commands, and return an error code if the firmware reports an error in execution. Previously this error would go ignored in most cases. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 34 ++++++++----------------------- drivers/net/wireless/wl12xx/wl1271_init.c | 7 +++++-- 2 files changed, 14 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 0666328ce9ab..46e5ea48651b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -74,6 +74,15 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); } + /* read back the status code of the command */ + wl1271_spi_read(wl, wl->cmd_box_addr, cmd, + sizeof(struct wl1271_cmd_header), false); + + if (cmd->status != CMD_STATUS_SUCCESS) { + wl1271_error("command execute failure %d", cmd->status); + ret = -EIO; + } + wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); @@ -306,7 +315,6 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) if (answer) { struct wl1271_command *cmd_answer; - u16 status; /* * The test command got in, we can read the answer. @@ -316,10 +324,6 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) wl1271_spi_read(wl, wl->cmd_box_addr, buf, buf_len, false); cmd_answer = buf; - status = le16_to_cpu(cmd_answer->header.status); - - if (status != CMD_STATUS_SUCCESS) - wl1271_error("TEST command answer error: %d", status); } return 0; @@ -354,11 +358,6 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) /* the interrogate command got in, we can read the answer */ wl1271_spi_read(wl, wl->cmd_box_addr, buf, len, false); - acx = buf; - if (le16_to_cpu(acx->cmd.status) != CMD_STATUS_SUCCESS) - wl1271_error("INTERROGATE command error: %d", - le16_to_cpu(acx->cmd.status)); - out: return ret; } @@ -507,11 +506,6 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, /* the read command got in, we can now read the answer */ wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd), false); - - if (le16_to_cpu(cmd->header.status) != CMD_STATUS_SUCCESS) - wl1271_error("error in read command result: %d", - le16_to_cpu(cmd->header.status)); - memcpy(answer, cmd->value, len); out: @@ -639,17 +633,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); if (ret < 0) { wl1271_error("SCAN failed"); - goto out; - } - - wl1271_spi_read(wl, wl->cmd_box_addr, params, sizeof(*params), - false); - - if (le16_to_cpu(params->header.status) != CMD_STATUS_SUCCESS) { - wl1271_error("Scan command error: %d", - le16_to_cpu(params->header.status)); wl->scanning = false; - ret = -EIO; goto out; } diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 417b4152feb1..7c2017f480ea 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -303,12 +303,15 @@ int wl1271_hw_init(struct wl1271 *wl) { int ret; + /* FIXME: the following parameter setting functions return error + * codes - the reason is so far unknown. The -EIO is therefore + * ignored for the time being. */ ret = wl1271_init_general_parms(wl); - if (ret < 0) + if (ret < 0 && ret != -EIO) return ret; ret = wl1271_init_radio_parms(wl); - if (ret < 0) + if (ret < 0 && ret != -EIO) return ret; /* Template settings */ -- cgit v1.2.3 From 19ad0715d8d9acc259ef02f83df767df2cf1eafe Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 2 Nov 2009 20:22:11 +0200 Subject: wl1271: Add retry implementation for PSM entries PSM entries can fail (transmitting the corresponding null-func may not be heard by the AP.) Previously, this scenario was not detected, and out-of-sync between STA and AP could occur. Add retry implementation for the entries to recover from the situation. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271.h | 3 ++ drivers/net/wireless/wl12xx/wl1271_boot.c | 3 +- drivers/net/wireless/wl12xx/wl1271_conf.h | 8 +++++ drivers/net/wireless/wl12xx/wl1271_event.c | 53 ++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_event.h | 7 ++++ drivers/net/wireless/wl12xx/wl1271_main.c | 5 ++- 6 files changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 566f1521ec22..94359b1a861f 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -417,6 +417,9 @@ struct wl1271 { /* PSM mode requested */ bool psm_requested; + /* retry counter for PSM entries */ + u8 psm_entry_retry; + /* in dBm */ int power_level; diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index 8678bea05ed5..b7c96454cca3 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -407,7 +407,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) /* unmask required mbox events */ wl->event_mask = BSS_LOSE_EVENT_ID | - SCAN_COMPLETE_EVENT_ID; + SCAN_COMPLETE_EVENT_ID | + PS_REPORT_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 061d47520a32..565373ede265 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h @@ -712,6 +712,14 @@ struct conf_conn_settings { * Range 0 - 255 */ u8 bet_max_consecutive; + + /* + * Specifies the maximum number of times to try PSM entry if it fails + * (if sending the appropriate null-func message fails.) + * + * Range 0 - 255 + */ + u8 psm_entry_retries; }; #define CONF_SR_ERR_TBL_MAX_VALUES 14 diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 31d396ba9188..e135d894b42a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -68,6 +68,40 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, return 0; } +static int wl1271_event_ps_report(struct wl1271 *wl, + struct event_mailbox *mbox, + bool *beacon_loss) +{ + int ret = 0; + + wl1271_debug(DEBUG_EVENT, "ps_status: 0x%x", mbox->ps_status); + + switch (mbox->ps_status) { + case EVENT_ENTER_POWER_SAVE_FAIL: + if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) { + wl->psm_entry_retry++; + wl1271_error("PSM entry failed, retrying %d\n", + wl->psm_entry_retry); + ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + } else { + wl->psm_entry_retry = 0; + *beacon_loss = true; + } + break; + case EVENT_ENTER_POWER_SAVE_SUCCESS: + wl->psm_entry_retry = 0; + break; + case EVENT_EXIT_POWER_SAVE_FAIL: + wl1271_info("PSM exit failed"); + break; + case EVENT_EXIT_POWER_SAVE_SUCCESS: + default: + break; + } + + return ret; +} + static void wl1271_event_mbox_dump(struct event_mailbox *mbox) { wl1271_debug(DEBUG_EVENT, "MBOX DUMP:"); @@ -79,6 +113,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) { int ret; u32 vector; + bool beacon_loss = false; wl1271_event_mbox_dump(mbox); @@ -101,7 +136,25 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); /* indicate to the stack, that beacons have been lost */ + beacon_loss = true; + } + + if (vector & PS_REPORT_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); + ret = wl1271_event_ps_report(wl, mbox, &beacon_loss); + if (ret < 0) + return ret; + } + + if (beacon_loss) { + /* Obviously, it's dangerous to release the mutex while + we are holding many of the variables in the wl struct. + That's why it's done last in the function, and care must + be taken that nothing more is done after this function + returns. */ + mutex_unlock(&wl->mutex); ieee80211_beacon_loss(wl->vif); + mutex_lock(&wl->mutex); } return 0; diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h index 3ab53d331f15..4e3f55ebb1a8 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.h +++ b/drivers/net/wireless/wl12xx/wl1271_event.h @@ -63,6 +63,13 @@ enum { EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, }; +enum { + EVENT_ENTER_POWER_SAVE_FAIL = 0, + EVENT_ENTER_POWER_SAVE_SUCCESS, + EVENT_EXIT_POWER_SAVE_FAIL, + EVENT_EXIT_POWER_SAVE_SUCCESS, +}; + struct event_debug_report { u8 debug_event_id; u8 num_params; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 0ae506a2e90b..d2149fcd3cf1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -222,7 +222,8 @@ static struct conf_drv_settings default_conf = { .snr_pkt_avg_weight = 10 }, .bet_enable = CONF_BET_MODE_ENABLE, - .bet_max_consecutive = 100 + .bet_max_consecutive = 100, + .psm_entry_retries = 3 }, .init = { .sr_err_tbl = { @@ -973,6 +974,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->rx_counter = 0; wl->elp = false; wl->psm = 0; + wl->psm_entry_retry = 0; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; @@ -1822,6 +1824,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) wl->elp = false; wl->psm = 0; wl->psm_requested = false; + wl->psm_entry_retry = 0; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; -- cgit v1.2.3 From ad150e966e987edcf737e1871d9e44a30d1aa58d Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 2 Nov 2009 20:22:12 +0200 Subject: wl1271: Correct endianness-handling of command status Correct the endianness-handling of the firmware command result status handling code. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 46e5ea48651b..8acee5cf0e61 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -48,6 +48,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) unsigned long timeout; u32 intr; int ret = 0; + u16 status; cmd = buf; cmd->id = cpu_to_le16(id); @@ -78,8 +79,9 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(struct wl1271_cmd_header), false); - if (cmd->status != CMD_STATUS_SUCCESS) { - wl1271_error("command execute failure %d", cmd->status); + status = le16_to_cpu(cmd->status); + if (status != CMD_STATUS_SUCCESS) { + wl1271_error("command execute failure %d", status); ret = -EIO; } -- cgit v1.2.3 From fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028a Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 2 Nov 2009 20:22:13 +0200 Subject: wl1271: Generalize command response reading Responses to firmware commands are read in by the command transmission function, as part of command flow. Previously responses were read in multiple places. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 67 +++++++++++++------------------- drivers/net/wireless/wl12xx/wl1271_cmd.h | 3 +- 2 files changed, 29 insertions(+), 41 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 8acee5cf0e61..990eb01b4c71 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -42,7 +42,8 @@ * @buf: buffer containing the command, must work with dma * @len: length of the buffer */ -int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) +int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, + size_t res_len) { struct wl1271_cmd_header *cmd; unsigned long timeout; @@ -76,8 +77,9 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) } /* read back the status code of the command */ - wl1271_spi_read(wl, wl->cmd_box_addr, cmd, - sizeof(struct wl1271_cmd_header), false); + if (res_len == 0) + res_len = sizeof(struct wl1271_cmd_header); + wl1271_spi_read(wl, wl->cmd_box_addr, cmd, res_len, false); status = le16_to_cpu(cmd->status); if (status != CMD_STATUS_SUCCESS) { @@ -273,7 +275,7 @@ int wl1271_cmd_join(struct wl1271 *wl) wl->tx_security_seq_16 = 0; wl->tx_security_seq_32 = 0; - ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); + ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0); if (ret < 0) { wl1271_error("failed to initiate cmd join"); goto out_free; @@ -305,30 +307,21 @@ out: int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) { int ret; + size_t res_len = 0; wl1271_debug(DEBUG_CMD, "cmd test"); - ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len); + if (answer) + res_len = buf_len; + + ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len); if (ret < 0) { wl1271_warning("TEST command failed"); return ret; } - if (answer) { - struct wl1271_command *cmd_answer; - - /* - * The test command got in, we can read the answer. - * The answer would be a wl1271_command, where the - * parameter array contains the actual answer. - */ - wl1271_spi_read(wl, wl->cmd_box_addr, buf, buf_len, false); - - cmd_answer = buf; - } - - return 0; + return ret; } /** @@ -351,16 +344,10 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) /* payload length, does not include any headers */ acx->len = cpu_to_le16(len - sizeof(*acx)); - ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); - if (ret < 0) { + ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len); + if (ret < 0) wl1271_error("INTERROGATE command failed"); - goto out; - } - - /* the interrogate command got in, we can read the answer */ - wl1271_spi_read(wl, wl->cmd_box_addr, buf, len, false); -out: return ret; } @@ -384,7 +371,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) /* payload length, does not include any headers */ acx->len = cpu_to_le16(len - sizeof(*acx)); - ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len); + ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0); if (ret < 0) { wl1271_warning("CONFIGURE command NOK"); return ret; @@ -417,7 +404,7 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) cmd_tx = CMD_DISABLE_TX; } - ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("rx %s cmd for channel %d failed", enable ? "start" : "stop", channel); @@ -427,7 +414,7 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", enable ? "start" : "stop", channel); - ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("tx %s cmd for channel %d failed", enable ? "start" : "stop", channel); @@ -469,7 +456,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */ ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, - sizeof(*ps_params)); + sizeof(*ps_params), 0); if (ret < 0) { wl1271_error("cmd set_ps_mode failed"); goto out; @@ -500,14 +487,14 @@ int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, cmd->addr = cpu_to_le32(addr); cmd->size = cpu_to_le32(len); - ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd), + sizeof(*cmd)); if (ret < 0) { wl1271_error("read memory command failed: %d", ret); goto out; } - /* the read command got in, we can now read the answer */ - wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd), false); + /* the read command got in */ memcpy(answer, cmd->value, len); out: @@ -609,7 +596,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, trigger->timeout = 0; ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, - sizeof(*trigger)); + sizeof(*trigger), 0); if (ret < 0) { wl1271_error("trigger scan to failed for hw scan"); goto out; @@ -632,7 +619,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, } } - ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); + ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); if (ret < 0) { wl1271_error("SCAN failed"); wl->scanning = false; @@ -670,7 +657,7 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, if (buf) memcpy(cmd->template_data, buf, buf_len); - ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("cmd set_template failed: %d", ret); goto out_free; @@ -849,7 +836,7 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) cmd->key_action = cpu_to_le16(KEY_SET_ID); cmd->key_type = KEY_WEP; - ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("cmd set_default_wep_key failed: %d", ret); goto out; @@ -906,7 +893,7 @@ int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); - ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_warning("could not set keys"); goto out; @@ -936,7 +923,7 @@ int wl1271_cmd_disconnect(struct wl1271 *wl) /* disconnect reason is not used in immediate disconnections */ cmd->type = DISCONNECT_IMMEDIATE; - ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd)); + ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0); if (ret < 0) { wl1271_error("failed to send disconnect command"); goto out_free; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 174b8209dbf3..9d7061b3c8a0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -29,7 +29,8 @@ struct acx_header; -int wl1271_cmd_send(struct wl1271 *wl, u16 type, void *buf, size_t buf_len); +int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, + size_t res_len); int wl1271_cmd_join(struct wl1271 *wl); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); -- cgit v1.2.3 From 3c6af5b54fe74b6e56efadc22927e4055d00e9fc Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 2 Nov 2009 13:43:32 -0500 Subject: wl1271: depend on INET wl1271_main.c:(.text+0x271052): undefined reference to `unregister_inetaddr_notifier' wl1271_main.c:(.text+0x2714d7): undefined reference to `register_inetaddr_notifier' Driver is doing some filtering based on IP addresses... Acked-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 33de7fa4f882..785e0244e305 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -42,6 +42,7 @@ config WL1251_SDIO config WL1271 tristate "TI wl1271 support" depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS + depends on INET select FW_LOADER select CRC7 ---help--- -- cgit v1.2.3 From 8848fd253bb26f09987405613bad3e0d53441ec0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:19:23 +0200 Subject: mwl8k: fix GET_STAT firmware command packet layout The GET_STAT command doesn't have an 'action' field like other commands do, so remove it. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 746532ebe5a8..32499984e917 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1590,7 +1590,6 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, */ struct mwl8k_cmd_802_11_get_stat { struct mwl8k_cmd_pkt header; - __le16 action; __le32 stats[64]; } __attribute__((packed)); @@ -1611,7 +1610,6 @@ static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_STAT); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->action = cpu_to_le16(MWL8K_CMD_GET); rc = mwl8k_post_cmd(hw, &cmd->header); if (!rc) { -- cgit v1.2.3 From c2c357ce309221b85fd36e50aade66d01a556cde Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:19:33 +0200 Subject: mwl8k: coding style cleanups Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 122 +++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 57 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 32499984e917..252ef9c83364 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -27,11 +27,6 @@ #define MWL8K_NAME KBUILD_MODNAME #define MWL8K_VERSION "0.10" -MODULE_DESCRIPTION(MWL8K_DESC); -MODULE_VERSION(MWL8K_VERSION); -MODULE_AUTHOR("Lennert Buytenhek "); -MODULE_LICENSE("GPL"); - static DEFINE_PCI_DEVICE_TABLE(mwl8k_table) = { { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = 8687, }, { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = 8687, }, @@ -138,7 +133,6 @@ struct mwl8k_priv { struct ieee80211_hw *hw; struct pci_dev *pdev; - u8 name[16]; /* firmware files and meta data */ struct mwl8k_firmware fw; @@ -353,14 +347,14 @@ static void mwl8k_release_firmware(struct mwl8k_priv *priv) /* Request fw image */ static int mwl8k_request_fw(struct mwl8k_priv *priv, - const char *fname, struct firmware **fw) + const char *fname, struct firmware **fw) { /* release current image */ if (*fw != NULL) mwl8k_release_fw(fw); return request_firmware((const struct firmware **)fw, - fname, &priv->pdev->dev); + fname, &priv->pdev->dev); } static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num) @@ -375,9 +369,8 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num) rc = mwl8k_request_fw(priv, filename, &priv->fw.helper); if (rc) { - printk(KERN_ERR - "%s Error requesting helper firmware file %s\n", - pci_name(priv->pdev), filename); + printk(KERN_ERR "%s: Error requesting helper firmware " + "file %s\n", pci_name(priv->pdev), filename); return rc; } @@ -386,8 +379,8 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num) rc = mwl8k_request_fw(priv, filename, &priv->fw.ucode); if (rc) { - printk(KERN_ERR "%s Error requesting firmware file %s\n", - pci_name(priv->pdev), filename); + printk(KERN_ERR "%s: Error requesting firmware file %s\n", + pci_name(priv->pdev), filename); mwl8k_release_fw(&priv->fw.helper); return rc; } @@ -542,32 +535,38 @@ static int mwl8k_feed_fw_image(struct mwl8k_priv *priv, return rc; } -static int mwl8k_load_firmware(struct mwl8k_priv *priv) +static int mwl8k_load_firmware(struct ieee80211_hw *hw) { - int loops, rc; + struct mwl8k_priv *priv = hw->priv; + struct firmware *fw = priv->fw.ucode; + int rc; + int loops; + + if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) { + struct firmware *helper = priv->fw.helper; - const u8 *ucode = priv->fw.ucode->data; - size_t ucode_len = priv->fw.ucode->size; - const u8 *helper = priv->fw.helper->data; - size_t helper_len = priv->fw.helper->size; + if (helper == NULL) { + printk(KERN_ERR "%s: helper image needed but none " + "given\n", pci_name(priv->pdev)); + return -EINVAL; + } - if (!memcmp(ucode, "\x01\x00\x00\x00", 4)) { - rc = mwl8k_load_fw_image(priv, helper, helper_len); + rc = mwl8k_load_fw_image(priv, helper->data, helper->size); if (rc) { printk(KERN_ERR "%s: unable to load firmware " - "helper image\n", pci_name(priv->pdev)); + "helper image\n", pci_name(priv->pdev)); return rc; } msleep(1); - rc = mwl8k_feed_fw_image(priv, ucode, ucode_len); + rc = mwl8k_feed_fw_image(priv, fw->data, fw->size); } else { - rc = mwl8k_load_fw_image(priv, ucode, ucode_len); + rc = mwl8k_load_fw_image(priv, fw->data, fw->size); } if (rc) { - printk(KERN_ERR "%s: unable to load firmware data\n", - pci_name(priv->pdev)); + printk(KERN_ERR "%s: unable to load firmware image\n", + pci_name(priv->pdev)); return rc; } @@ -772,7 +771,7 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) pci_alloc_consistent(priv->pdev, size, &rxq->rx_desc_dma); if (rxq->rx_desc_area == NULL) { printk(KERN_ERR "%s: failed to alloc RX descriptors\n", - priv->name); + wiphy_name(hw->wiphy)); return -ENOMEM; } memset(rxq->rx_desc_area, 0, size); @@ -781,7 +780,7 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) sizeof(*rxq->rx_skb), GFP_KERNEL); if (rxq->rx_skb == NULL) { printk(KERN_ERR "%s: failed to alloc RX skbuff list\n", - priv->name); + wiphy_name(hw->wiphy)); pci_free_consistent(priv->pdev, size, rxq->rx_desc_area, rxq->rx_desc_dma); return -ENOMEM; @@ -934,9 +933,9 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) wh = (struct ieee80211_hdr *)skb->data; /* - * Check for pending join operation. save a copy of - * the beacon and schedule a tasklet to send finalize - * join command to the firmware. + * Check for a pending join operation. Save a + * copy of the beacon and schedule a tasklet to + * send a FINALIZE_JOIN command to the firmware. */ if (mwl8k_capture_bssid(priv, wh)) mwl8k_save_beacon(priv, skb); @@ -1024,7 +1023,7 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) pci_alloc_consistent(priv->pdev, size, &txq->tx_desc_dma); if (txq->tx_desc_area == NULL) { printk(KERN_ERR "%s: failed to alloc TX descriptors\n", - priv->name); + wiphy_name(hw->wiphy)); return -ENOMEM; } memset(txq->tx_desc_area, 0, size); @@ -1033,7 +1032,7 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) GFP_KERNEL); if (txq->tx_skb == NULL) { printk(KERN_ERR "%s: failed to alloc TX skbuff list\n", - priv->name); + wiphy_name(hw->wiphy)); pci_free_consistent(priv->pdev, size, txq->tx_desc_area, txq->tx_desc_dma); return -ENOMEM; @@ -1154,8 +1153,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) mwl8k_scan_tx_ring(priv, txinfo); for (index = 0; index < MWL8K_TX_QUEUES; index++) - printk(KERN_ERR - "TXQ:%u L:%u H:%u T:%u FW:%u DRV:%u U:%u\n", + printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u " + "DRV:%u U:%u\n", index, txinfo[index].len, txinfo[index].head, @@ -1317,7 +1316,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (pci_dma_mapping_error(priv->pdev, dma)) { printk(KERN_DEBUG "%s: failed to dma map skb, " - "dropping TX frame.\n", priv->name); + "dropping TX frame.\n", wiphy_name(hw->wiphy)); dev_kfree_skb(skb); return NETDEV_TX_OK; } @@ -1431,7 +1430,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) unsigned long timeout = 0; u8 buf[32]; - cmd->result = 0xFFFF; + cmd->result = 0xffff; dma_size = le16_to_cpu(cmd->length); dma_addr = pci_map_single(priv->pdev, cmd, dma_size, PCI_DMA_BIDIRECTIONAL); @@ -1464,7 +1463,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) if (!timeout) { printk(KERN_ERR "%s: Command %s timeout after %u ms\n", - priv->name, + wiphy_name(hw->wiphy), mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), MWL8K_CMD_TIMEOUT_MS); rc = -ETIMEDOUT; @@ -1472,7 +1471,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) rc = cmd->result ? -EINVAL : 0; if (rc) printk(KERN_ERR "%s: Command %s error 0x%x\n", - priv->name, + wiphy_name(hw->wiphy), mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), le16_to_cpu(cmd->result)); } @@ -2091,8 +2090,8 @@ static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame, /* XXX TBD Might just have to abort and return an error */ if (payload_len > MWL8K_FJ_BEACON_MAXLEN) printk(KERN_ERR "%s(): WARNING: Incomplete beacon " - "sent to firmware. Sz=%u MAX=%u\n", __func__, - payload_len, MWL8K_FJ_BEACON_MAXLEN); + "sent to firmware. Sz=%u MAX=%u\n", __func__, + payload_len, MWL8K_FJ_BEACON_MAXLEN); if (payload_len > MWL8K_FJ_BEACON_MAXLEN) payload_len = MWL8K_FJ_BEACON_MAXLEN; @@ -2339,9 +2338,10 @@ static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw, cmd->rate_type = cpu_to_le32(rate_type); if (rate_table != NULL) { - /* Copy over each field manually so - * that bitflipping can be done - */ + /* + * Copy over each field manually so that endian + * conversion can be done. + */ cmd->rate_table.allow_rate_drop = cpu_to_le32(rate_table->allow_rate_drop); cmd->rate_table.num_rates = @@ -2416,7 +2416,7 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (priv->current_channel == NULL) { printk(KERN_DEBUG "%s: dropped TX frame since radio " - "disabled\n", priv->name); + "disabled\n", wiphy_name(hw->wiphy)); dev_kfree_skb(skb); return NETDEV_TX_OK; } @@ -2435,7 +2435,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) IRQF_SHARED, MWL8K_NAME, hw); if (rc) { printk(KERN_ERR "%s: failed to register IRQ handler\n", - priv->name); + wiphy_name(hw->wiphy)); return -EIO; } @@ -2862,14 +2862,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->pdev = pdev; priv->wmm_enabled = false; priv->pending_tx_pkts = 0; - strncpy(priv->name, MWL8K_NAME, sizeof(priv->name)); SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); priv->regs = pci_iomap(pdev, 1, 0x10000); if (priv->regs == NULL) { - printk(KERN_ERR "%s: Cannot map device memory\n", priv->name); + printk(KERN_ERR "%s: Cannot map device memory\n", + wiphy_name(hw->wiphy)); goto err_iounmap; } @@ -2952,7 +2952,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { printk(KERN_ERR "%s: failed to register IRQ handler\n", - priv->name); + wiphy_name(hw->wiphy)); goto err_free_queues; } @@ -2962,14 +2962,16 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Ask userland hotplug daemon for the device firmware */ rc = mwl8k_request_firmware(priv, (u32)id->driver_data); if (rc) { - printk(KERN_ERR "%s: Firmware files not found\n", priv->name); + printk(KERN_ERR "%s: Firmware files not found\n", + wiphy_name(hw->wiphy)); goto err_free_irq; } /* Load firmware into hardware */ - rc = mwl8k_load_firmware(priv); + rc = mwl8k_load_firmware(hw); if (rc) { - printk(KERN_ERR "%s: Cannot start firmware\n", priv->name); + printk(KERN_ERR "%s: Cannot start firmware\n", + wiphy_name(hw->wiphy)); goto err_stop_firmware; } @@ -2986,14 +2988,15 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Get config data, mac addrs etc */ rc = mwl8k_cmd_get_hw_spec(hw); if (rc) { - printk(KERN_ERR "%s: Cannot initialise firmware\n", priv->name); + printk(KERN_ERR "%s: Cannot initialise firmware\n", + wiphy_name(hw->wiphy)); goto err_stop_firmware; } /* Turn radio off */ rc = mwl8k_cmd_802_11_radio_disable(hw); if (rc) { - printk(KERN_ERR "%s: Cannot disable\n", priv->name); + printk(KERN_ERR "%s: Cannot disable\n", wiphy_name(hw->wiphy)); goto err_stop_firmware; } @@ -3003,7 +3006,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, rc = ieee80211_register_hw(hw); if (rc) { - printk(KERN_ERR "%s: Cannot register device\n", priv->name); + printk(KERN_ERR "%s: Cannot register device\n", + wiphy_name(hw->wiphy)); goto err_stop_firmware; } @@ -3086,8 +3090,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) mwl8k_rxq_deinit(hw, 0); - pci_free_consistent(priv->pdev, 4, - priv->cookie, priv->cookie_dma); + pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); pci_iounmap(pdev, priv->regs); pci_set_drvdata(pdev, NULL); @@ -3116,3 +3119,8 @@ static void __exit mwl8k_exit(void) module_init(mwl8k_init); module_exit(mwl8k_exit); + +MODULE_DESCRIPTION(MWL8K_DESC); +MODULE_VERSION(MWL8K_VERSION); +MODULE_AUTHOR("Lennert Buytenhek "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 88de754ad59025eba797e7a8375807755577f450 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:19:37 +0200 Subject: mwl8k: minor transmit quiescing rework Minor changes to the transmit quiescing logic: - Clarify the locking rules for ->tx_wait: only the holder of fw_mutex can wait for the TX path to become idle, but tx_wait itself is read and cleared by the TX reclaim tasklet under tx_lock. - Inline mwl8k_txq_busy() in its callers. - There's no need to kick the transmitter again in mwl8k_tx_wait_empty(), since it will have been kicked when the packets currently in the TX ring were added to it. - If the TX ring didn't drain in time, run mwl8k_scan_tx_ring() after reading priv->pending_pkts without dropping tx_lock in between. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 252ef9c83364..ba7b8efea778 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -142,12 +142,14 @@ struct mwl8k_priv { struct mutex fw_mutex; struct task_struct *fw_mutex_owner; int fw_mutex_depth; - struct completion *tx_wait; struct completion *hostcmd_wait; /* lock held over TX and TX reap */ spinlock_t tx_lock; + /* TX quiesce completion, protected by fw_mutex and tx_lock */ + struct completion *tx_wait; + struct ieee80211_vif *vif; struct ieee80211_channel *current_channel; @@ -1064,11 +1066,6 @@ static inline void mwl8k_tx_start(struct mwl8k_priv *priv) ioread32(priv->regs + MWL8K_HIU_INT_CODE); } -static inline int mwl8k_txq_busy(struct mwl8k_priv *priv) -{ - return priv->pending_tx_pkts; -} - struct mwl8k_txq_info { u32 fw_owned; u32 drv_owned; @@ -1088,7 +1085,6 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, memset(txinfo, 0, MWL8K_TX_QUEUES * sizeof(struct mwl8k_txq_info)); - spin_lock_bh(&priv->tx_lock); for (count = 0; count < MWL8K_TX_QUEUES; count++) { txq = priv->txq + count; txinfo[count].len = txq->tx_stats.len; @@ -1107,30 +1103,26 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, txinfo[count].unused++; } } - spin_unlock_bh(&priv->tx_lock); return ndescs; } /* - * Must be called with hw->fw_mutex held and tx queues stopped. + * Must be called with priv->fw_mutex held and tx queues stopped. */ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; - DECLARE_COMPLETION_ONSTACK(cmd_wait); + DECLARE_COMPLETION_ONSTACK(tx_wait); u32 count; unsigned long timeout; might_sleep(); spin_lock_bh(&priv->tx_lock); - count = mwl8k_txq_busy(priv); - if (count) { - priv->tx_wait = &cmd_wait; - if (priv->radio_on) - mwl8k_tx_start(priv); - } + count = priv->pending_tx_pkts; + if (count) + priv->tx_wait = &tx_wait; spin_unlock_bh(&priv->tx_lock); if (count) { @@ -1138,20 +1130,20 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) int index; int newcount; - timeout = wait_for_completion_timeout(&cmd_wait, + timeout = wait_for_completion_timeout(&tx_wait, msecs_to_jiffies(5000)); if (timeout) return 0; spin_lock_bh(&priv->tx_lock); priv->tx_wait = NULL; - newcount = mwl8k_txq_busy(priv); + newcount = priv->pending_tx_pkts; + mwl8k_scan_tx_ring(priv, txinfo); spin_unlock_bh(&priv->tx_lock); printk(KERN_ERR "%s(%u) TIMEDOUT:5000ms Pend:%u-->%u\n", __func__, __LINE__, count, newcount); - mwl8k_scan_tx_ring(priv, txinfo); for (index = 0; index < MWL8K_TX_QUEUES; index++) printk(KERN_ERR "TXQ:%u L:%u H:%u T:%u FW:%u " "DRV:%u U:%u\n", @@ -2397,7 +2389,7 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) if (status & MWL8K_A2H_INT_QUEUE_EMPTY) { if (!mutex_is_locked(&priv->fw_mutex) && - priv->radio_on && mwl8k_txq_busy(priv)) + priv->radio_on && priv->pending_tx_pkts) mwl8k_tx_start(priv); } @@ -2800,7 +2792,7 @@ static void mwl8k_tx_reclaim_handler(unsigned long data) for (i = 0; i < MWL8K_TX_QUEUES; i++) mwl8k_txq_reclaim(hw, i, 0); - if (priv->tx_wait != NULL && mwl8k_txq_busy(priv) == 0) { + if (priv->tx_wait != NULL && !priv->pending_tx_pkts) { complete(priv->tx_wait); priv->tx_wait = NULL; } @@ -2932,11 +2924,12 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, mutex_init(&priv->fw_mutex); priv->fw_mutex_owner = NULL; priv->fw_mutex_depth = 0; - priv->tx_wait = NULL; priv->hostcmd_wait = NULL; spin_lock_init(&priv->tx_lock); + priv->tx_wait = NULL; + for (i = 0; i < MWL8K_TX_QUEUES; i++) { rc = mwl8k_txq_init(hw, i); if (rc) -- cgit v1.2.3 From d5e308457e8e9b4988fbd69d38c30782125b3f65 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:19:41 +0200 Subject: mwl8k: fix multicast address filter programming mwl8k's ->prepare_multicast() currently just enables reception of all multicast packets, which is somewhat ineffective. Fix this by either disabling all multicast RX, enabling multicast RX according to the multicast address filter table, or enabling all multicast RX, depending on whether ->prepare_multicast() was given any multicast addresses and whether the hardware multicast address filter table is large enough to fit all requested addresses. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index ba7b8efea778..0b4fa14aa176 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1539,7 +1539,10 @@ struct mwl8k_cmd_mac_multicast_adr { __u8 addr[0][ETH_ALEN]; }; -#define MWL8K_ENABLE_RX_MULTICAST 0x000F +#define MWL8K_ENABLE_RX_DIRECTED 0x0001 +#define MWL8K_ENABLE_RX_MULTICAST 0x0002 +#define MWL8K_ENABLE_RX_ALL_MULTICAST 0x0004 +#define MWL8K_ENABLE_RX_BROADCAST 0x0008 static struct mwl8k_cmd_pkt * __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, @@ -1547,11 +1550,14 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_mac_multicast_adr *cmd; + int allmulti; int size; - int i; - if (mc_count > priv->num_mcaddrs) - mc_count = priv->num_mcaddrs; + allmulti = 0; + if (mc_count > priv->num_mcaddrs) { + allmulti = 1; + mc_count = 0; + } size = sizeof(*cmd) + mc_count * ETH_ALEN; @@ -1561,16 +1567,24 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR); cmd->header.length = cpu_to_le16(size); - cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); - cmd->numaddr = cpu_to_le16(mc_count); - - for (i = 0; i < mc_count && mclist; i++) { - if (mclist->da_addrlen != ETH_ALEN) { - kfree(cmd); - return NULL; + cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_DIRECTED | + MWL8K_ENABLE_RX_BROADCAST); + + if (allmulti) { + cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_ALL_MULTICAST); + } else if (mc_count) { + int i; + + cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); + cmd->numaddr = cpu_to_le16(mc_count); + for (i = 0; i < mc_count && mclist; i++) { + if (mclist->da_addrlen != ETH_ALEN) { + kfree(cmd); + return NULL; + } + memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN); + mclist = mclist->next; } - memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN); - mclist = mclist->next; } return &cmd->header; -- cgit v1.2.3 From 3779752d764b86077375510b1fd13d8fb2c7c3a5 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:19:45 +0200 Subject: mwl8k: use the mac80211-provided workqueue instead of creating our own Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 0b4fa14aa176..77985e9a13a2 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -195,9 +195,6 @@ struct mwl8k_priv { /* Tasklet to reclaim TX descriptors and buffers after tx */ struct tasklet_struct tx_reclaim_task; - - /* Work thread to serialize configuration requests */ - struct workqueue_struct *config_wq; }; /* Per interface specific private data */ @@ -881,9 +878,11 @@ mwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh) !compare_ether_addr(wh->addr3, priv->capture_bssid); } -static inline void mwl8k_save_beacon(struct mwl8k_priv *priv, - struct sk_buff *skb) +static inline void mwl8k_save_beacon(struct ieee80211_hw *hw, + struct sk_buff *skb) { + struct mwl8k_priv *priv = hw->priv; + priv->capture_beacon = false; memset(priv->capture_bssid, 0, ETH_ALEN); @@ -894,8 +893,7 @@ static inline void mwl8k_save_beacon(struct mwl8k_priv *priv, */ priv->beacon_skb = skb_copy(skb, GFP_ATOMIC); if (priv->beacon_skb != NULL) - queue_work(priv->config_wq, - &priv->finalize_join_worker); + ieee80211_queue_work(hw, &priv->finalize_join_worker); } static int rxq_process(struct ieee80211_hw *hw, int index, int limit) @@ -940,7 +938,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) * send a FINALIZE_JOIN command to the firmware. */ if (mwl8k_capture_bssid(priv, wh)) - mwl8k_save_beacon(priv, skb); + mwl8k_save_beacon(hw, skb); memset(&status, 0, sizeof(status)); status.mactime = 0; @@ -2504,9 +2502,6 @@ static void mwl8k_stop(struct ieee80211_hw *hw) /* Stop tx reclaim tasklet */ tasklet_disable(&priv->tx_reclaim_task); - /* Stop config thread */ - flush_workqueue(priv->config_wq); - /* Return all skbs to mac80211 */ for (i = 0; i < MWL8K_TX_QUEUES; i++) mwl8k_txq_reclaim(hw, i, 1); @@ -2920,11 +2915,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, mwl8k_tx_reclaim_handler, (unsigned long)hw); tasklet_disable(&priv->tx_reclaim_task); - /* Config workthread */ - priv->config_wq = create_singlethread_workqueue("mwl8k_config"); - if (priv->config_wq == NULL) - goto err_iounmap; - /* Power management cookie */ priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); if (priv->cookie == NULL) @@ -3047,9 +3037,6 @@ err_iounmap: if (priv->regs != NULL) pci_iounmap(pdev, priv->regs); - if (priv->config_wq != NULL) - destroy_workqueue(priv->config_wq); - pci_set_drvdata(pdev, NULL); ieee80211_free_hw(hw); @@ -3082,9 +3069,6 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) /* Remove tx reclaim tasklet */ tasklet_kill(&priv->tx_reclaim_task); - /* Stop config thread */ - destroy_workqueue(priv->config_wq); - /* Stop hardware */ mwl8k_hw_reset(priv); -- cgit v1.2.3 From 447ced07d04525218ae586cd70b759b48bcb1fc8 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:19:50 +0200 Subject: mwl8k: implement FIF_ALLMULTI Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 77985e9a13a2..cc58ecba211a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1543,16 +1543,14 @@ struct mwl8k_cmd_mac_multicast_adr { #define MWL8K_ENABLE_RX_BROADCAST 0x0008 static struct mwl8k_cmd_pkt * -__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, +__mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti, int mc_count, struct dev_addr_list *mclist) { struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_mac_multicast_adr *cmd; - int allmulti; int size; - allmulti = 0; - if (mc_count > priv->num_mcaddrs) { + if (allmulti || mc_count > priv->num_mcaddrs) { allmulti = 1; mc_count = 0; } @@ -2680,7 +2678,14 @@ static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, { struct mwl8k_cmd_pkt *cmd; - cmd = __mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist); + /* + * Synthesize and return a command packet that programs the + * hardware multicast address filter. At this point we don't + * know whether FIF_ALLMULTI is being requested, but if it is, + * we'll end up throwing this packet away and creating a new + * one in mwl8k_configure_filter(). + */ + cmd = __mwl8k_cmd_mac_multicast_adr(hw, 0, mc_count, mclist); return (unsigned long)cmd; } @@ -2691,10 +2696,10 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct mwl8k_priv *priv = hw->priv; - struct mwl8k_cmd_pkt *multicast_adr_cmd; + struct mwl8k_cmd_pkt *cmd; /* Clear unsupported feature flags */ - *total_flags &= FIF_BCN_PRBRESP_PROMISC; + *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; if (mwl8k_fw_lock(hw)) return; @@ -2713,10 +2718,22 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, } } - multicast_adr_cmd = (void *)(unsigned long)multicast; - if (multicast_adr_cmd != NULL) { - mwl8k_post_cmd(hw, multicast_adr_cmd); - kfree(multicast_adr_cmd); + cmd = (void *)(unsigned long)multicast; + + /* + * If FIF_ALLMULTI is being requested, throw away the command + * packet that ->prepare_multicast() built and replace it with + * a command packet that enables reception of all multicast + * packets. + */ + if (*total_flags & FIF_ALLMULTI) { + kfree(cmd); + cmd = __mwl8k_cmd_mac_multicast_adr(hw, 1, 0, NULL); + } + + if (cmd != NULL) { + mwl8k_post_cmd(hw, cmd); + kfree(cmd); } mwl8k_fw_unlock(hw); -- cgit v1.2.3 From 77165d8809cda1a77bc8752148a6252d7735c12e Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:19:53 +0200 Subject: mwl8k: enforce FIF_BCN_PRBRESP_PROMISC when no STA interfaces are active When FIF_BCN_PRBRESP_PROMISC is not set, we enable the hardware's BSS filter so that we'll only see packets destined for our BSS. But if no STA interfaces have been configured, we would end up passing the BSSID 00:00:00:00:00:00 into the POST_SCAN command, which actually disables the hardware's BSS filter, as it's not a valid BSSID. Fix this by passing in 01:00:00:00:00:00 instead (the criterion is that the OUI part of the BSSID must be nonzero), and add comments to explain what PRE_SCAN and POST_SCAN do. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index cc58ecba211a..53447f6a0e54 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2705,12 +2705,23 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, return; if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { + /* + * Disable the BSS filter. + */ mwl8k_cmd_set_pre_scan(hw); - else { + } else { u8 *bssid; - bssid = "\x00\x00\x00\x00\x00\x00"; + /* + * Enable the BSS filter. + * + * If there is an active STA interface, use that + * interface's BSSID, otherwise use a dummy one + * (where the OUI part needs to be nonzero for + * the BSSID to be accepted by POST_SCAN). + */ + bssid = "\x01\x00\x00\x00\x00\x00"; if (priv->vif != NULL) bssid = MWL8K_VIF(priv->vif)->bssid; -- cgit v1.2.3 From 32060e1b64f23fe315a35d2df8c2c7ad010df73e Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:04 +0200 Subject: mwl8k: clear hardware MAC address if no STA interface configured If there is no STA interface configured, clear the hardware MAC address to prevent ACKing frames sent to our MAC address. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 53447f6a0e54..fcf7139c77c8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -280,6 +280,7 @@ static const struct ieee80211_rate mwl8k_rates[] = { #define MWL8K_CMD_MIMO_CONFIG 0x0125 #define MWL8K_CMD_USE_FIXED_RATE 0x0126 #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 +#define MWL8K_CMD_SET_MAC_ADDR 0x0202 #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 #define MWL8K_CMD_UPDATE_STADB 0x1123 @@ -309,6 +310,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(MIMO_CONFIG); MWL8K_CMDNAME(USE_FIXED_RATE); MWL8K_CMDNAME(ENABLE_SNIFFER); + MWL8K_CMDNAME(SET_MAC_ADDR); MWL8K_CMDNAME(SET_RATEADAPT_MODE); MWL8K_CMDNAME(UPDATE_STADB); default: @@ -1902,6 +1904,34 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) return rc; } +/* + * CMD_SET_MAC_ADDR. + */ +struct mwl8k_cmd_set_mac_addr { + struct mwl8k_cmd_pkt header; + __u8 mac_addr[ETH_ALEN]; +} __attribute__((packed)); + +static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) +{ + struct mwl8k_cmd_set_mac_addr *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + memcpy(cmd->mac_addr, mac, ETH_ALEN); + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + + /* * CMD_SET_RATEADAPT_MODE. */ @@ -2527,7 +2557,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, mwl8k_vif = MWL8K_VIF(conf->vif); memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); - /* Save the mac address */ + /* Set and save the mac address */ + mwl8k_set_mac_addr(hw, conf->mac_addr); memcpy(mwl8k_vif->mac_addr, conf->mac_addr, ETH_ALEN); /* Back pointer to parent config block */ @@ -2555,6 +2586,8 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, if (priv->vif == NULL) return; + mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); + priv->vif = NULL; } @@ -3025,6 +3058,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_stop_firmware; } + /* Clear MAC address */ + rc = mwl8k_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); + if (rc) { + printk(KERN_ERR "%s: Cannot clear MAC address\n", + wiphy_name(hw->wiphy)); + goto err_stop_firmware; + } + /* Disable interrupts */ iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); -- cgit v1.2.3 From 3d76e82c9538d8104e578ca460d35f214bfddfd3 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:16 +0200 Subject: mwl8k: use cond_resched() when loading firmware blocks Since each firmware block takes on the order of several hundred usec to upload to the hardware, using msleep in the inner loop would make the firmware loading process take a lot more time than just doing busy-waiting like we do now. But if we keep the busy-waiting, we can at least add a cond_resched() to the inner loop so that we give other tasks a chance to run while the firmware is being loaded. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index fcf7139c77c8..496d3c5097d5 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -428,6 +429,7 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length) break; } + cond_resched(); udelay(1); } while (--loops); -- cgit v1.2.3 From 22995b2411d4c5bbd832a54c4ef6ad3e24a2a34b Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:25 +0200 Subject: mwl8k: clarify WME transmit queue 0/1 swizzling Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 496d3c5097d5..76c9263f70ac 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -84,12 +84,6 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); MWL8K_A2H_INT_RX_READY | \ MWL8K_A2H_INT_TX_DONE) -/* WME stream classes */ -#define WME_AC_BE 0 /* best effort */ -#define WME_AC_BK 1 /* background */ -#define WME_AC_VI 2 /* video */ -#define WME_AC_VO 3 /* voice */ - #define MWL8K_RX_QUEUES 1 #define MWL8K_TX_QUEUES 4 @@ -968,24 +962,10 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) * Packet transmission. */ -/* Transmit queue assignment. */ -enum { - MWL8K_WME_AC_BK = 0, /* background access */ - MWL8K_WME_AC_BE = 1, /* best effort access */ - MWL8K_WME_AC_VI = 2, /* video access */ - MWL8K_WME_AC_VO = 3, /* voice access */ -}; - /* Transmit packet ACK policy */ #define MWL8K_TXD_ACK_POLICY_NORMAL 0 #define MWL8K_TXD_ACK_POLICY_BLOCKACK 3 -#define GET_TXQ(_ac) (\ - ((_ac) == WME_AC_VO) ? MWL8K_WME_AC_VO : \ - ((_ac) == WME_AC_VI) ? MWL8K_WME_AC_VI : \ - ((_ac) == WME_AC_BK) ? MWL8K_WME_AC_BK : \ - MWL8K_WME_AC_BE) - #define MWL8K_TXD_STATUS_OK 0x00000001 #define MWL8K_TXD_STATUS_OK_RETRY 0x00000002 #define MWL8K_TXD_STATUS_OK_MORE_RETRY 0x00000004 @@ -2069,6 +2049,12 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, if (cmd == NULL) return -ENOMEM; + /* + * Queues 0 (BE) and 1 (BK) are swapped in hardware for + * this call. + */ + qnum ^= !(qnum >> 1); + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); -- cgit v1.2.3 From 5dfd3e2c6fb69cf4295ec139107f4ebd3f7fbff0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:29 +0200 Subject: mwl8k: report rate and other information for received frames When receiving a frame, report the antenna info, long/short preamble status, 20/40 MHz flag, long/short guard interval status, MCS/legacy rate status, and MCS/legacy rate index to the stack. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 76c9263f70ac..75c9261abad8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -169,7 +169,7 @@ struct mwl8k_priv { /* PHY parameters */ struct ieee80211_supported_band band; struct ieee80211_channel channels[14]; - struct ieee80211_rate rates[12]; + struct ieee80211_rate rates[13]; bool radio_on; bool radio_short_preamble; @@ -208,7 +208,7 @@ struct mwl8k_vif { * Subset of supported legacy rates. * Intersection of AP and STA supported rates. */ - struct ieee80211_rate legacy_rates[12]; + struct ieee80211_rate legacy_rates[13]; /* number of supported legacy rates */ u8 legacy_nrates; @@ -240,9 +240,10 @@ static const struct ieee80211_rate mwl8k_rates[] = { { .bitrate = 10, .hw_value = 2, }, { .bitrate = 20, .hw_value = 4, }, { .bitrate = 55, .hw_value = 11, }, + { .bitrate = 110, .hw_value = 22, }, + { .bitrate = 220, .hw_value = 44, }, { .bitrate = 60, .hw_value = 12, }, { .bitrate = 90, .hw_value = 18, }, - { .bitrate = 110, .hw_value = 22, }, { .bitrate = 120, .hw_value = 24, }, { .bitrate = 180, .hw_value = 36, }, { .bitrate = 240, .hw_value = 48, }, @@ -601,7 +602,7 @@ struct ewc_ht_info { /* Peer Entry flags - used to define the type of the peer node */ #define MWL8K_PEER_TYPE_ACCESSPOINT 2 -#define MWL8K_IEEE_LEGACY_DATA_RATES 12 +#define MWL8K_IEEE_LEGACY_DATA_RATES 13 #define MWL8K_MCS_BITMAP_SIZE 16 struct peer_capability_info { @@ -751,6 +752,13 @@ struct mwl8k_rx_desc { #define MWL8K_RX_DESCS 256 #define MWL8K_RX_MAXSZ 3800 +#define RATE_INFO_SHORTPRE 0x8000 +#define RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3) +#define RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f) +#define RATE_INFO_40MHZ 0x0004 +#define RATE_INFO_SHORTGI 0x0002 +#define RATE_INFO_MCS_FORMAT 0x0001 + static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) { struct mwl8k_priv *priv = hw->priv; @@ -907,6 +915,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) struct ieee80211_rx_status status; unsigned long addr; struct ieee80211_hdr *wh; + u16 rate_info; rx_desc = rxq->rx_desc_area + rxq->rx_head; if (!(rx_desc->rx_ctrl & MWL8K_RX_CTRL_OWNED_BY_HOST)) @@ -938,14 +947,24 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) if (mwl8k_capture_bssid(priv, wh)) mwl8k_save_beacon(hw, skb); + rate_info = le16_to_cpu(rx_desc->rate_info); + memset(&status, 0, sizeof(status)); status.mactime = 0; status.signal = -rx_desc->rssi; status.noise = -rx_desc->noise_level; status.qual = rx_desc->link_quality; - status.antenna = 1; - status.rate_idx = 1; + status.antenna = RATE_INFO_ANTSELECT(rate_info); + status.rate_idx = RATE_INFO_RATEID(rate_info); status.flag = 0; + if (rate_info & RATE_INFO_SHORTPRE) + status.flag |= RX_FLAG_SHORTPRE; + if (rate_info & RATE_INFO_40MHZ) + status.flag |= RX_FLAG_40MHZ; + if (rate_info & RATE_INFO_SHORTGI) + status.flag |= RX_FLAG_SHORT_GI; + if (rate_info & RATE_INFO_MCS_FORMAT) + status.flag |= RX_FLAG_HT; status.band = IEEE80211_BAND_2GHZ; status.freq = ieee80211_channel_to_frequency(rx_desc->channel); memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); -- cgit v1.2.3 From a43c49a817f31ce1accc029239827b108319ecf9 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:32 +0200 Subject: mwl8k: add support for enabling hardware sniffer mode Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 66 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 75c9261abad8..94cbf93a8bf5 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -173,6 +173,7 @@ struct mwl8k_priv { bool radio_on; bool radio_short_preamble; + bool sniffer_enabled; bool wmm_enabled; /* XXX need to convert this to handle multiple interfaces */ @@ -2560,6 +2561,18 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, if (conf->type != NL80211_IFTYPE_STATION) return -EINVAL; + /* + * Reject interface creation if sniffer mode is active, as + * STA operation is mutually exclusive with hardware sniffer + * mode. + */ + if (priv->sniffer_enabled) { + printk(KERN_INFO "%s: unable to create STA " + "interface due to sniffer mode being enabled\n", + wiphy_name(hw->wiphy)); + return -EINVAL; + } + /* Clean out driver private area */ mwl8k_vif = MWL8K_VIF(conf->vif); memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); @@ -2730,13 +2743,56 @@ static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, return (unsigned long)cmd; } +static int +mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags) +{ + struct mwl8k_priv *priv = hw->priv; + + /* + * Hardware sniffer mode is mutually exclusive with STA + * operation, so refuse to enable sniffer mode if a STA + * interface is active. + */ + if (priv->vif != NULL) { + if (net_ratelimit()) + printk(KERN_INFO "%s: not enabling sniffer " + "mode because STA interface is active\n", + wiphy_name(hw->wiphy)); + return 0; + } + + if (!priv->sniffer_enabled) { + if (mwl8k_enable_sniffer(hw, 1)) + return 0; + priv->sniffer_enabled = true; + } + + *total_flags &= FIF_PROMISC_IN_BSS | FIF_ALLMULTI | + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL | + FIF_OTHER_BSS; + + return 1; +} + static void mwl8k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) { struct mwl8k_priv *priv = hw->priv; - struct mwl8k_cmd_pkt *cmd; + struct mwl8k_cmd_pkt *cmd = (void *)(unsigned long)multicast; + + /* + * Enable hardware sniffer mode if FIF_CONTROL or + * FIF_OTHER_BSS is requested. + */ + if (*total_flags & (FIF_CONTROL | FIF_OTHER_BSS) && + mwl8k_configure_filter_sniffer(hw, changed_flags, total_flags)) { + kfree(cmd); + return; + } /* Clear unsupported feature flags */ *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; @@ -2744,6 +2800,11 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, if (mwl8k_fw_lock(hw)) return; + if (priv->sniffer_enabled) { + mwl8k_enable_sniffer(hw, 0); + priv->sniffer_enabled = false; + } + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { /* @@ -2769,8 +2830,6 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, } } - cmd = (void *)(unsigned long)multicast; - /* * If FIF_ALLMULTI is being requested, throw away the command * packet that ->prepare_multicast() built and replace it with @@ -2929,6 +2988,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv = hw->priv; priv->hw = hw; priv->pdev = pdev; + priv->sniffer_enabled = false; priv->wmm_enabled = false; priv->pending_tx_pkts = 0; -- cgit v1.2.3 From 45eb400d50e1ad84a8e8f9e9a82cd8ae13d7d691 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:40 +0200 Subject: mwl8k: shorten receive/transmit state variable names To conserve horizontal space. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 194 +++++++++++++++++++++---------------------- 1 file changed, 93 insertions(+), 101 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 94cbf93a8bf5..80df2ebbd602 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -88,30 +88,30 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); #define MWL8K_TX_QUEUES 4 struct mwl8k_rx_queue { - int rx_desc_count; + int rxd_count; /* hw receives here */ - int rx_head; + int head; /* refill descs here */ - int rx_tail; + int tail; - struct mwl8k_rx_desc *rx_desc_area; - dma_addr_t rx_desc_dma; - struct sk_buff **rx_skb; + struct mwl8k_rx_desc *rxd; + dma_addr_t rxd_dma; + struct sk_buff **skb; }; struct mwl8k_tx_queue { /* hw transmits here */ - int tx_head; + int head; /* sw appends here */ - int tx_tail; + int tail; - struct ieee80211_tx_queue_stats tx_stats; - struct mwl8k_tx_desc *tx_desc_area; - dma_addr_t tx_desc_dma; - struct sk_buff **tx_skb; + struct ieee80211_tx_queue_stats stats; + struct mwl8k_tx_desc *txd; + dma_addr_t txd_dma; + struct sk_buff **skb; }; /* Pointers to the firmware data and meta information about it. */ @@ -738,7 +738,7 @@ struct mwl8k_rx_desc { __u8 link_quality; __u8 noise_level; __le32 pkt_phys_addr; - __le32 next_rx_desc_phys_addr; + __le32 next_rxd_phys_addr; __le16 qos_control; __le16 rate_info; __le32 pad0[4]; @@ -767,42 +767,38 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) int size; int i; - rxq->rx_desc_count = 0; - rxq->rx_head = 0; - rxq->rx_tail = 0; + rxq->rxd_count = 0; + rxq->head = 0; + rxq->tail = 0; size = MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc); - rxq->rx_desc_area = - pci_alloc_consistent(priv->pdev, size, &rxq->rx_desc_dma); - if (rxq->rx_desc_area == NULL) { + rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma); + if (rxq->rxd == NULL) { printk(KERN_ERR "%s: failed to alloc RX descriptors\n", wiphy_name(hw->wiphy)); return -ENOMEM; } - memset(rxq->rx_desc_area, 0, size); + memset(rxq->rxd, 0, size); - rxq->rx_skb = kmalloc(MWL8K_RX_DESCS * - sizeof(*rxq->rx_skb), GFP_KERNEL); - if (rxq->rx_skb == NULL) { + rxq->skb = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->skb), GFP_KERNEL); + if (rxq->skb == NULL) { printk(KERN_ERR "%s: failed to alloc RX skbuff list\n", wiphy_name(hw->wiphy)); - pci_free_consistent(priv->pdev, size, - rxq->rx_desc_area, rxq->rx_desc_dma); + pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma); return -ENOMEM; } - memset(rxq->rx_skb, 0, MWL8K_RX_DESCS * sizeof(*rxq->rx_skb)); + memset(rxq->skb, 0, MWL8K_RX_DESCS * sizeof(*rxq->skb)); for (i = 0; i < MWL8K_RX_DESCS; i++) { struct mwl8k_rx_desc *rx_desc; int nexti; - rx_desc = rxq->rx_desc_area + i; + rx_desc = rxq->rxd + i; nexti = (i + 1) % MWL8K_RX_DESCS; - rx_desc->next_rx_desc_phys_addr = - cpu_to_le32(rxq->rx_desc_dma - + nexti * sizeof(*rx_desc)); + rx_desc->next_rxd_phys_addr = + cpu_to_le32(rxq->rxd_dma + nexti * sizeof(*rx_desc)); rx_desc->rx_ctrl = MWL8K_RX_CTRL_OWNED_BY_HOST; } @@ -816,7 +812,7 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit) int refilled; refilled = 0; - while (rxq->rx_desc_count < MWL8K_RX_DESCS && limit--) { + while (rxq->rxd_count < MWL8K_RX_DESCS && limit--) { struct sk_buff *skb; int rx; @@ -824,19 +820,19 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit) if (skb == NULL) break; - rxq->rx_desc_count++; + rxq->rxd_count++; - rx = rxq->rx_tail; - rxq->rx_tail = (rx + 1) % MWL8K_RX_DESCS; + rx = rxq->tail; + rxq->tail = (rx + 1) % MWL8K_RX_DESCS; - rxq->rx_desc_area[rx].pkt_phys_addr = + rxq->rxd[rx].pkt_phys_addr = cpu_to_le32(pci_map_single(priv->pdev, skb->data, MWL8K_RX_MAXSZ, DMA_FROM_DEVICE)); - rxq->rx_desc_area[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ); - rxq->rx_skb[rx] = skb; + rxq->rxd[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ); + rxq->skb[rx] = skb; wmb(); - rxq->rx_desc_area[rx].rx_ctrl = 0; + rxq->rxd[rx].rx_ctrl = 0; refilled++; } @@ -852,24 +848,24 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) int i; for (i = 0; i < MWL8K_RX_DESCS; i++) { - if (rxq->rx_skb[i] != NULL) { + if (rxq->skb[i] != NULL) { unsigned long addr; - addr = le32_to_cpu(rxq->rx_desc_area[i].pkt_phys_addr); + addr = le32_to_cpu(rxq->rxd[i].pkt_phys_addr); pci_unmap_single(priv->pdev, addr, MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); - kfree_skb(rxq->rx_skb[i]); - rxq->rx_skb[i] = NULL; + kfree_skb(rxq->skb[i]); + rxq->skb[i] = NULL; } } - kfree(rxq->rx_skb); - rxq->rx_skb = NULL; + kfree(rxq->skb); + rxq->skb = NULL; pci_free_consistent(priv->pdev, MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc), - rxq->rx_desc_area, rxq->rx_desc_dma); - rxq->rx_desc_area = NULL; + rxq->rxd, rxq->rxd_dma); + rxq->rxd = NULL; } @@ -910,7 +906,7 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) int processed; processed = 0; - while (rxq->rx_desc_count && limit--) { + while (rxq->rxd_count && limit--) { struct mwl8k_rx_desc *rx_desc; struct sk_buff *skb; struct ieee80211_rx_status status; @@ -918,18 +914,18 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) struct ieee80211_hdr *wh; u16 rate_info; - rx_desc = rxq->rx_desc_area + rxq->rx_head; + rx_desc = rxq->rxd + rxq->head; if (!(rx_desc->rx_ctrl & MWL8K_RX_CTRL_OWNED_BY_HOST)) break; rmb(); - skb = rxq->rx_skb[rxq->rx_head]; + skb = rxq->skb[rxq->head]; if (skb == NULL) break; - rxq->rx_skb[rxq->rx_head] = NULL; + rxq->skb[rxq->head] = NULL; - rxq->rx_head = (rxq->rx_head + 1) % MWL8K_RX_DESCS; - rxq->rx_desc_count--; + rxq->head = (rxq->head + 1) % MWL8K_RX_DESCS; + rxq->rxd_count--; addr = le32_to_cpu(rx_desc->pkt_phys_addr); pci_unmap_single(priv->pdev, addr, @@ -1000,7 +996,7 @@ struct mwl8k_tx_desc { __le32 pkt_phys_addr; __le16 pkt_len; __u8 dest_MAC_addr[ETH_ALEN]; - __le32 next_tx_desc_phys_addr; + __le32 next_txd_phys_addr; __le32 reserved; __le16 rate_info; __u8 peer_id; @@ -1016,44 +1012,40 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) int size; int i; - memset(&txq->tx_stats, 0, sizeof(struct ieee80211_tx_queue_stats)); - txq->tx_stats.limit = MWL8K_TX_DESCS; - txq->tx_head = 0; - txq->tx_tail = 0; + memset(&txq->stats, 0, sizeof(struct ieee80211_tx_queue_stats)); + txq->stats.limit = MWL8K_TX_DESCS; + txq->head = 0; + txq->tail = 0; size = MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc); - txq->tx_desc_area = - pci_alloc_consistent(priv->pdev, size, &txq->tx_desc_dma); - if (txq->tx_desc_area == NULL) { + txq->txd = pci_alloc_consistent(priv->pdev, size, &txq->txd_dma); + if (txq->txd == NULL) { printk(KERN_ERR "%s: failed to alloc TX descriptors\n", wiphy_name(hw->wiphy)); return -ENOMEM; } - memset(txq->tx_desc_area, 0, size); + memset(txq->txd, 0, size); - txq->tx_skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->tx_skb), - GFP_KERNEL); - if (txq->tx_skb == NULL) { + txq->skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->skb), GFP_KERNEL); + if (txq->skb == NULL) { printk(KERN_ERR "%s: failed to alloc TX skbuff list\n", wiphy_name(hw->wiphy)); - pci_free_consistent(priv->pdev, size, - txq->tx_desc_area, txq->tx_desc_dma); + pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma); return -ENOMEM; } - memset(txq->tx_skb, 0, MWL8K_TX_DESCS * sizeof(*txq->tx_skb)); + memset(txq->skb, 0, MWL8K_TX_DESCS * sizeof(*txq->skb)); for (i = 0; i < MWL8K_TX_DESCS; i++) { struct mwl8k_tx_desc *tx_desc; int nexti; - tx_desc = txq->tx_desc_area + i; + tx_desc = txq->txd + i; nexti = (i + 1) % MWL8K_TX_DESCS; tx_desc->status = 0; - tx_desc->next_tx_desc_phys_addr = - cpu_to_le32(txq->tx_desc_dma + - nexti * sizeof(*tx_desc)); + tx_desc->next_txd_phys_addr = + cpu_to_le32(txq->txd_dma + nexti * sizeof(*tx_desc)); } return 0; @@ -1089,11 +1081,11 @@ static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv, for (count = 0; count < MWL8K_TX_QUEUES; count++) { txq = priv->txq + count; - txinfo[count].len = txq->tx_stats.len; - txinfo[count].head = txq->tx_head; - txinfo[count].tail = txq->tx_tail; + txinfo[count].len = txq->stats.len; + txinfo[count].head = txq->head; + txinfo[count].tail = txq->tail; for (desc = 0; desc < MWL8K_TX_DESCS; desc++) { - tx_desc = txq->tx_desc_area + desc; + tx_desc = txq->txd + desc; status = le32_to_cpu(tx_desc->status); if (status & MWL8K_TXD_STATUS_FW_OWNED) @@ -1174,7 +1166,7 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) struct mwl8k_tx_queue *txq = priv->txq + index; int wake = 0; - while (txq->tx_stats.len > 0) { + while (txq->stats.len > 0) { int tx; struct mwl8k_tx_desc *tx_desc; unsigned long addr; @@ -1183,8 +1175,8 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) struct ieee80211_tx_info *info; u32 status; - tx = txq->tx_head; - tx_desc = txq->tx_desc_area + tx; + tx = txq->head; + tx_desc = txq->txd + tx; status = le32_to_cpu(tx_desc->status); @@ -1195,15 +1187,15 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) ~cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED); } - txq->tx_head = (tx + 1) % MWL8K_TX_DESCS; - BUG_ON(txq->tx_stats.len == 0); - txq->tx_stats.len--; + txq->head = (tx + 1) % MWL8K_TX_DESCS; + BUG_ON(txq->stats.len == 0); + txq->stats.len--; priv->pending_tx_pkts--; addr = le32_to_cpu(tx_desc->pkt_phys_addr); size = le16_to_cpu(tx_desc->pkt_len); - skb = txq->tx_skb[tx]; - txq->tx_skb[tx] = NULL; + skb = txq->skb[tx]; + txq->skb[tx] = NULL; BUG_ON(skb == NULL); pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE); @@ -1236,13 +1228,13 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) mwl8k_txq_reclaim(hw, index, 1); - kfree(txq->tx_skb); - txq->tx_skb = NULL; + kfree(txq->skb); + txq->skb = NULL; pci_free_consistent(priv->pdev, MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc), - txq->tx_desc_area, txq->tx_desc_dma); - txq->tx_desc_area = NULL; + txq->txd, txq->txd_dma); + txq->txd = NULL; } static int @@ -1319,10 +1311,10 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) txq = priv->txq + index; - BUG_ON(txq->tx_skb[txq->tx_tail] != NULL); - txq->tx_skb[txq->tx_tail] = skb; + BUG_ON(txq->skb[txq->tail] != NULL); + txq->skb[txq->tail] = skb; - tx = txq->tx_desc_area + txq->tx_tail; + tx = txq->txd + txq->tail; tx->data_rate = txdatarate; tx->tx_priority = index; tx->qos_control = cpu_to_le16(qos); @@ -1333,15 +1325,15 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) wmb(); tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); - txq->tx_stats.count++; - txq->tx_stats.len++; + txq->stats.count++; + txq->stats.len++; priv->pending_tx_pkts++; - txq->tx_tail++; - if (txq->tx_tail == MWL8K_TX_DESCS) - txq->tx_tail = 0; + txq->tail++; + if (txq->tail == MWL8K_TX_DESCS) + txq->tail = 0; - if (txq->tx_head == txq->tx_tail) + if (txq->head == txq->tail) ieee80211_stop_queue(hw, index); mwl8k_tx_start(priv); @@ -1492,7 +1484,7 @@ struct mwl8k_cmd_get_hw_spec { __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; __le32 caps2; __le32 num_tx_desc_per_queue; - __le32 total_rx_desc; + __le32 total_rxd; } __attribute__((packed)); static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw) @@ -1511,12 +1503,12 @@ static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw) memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); - cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rx_desc_dma); + cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); for (i = 0; i < MWL8K_TX_QUEUES; i++) - cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].tx_desc_dma); + cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); - cmd->total_rx_desc = cpu_to_le32(MWL8K_RX_DESCS); + cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); rc = mwl8k_post_cmd(hw, &cmd->header); @@ -2888,7 +2880,7 @@ static int mwl8k_get_tx_stats(struct ieee80211_hw *hw, spin_lock_bh(&priv->tx_lock); for (index = 0; index < MWL8K_TX_QUEUES; index++) { txq = priv->txq + index; - memcpy(&stats[index], &txq->tx_stats, + memcpy(&stats[index], &txq->stats, sizeof(struct ieee80211_tx_queue_stats)); } spin_unlock_bh(&priv->tx_lock); -- cgit v1.2.3 From 5b9482dda6dda11dc7050ffa5b4ebfb0c775880f Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:43 +0200 Subject: mwl8k: pci BAR mapping changes Map BAR0 as well, as we need to write to it during init on some chips. Also, if BAR0 is a 64bit BAR, the register BAR becomes BAR2, so try mapping BAR2 if mapping BAR1 fails. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 80df2ebbd602..c0317e298c11 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -124,6 +124,7 @@ struct mwl8k_firmware { }; struct mwl8k_priv { + void __iomem *sram; void __iomem *regs; struct ieee80211_hw *hw; @@ -2987,13 +2988,27 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); - priv->regs = pci_iomap(pdev, 1, 0x10000); - if (priv->regs == NULL) { - printk(KERN_ERR "%s: Cannot map device memory\n", + priv->sram = pci_iomap(pdev, 0, 0x10000); + if (priv->sram == NULL) { + printk(KERN_ERR "%s: Cannot map device SRAM\n", wiphy_name(hw->wiphy)); goto err_iounmap; } + /* + * If BAR0 is a 32 bit BAR, the register BAR will be BAR1. + * If BAR0 is a 64 bit BAR, the register BAR will be BAR2. + */ + priv->regs = pci_iomap(pdev, 1, 0x10000); + if (priv->regs == NULL) { + priv->regs = pci_iomap(pdev, 2, 0x10000); + if (priv->regs == NULL) { + printk(KERN_ERR "%s: Cannot map device registers\n", + wiphy_name(hw->wiphy)); + goto err_iounmap; + } + } + memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels)); priv->band.band = IEEE80211_BAND_2GHZ; priv->band.channels = priv->channels; @@ -3165,6 +3180,9 @@ err_iounmap: if (priv->regs != NULL) pci_iounmap(pdev, priv->regs); + if (priv->sram != NULL) + pci_iounmap(pdev, priv->sram); + pci_set_drvdata(pdev, NULL); ieee80211_free_hw(hw); @@ -3212,6 +3230,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) pci_free_consistent(priv->pdev, 4, priv->cookie, priv->cookie_dma); pci_iounmap(pdev, priv->regs); + pci_iounmap(pdev, priv->sram); pci_set_drvdata(pdev, NULL); ieee80211_free_hw(hw); pci_release_regions(pdev); -- cgit v1.2.3 From 5ed176e1c425f9bd1af161d66d348f6116a04fc6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Nov 2009 14:42:28 +0100 Subject: mac80211: make ieee80211_find_sta per virtual interface Since we have a TODO item to make all station management dependent on virtual interfaces, I figured I'd start with pushing such a change to drivers before more drivers start using the ieee80211_find_sta() API with a hw pointer and cause us grief later on. For now continue exporting the old API in form of ieee80211_find_sta_by_hw(), but discourage its use strongly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 3 ++- drivers/net/wireless/ath/ath9k/xmit.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- include/net/mac80211.h | 25 +++++++++++++++++++++++-- net/mac80211/sta_info.c | 18 ++++++++++++++++-- 7 files changed, 47 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c880a55939bf..355dd1834e1d 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -202,7 +202,8 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, } rcu_read_lock(); - sta = ieee80211_find_sta(sc->hw, hdr->addr2); + /* XXX: use ieee80211_find_sta! */ + sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr2); if (sta) { an = (struct ath_node *) sta->drv_priv; if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD && diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2a4efcbced60..8e052f406c35 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -282,7 +282,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, rcu_read_lock(); - sta = ieee80211_find_sta(sc->hw, hdr->addr1); + /* XXX: use ieee80211_find_sta! */ + sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr1); if (!sta) { rcu_read_unlock(); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 819a81bbb1b7..dc81e19674f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -913,7 +913,8 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) rcu_read_lock(); - sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr); + sta = ieee80211_find_sta(priv->vif, + priv->stations[sta_id].sta.sta.addr); if (!sta) { rcu_read_unlock(); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7373b2f50aca..e0b5b4aef41d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2300,7 +2300,7 @@ static void iwl_ht_conf(struct iwl_priv *priv, switch (priv->iw_mode) { case NL80211_IFTYPE_STATION: rcu_read_lock(); - sta = ieee80211_find_sta(priv->hw, priv->bssid); + sta = ieee80211_find_sta(priv->vif, priv->bssid); if (sta) { struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; int maxstreams; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 74cc8dbe9359..eba36f737388 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1017,7 +1017,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) */ if (priv->current_ht_config.is_ht) { rcu_read_lock(); - sta = ieee80211_find_sta(priv->hw, addr); + sta = ieee80211_find_sta(priv->vif, addr); if (sta) { memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); cur_ht_config = &ht_config; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e12293e60ac1..7f035d779db9 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2106,15 +2106,36 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, /** * ieee80211_find_sta - find a station * - * @hw: pointer as obtained from ieee80211_alloc_hw() + * @vif: virtual interface to look for station on * @addr: station's address * * This function must be called under RCU lock and the * resulting pointer is only valid under RCU lock as well. */ -struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, +struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, const u8 *addr); +/** + * ieee80211_find_sta_by_hw - find a station on hardware + * + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @addr: station's address + * + * This function must be called under RCU lock and the + * resulting pointer is only valid under RCU lock as well. + * + * NOTE: This function should not be used! When mac80211 is converted + * internally to properly keep track of stations on multiple + * virtual interfaces, it will not always know which station to + * return here since a single address might be used by multiple + * logical stations (e.g. consider a station connecting to another + * BSSID on the same AP hardware without disconnecting first). + * + * DO NOT USE THIS FUNCTION. + */ +struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, + const u8 *addr); + /** * ieee80211_beacon_loss - inform hardware does not receive beacons * diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 594f2318c3d8..cde2da7a74df 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -801,8 +801,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, sta_info_destroy(sta); } -struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, - const u8 *addr) +struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, + const u8 *addr) { struct sta_info *sta = sta_info_get(hw_to_local(hw), addr); @@ -810,4 +810,18 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, return NULL; return &sta->sta; } +EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw); + +struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, + const u8 *addr) +{ + struct ieee80211_sub_if_data *sdata; + + if (!vif) + return NULL; + + sdata = vif_to_sdata(vif); + + return ieee80211_find_sta_by_hw(&sdata->local->hw, addr); +} EXPORT_SYMBOL(ieee80211_find_sta); -- cgit v1.2.3 From 71eafe3230073917456973d67bc49eaa874c5a42 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:31:58 +0100 Subject: rt2800usb: make Kconfig help entry more helpful Document known issues with the driver to aid distribution makers, users and developers in making informed decisions instead of wasting their time needlessly. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index a6796a130486..1803c1bb4e3d 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -104,7 +104,7 @@ config RT73USB When compiled as a module, this driver will be called rt73usb. config RT2800USB - tristate "Ralink rt2800 (USB) support" + tristate "Ralink rt2800 (USB) support (EXPERIMENTAL)" depends on USB && EXPERIMENTAL select RT2X00_LIB_USB select RT2X00_LIB_HT @@ -115,6 +115,10 @@ config RT2800USB This adds experimental support for rt2800 wireless chipset family. Supported chips: RT2770, RT2870 & RT3070. + Known issues: + - support for RT2870 chips doesn't work with 802.11n APs yet + - support for RT3070 chips is non-functional at the moment + When compiled as a module, this driver will be called "rt2800usb.ko". config RT2X00_LIB_PCI -- cgit v1.2.3 From f44eafa76be981b57667adcef5153b18e8a21904 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:32:10 +0100 Subject: rt2800pci: make Kconfig help entry more helpful Document known issues with the driver to aid distribution makers, users and developers in making informed decisions instead of wasting their time needlessly. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 1803c1bb4e3d..18e5b8e6c34f 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -64,7 +64,7 @@ config RT2800PCI_SOC default y config RT2800PCI - tristate "Ralink rt2800 (PCI/PCMCIA) support" + tristate "Ralink rt2800 (PCI/PCMCIA) support (VERY EXPERIMENTAL)" depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL select RT2X00_LIB_PCI if RT2800PCI_PCI select RT2X00_LIB_SOC if RT2800PCI_SOC @@ -77,6 +77,9 @@ config RT2800PCI This adds support for rt2800 wireless chipset family. Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890 & RT3052 + This driver is non-functional at the moment and is intended for + developers. + When compiled as a module, this driver will be called "rt2800pci.ko". config RT2500USB -- cgit v1.2.3 From a8ea2b23f62e23c2afac291f9caa500bd1a60618 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:32:17 +0100 Subject: rt2800usb: fix rt2800usb_rfcsr_read() The driver should write the read request into RF_CSR_CFG register and not BBP_CSR_CFG one in rt2800usb_rfcsr_read(). Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 9fe770f7d7bb..b3e266e77909 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -167,7 +167,7 @@ static void rt2800usb_rfcsr_read(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); - rt2x00usb_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); + rt2x00usb_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); WAIT_FOR_RFCSR(rt2x00dev, ®); } -- cgit v1.2.3 From f644fea1a8433f65f78a36cd7b23b8f57b0f77e4 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:32:24 +0100 Subject: rt2800pci: fix crypto in TX frame Based on rt2800usb patch from Benoit PAPILLAULT (commit 17616310836ad2cc45a64576ef0e1520b0dcc81b). Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index be81788b80c7..5b3f40356c64 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -2195,7 +2195,7 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size); rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? - (skbdesc->entry->entry_idx + 1) : 0xff); + txdesc->key_idx : 0xff); rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, skb->len - txdesc->l2pad); rt2x00_set_field32(&word, TXWI_W1_PACKETID, -- cgit v1.2.3 From 8807bb8cddbeb5b48bd9c6e40396af07980c7cdf Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:32:32 +0100 Subject: rt2800pci: fix comment about register access Registers used for indirect BBP and RF registers access are respectively BBPCSR and RFCSR, also make it clear that all CSR registers access goes through rt2x00pci_register_[read,write]() methods. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 5b3f40356c64..e4a1a858a2fd 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -56,8 +56,10 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /* * Register access. + * All access to the CSR registers will go through the methods + * rt2x00pci_register_read and rt2x00pci_register_write. * BBP and RF register require indirect register access, - * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this. + * and use the CSR registers BBPCSR and RFCSR to achieve this. * These indirect registers work with busy bits, * and we will try maximal REGISTER_BUSY_COUNT times to access * the register while taking a REGISTER_BUSY_DELAY us delay -- cgit v1.2.3 From 77dba493618b5b5c84c9e375b6e3d51862ca7408 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:32:40 +0100 Subject: rt2800pci: fix comment about IV/EIV fields The bit tested by hardware is TXD_W3_WIV and its value equals the negated value of ENTRY_TXD_ENCRYPT_IV bit. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index e4a1a858a2fd..5d3c48b9f5cc 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -2206,8 +2206,8 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, /* * Always write 0 to IV/EIV fields, hardware will insert the IV - * from the IVEIV register when ENTRY_TXD_ENCRYPT_IV is set to 0. - * When ENTRY_TXD_ENCRYPT_IV is set to 1 it will use the IV data + * from the IVEIV register when TXD_W3_WIV is set to 0. + * When TXD_W3_WIV is set to 1 it will use the IV data * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which * crypto entry in the registers should be used to encrypt the frame. */ -- cgit v1.2.3 From 02a39c209bda97f5dfd0c390c3926c131a052e34 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:32:50 +0100 Subject: rt2x00: fix rt2x00usb_register_read() comment Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00usb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index bd2d59c85f1b..9093516d9af1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -232,7 +232,7 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, } /** - * rt2x00usb_regbusy_read - Read 32bit register word + * rt2x00usb_register_read - Read 32bit register word * @rt2x00dev: Device pointer, see &struct rt2x00_dev. * @offset: Register offset * @value: Pointer to where register contents should be stored -- cgit v1.2.3 From 3306ef642a4dec6ba5341eceb8b9cb1e4a82ddb0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:32:58 +0100 Subject: rt2800usb: use rt2x00usb_register_multiwrite() to set key entries Since struct hw_key_entry is 32-bytes large and is smaller than CSR cache size (which is 64-bytes large) we can use the standard rt2x00usb_register_multiwrite() helper to set key entries. This cleanup is a part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index b3e266e77909..39a652bc29dd 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -392,7 +392,6 @@ static int rt2800usb_config_shared_key(struct rt2x00_dev *rt2x00dev, { struct hw_key_entry key_entry; struct rt2x00_field32 field; - int timeout; u32 offset; u32 reg; @@ -407,12 +406,8 @@ static int rt2800usb_config_shared_key(struct rt2x00_dev *rt2x00dev, sizeof(key_entry.rx_mic)); offset = SHARED_KEY_ENTRY(key->hw_key_idx); - timeout = REGISTER_TIMEOUT32(sizeof(key_entry)); - rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, - offset, &key_entry, - sizeof(key_entry), - timeout); + rt2x00usb_register_multiwrite(rt2x00dev, offset, + &key_entry, sizeof(key_entry)); } /* @@ -445,7 +440,6 @@ static int rt2800usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, struct ieee80211_key_conf *key) { struct hw_key_entry key_entry; - int timeout; u32 offset; if (crypto->cmd == SET_KEY) { @@ -467,12 +461,8 @@ static int rt2800usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, sizeof(key_entry.rx_mic)); offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx); - timeout = REGISTER_TIMEOUT32(sizeof(key_entry)); - rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, - offset, &key_entry, - sizeof(key_entry), - timeout); + rt2x00usb_register_multiwrite(rt2x00dev, offset, + &key_entry, sizeof(key_entry)); } /* -- cgit v1.2.3 From d07624f191a14e2a59e1fe884a13582f24d7f8cb Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:35:39 +0100 Subject: rt2800usb: fix comments in rt2800usb.h Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 4d9991c9a51c..7b1130a22c55 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -61,7 +61,7 @@ /* * Signal information. - * Defaul offset is required for RSSI <-> dBm conversion. + * Default offset is required for RSSI <-> dBm conversion. */ #define DEFAULT_RSSI_OFFSET 120 /* FIXME */ @@ -86,12 +86,6 @@ * USB registers. */ -/* - * HOST-MCU shared memory - */ -#define HOST_CMD_CSR 0x0404 -#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x000000ff) - /* * INT_SOURCE_CSR: Interrupt source register. * Write one to clear corresponding bit. @@ -350,6 +344,12 @@ #define PBF_SYS_CTRL_READY FIELD32(0x00000080) #define PBF_SYS_CTRL_HOST_RAM_WRITE FIELD32(0x00010000) +/* + * HOST-MCU shared memory + */ +#define HOST_CMD_CSR 0x0404 +#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x000000ff) + /* * PBF registers * Most are for debug. Driver doesn't touch PBF register. @@ -1776,7 +1776,7 @@ struct mac_iveiv_entry { /* * Word3 - * WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI + * WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI * QSEL: Select on-chip FIFO ID for 2nd-stage output scheduler. * 0:MGMT, 1:HCCA 2:EDCA */ -- cgit v1.2.3 From b35686d0b2d754d627aeb0c4340884aeaed8e4f3 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:36:33 +0100 Subject: rt2x00: remove needless ifdefs from rt2x00leds.h Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00leds.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.h b/drivers/net/wireless/rt2x00/rt2x00leds.h index 1046977e6a12..8e03c045e037 100644 --- a/drivers/net/wireless/rt2x00/rt2x00leds.h +++ b/drivers/net/wireless/rt2x00/rt2x00leds.h @@ -33,8 +33,6 @@ enum led_type { LED_TYPE_QUALITY, }; -#ifdef CONFIG_RT2X00_LIB_LEDS - struct rt2x00_led { struct rt2x00_dev *rt2x00dev; struct led_classdev led_dev; @@ -45,6 +43,4 @@ struct rt2x00_led { #define LED_REGISTERED ( 1 << 1 ) }; -#endif /* CONFIG_RT2X00_LIB_LEDS */ - #endif /* RT2X00LEDS_H */ -- cgit v1.2.3 From e9a6269d5bcb1c7cd18cea02a9a73fac8712f2d1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 2 Nov 2009 12:15:15 -0500 Subject: wl1271: use __dev_alloc_skb() on RX RX is handled in a workqueue therefore allocating for GFP_ATOMIC is overkill and not required. Signed-off-by: Luis R. Rodriguez Acked-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 37d81ab6acc0..ca645f38109b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -159,7 +159,7 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) u8 *buf; u8 beacon = 0; - skb = dev_alloc_skb(length); + skb = __dev_alloc_skb(length, GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return; -- cgit v1.2.3 From abbb505dddef31707d06ff26539639ccdfa56f45 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:33:05 +0100 Subject: rt2800usb: add rt2800_register_[read,write]() wrappers Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 384 ++++++++++++++++---------------- drivers/net/wireless/rt2x00/rt2800usb.h | 21 ++ 2 files changed, 213 insertions(+), 192 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 39a652bc29dd..73e7f2bafe10 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -46,7 +46,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /* * Register access. * All access to the CSR registers will go through the methods - * rt2x00usb_register_read and rt2x00usb_register_write. + * rt2800_register_read and rt2800_register_write. * BBP and RF register require indirect register access, * and use the CSR registers BBPCSR and RFCSR to achieve this. * These indirect registers work with busy bits, @@ -85,7 +85,7 @@ static void rt2800usb_bbp_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); - rt2x00usb_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); + rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); } mutex_unlock(&rt2x00dev->csr_mutex); @@ -112,7 +112,7 @@ static void rt2800usb_bbp_read(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); - rt2x00usb_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); + rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); WAIT_FOR_BBP(rt2x00dev, ®); } @@ -140,7 +140,7 @@ static void rt2800usb_rfcsr_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); - rt2x00usb_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); + rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); } mutex_unlock(&rt2x00dev->csr_mutex); @@ -167,7 +167,7 @@ static void rt2800usb_rfcsr_read(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); - rt2x00usb_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); + rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); WAIT_FOR_RFCSR(rt2x00dev, ®); } @@ -195,7 +195,7 @@ static void rt2800usb_rf_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, RF_CSR_CFG0_SEL, 0); rt2x00_set_field32(®, RF_CSR_CFG0_BUSY, 1); - rt2x00usb_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg); + rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg); rt2x00_rf_write(rt2x00dev, word, value); } @@ -219,11 +219,11 @@ static void rt2800usb_mcu_request(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); - rt2x00usb_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg); + rt2800_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg); reg = 0; rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); - rt2x00usb_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg); + rt2800_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg); } mutex_unlock(&rt2x00dev->csr_mutex); @@ -233,8 +233,8 @@ static void rt2800usb_mcu_request(struct rt2x00_dev *rt2x00dev, static const struct rt2x00debug rt2800usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2x00usb_register_read, - .write = rt2x00usb_register_write, + .read = rt2800_register_read, + .write = rt2800_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, .word_size = sizeof(u32), @@ -268,7 +268,7 @@ static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); + rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); } @@ -317,7 +317,7 @@ static int rt2800usb_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt2x00usb_register_read(led->rt2x00dev, LED_CFG, ®); + rt2800_register_read(led->rt2x00dev, LED_CFG, ®); rt2x00_set_field32(®, LED_CFG_ON_PERIOD, *delay_on); rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); @@ -325,7 +325,7 @@ static int rt2800usb_blink_set(struct led_classdev *led_cdev, rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 12); rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3); rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1); - rt2x00usb_register_write(led->rt2x00dev, LED_CFG, reg); + rt2800_register_write(led->rt2x00dev, LED_CFG, reg); return 0; } @@ -356,7 +356,7 @@ static void rt2800usb_config_wcid_attr(struct rt2x00_dev *rt2x00dev, offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); - rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2800_register_read(rt2x00dev, offset, ®); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, @@ -364,7 +364,7 @@ static void rt2800usb_config_wcid_attr(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, (crypto->cmd == SET_KEY) * crypto->bssidx); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); - rt2x00usb_register_write(rt2x00dev, offset, reg); + rt2800_register_write(rt2x00dev, offset, reg); offset = MAC_IVEIV_ENTRY(key->hw_key_idx); @@ -422,10 +422,10 @@ static int rt2800usb_config_shared_key(struct rt2x00_dev *rt2x00dev, offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); - rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2800_register_read(rt2x00dev, offset, ®); rt2x00_set_field32(®, field, (crypto->cmd == SET_KEY) * crypto->cipher); - rt2x00usb_register_write(rt2x00dev, offset, reg); + rt2800_register_write(rt2x00dev, offset, reg); /* * Update WCID information @@ -484,7 +484,7 @@ static void rt2800usb_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2x00usb_register_read(rt2x00dev, RX_FILTER_CFG, ®); + rt2800_register_read(rt2x00dev, RX_FILTER_CFG, ®); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, @@ -513,7 +513,7 @@ static void rt2800usb_config_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, !(filter_flags & FIF_CONTROL)); - rt2x00usb_register_write(rt2x00dev, RX_FILTER_CFG, reg); + rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg); } static void rt2800usb_config_intf(struct rt2x00_dev *rt2x00dev, @@ -532,16 +532,16 @@ static void rt2800usb_config_intf(struct rt2x00_dev *rt2x00dev, * bits which (when set to 0) will invalidate the entire beacon. */ beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - rt2x00usb_register_write(rt2x00dev, beacon_base, 0); + rt2800_register_write(rt2x00dev, beacon_base, 0); /* * Enable synchronisation. */ - rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); - rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); } if (flags & CONFIG_UPDATE_MAC) { @@ -569,43 +569,43 @@ static void rt2800usb_config_erp(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20); - rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, !!erp->short_preamble); rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, !!erp->short_preamble); - rt2x00usb_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); - rt2x00usb_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, erp->cts_protection ? 2 : 0); - rt2x00usb_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - rt2x00usb_register_write(rt2x00dev, LEGACY_BASIC_RATE, + rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, erp->basic_rates); - rt2x00usb_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); - rt2x00usb_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); + rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); - rt2x00usb_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); + rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, XIFS_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); rt2x00_set_field32(®, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs); rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs); rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4); rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); - rt2x00usb_register_write(rt2x00dev, XIFS_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); - rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, erp->beacon_int * 16); - rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); } static void rt2800usb_config_ant(struct rt2x00_dev *rt2x00dev, @@ -813,11 +813,11 @@ static void rt2800usb_config_channel(struct rt2x00_dev *rt2x00dev, rt2800usb_bbp_write(rt2x00dev, 75, 0x50); } - rt2x00usb_register_read(rt2x00dev, TX_BAND_CFG, ®); + rt2800_register_read(rt2x00dev, TX_BAND_CFG, ®); rt2x00_set_field32(®, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf)); rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); - rt2x00usb_register_write(rt2x00dev, TX_BAND_CFG, reg); + rt2800_register_write(rt2x00dev, TX_BAND_CFG, reg); tx_pin = 0; @@ -840,7 +840,7 @@ static void rt2800usb_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14); rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14); - rt2x00usb_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); + rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); rt2800usb_bbp_read(rt2x00dev, 4, &bbp); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); @@ -876,7 +876,7 @@ static void rt2800usb_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(®, BBP1_TX_POWER, 0); rt2800usb_bbp_write(rt2x00dev, 1, r1); - rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_0, ®); + rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, ®); rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_0_2MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_0_55MBS, value); @@ -885,9 +885,9 @@ static void rt2800usb_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_0_9MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_0_12MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_0_18MBS, value); - rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_0, reg); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, reg); - rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_1, ®); + rt2800_register_read(rt2x00dev, TX_PWR_CFG_1, ®); rt2x00_set_field32(®, TX_PWR_CFG_1_24MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_1_36MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_1_48MBS, value); @@ -896,9 +896,9 @@ static void rt2800usb_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_1_MCS1, value); rt2x00_set_field32(®, TX_PWR_CFG_1_MCS2, value); rt2x00_set_field32(®, TX_PWR_CFG_1_MCS3, value); - rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_1, reg); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, reg); - rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_2, ®); + rt2800_register_read(rt2x00dev, TX_PWR_CFG_2, ®); rt2x00_set_field32(®, TX_PWR_CFG_2_MCS4, value); rt2x00_set_field32(®, TX_PWR_CFG_2_MCS5, value); rt2x00_set_field32(®, TX_PWR_CFG_2_MCS6, value); @@ -907,9 +907,9 @@ static void rt2800usb_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_2_MCS9, value); rt2x00_set_field32(®, TX_PWR_CFG_2_MCS10, value); rt2x00_set_field32(®, TX_PWR_CFG_2_MCS11, value); - rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_2, reg); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, reg); - rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_3, ®); + rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, ®); rt2x00_set_field32(®, TX_PWR_CFG_3_MCS12, value); rt2x00_set_field32(®, TX_PWR_CFG_3_MCS13, value); rt2x00_set_field32(®, TX_PWR_CFG_3_MCS14, value); @@ -918,14 +918,14 @@ static void rt2800usb_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN2, value); rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN3, value); rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN4, value); - rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_3, reg); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, reg); - rt2x00usb_register_read(rt2x00dev, TX_PWR_CFG_4, ®); + rt2800_register_read(rt2x00dev, TX_PWR_CFG_4, ®); rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN5, value); rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN6, value); rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN7, value); rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN8, value); - rt2x00usb_register_write(rt2x00dev, TX_PWR_CFG_4, reg); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, reg); } static void rt2800usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, @@ -933,7 +933,7 @@ static void rt2800usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00usb_register_read(rt2x00dev, TX_RTY_CFG, ®); + rt2800_register_read(rt2x00dev, TX_RTY_CFG, ®); rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, libconf->conf->short_frame_max_tx_count); rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, @@ -942,7 +942,7 @@ static void rt2800usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_RTY_CFG_NON_AGG_RTY_MODE, 0); rt2x00_set_field32(®, TX_RTY_CFG_AGG_RTY_MODE, 0); rt2x00_set_field32(®, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1); - rt2x00usb_register_write(rt2x00dev, TX_RTY_CFG, reg); + rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg); } static void rt2800usb_config_ps(struct rt2x00_dev *rt2x00dev, @@ -954,24 +954,24 @@ static void rt2800usb_config_ps(struct rt2x00_dev *rt2x00dev, u32 reg; if (state == STATE_SLEEP) { - rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); - rt2x00usb_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5); rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, libconf->conf->listen_interval - 1); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 1); - rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); } else { rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); - rt2x00usb_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); - rt2x00usb_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); } } @@ -1004,7 +1004,7 @@ static void rt2800usb_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2x00usb_register_read(rt2x00dev, RX_STA_CNT0, ®); + rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); } @@ -1162,7 +1162,7 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, * Wait for stable hardware. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2800_register_read(rt2x00dev, MAC_CSR0, ®); if (reg && reg != ~0) break; msleep(1); @@ -1182,8 +1182,8 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, data + offset, length, REGISTER_TIMEOUT32(length)); - rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); - rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); /* * Send firmware request to device to load firmware, @@ -1198,7 +1198,7 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, } msleep(10); - rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); /* * Send signal to firmware during boot time. @@ -1217,7 +1217,7 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, * Wait for device to stabilize. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY)) break; msleep(1); @@ -1231,8 +1231,8 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, /* * Initialize firmware. */ - rt2x00usb_register_write(rt2x00dev, H2M_BBP_AGENT, 0); - rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); msleep(1); return 0; @@ -1250,7 +1250,7 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) * Wait untill BBP and RF are ready. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2800_register_read(rt2x00dev, MAC_CSR0, ®); if (reg && reg != ~0) break; msleep(1); @@ -1261,59 +1261,59 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) return -EBUSY; } - rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, ®); - rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); + rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); - rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); - rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); + rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, USB_MODE_RESET, REGISTER_TIMEOUT); - rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); - rt2x00usb_register_read(rt2x00dev, BCN_OFFSET0, ®); + rt2800_register_read(rt2x00dev, BCN_OFFSET0, ®); rt2x00_set_field32(®, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */ rt2x00_set_field32(®, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */ rt2x00_set_field32(®, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */ rt2x00_set_field32(®, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */ - rt2x00usb_register_write(rt2x00dev, BCN_OFFSET0, reg); + rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg); - rt2x00usb_register_read(rt2x00dev, BCN_OFFSET1, ®); + rt2800_register_read(rt2x00dev, BCN_OFFSET1, ®); rt2x00_set_field32(®, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */ rt2x00_set_field32(®, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */ rt2x00_set_field32(®, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */ rt2x00_set_field32(®, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */ - rt2x00usb_register_write(rt2x00dev, BCN_OFFSET1, reg); + rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg); - rt2x00usb_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); - rt2x00usb_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); + rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); - rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); - rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0); - rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { - rt2x00usb_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); - rt2x00usb_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); - rt2x00usb_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); + rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); } else { - rt2x00usb_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); - rt2x00usb_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); } - rt2x00usb_register_read(rt2x00dev, TX_LINK_CFG, ®); + rt2800_register_read(rt2x00dev, TX_LINK_CFG, ®); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32); rt2x00_set_field32(®, TX_LINK_CFG_MFB_ENABLE, 0); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0); @@ -1322,14 +1322,14 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TX_LINK_CFG_TX_CF_ACK_EN, 1); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB, 0); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFS, 0); - rt2x00usb_register_write(rt2x00dev, TX_LINK_CFG, reg); + rt2800_register_write(rt2x00dev, TX_LINK_CFG, reg); - rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); rt2x00_set_field32(®, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9); rt2x00_set_field32(®, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10); - rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, MAX_LEN_CFG, ®); + rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION && rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION) @@ -1338,19 +1338,19 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); rt2x00_set_field32(®, MAX_LEN_CFG_MIN_PSDU, 0); rt2x00_set_field32(®, MAX_LEN_CFG_MIN_MPDU, 0); - rt2x00usb_register_write(rt2x00dev, MAX_LEN_CFG, reg); + rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); - rt2x00usb_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); + rt2800_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); - rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); rt2x00_set_field32(®, AUTO_RSP_CFG_AUTORESPONDER, 1); rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MMODE, 0); rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MREF, 0); rt2x00_set_field32(®, AUTO_RSP_CFG_DUAL_CTS_EN, 0); rt2x00_set_field32(®, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0); - rt2x00usb_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); - rt2x00usb_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 8); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV, 1); @@ -1360,9 +1360,9 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1); rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2x00usb_register_write(rt2x00dev, CCK_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 8); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV, 1); @@ -1372,9 +1372,9 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1); rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2x00usb_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, 0x4004); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_NAV, 1); @@ -1384,9 +1384,9 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0); rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2x00usb_register_write(rt2x00dev, MM20_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV, 1); @@ -1396,9 +1396,9 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1); rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2x00usb_register_write(rt2x00dev, MM40_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, 0x4004); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_NAV, 1); @@ -1408,9 +1408,9 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0); rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2x00usb_register_write(rt2x00dev, GF20_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, 0x4084); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_NAV, 1); @@ -1420,11 +1420,11 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1); rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2x00usb_register_write(rt2x00dev, GF40_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); - rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006); + rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); - rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); @@ -1434,26 +1434,26 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, WPDMA_GLO_CFG_BIG_ENDIAN, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_HDR_SCATTER, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_HDR_SEG_LEN, 0); - rt2x00usb_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - rt2x00usb_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); - rt2x00usb_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); + rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); + rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); - rt2x00usb_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32); rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, IEEE80211_MAX_RTS_THRESHOLD); rt2x00_set_field32(®, TX_RTS_CFG_RTS_FBK_EN, 0); - rt2x00usb_register_write(rt2x00dev, TX_RTS_CFG, reg); + rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); - rt2x00usb_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca); - rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + rt2800_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca); + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); /* * ASIC will keep garbage value after boot, clear encryption keys. */ for (i = 0; i < 4; i++) - rt2x00usb_register_write(rt2x00dev, + rt2800_register_write(rt2x00dev, SHARED_KEY_MODE_ENTRY(i), 0); for (i = 0; i < 256; i++) { @@ -1461,8 +1461,8 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00usb_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), wcid, sizeof(wcid)); - rt2x00usb_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); - rt2x00usb_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); + rt2800_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); + rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); } /* @@ -1471,20 +1471,20 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) * the first byte since that byte contains the VALID and OWNER * bits which (when set to 0) will invalidate the entire beacon. */ - rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); - rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); - rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); - rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); - rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE4, 0); - rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE5, 0); - rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE6, 0); - rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE7, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE4, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE5, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0); - rt2x00usb_register_read(rt2x00dev, USB_CYC_CFG, ®); + rt2800_register_read(rt2x00dev, USB_CYC_CFG, ®); rt2x00_set_field32(®, USB_CYC_CFG_CLOCK_CYCLE, 30); - rt2x00usb_register_write(rt2x00dev, USB_CYC_CFG, reg); + rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg); - rt2x00usb_register_read(rt2x00dev, HT_FBK_CFG0, ®); + rt2800_register_read(rt2x00dev, HT_FBK_CFG0, ®); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS0FBK, 0); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS1FBK, 0); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS2FBK, 1); @@ -1493,9 +1493,9 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS5FBK, 4); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS6FBK, 5); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS7FBK, 6); - rt2x00usb_register_write(rt2x00dev, HT_FBK_CFG0, reg); + rt2800_register_write(rt2x00dev, HT_FBK_CFG0, reg); - rt2x00usb_register_read(rt2x00dev, HT_FBK_CFG1, ®); + rt2800_register_read(rt2x00dev, HT_FBK_CFG1, ®); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS8FBK, 8); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS9FBK, 8); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS10FBK, 9); @@ -1504,9 +1504,9 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS13FBK, 12); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS14FBK, 13); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS15FBK, 14); - rt2x00usb_register_write(rt2x00dev, HT_FBK_CFG1, reg); + rt2800_register_write(rt2x00dev, HT_FBK_CFG1, reg); - rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG0, ®); + rt2800_register_read(rt2x00dev, LG_FBK_CFG0, ®); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 9); @@ -1515,26 +1515,26 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 13); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); - rt2x00usb_register_write(rt2x00dev, LG_FBK_CFG0, reg); + rt2800_register_write(rt2x00dev, LG_FBK_CFG0, reg); - rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG1, ®); + rt2800_register_read(rt2x00dev, LG_FBK_CFG1, ®); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS0FBK, 0); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS1FBK, 0); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS2FBK, 1); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS3FBK, 2); - rt2x00usb_register_write(rt2x00dev, LG_FBK_CFG1, reg); + rt2800_register_write(rt2x00dev, LG_FBK_CFG1, reg); /* * We must clear the error counters. * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2x00usb_register_read(rt2x00dev, RX_STA_CNT0, ®); - rt2x00usb_register_read(rt2x00dev, RX_STA_CNT1, ®); - rt2x00usb_register_read(rt2x00dev, RX_STA_CNT2, ®); - rt2x00usb_register_read(rt2x00dev, TX_STA_CNT0, ®); - rt2x00usb_register_read(rt2x00dev, TX_STA_CNT1, ®); - rt2x00usb_register_read(rt2x00dev, TX_STA_CNT2, ®); + rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); + rt2800_register_read(rt2x00dev, RX_STA_CNT1, ®); + rt2800_register_read(rt2x00dev, RX_STA_CNT2, ®); + rt2800_register_read(rt2x00dev, TX_STA_CNT0, ®); + rt2800_register_read(rt2x00dev, TX_STA_CNT1, ®); + rt2800_register_read(rt2x00dev, TX_STA_CNT2, ®); return 0; } @@ -1545,7 +1545,7 @@ static int rt2800usb_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) u32 reg; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00usb_register_read(rt2x00dev, MAC_STATUS_CFG, ®); + rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, ®); if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY)) return 0; @@ -1565,8 +1565,8 @@ static int rt2800usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) * BBP was enabled after firmware was loaded, * but we need to reactivate it now. */ - rt2x00usb_register_write(rt2x00dev, H2M_BBP_AGENT, 0); - rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); msleep(1); for (i = 0; i < REGISTER_BUSY_COUNT; i++) { @@ -1768,11 +1768,11 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, (state == STATE_RADIO_RX_ON) || (state == STATE_RADIO_RX_ON_LINK)); - rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); } static int rt2800usb_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) @@ -1781,7 +1781,7 @@ static int rt2800usb_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) u32 reg; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) return 0; @@ -1807,20 +1807,20 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) rt2800usb_init_rfcsr(rt2x00dev))) return -EIO; - rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); - rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); udelay(50); - rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); - rt2x00usb_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - rt2x00usb_register_read(rt2x00dev, USB_DMA_CFG, ®); + rt2800_register_read(rt2x00dev, USB_DMA_CFG, ®); rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0); /* Don't use bulk in aggregation when working with USB 1.1 */ rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, @@ -1834,12 +1834,12 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) ((RX_ENTRIES * DATA_FRAME_SIZE) / 1024) - 3); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_EN, 1); rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); - rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, reg); + rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg); - rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); - rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); /* * Initialize LED control @@ -1863,14 +1863,14 @@ static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00usb_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2x00usb_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0); - rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0); - rt2x00usb_register_write(rt2x00dev, TX_PIN_CFG, 0); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0); + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); + rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); /* Wait for DMA, ignore error */ rt2800usb_wait_wpdma_ready(rt2x00dev); @@ -2038,9 +2038,9 @@ static void rt2800usb_write_beacon(struct queue_entry *entry) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); - rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); /* * Write entire beacon with descriptor to register. @@ -2083,12 +2083,12 @@ static void rt2800usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, return; } - rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) { rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); - rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); } } @@ -2316,7 +2316,7 @@ static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2800_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2870, value, reg); /* @@ -2659,33 +2659,33 @@ static int rt2800usb_set_rts_threshold(struct ieee80211_hw *hw, u32 value) u32 reg; bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD); - rt2x00usb_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, value); - rt2x00usb_register_write(rt2x00dev, TX_RTS_CFG, reg); + rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); - rt2x00usb_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, enabled); - rt2x00usb_register_write(rt2x00dev, CCK_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, enabled); - rt2x00usb_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, enabled); - rt2x00usb_register_write(rt2x00dev, MM20_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, enabled); - rt2x00usb_register_write(rt2x00dev, MM40_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, enabled); - rt2x00usb_register_write(rt2x00dev, GF20_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - rt2x00usb_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); rt2x00_set_field32(®, GF40_PROT_CFG_RTS_TH_EN, enabled); - rt2x00usb_register_write(rt2x00dev, GF40_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); return 0; } @@ -2724,35 +2724,35 @@ static int rt2800usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, field.bit_offset = (queue_idx & 1) * 16; field.bit_mask = 0xffff << field.bit_offset; - rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2800_register_read(rt2x00dev, offset, ®); rt2x00_set_field32(®, field, queue->txop); - rt2x00usb_register_write(rt2x00dev, offset, reg); + rt2800_register_write(rt2x00dev, offset, reg); /* Update WMM registers */ field.bit_offset = queue_idx * 4; field.bit_mask = 0xf << field.bit_offset; - rt2x00usb_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); + rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); rt2x00_set_field32(®, field, queue->aifs); - rt2x00usb_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); + rt2800_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); - rt2x00usb_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); + rt2800_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); rt2x00_set_field32(®, field, queue->cw_min); - rt2x00usb_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); + rt2800_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); - rt2x00usb_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); + rt2800_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); rt2x00_set_field32(®, field, queue->cw_max); - rt2x00usb_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); + rt2800_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); /* Update EDCA registers */ offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx); - rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2800_register_read(rt2x00dev, offset, ®); rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop); rt2x00_set_field32(®, EDCA_AC0_CFG_AIFSN, queue->aifs); rt2x00_set_field32(®, EDCA_AC0_CFG_CWMIN, queue->cw_min); rt2x00_set_field32(®, EDCA_AC0_CFG_CWMAX, queue->cw_max); - rt2x00usb_register_write(rt2x00dev, offset, reg); + rt2800_register_write(rt2x00dev, offset, reg); return 0; } @@ -2763,9 +2763,9 @@ static u64 rt2800usb_get_tsf(struct ieee80211_hw *hw) u64 tsf; u32 reg; - rt2x00usb_register_read(rt2x00dev, TSF_TIMER_DW1, ®); + rt2800_register_read(rt2x00dev, TSF_TIMER_DW1, ®); tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32; - rt2x00usb_register_read(rt2x00dev, TSF_TIMER_DW0, ®); + rt2800_register_read(rt2x00dev, TSF_TIMER_DW0, ®); tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD); return tsf; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 7b1130a22c55..9d2dcc5f849c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -27,6 +27,27 @@ #ifndef RT2800USB_H #define RT2800USB_H +static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) +{ + rt2x00usb_register_read(rt2x00dev, offset, value); +} + +static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + rt2x00usb_register_write(rt2x00dev, offset, value); +} + +static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + rt2x00usb_register_write_lock(rt2x00dev, offset, value); +} + /* * RF chip defines. * -- cgit v1.2.3 From 9ca21eb7cd2ba4f837bcde5e1c9ec0c784cfc03d Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:33:13 +0100 Subject: rt2800pci: add rt2800_register_[read,write]() wrappers Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 479 ++++++++++++++++---------------- drivers/net/wireless/rt2x00/rt2800pci.h | 21 ++ 2 files changed, 261 insertions(+), 239 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 5d3c48b9f5cc..802086dce707 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -57,7 +57,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /* * Register access. * All access to the CSR registers will go through the methods - * rt2x00pci_register_read and rt2x00pci_register_write. + * rt2800_register_read and rt2800_register_write. * BBP and RF register require indirect register access, * and use the CSR registers BBPCSR and RFCSR to achieve this. * These indirect registers work with busy bits, @@ -66,6 +66,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * between each attampt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. + * The _lock versions must be used if you already hold the csr_mutex */ #define WAIT_FOR_BBP(__dev, __reg) \ rt2x00pci_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) @@ -96,7 +97,7 @@ static void rt2800pci_bbp_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); - rt2x00pci_register_write(rt2x00dev, BBP_CSR_CFG, reg); + rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); } mutex_unlock(&rt2x00dev->csr_mutex); @@ -124,7 +125,7 @@ static void rt2800pci_bbp_read(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); - rt2x00pci_register_write(rt2x00dev, BBP_CSR_CFG, reg); + rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); WAIT_FOR_BBP(rt2x00dev, ®); } @@ -152,7 +153,7 @@ static void rt2800pci_rfcsr_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); - rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG, reg); + rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); } mutex_unlock(&rt2x00dev->csr_mutex); @@ -179,7 +180,7 @@ static void rt2800pci_rfcsr_read(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); - rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG, reg); + rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); WAIT_FOR_RFCSR(rt2x00dev, ®); } @@ -207,7 +208,7 @@ static void rt2800pci_rf_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, RF_CSR_CFG0_SEL, 0); rt2x00_set_field32(®, RF_CSR_CFG0_BUSY, 1); - rt2x00pci_register_write(rt2x00dev, RF_CSR_CFG0, reg); + rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg); rt2x00_rf_write(rt2x00dev, word, value); } @@ -238,11 +239,11 @@ static void rt2800pci_mcu_request(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); - rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); + rt2800_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg); reg = 0; rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); - rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); + rt2800_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg); } mutex_unlock(&rt2x00dev->csr_mutex); @@ -254,7 +255,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) u32 reg; for (i = 0; i < 200; i++) { - rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); + rt2800_register_read(rt2x00dev, H2M_MAILBOX_CID, ®); if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) || (rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) || @@ -268,8 +269,8 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) if (i == 200) ERROR(rt2x00dev, "MCU request failed, no response from hardware\n"); - rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); - rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); } #ifdef CONFIG_RT2800PCI_WISOC @@ -291,7 +292,7 @@ static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) struct rt2x00_dev *rt2x00dev = eeprom->data; u32 reg; - rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); + rt2800_register_read(rt2x00dev, E2PROM_CSR, ®); eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN); eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT); @@ -313,7 +314,7 @@ static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom) rt2x00_set_field32(®, E2PROM_CSR_CHIP_SELECT, !!eeprom->reg_chip_select); - rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg); + rt2800_register_write(rt2x00dev, E2PROM_CSR, reg); } static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) @@ -321,7 +322,7 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) struct eeprom_93cx6 eeprom; u32 reg; - rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, ®); + rt2800_register_read(rt2x00dev, E2PROM_CSR, ®); eeprom.data = rt2x00dev; eeprom.register_read = rt2800pci_eepromregister_read; @@ -342,23 +343,23 @@ static void rt2800pci_efuse_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, EFUSE_CTRL, ®); + rt2800_register_read(rt2x00dev, EFUSE_CTRL, ®); rt2x00_set_field32(®, EFUSE_CTRL_ADDRESS_IN, i); rt2x00_set_field32(®, EFUSE_CTRL_MODE, 0); rt2x00_set_field32(®, EFUSE_CTRL_KICK, 1); - rt2x00pci_register_write(rt2x00dev, EFUSE_CTRL, reg); + rt2800_register_write(rt2x00dev, EFUSE_CTRL, reg); /* Wait until the EEPROM has been loaded */ rt2x00pci_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®); /* Apparently the data is read from end to start */ - rt2x00pci_register_read(rt2x00dev, EFUSE_DATA3, + rt2800_register_read(rt2x00dev, EFUSE_DATA3, (u32 *)&rt2x00dev->eeprom[i]); - rt2x00pci_register_read(rt2x00dev, EFUSE_DATA2, + rt2800_register_read(rt2x00dev, EFUSE_DATA2, (u32 *)&rt2x00dev->eeprom[i + 2]); - rt2x00pci_register_read(rt2x00dev, EFUSE_DATA1, + rt2800_register_read(rt2x00dev, EFUSE_DATA1, (u32 *)&rt2x00dev->eeprom[i + 4]); - rt2x00pci_register_read(rt2x00dev, EFUSE_DATA0, + rt2800_register_read(rt2x00dev, EFUSE_DATA0, (u32 *)&rt2x00dev->eeprom[i + 6]); } @@ -383,8 +384,8 @@ static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) static const struct rt2x00debug rt2800pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2x00pci_register_read, - .write = rt2x00pci_register_write, + .read = rt2800_register_read, + .write = rt2800_register_write, .flags = RT2X00DEBUGFS_OFFSET, .word_base = CSR_REG_BASE, .word_size = sizeof(u32), @@ -418,7 +419,7 @@ static int rt2800pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00pci_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); + rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); } @@ -467,7 +468,7 @@ static int rt2800pci_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt2x00pci_register_read(led->rt2x00dev, LED_CFG, ®); + rt2800_register_read(led->rt2x00dev, LED_CFG, ®); rt2x00_set_field32(®, LED_CFG_ON_PERIOD, *delay_on); rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); @@ -475,7 +476,7 @@ static int rt2800pci_blink_set(struct led_classdev *led_cdev, rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 12); rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3); rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1); - rt2x00pci_register_write(led->rt2x00dev, LED_CFG, reg); + rt2800_register_write(led->rt2x00dev, LED_CFG, reg); return 0; } @@ -506,7 +507,7 @@ static void rt2800pci_config_wcid_attr(struct rt2x00_dev *rt2x00dev, offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); - rt2x00pci_register_read(rt2x00dev, offset, ®); + rt2800_register_read(rt2x00dev, offset, ®); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, @@ -514,7 +515,7 @@ static void rt2800pci_config_wcid_attr(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, (crypto->cmd == SET_KEY) * crypto->bssidx); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); - rt2x00pci_register_write(rt2x00dev, offset, reg); + rt2800_register_write(rt2x00dev, offset, reg); offset = MAC_IVEIV_ENTRY(key->hw_key_idx); @@ -572,10 +573,10 @@ static int rt2800pci_config_shared_key(struct rt2x00_dev *rt2x00dev, offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); - rt2x00pci_register_read(rt2x00dev, offset, ®); + rt2800_register_read(rt2x00dev, offset, ®); rt2x00_set_field32(®, field, (crypto->cmd == SET_KEY) * crypto->cipher); - rt2x00pci_register_write(rt2x00dev, offset, reg); + rt2800_register_write(rt2x00dev, offset, reg); /* * Update WCID information @@ -635,7 +636,7 @@ static void rt2800pci_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt2x00pci_register_read(rt2x00dev, RX_FILTER_CFG, ®); + rt2800_register_read(rt2x00dev, RX_FILTER_CFG, ®); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, @@ -664,7 +665,7 @@ static void rt2800pci_config_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, !(filter_flags & FIF_CONTROL)); - rt2x00pci_register_write(rt2x00dev, RX_FILTER_CFG, reg); + rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg); } static void rt2800pci_config_intf(struct rt2x00_dev *rt2x00dev, @@ -683,16 +684,16 @@ static void rt2800pci_config_intf(struct rt2x00_dev *rt2x00dev, * bits which (when set to 0) will invalidate the entire beacon. */ beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - rt2x00pci_register_write(rt2x00dev, beacon_base, 0); + rt2800_register_write(rt2x00dev, beacon_base, 0); /* * Enable synchronisation. */ - rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); - rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); } if (flags & CONFIG_UPDATE_MAC) { @@ -720,43 +721,43 @@ static void rt2800pci_config_erp(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20); - rt2x00pci_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, !!erp->short_preamble); rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, !!erp->short_preamble); - rt2x00pci_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); - rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, erp->cts_protection ? 2 : 0); - rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - rt2x00pci_register_write(rt2x00dev, LEGACY_BASIC_RATE, + rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, erp->basic_rates); - rt2x00pci_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); - rt2x00pci_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); + rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); - rt2x00pci_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); + rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, XIFS_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); rt2x00_set_field32(®, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs); rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs); rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4); rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); - rt2x00pci_register_write(rt2x00dev, XIFS_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); - rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, erp->beacon_int * 16); - rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); } static void rt2800pci_config_ant(struct rt2x00_dev *rt2x00dev, @@ -965,11 +966,11 @@ static void rt2800pci_config_channel(struct rt2x00_dev *rt2x00dev, rt2800pci_bbp_write(rt2x00dev, 75, 0x50); } - rt2x00pci_register_read(rt2x00dev, TX_BAND_CFG, ®); + rt2800_register_read(rt2x00dev, TX_BAND_CFG, ®); rt2x00_set_field32(®, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf)); rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); - rt2x00pci_register_write(rt2x00dev, TX_BAND_CFG, reg); + rt2800_register_write(rt2x00dev, TX_BAND_CFG, reg); tx_pin = 0; @@ -992,7 +993,7 @@ static void rt2800pci_config_channel(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14); rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14); - rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); + rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); rt2800pci_bbp_read(rt2x00dev, 4, &bbp); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); @@ -1028,7 +1029,7 @@ static void rt2800pci_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(®, BBP1_TX_POWER, 0); rt2800pci_bbp_write(rt2x00dev, 1, r1); - rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_0, ®); + rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, ®); rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_0_2MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_0_55MBS, value); @@ -1037,9 +1038,9 @@ static void rt2800pci_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_0_9MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_0_12MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_0_18MBS, value); - rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_0, reg); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, reg); - rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_1, ®); + rt2800_register_read(rt2x00dev, TX_PWR_CFG_1, ®); rt2x00_set_field32(®, TX_PWR_CFG_1_24MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_1_36MBS, value); rt2x00_set_field32(®, TX_PWR_CFG_1_48MBS, value); @@ -1048,9 +1049,9 @@ static void rt2800pci_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_1_MCS1, value); rt2x00_set_field32(®, TX_PWR_CFG_1_MCS2, value); rt2x00_set_field32(®, TX_PWR_CFG_1_MCS3, value); - rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_1, reg); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, reg); - rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_2, ®); + rt2800_register_read(rt2x00dev, TX_PWR_CFG_2, ®); rt2x00_set_field32(®, TX_PWR_CFG_2_MCS4, value); rt2x00_set_field32(®, TX_PWR_CFG_2_MCS5, value); rt2x00_set_field32(®, TX_PWR_CFG_2_MCS6, value); @@ -1059,9 +1060,9 @@ static void rt2800pci_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_2_MCS9, value); rt2x00_set_field32(®, TX_PWR_CFG_2_MCS10, value); rt2x00_set_field32(®, TX_PWR_CFG_2_MCS11, value); - rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_2, reg); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, reg); - rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_3, ®); + rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, ®); rt2x00_set_field32(®, TX_PWR_CFG_3_MCS12, value); rt2x00_set_field32(®, TX_PWR_CFG_3_MCS13, value); rt2x00_set_field32(®, TX_PWR_CFG_3_MCS14, value); @@ -1070,14 +1071,14 @@ static void rt2800pci_config_txpower(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN2, value); rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN3, value); rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN4, value); - rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_3, reg); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, reg); - rt2x00pci_register_read(rt2x00dev, TX_PWR_CFG_4, ®); + rt2800_register_read(rt2x00dev, TX_PWR_CFG_4, ®); rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN5, value); rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN6, value); rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN7, value); rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN8, value); - rt2x00pci_register_write(rt2x00dev, TX_PWR_CFG_4, reg); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, reg); } static void rt2800pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, @@ -1085,7 +1086,7 @@ static void rt2800pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, TX_RTY_CFG, ®); + rt2800_register_read(rt2x00dev, TX_RTY_CFG, ®); rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, libconf->conf->short_frame_max_tx_count); rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, @@ -1094,7 +1095,7 @@ static void rt2800pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TX_RTY_CFG_NON_AGG_RTY_MODE, 0); rt2x00_set_field32(®, TX_RTY_CFG_AGG_RTY_MODE, 0); rt2x00_set_field32(®, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1); - rt2x00pci_register_write(rt2x00dev, TX_RTY_CFG, reg); + rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg); } static void rt2800pci_config_ps(struct rt2x00_dev *rt2x00dev, @@ -1106,24 +1107,24 @@ static void rt2800pci_config_ps(struct rt2x00_dev *rt2x00dev, u32 reg; if (state == STATE_SLEEP) { - rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); - rt2x00pci_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5); rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, libconf->conf->listen_interval - 1); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 1); - rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); } else { rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); - rt2x00pci_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); - rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); } } @@ -1156,7 +1157,7 @@ static void rt2800pci_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt2x00pci_register_read(rt2x00dev, RX_STA_CNT0, ®); + rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); } @@ -1259,7 +1260,7 @@ static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev, * Wait for stable hardware. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); + rt2800_register_read(rt2x00dev, MAC_CSR0, ®); if (reg && reg != ~0) break; msleep(1); @@ -1270,27 +1271,27 @@ static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev, return -EBUSY; } - rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002); - rt2x00pci_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000); + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002); + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000); /* * Disable DMA, will be reenabled later when enabling * the radio. */ - rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); /* * enable Host program ram write selection */ reg = 0; rt2x00_set_field32(®, PBF_SYS_CTRL_HOST_RAM_WRITE, 1); - rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, reg); + rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg); /* * Write firmware to device. @@ -1298,14 +1299,14 @@ static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, data, len); - rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); - rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); + rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); + rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); /* * Wait for device to stabilize. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); if (rt2x00_get_field32(reg, PBF_SYS_CTRL_READY)) break; msleep(1); @@ -1324,8 +1325,8 @@ static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev, /* * Initialize BBP R/W access agent */ - rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0); - rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); return 0; } @@ -1375,7 +1376,7 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) struct queue_entry_priv_pci *entry_priv; u32 reg; - rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®); + rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, ®); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1); @@ -1383,54 +1384,54 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1); - rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg); + rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg); - rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); - rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); + rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); + rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); /* * Initialize registers. */ entry_priv = rt2x00dev->tx[0].entries[0].priv_data; - rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma); - rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT0, rt2x00dev->tx[0].limit); - rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX0, 0); - rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX0, 0); + rt2800_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma); + rt2800_register_write(rt2x00dev, TX_MAX_CNT0, rt2x00dev->tx[0].limit); + rt2800_register_write(rt2x00dev, TX_CTX_IDX0, 0); + rt2800_register_write(rt2x00dev, TX_DTX_IDX0, 0); entry_priv = rt2x00dev->tx[1].entries[0].priv_data; - rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma); - rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT1, rt2x00dev->tx[1].limit); - rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX1, 0); - rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX1, 0); + rt2800_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma); + rt2800_register_write(rt2x00dev, TX_MAX_CNT1, rt2x00dev->tx[1].limit); + rt2800_register_write(rt2x00dev, TX_CTX_IDX1, 0); + rt2800_register_write(rt2x00dev, TX_DTX_IDX1, 0); entry_priv = rt2x00dev->tx[2].entries[0].priv_data; - rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma); - rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT2, rt2x00dev->tx[2].limit); - rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX2, 0); - rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX2, 0); + rt2800_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma); + rt2800_register_write(rt2x00dev, TX_MAX_CNT2, rt2x00dev->tx[2].limit); + rt2800_register_write(rt2x00dev, TX_CTX_IDX2, 0); + rt2800_register_write(rt2x00dev, TX_DTX_IDX2, 0); entry_priv = rt2x00dev->tx[3].entries[0].priv_data; - rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma); - rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT3, rt2x00dev->tx[3].limit); - rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX3, 0); - rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX3, 0); + rt2800_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma); + rt2800_register_write(rt2x00dev, TX_MAX_CNT3, rt2x00dev->tx[3].limit); + rt2800_register_write(rt2x00dev, TX_CTX_IDX3, 0); + rt2800_register_write(rt2x00dev, TX_DTX_IDX3, 0); entry_priv = rt2x00dev->rx->entries[0].priv_data; - rt2x00pci_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma); - rt2x00pci_register_write(rt2x00dev, RX_MAX_CNT, rt2x00dev->rx[0].limit); - rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, rt2x00dev->rx[0].limit - 1); - rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0); + rt2800_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma); + rt2800_register_write(rt2x00dev, RX_MAX_CNT, rt2x00dev->rx[0].limit); + rt2800_register_write(rt2x00dev, RX_CRX_IDX, rt2x00dev->rx[0].limit - 1); + rt2800_register_write(rt2x00dev, RX_DRX_IDX, 0); /* * Enable global DMA configuration */ - rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - rt2x00pci_register_write(rt2x00dev, DELAY_INT_CFG, 0); + rt2800_register_write(rt2x00dev, DELAY_INT_CFG, 0); return 0; } @@ -1440,47 +1441,47 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) u32 reg; unsigned int i; - rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); - rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); - rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); - rt2x00pci_register_read(rt2x00dev, BCN_OFFSET0, ®); + rt2800_register_read(rt2x00dev, BCN_OFFSET0, ®); rt2x00_set_field32(®, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */ rt2x00_set_field32(®, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */ rt2x00_set_field32(®, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */ rt2x00_set_field32(®, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */ - rt2x00pci_register_write(rt2x00dev, BCN_OFFSET0, reg); + rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg); - rt2x00pci_register_read(rt2x00dev, BCN_OFFSET1, ®); + rt2800_register_read(rt2x00dev, BCN_OFFSET1, ®); rt2x00_set_field32(®, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */ rt2x00_set_field32(®, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */ rt2x00_set_field32(®, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */ rt2x00_set_field32(®, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */ - rt2x00pci_register_write(rt2x00dev, BCN_OFFSET1, reg); + rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg); - rt2x00pci_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); - rt2x00pci_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); + rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); - rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); - rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2x00_set_field32(®, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0); - rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); - rt2x00pci_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); - rt2x00pci_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); - rt2x00pci_register_read(rt2x00dev, TX_LINK_CFG, ®); + rt2800_register_read(rt2x00dev, TX_LINK_CFG, ®); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32); rt2x00_set_field32(®, TX_LINK_CFG_MFB_ENABLE, 0); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0); @@ -1489,14 +1490,14 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TX_LINK_CFG_TX_CF_ACK_EN, 1); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB, 0); rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFS, 0); - rt2x00pci_register_write(rt2x00dev, TX_LINK_CFG, reg); + rt2800_register_write(rt2x00dev, TX_LINK_CFG, reg); - rt2x00pci_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); rt2x00_set_field32(®, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9); rt2x00_set_field32(®, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10); - rt2x00pci_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, MAX_LEN_CFG, ®); + rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION && rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION) @@ -1505,19 +1506,19 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); rt2x00_set_field32(®, MAX_LEN_CFG_MIN_PSDU, 0); rt2x00_set_field32(®, MAX_LEN_CFG_MIN_MPDU, 0); - rt2x00pci_register_write(rt2x00dev, MAX_LEN_CFG, reg); + rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); - rt2x00pci_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); + rt2800_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); - rt2x00pci_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); rt2x00_set_field32(®, AUTO_RSP_CFG_AUTORESPONDER, 1); rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MMODE, 0); rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MREF, 0); rt2x00_set_field32(®, AUTO_RSP_CFG_DUAL_CTS_EN, 0); rt2x00_set_field32(®, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0); - rt2x00pci_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); - rt2x00pci_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 8); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV, 1); @@ -1527,9 +1528,9 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1); rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2x00pci_register_write(rt2x00dev, CCK_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 8); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV, 1); @@ -1539,9 +1540,9 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1); rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, 0x4004); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_NAV, 1); @@ -1551,9 +1552,9 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0); rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2x00pci_register_write(rt2x00dev, MM20_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV, 1); @@ -1563,9 +1564,9 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1); rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2x00pci_register_write(rt2x00dev, MM40_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, 0x4004); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_NAV, 1); @@ -1575,9 +1576,9 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0); rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2x00pci_register_write(rt2x00dev, GF20_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, 0x4084); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, 0); rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_NAV, 1); @@ -1587,26 +1588,26 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1); rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1); rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2x00pci_register_write(rt2x00dev, GF40_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); - rt2x00pci_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); - rt2x00pci_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); + rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); + rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); - rt2x00pci_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32); rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, IEEE80211_MAX_RTS_THRESHOLD); rt2x00_set_field32(®, TX_RTS_CFG_RTS_FBK_EN, 0); - rt2x00pci_register_write(rt2x00dev, TX_RTS_CFG, reg); + rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); - rt2x00pci_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca); - rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + rt2800_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca); + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); /* * ASIC will keep garbage value after boot, clear encryption keys. */ for (i = 0; i < 4; i++) - rt2x00pci_register_write(rt2x00dev, + rt2800_register_write(rt2x00dev, SHARED_KEY_MODE_ENTRY(i), 0); for (i = 0; i < 256; i++) { @@ -1614,8 +1615,8 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), wcid, sizeof(wcid)); - rt2x00pci_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); - rt2x00pci_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); + rt2800_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); + rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); } /* @@ -1624,16 +1625,16 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) * the first byte since that byte contains the VALID and OWNER * bits which (when set to 0) will invalidate the entire beacon. */ - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0); - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0); - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0); - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0); - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE4, 0); - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE5, 0); - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE6, 0); - rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE7, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE4, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE5, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0); - rt2x00pci_register_read(rt2x00dev, HT_FBK_CFG0, ®); + rt2800_register_read(rt2x00dev, HT_FBK_CFG0, ®); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS0FBK, 0); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS1FBK, 0); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS2FBK, 1); @@ -1642,9 +1643,9 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS5FBK, 4); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS6FBK, 5); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS7FBK, 6); - rt2x00pci_register_write(rt2x00dev, HT_FBK_CFG0, reg); + rt2800_register_write(rt2x00dev, HT_FBK_CFG0, reg); - rt2x00pci_register_read(rt2x00dev, HT_FBK_CFG1, ®); + rt2800_register_read(rt2x00dev, HT_FBK_CFG1, ®); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS8FBK, 8); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS9FBK, 8); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS10FBK, 9); @@ -1653,9 +1654,9 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS13FBK, 12); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS14FBK, 13); rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS15FBK, 14); - rt2x00pci_register_write(rt2x00dev, HT_FBK_CFG1, reg); + rt2800_register_write(rt2x00dev, HT_FBK_CFG1, reg); - rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG0, ®); + rt2800_register_read(rt2x00dev, LG_FBK_CFG0, ®); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 9); @@ -1664,26 +1665,26 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 13); rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); - rt2x00pci_register_write(rt2x00dev, LG_FBK_CFG0, reg); + rt2800_register_write(rt2x00dev, LG_FBK_CFG0, reg); - rt2x00pci_register_read(rt2x00dev, LG_FBK_CFG1, ®); + rt2800_register_read(rt2x00dev, LG_FBK_CFG1, ®); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS0FBK, 0); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS1FBK, 0); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS2FBK, 1); rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS3FBK, 2); - rt2x00pci_register_write(rt2x00dev, LG_FBK_CFG1, reg); + rt2800_register_write(rt2x00dev, LG_FBK_CFG1, reg); /* * We must clear the error counters. * These registers are cleared on read, * so we may pass a useless variable to store the value. */ - rt2x00pci_register_read(rt2x00dev, RX_STA_CNT0, ®); - rt2x00pci_register_read(rt2x00dev, RX_STA_CNT1, ®); - rt2x00pci_register_read(rt2x00dev, RX_STA_CNT2, ®); - rt2x00pci_register_read(rt2x00dev, TX_STA_CNT0, ®); - rt2x00pci_register_read(rt2x00dev, TX_STA_CNT1, ®); - rt2x00pci_register_read(rt2x00dev, TX_STA_CNT2, ®); + rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); + rt2800_register_read(rt2x00dev, RX_STA_CNT1, ®); + rt2800_register_read(rt2x00dev, RX_STA_CNT2, ®); + rt2800_register_read(rt2x00dev, TX_STA_CNT0, ®); + rt2800_register_read(rt2x00dev, TX_STA_CNT1, ®); + rt2800_register_read(rt2x00dev, TX_STA_CNT2, ®); return 0; } @@ -1694,7 +1695,7 @@ static int rt2800pci_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) u32 reg; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, MAC_STATUS_CFG, ®); + rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, ®); if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY)) return 0; @@ -1714,8 +1715,8 @@ static int rt2800pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) * BBP was enabled after firmware was loaded, * but we need to reactivate it now. */ - rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0); - rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); msleep(1); for (i = 0; i < REGISTER_BUSY_COUNT; i++) { @@ -1928,11 +1929,11 @@ static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, (state == STATE_RADIO_RX_ON) || (state == STATE_RADIO_RX_ON_LINK)); - rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); } static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, @@ -1946,11 +1947,11 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, * should clear the register to assure a clean state. */ if (state == STATE_RADIO_IRQ_ON) { - rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); - rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); } - rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); rt2x00_set_field32(®, INT_MASK_CSR_RXDELAYINT, mask); rt2x00_set_field32(®, INT_MASK_CSR_TXDELAYINT, mask); rt2x00_set_field32(®, INT_MASK_CSR_RX_DONE, mask); @@ -1969,7 +1970,7 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, INT_MASK_CSR_GPTIMER, mask); rt2x00_set_field32(®, INT_MASK_CSR_RX_COHERENT, mask); rt2x00_set_field32(®, INT_MASK_CSR_TX_COHERENT, mask); - rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); + rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); } static int rt2800pci_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) @@ -1978,7 +1979,7 @@ static int rt2800pci_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) u32 reg; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) return 0; @@ -2014,22 +2015,22 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Enable RX. */ - rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); - rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); - rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); /* * Initialize LED control @@ -2053,21 +2054,21 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2x00pci_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0); - rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0); - rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, 0); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0); + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); + rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); - rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280); + rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280); - rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®); + rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, ®); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, 1); @@ -2075,10 +2076,10 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX4, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX5, 1); rt2x00_set_field32(®, WPDMA_RST_IDX_DRX_IDX0, 1); - rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg); + rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg); - rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); - rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); + rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); + rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); /* Wait for DMA, ignore error */ rt2800pci_wait_wpdma_ready(rt2x00dev); @@ -2267,9 +2268,9 @@ static void rt2800pci_write_beacon(struct queue_entry *entry) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); - rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); /* * Write entire beacon with descriptor to register. @@ -2297,12 +2298,12 @@ static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, u32 reg; if (queue_idx == QID_BEACON) { - rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) { rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 1); - rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); } return; } @@ -2318,7 +2319,7 @@ static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, else qidx = queue_idx; - rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx); + rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx); } static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, @@ -2327,16 +2328,16 @@ static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, u32 reg; if (qid == QID_BEACON) { - rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, 0); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, 0); return; } - rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, ®); + rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, ®); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, (qid == QID_AC_BE)); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, (qid == QID_AC_BK)); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, (qid == QID_AC_VI)); rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, (qid == QID_AC_VO)); - rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg); + rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg); } /* @@ -2432,7 +2433,7 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry, * Set RX IDX in register to inform hardware that we have handled * this entry and it is available for reuse again. */ - rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx); + rt2800_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx); /* * Remove TXWI descriptor from start of buffer. @@ -2469,7 +2470,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) old_reg = 0; while (1) { - rt2x00pci_register_read(rt2x00dev, TX_STA_FIFO, ®); + rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®); if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID)) break; @@ -2553,8 +2554,8 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) u32 reg; /* Read status and ACK all interrupts */ - rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); - rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); + rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); + rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); if (!reg) return IRQ_NONE; @@ -2711,7 +2712,7 @@ static int rt2800pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); + rt2800_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip_rf(rt2x00dev, value, reg); if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && @@ -3022,33 +3023,33 @@ static int rt2800pci_set_rts_threshold(struct ieee80211_hw *hw, u32 value) u32 reg; bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD); - rt2x00pci_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, value); - rt2x00pci_register_write(rt2x00dev, TX_RTS_CFG, reg); + rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); - rt2x00pci_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, enabled); - rt2x00pci_register_write(rt2x00dev, CCK_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, enabled); - rt2x00pci_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, enabled); - rt2x00pci_register_write(rt2x00dev, MM20_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, enabled); - rt2x00pci_register_write(rt2x00dev, MM40_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, enabled); - rt2x00pci_register_write(rt2x00dev, GF20_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - rt2x00pci_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); rt2x00_set_field32(®, GF40_PROT_CFG_RTS_TH_EN, enabled); - rt2x00pci_register_write(rt2x00dev, GF40_PROT_CFG, reg); + rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); return 0; } @@ -3087,35 +3088,35 @@ static int rt2800pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, field.bit_offset = (queue_idx & 1) * 16; field.bit_mask = 0xffff << field.bit_offset; - rt2x00pci_register_read(rt2x00dev, offset, ®); + rt2800_register_read(rt2x00dev, offset, ®); rt2x00_set_field32(®, field, queue->txop); - rt2x00pci_register_write(rt2x00dev, offset, reg); + rt2800_register_write(rt2x00dev, offset, reg); /* Update WMM registers */ field.bit_offset = queue_idx * 4; field.bit_mask = 0xf << field.bit_offset; - rt2x00pci_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); + rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); rt2x00_set_field32(®, field, queue->aifs); - rt2x00pci_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); + rt2800_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); - rt2x00pci_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); + rt2800_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); rt2x00_set_field32(®, field, queue->cw_min); - rt2x00pci_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); + rt2800_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); - rt2x00pci_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); + rt2800_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); rt2x00_set_field32(®, field, queue->cw_max); - rt2x00pci_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); + rt2800_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); /* Update EDCA registers */ offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx); - rt2x00pci_register_read(rt2x00dev, offset, ®); + rt2800_register_read(rt2x00dev, offset, ®); rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop); rt2x00_set_field32(®, EDCA_AC0_CFG_AIFSN, queue->aifs); rt2x00_set_field32(®, EDCA_AC0_CFG_CWMIN, queue->cw_min); rt2x00_set_field32(®, EDCA_AC0_CFG_CWMAX, queue->cw_max); - rt2x00pci_register_write(rt2x00dev, offset, reg); + rt2800_register_write(rt2x00dev, offset, reg); return 0; } @@ -3126,9 +3127,9 @@ static u64 rt2800pci_get_tsf(struct ieee80211_hw *hw) u64 tsf; u32 reg; - rt2x00pci_register_read(rt2x00dev, TSF_TIMER_DW1, ®); + rt2800_register_read(rt2x00dev, TSF_TIMER_DW1, ®); tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32; - rt2x00pci_register_read(rt2x00dev, TSF_TIMER_DW0, ®); + rt2800_register_read(rt2x00dev, TSF_TIMER_DW0, ®); tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD); return tsf; diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index 856908815221..0349be77af39 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -27,6 +27,27 @@ #ifndef RT2800PCI_H #define RT2800PCI_H +static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) +{ + rt2x00pci_register_read(rt2x00dev, offset, value); +} + +static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + rt2x00pci_register_write(rt2x00dev, offset, value); +} + +static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + rt2x00pci_register_write(rt2x00dev, offset, value); +} + /* * RF chip defines. * -- cgit v1.2.3 From 678b4eee767b3d92bb187d2ca17d33400f26f880 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:33:20 +0100 Subject: rt2800usb: add rt2800_register_multi[read,write]() wrappers Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 16 ++++++++-------- drivers/net/wireless/rt2x00/rt2800usb.h | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 73e7f2bafe10..d7307b28a015 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -374,7 +374,7 @@ static void rt2800usb_config_wcid_attr(struct rt2x00_dev *rt2x00dev, (crypto->cipher == CIPHER_AES)) iveiv_entry.iv[3] |= 0x20; iveiv_entry.iv[3] |= key->keyidx << 6; - rt2x00usb_register_multiwrite(rt2x00dev, offset, + rt2800_register_multiwrite(rt2x00dev, offset, &iveiv_entry, sizeof(iveiv_entry)); offset = MAC_WCID_ENTRY(key->hw_key_idx); @@ -382,7 +382,7 @@ static void rt2800usb_config_wcid_attr(struct rt2x00_dev *rt2x00dev, memset(&wcid_entry, 0, sizeof(wcid_entry)); if (crypto->cmd == SET_KEY) memcpy(&wcid_entry, crypto->address, ETH_ALEN); - rt2x00usb_register_multiwrite(rt2x00dev, offset, + rt2800_register_multiwrite(rt2x00dev, offset, &wcid_entry, sizeof(wcid_entry)); } @@ -406,7 +406,7 @@ static int rt2800usb_config_shared_key(struct rt2x00_dev *rt2x00dev, sizeof(key_entry.rx_mic)); offset = SHARED_KEY_ENTRY(key->hw_key_idx); - rt2x00usb_register_multiwrite(rt2x00dev, offset, + rt2800_register_multiwrite(rt2x00dev, offset, &key_entry, sizeof(key_entry)); } @@ -461,7 +461,7 @@ static int rt2800usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, sizeof(key_entry.rx_mic)); offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx); - rt2x00usb_register_multiwrite(rt2x00dev, offset, + rt2800_register_multiwrite(rt2x00dev, offset, &key_entry, sizeof(key_entry)); } @@ -549,7 +549,7 @@ static void rt2800usb_config_intf(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); conf->mac[1] = cpu_to_le32(reg); - rt2x00usb_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, + rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, conf->mac, sizeof(conf->mac)); } @@ -559,7 +559,7 @@ static void rt2800usb_config_intf(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); conf->bssid[1] = cpu_to_le32(reg); - rt2x00usb_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, + rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, conf->bssid, sizeof(conf->bssid)); } } @@ -1458,7 +1458,7 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) for (i = 0; i < 256; i++) { u32 wcid[2] = { 0xffffffff, 0x00ffffff }; - rt2x00usb_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), + rt2800_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), wcid, sizeof(wcid)); rt2800_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); @@ -2646,7 +2646,7 @@ static void rt2800usb_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 offset; offset = MAC_IVEIV_ENTRY(hw_key_idx); - rt2x00usb_register_multiread(rt2x00dev, offset, + rt2800_register_multiread(rt2x00dev, offset, &iveiv_entry, sizeof(iveiv_entry)); memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16)); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 9d2dcc5f849c..95a4f96a5fc6 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -48,6 +48,20 @@ static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev, rt2x00usb_register_write_lock(rt2x00dev, offset, value); } +static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + rt2x00usb_register_multiread(rt2x00dev, offset, value, length); +} + +static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + rt2x00usb_register_multiwrite(rt2x00dev, offset, value, length); +} + /* * RF chip defines. * -- cgit v1.2.3 From 4f2732ce8d02836b94299f64bc29b030545d654a Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:33:27 +0100 Subject: rt2800pci: add rt2800_register_multi[read,write]() wrappers Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 22 +++++++++++----------- drivers/net/wireless/rt2x00/rt2800pci.h | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 802086dce707..8b98ff822f19 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -525,7 +525,7 @@ static void rt2800pci_config_wcid_attr(struct rt2x00_dev *rt2x00dev, (crypto->cipher == CIPHER_AES)) iveiv_entry.iv[3] |= 0x20; iveiv_entry.iv[3] |= key->keyidx << 6; - rt2x00pci_register_multiwrite(rt2x00dev, offset, + rt2800_register_multiwrite(rt2x00dev, offset, &iveiv_entry, sizeof(iveiv_entry)); offset = MAC_WCID_ENTRY(key->hw_key_idx); @@ -533,7 +533,7 @@ static void rt2800pci_config_wcid_attr(struct rt2x00_dev *rt2x00dev, memset(&wcid_entry, 0, sizeof(wcid_entry)); if (crypto->cmd == SET_KEY) memcpy(&wcid_entry, crypto->address, ETH_ALEN); - rt2x00pci_register_multiwrite(rt2x00dev, offset, + rt2800_register_multiwrite(rt2x00dev, offset, &wcid_entry, sizeof(wcid_entry)); } @@ -557,7 +557,7 @@ static int rt2800pci_config_shared_key(struct rt2x00_dev *rt2x00dev, sizeof(key_entry.rx_mic)); offset = SHARED_KEY_ENTRY(key->hw_key_idx); - rt2x00pci_register_multiwrite(rt2x00dev, offset, + rt2800_register_multiwrite(rt2x00dev, offset, &key_entry, sizeof(key_entry)); } @@ -613,7 +613,7 @@ static int rt2800pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, sizeof(key_entry.rx_mic)); offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx); - rt2x00pci_register_multiwrite(rt2x00dev, offset, + rt2800_register_multiwrite(rt2x00dev, offset, &key_entry, sizeof(key_entry)); } @@ -701,7 +701,7 @@ static void rt2800pci_config_intf(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); conf->mac[1] = cpu_to_le32(reg); - rt2x00pci_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, + rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, conf->mac, sizeof(conf->mac)); } @@ -711,7 +711,7 @@ static void rt2800pci_config_intf(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); conf->bssid[1] = cpu_to_le32(reg); - rt2x00pci_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, + rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, conf->bssid, sizeof(conf->bssid)); } } @@ -1296,7 +1296,7 @@ static int rt2800pci_load_firmware(struct rt2x00_dev *rt2x00dev, /* * Write firmware to device. */ - rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, + rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, data, len); rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); @@ -1612,7 +1612,7 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) for (i = 0; i < 256; i++) { u32 wcid[2] = { 0xffffffff, 0x00ffffff }; - rt2x00pci_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), + rt2800_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), wcid, sizeof(wcid)); rt2800_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); @@ -2276,10 +2276,10 @@ static void rt2800pci_write_beacon(struct queue_entry *entry) * Write entire beacon with descriptor to register. */ beacon_base = HW_BEACON_OFFSET(entry->entry_idx); - rt2x00pci_register_multiwrite(rt2x00dev, + rt2800_register_multiwrite(rt2x00dev, beacon_base, skbdesc->desc, skbdesc->desc_len); - rt2x00pci_register_multiwrite(rt2x00dev, + rt2800_register_multiwrite(rt2x00dev, beacon_base + skbdesc->desc_len, entry->skb->data, entry->skb->len); @@ -3010,7 +3010,7 @@ static void rt2800pci_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 offset; offset = MAC_IVEIV_ENTRY(hw_key_idx); - rt2x00pci_register_multiread(rt2x00dev, offset, + rt2800_register_multiread(rt2x00dev, offset, &iveiv_entry, sizeof(iveiv_entry)); memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16)); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index 0349be77af39..bace4921e8cd 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -48,6 +48,21 @@ static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, offset, value); } +static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u16 length) +{ + rt2x00pci_register_multiread(rt2x00dev, offset, value, length); +} + +static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const void *value, + const u16 length) +{ + rt2x00pci_register_multiwrite(rt2x00dev, offset, value, length); +} + /* * RF chip defines. * -- cgit v1.2.3 From ab209b9834d43ac7c01e803681c5c50c941e4de3 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:33:34 +0100 Subject: rt2800usb: add rt2800_regbusy_read() wrapper Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 10 +++++----- drivers/net/wireless/rt2x00/rt2800usb.h | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index d7307b28a015..28d2e8b80105 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -58,14 +58,14 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * The _lock versions must be used if you already hold the csr_mutex */ #define WAIT_FOR_BBP(__dev, __reg) \ - rt2x00usb_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) + rt2800_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) #define WAIT_FOR_RFCSR(__dev, __reg) \ - rt2x00usb_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) + rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) #define WAIT_FOR_RF(__dev, __reg) \ - rt2x00usb_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) + rt2800_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) #define WAIT_FOR_MCU(__dev, __reg) \ - rt2x00usb_regbusy_read((__dev), H2M_MAILBOX_CSR, \ - H2M_MAILBOX_CSR_OWNER, (__reg)) + rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \ + H2M_MAILBOX_CSR_OWNER, (__reg)) static void rt2800usb_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 95a4f96a5fc6..180dfce41b20 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -62,6 +62,14 @@ static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev, rt2x00usb_register_multiwrite(rt2x00dev, offset, value, length); } +static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field32 field, + u32 *reg) +{ + return rt2x00usb_regbusy_read(rt2x00dev, offset, field, reg); +} + /* * RF chip defines. * -- cgit v1.2.3 From b4a77d0dee11db834bebe0cc78c211cfebf0d924 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:33:41 +0100 Subject: rt2800pci: add rt2800_regbusy_read() wrapper Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 12 ++++++------ drivers/net/wireless/rt2x00/rt2800pci.h | 8 ++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 8b98ff822f19..cb55e6d10b67 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -69,14 +69,14 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * The _lock versions must be used if you already hold the csr_mutex */ #define WAIT_FOR_BBP(__dev, __reg) \ - rt2x00pci_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) + rt2800_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) #define WAIT_FOR_RFCSR(__dev, __reg) \ - rt2x00pci_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) + rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) #define WAIT_FOR_RF(__dev, __reg) \ - rt2x00pci_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) + rt2800_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) #define WAIT_FOR_MCU(__dev, __reg) \ - rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \ - H2M_MAILBOX_CSR_OWNER, (__reg)) + rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \ + H2M_MAILBOX_CSR_OWNER, (__reg)) static void rt2800pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) @@ -350,7 +350,7 @@ static void rt2800pci_efuse_read(struct rt2x00_dev *rt2x00dev, rt2800_register_write(rt2x00dev, EFUSE_CTRL, reg); /* Wait until the EEPROM has been loaded */ - rt2x00pci_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®); + rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®); /* Apparently the data is read from end to start */ rt2800_register_read(rt2x00dev, EFUSE_DATA3, diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index bace4921e8cd..392f580cbb60 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -63,6 +63,14 @@ static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_multiwrite(rt2x00dev, offset, value, length); } +static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const struct rt2x00_field32 field, + u32 *reg) +{ + return rt2x00pci_regbusy_read(rt2x00dev, offset, field, reg); +} + /* * RF chip defines. * -- cgit v1.2.3 From eff6eced615f80cef3e4979691c7920961dda47c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:33:50 +0100 Subject: rt2800usb: add rt2800_bbp_[read,write]() wrappers Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 138 +++++++++++++++++--------------- 1 file changed, 75 insertions(+), 63 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 28d2e8b80105..d26e1ea4105a 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -122,6 +122,18 @@ static void rt2800usb_bbp_read(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } +static inline void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + rt2800usb_bbp_write(rt2x00dev, word, value); +} + +static inline void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + rt2800usb_bbp_read(rt2x00dev, word, value); +} + static void rt2800usb_rfcsr_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { @@ -248,8 +260,8 @@ static const struct rt2x00debug rt2800usb_rt2x00debug = { .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = rt2800usb_bbp_read, - .write = rt2800usb_bbp_write, + .read = rt2800_bbp_read, + .write = rt2800_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), @@ -614,8 +626,8 @@ static void rt2800usb_config_ant(struct rt2x00_dev *rt2x00dev, u8 r1; u8 r3; - rt2800usb_bbp_read(rt2x00dev, 1, &r1); - rt2800usb_bbp_read(rt2x00dev, 3, &r3); + rt2800_bbp_read(rt2x00dev, 1, &r1); + rt2800_bbp_read(rt2x00dev, 3, &r3); /* * Configure the TX antenna. @@ -647,8 +659,8 @@ static void rt2800usb_config_ant(struct rt2x00_dev *rt2x00dev, break; } - rt2800usb_bbp_write(rt2x00dev, 3, r3); - rt2800usb_bbp_write(rt2x00dev, 1, r1); + rt2800_bbp_write(rt2x00dev, 3, r3); + rt2800_bbp_write(rt2x00dev, 1, r1); } static void rt2800usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, @@ -791,26 +803,26 @@ static void rt2800usb_config_channel(struct rt2x00_dev *rt2x00dev, /* * Change BBP settings */ - rt2800usb_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); - rt2800usb_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); - rt2800usb_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); - rt2800usb_bbp_write(rt2x00dev, 86, 0); + rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 86, 0); if (rf->channel <= 14) { if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { - rt2800usb_bbp_write(rt2x00dev, 82, 0x62); - rt2800usb_bbp_write(rt2x00dev, 75, 0x46); + rt2800_bbp_write(rt2x00dev, 82, 0x62); + rt2800_bbp_write(rt2x00dev, 75, 0x46); } else { - rt2800usb_bbp_write(rt2x00dev, 82, 0x84); - rt2800usb_bbp_write(rt2x00dev, 75, 0x50); + rt2800_bbp_write(rt2x00dev, 82, 0x84); + rt2800_bbp_write(rt2x00dev, 75, 0x50); } } else { - rt2800usb_bbp_write(rt2x00dev, 82, 0xf2); + rt2800_bbp_write(rt2x00dev, 82, 0xf2); if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) - rt2800usb_bbp_write(rt2x00dev, 75, 0x46); + rt2800_bbp_write(rt2x00dev, 75, 0x46); else - rt2800usb_bbp_write(rt2x00dev, 75, 0x50); + rt2800_bbp_write(rt2x00dev, 75, 0x50); } rt2800_register_read(rt2x00dev, TX_BAND_CFG, ®); @@ -842,23 +854,23 @@ static void rt2800usb_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); - rt2800usb_bbp_read(rt2x00dev, 4, &bbp); + rt2800_bbp_read(rt2x00dev, 4, &bbp); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); - rt2800usb_bbp_write(rt2x00dev, 4, bbp); + rt2800_bbp_write(rt2x00dev, 4, bbp); - rt2800usb_bbp_read(rt2x00dev, 3, &bbp); + rt2800_bbp_read(rt2x00dev, 3, &bbp); rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); - rt2800usb_bbp_write(rt2x00dev, 3, bbp); + rt2800_bbp_write(rt2x00dev, 3, bbp); if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { if (conf_is_ht40(conf)) { - rt2800usb_bbp_write(rt2x00dev, 69, 0x1a); - rt2800usb_bbp_write(rt2x00dev, 70, 0x0a); - rt2800usb_bbp_write(rt2x00dev, 73, 0x16); + rt2800_bbp_write(rt2x00dev, 69, 0x1a); + rt2800_bbp_write(rt2x00dev, 70, 0x0a); + rt2800_bbp_write(rt2x00dev, 73, 0x16); } else { - rt2800usb_bbp_write(rt2x00dev, 69, 0x16); - rt2800usb_bbp_write(rt2x00dev, 70, 0x08); - rt2800usb_bbp_write(rt2x00dev, 73, 0x11); + rt2800_bbp_write(rt2x00dev, 69, 0x16); + rt2800_bbp_write(rt2x00dev, 70, 0x08); + rt2800_bbp_write(rt2x00dev, 73, 0x11); } } @@ -872,9 +884,9 @@ static void rt2800usb_config_txpower(struct rt2x00_dev *rt2x00dev, u32 value = TXPOWER_G_TO_DEV(txpower); u8 r1; - rt2800usb_bbp_read(rt2x00dev, 1, &r1); + rt2800_bbp_read(rt2x00dev, 1, &r1); rt2x00_set_field8(®, BBP1_TX_POWER, 0); - rt2800usb_bbp_write(rt2x00dev, 1, r1); + rt2800_bbp_write(rt2x00dev, 1, r1); rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, ®); rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value); @@ -1027,7 +1039,7 @@ static inline void rt2800usb_set_vgc(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, u8 vgc_level) { if (qual->vgc_level != vgc_level) { - rt2800usb_bbp_write(rt2x00dev, 66, vgc_level); + rt2800_bbp_write(rt2x00dev, 66, vgc_level); qual->vgc_level = vgc_level; qual->vgc_level_reg = vgc_level; } @@ -1570,7 +1582,7 @@ static int rt2800usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) msleep(1); for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800usb_bbp_read(rt2x00dev, 0, &value); + rt2800_bbp_read(rt2x00dev, 0, &value); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); @@ -1591,34 +1603,34 @@ static int rt2800usb_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800usb_wait_bbp_ready(rt2x00dev))) return -EACCES; - rt2800usb_bbp_write(rt2x00dev, 65, 0x2c); - rt2800usb_bbp_write(rt2x00dev, 66, 0x38); - rt2800usb_bbp_write(rt2x00dev, 69, 0x12); - rt2800usb_bbp_write(rt2x00dev, 70, 0x0a); - rt2800usb_bbp_write(rt2x00dev, 73, 0x10); - rt2800usb_bbp_write(rt2x00dev, 81, 0x37); - rt2800usb_bbp_write(rt2x00dev, 82, 0x62); - rt2800usb_bbp_write(rt2x00dev, 83, 0x6a); - rt2800usb_bbp_write(rt2x00dev, 84, 0x99); - rt2800usb_bbp_write(rt2x00dev, 86, 0x00); - rt2800usb_bbp_write(rt2x00dev, 91, 0x04); - rt2800usb_bbp_write(rt2x00dev, 92, 0x00); - rt2800usb_bbp_write(rt2x00dev, 103, 0x00); - rt2800usb_bbp_write(rt2x00dev, 105, 0x05); + rt2800_bbp_write(rt2x00dev, 65, 0x2c); + rt2800_bbp_write(rt2x00dev, 66, 0x38); + rt2800_bbp_write(rt2x00dev, 69, 0x12); + rt2800_bbp_write(rt2x00dev, 70, 0x0a); + rt2800_bbp_write(rt2x00dev, 73, 0x10); + rt2800_bbp_write(rt2x00dev, 81, 0x37); + rt2800_bbp_write(rt2x00dev, 82, 0x62); + rt2800_bbp_write(rt2x00dev, 83, 0x6a); + rt2800_bbp_write(rt2x00dev, 84, 0x99); + rt2800_bbp_write(rt2x00dev, 86, 0x00); + rt2800_bbp_write(rt2x00dev, 91, 0x04); + rt2800_bbp_write(rt2x00dev, 92, 0x00); + rt2800_bbp_write(rt2x00dev, 103, 0x00); + rt2800_bbp_write(rt2x00dev, 105, 0x05); if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { - rt2800usb_bbp_write(rt2x00dev, 69, 0x16); - rt2800usb_bbp_write(rt2x00dev, 73, 0x12); + rt2800_bbp_write(rt2x00dev, 69, 0x16); + rt2800_bbp_write(rt2x00dev, 73, 0x12); } if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) { - rt2800usb_bbp_write(rt2x00dev, 84, 0x19); + rt2800_bbp_write(rt2x00dev, 84, 0x19); } if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { - rt2800usb_bbp_write(rt2x00dev, 70, 0x0a); - rt2800usb_bbp_write(rt2x00dev, 84, 0x99); - rt2800usb_bbp_write(rt2x00dev, 105, 0x05); + rt2800_bbp_write(rt2x00dev, 70, 0x0a); + rt2800_bbp_write(rt2x00dev, 84, 0x99); + rt2800_bbp_write(rt2x00dev, 105, 0x05); } for (i = 0; i < EEPROM_BBP_SIZE; i++) { @@ -1627,7 +1639,7 @@ static int rt2800usb_init_bbp(struct rt2x00_dev *rt2x00dev) if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); - rt2800usb_bbp_write(rt2x00dev, reg_id, value); + rt2800_bbp_write(rt2x00dev, reg_id, value); } } @@ -1646,9 +1658,9 @@ static u8 rt2800usb_init_rx_filter(struct rt2x00_dev *rt2x00dev, rt2800usb_rfcsr_write(rt2x00dev, 24, rfcsr24); - rt2800usb_bbp_read(rt2x00dev, 4, &bbp); + rt2800_bbp_read(rt2x00dev, 4, &bbp); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); - rt2800usb_bbp_write(rt2x00dev, 4, bbp); + rt2800_bbp_write(rt2x00dev, 4, bbp); rt2800usb_rfcsr_read(rt2x00dev, 22, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); @@ -1657,13 +1669,13 @@ static u8 rt2800usb_init_rx_filter(struct rt2x00_dev *rt2x00dev, /* * Set power & frequency of passband test tone */ - rt2800usb_bbp_write(rt2x00dev, 24, 0); + rt2800_bbp_write(rt2x00dev, 24, 0); for (i = 0; i < 100; i++) { - rt2800usb_bbp_write(rt2x00dev, 25, 0x90); + rt2800_bbp_write(rt2x00dev, 25, 0x90); msleep(1); - rt2800usb_bbp_read(rt2x00dev, 55, &passband); + rt2800_bbp_read(rt2x00dev, 55, &passband); if (passband) break; } @@ -1671,13 +1683,13 @@ static u8 rt2800usb_init_rx_filter(struct rt2x00_dev *rt2x00dev, /* * Set power & frequency of stopband test tone */ - rt2800usb_bbp_write(rt2x00dev, 24, 0x06); + rt2800_bbp_write(rt2x00dev, 24, 0x06); for (i = 0; i < 100; i++) { - rt2800usb_bbp_write(rt2x00dev, 25, 0x90); + rt2800_bbp_write(rt2x00dev, 25, 0x90); msleep(1); - rt2800usb_bbp_read(rt2x00dev, 55, &stopband); + rt2800_bbp_read(rt2x00dev, 55, &stopband); if ((passband - stopband) <= filter_target) { rfcsr24++; @@ -1744,7 +1756,7 @@ static int rt2800usb_init_rfcsr(struct rt2x00_dev *rt2x00dev) /* * Set back to initial state */ - rt2800usb_bbp_write(rt2x00dev, 24, 0); + rt2800_bbp_write(rt2x00dev, 24, 0); rt2800usb_rfcsr_read(rt2x00dev, 22, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); @@ -1753,9 +1765,9 @@ static int rt2800usb_init_rfcsr(struct rt2x00_dev *rt2x00dev) /* * set BBP back to BW20 */ - rt2800usb_bbp_read(rt2x00dev, 4, &bbp); + rt2800_bbp_read(rt2x00dev, 4, &bbp); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0); - rt2800usb_bbp_write(rt2x00dev, 4, bbp); + rt2800_bbp_write(rt2x00dev, 4, bbp); return 0; } -- cgit v1.2.3 From 3e2c9df7b940c8d1d0626f61038e10a32d65f27d Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:33:57 +0100 Subject: rt2800pci: add rt2800_bbp_[read,write]() wrappers Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 138 +++++++++++++++++--------------- 1 file changed, 75 insertions(+), 63 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index cb55e6d10b67..12344fd02b3b 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -135,6 +135,18 @@ static void rt2800pci_bbp_read(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } +static inline void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + rt2800pci_bbp_write(rt2x00dev, word, value); +} + +static inline void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + rt2800pci_bbp_read(rt2x00dev, word, value); +} + static void rt2800pci_rfcsr_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { @@ -399,8 +411,8 @@ static const struct rt2x00debug rt2800pci_rt2x00debug = { .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { - .read = rt2800pci_bbp_read, - .write = rt2800pci_bbp_write, + .read = rt2800_bbp_read, + .write = rt2800_bbp_write, .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), @@ -766,8 +778,8 @@ static void rt2800pci_config_ant(struct rt2x00_dev *rt2x00dev, u8 r1; u8 r3; - rt2800pci_bbp_read(rt2x00dev, 1, &r1); - rt2800pci_bbp_read(rt2x00dev, 3, &r3); + rt2800_bbp_read(rt2x00dev, 1, &r1); + rt2800_bbp_read(rt2x00dev, 3, &r3); /* * Configure the TX antenna. @@ -800,8 +812,8 @@ static void rt2800pci_config_ant(struct rt2x00_dev *rt2x00dev, break; } - rt2800pci_bbp_write(rt2x00dev, 3, r3); - rt2800pci_bbp_write(rt2x00dev, 1, r1); + rt2800_bbp_write(rt2x00dev, 3, r3); + rt2800_bbp_write(rt2x00dev, 1, r1); } static void rt2800pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, @@ -944,26 +956,26 @@ static void rt2800pci_config_channel(struct rt2x00_dev *rt2x00dev, /* * Change BBP settings */ - rt2800pci_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); - rt2800pci_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); - rt2800pci_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); - rt2800pci_bbp_write(rt2x00dev, 86, 0); + rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 86, 0); if (rf->channel <= 14) { if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { - rt2800pci_bbp_write(rt2x00dev, 82, 0x62); - rt2800pci_bbp_write(rt2x00dev, 75, 0x46); + rt2800_bbp_write(rt2x00dev, 82, 0x62); + rt2800_bbp_write(rt2x00dev, 75, 0x46); } else { - rt2800pci_bbp_write(rt2x00dev, 82, 0x84); - rt2800pci_bbp_write(rt2x00dev, 75, 0x50); + rt2800_bbp_write(rt2x00dev, 82, 0x84); + rt2800_bbp_write(rt2x00dev, 75, 0x50); } } else { - rt2800pci_bbp_write(rt2x00dev, 82, 0xf2); + rt2800_bbp_write(rt2x00dev, 82, 0xf2); if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) - rt2800pci_bbp_write(rt2x00dev, 75, 0x46); + rt2800_bbp_write(rt2x00dev, 75, 0x46); else - rt2800pci_bbp_write(rt2x00dev, 75, 0x50); + rt2800_bbp_write(rt2x00dev, 75, 0x50); } rt2800_register_read(rt2x00dev, TX_BAND_CFG, ®); @@ -995,23 +1007,23 @@ static void rt2800pci_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); - rt2800pci_bbp_read(rt2x00dev, 4, &bbp); + rt2800_bbp_read(rt2x00dev, 4, &bbp); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); - rt2800pci_bbp_write(rt2x00dev, 4, bbp); + rt2800_bbp_write(rt2x00dev, 4, bbp); - rt2800pci_bbp_read(rt2x00dev, 3, &bbp); + rt2800_bbp_read(rt2x00dev, 3, &bbp); rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); - rt2800pci_bbp_write(rt2x00dev, 3, bbp); + rt2800_bbp_write(rt2x00dev, 3, bbp); if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { if (conf_is_ht40(conf)) { - rt2800pci_bbp_write(rt2x00dev, 69, 0x1a); - rt2800pci_bbp_write(rt2x00dev, 70, 0x0a); - rt2800pci_bbp_write(rt2x00dev, 73, 0x16); + rt2800_bbp_write(rt2x00dev, 69, 0x1a); + rt2800_bbp_write(rt2x00dev, 70, 0x0a); + rt2800_bbp_write(rt2x00dev, 73, 0x16); } else { - rt2800pci_bbp_write(rt2x00dev, 69, 0x16); - rt2800pci_bbp_write(rt2x00dev, 70, 0x08); - rt2800pci_bbp_write(rt2x00dev, 73, 0x11); + rt2800_bbp_write(rt2x00dev, 69, 0x16); + rt2800_bbp_write(rt2x00dev, 70, 0x08); + rt2800_bbp_write(rt2x00dev, 73, 0x11); } } @@ -1025,9 +1037,9 @@ static void rt2800pci_config_txpower(struct rt2x00_dev *rt2x00dev, u32 value = TXPOWER_G_TO_DEV(txpower); u8 r1; - rt2800pci_bbp_read(rt2x00dev, 1, &r1); + rt2800_bbp_read(rt2x00dev, 1, &r1); rt2x00_set_field8(®, BBP1_TX_POWER, 0); - rt2800pci_bbp_write(rt2x00dev, 1, r1); + rt2800_bbp_write(rt2x00dev, 1, r1); rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, ®); rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value); @@ -1176,7 +1188,7 @@ static inline void rt2800pci_set_vgc(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, u8 vgc_level) { if (qual->vgc_level != vgc_level) { - rt2800pci_bbp_write(rt2x00dev, 66, vgc_level); + rt2800_bbp_write(rt2x00dev, 66, vgc_level); qual->vgc_level = vgc_level; qual->vgc_level_reg = vgc_level; } @@ -1720,7 +1732,7 @@ static int rt2800pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) msleep(1); for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800pci_bbp_read(rt2x00dev, 0, &value); + rt2800_bbp_read(rt2x00dev, 0, &value); if ((value != 0xff) && (value != 0x00)) return 0; udelay(REGISTER_BUSY_DELAY); @@ -1741,33 +1753,33 @@ static int rt2800pci_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800pci_wait_bbp_ready(rt2x00dev))) return -EACCES; - rt2800pci_bbp_write(rt2x00dev, 65, 0x2c); - rt2800pci_bbp_write(rt2x00dev, 66, 0x38); - rt2800pci_bbp_write(rt2x00dev, 69, 0x12); - rt2800pci_bbp_write(rt2x00dev, 70, 0x0a); - rt2800pci_bbp_write(rt2x00dev, 73, 0x10); - rt2800pci_bbp_write(rt2x00dev, 81, 0x37); - rt2800pci_bbp_write(rt2x00dev, 82, 0x62); - rt2800pci_bbp_write(rt2x00dev, 83, 0x6a); - rt2800pci_bbp_write(rt2x00dev, 84, 0x99); - rt2800pci_bbp_write(rt2x00dev, 86, 0x00); - rt2800pci_bbp_write(rt2x00dev, 91, 0x04); - rt2800pci_bbp_write(rt2x00dev, 92, 0x00); - rt2800pci_bbp_write(rt2x00dev, 103, 0x00); - rt2800pci_bbp_write(rt2x00dev, 105, 0x05); + rt2800_bbp_write(rt2x00dev, 65, 0x2c); + rt2800_bbp_write(rt2x00dev, 66, 0x38); + rt2800_bbp_write(rt2x00dev, 69, 0x12); + rt2800_bbp_write(rt2x00dev, 70, 0x0a); + rt2800_bbp_write(rt2x00dev, 73, 0x10); + rt2800_bbp_write(rt2x00dev, 81, 0x37); + rt2800_bbp_write(rt2x00dev, 82, 0x62); + rt2800_bbp_write(rt2x00dev, 83, 0x6a); + rt2800_bbp_write(rt2x00dev, 84, 0x99); + rt2800_bbp_write(rt2x00dev, 86, 0x00); + rt2800_bbp_write(rt2x00dev, 91, 0x04); + rt2800_bbp_write(rt2x00dev, 92, 0x00); + rt2800_bbp_write(rt2x00dev, 103, 0x00); + rt2800_bbp_write(rt2x00dev, 105, 0x05); if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { - rt2800pci_bbp_write(rt2x00dev, 69, 0x16); - rt2800pci_bbp_write(rt2x00dev, 73, 0x12); + rt2800_bbp_write(rt2x00dev, 69, 0x16); + rt2800_bbp_write(rt2x00dev, 73, 0x12); } if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) - rt2800pci_bbp_write(rt2x00dev, 84, 0x19); + rt2800_bbp_write(rt2x00dev, 84, 0x19); if (rt2x00_rt(&rt2x00dev->chip, RT3052)) { - rt2800pci_bbp_write(rt2x00dev, 31, 0x08); - rt2800pci_bbp_write(rt2x00dev, 78, 0x0e); - rt2800pci_bbp_write(rt2x00dev, 80, 0x08); + rt2800_bbp_write(rt2x00dev, 31, 0x08); + rt2800_bbp_write(rt2x00dev, 78, 0x0e); + rt2800_bbp_write(rt2x00dev, 80, 0x08); } for (i = 0; i < EEPROM_BBP_SIZE; i++) { @@ -1776,7 +1788,7 @@ static int rt2800pci_init_bbp(struct rt2x00_dev *rt2x00dev) if (eeprom != 0xffff && eeprom != 0x0000) { reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); - rt2800pci_bbp_write(rt2x00dev, reg_id, value); + rt2800_bbp_write(rt2x00dev, reg_id, value); } } @@ -1795,9 +1807,9 @@ static u8 rt2800pci_init_rx_filter(struct rt2x00_dev *rt2x00dev, rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24); - rt2800pci_bbp_read(rt2x00dev, 4, &bbp); + rt2800_bbp_read(rt2x00dev, 4, &bbp); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); - rt2800pci_bbp_write(rt2x00dev, 4, bbp); + rt2800_bbp_write(rt2x00dev, 4, bbp); rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); @@ -1806,13 +1818,13 @@ static u8 rt2800pci_init_rx_filter(struct rt2x00_dev *rt2x00dev, /* * Set power & frequency of passband test tone */ - rt2800pci_bbp_write(rt2x00dev, 24, 0); + rt2800_bbp_write(rt2x00dev, 24, 0); for (i = 0; i < 100; i++) { - rt2800pci_bbp_write(rt2x00dev, 25, 0x90); + rt2800_bbp_write(rt2x00dev, 25, 0x90); msleep(1); - rt2800pci_bbp_read(rt2x00dev, 55, &passband); + rt2800_bbp_read(rt2x00dev, 55, &passband); if (passband) break; } @@ -1820,13 +1832,13 @@ static u8 rt2800pci_init_rx_filter(struct rt2x00_dev *rt2x00dev, /* * Set power & frequency of stopband test tone */ - rt2800pci_bbp_write(rt2x00dev, 24, 0x06); + rt2800_bbp_write(rt2x00dev, 24, 0x06); for (i = 0; i < 100; i++) { - rt2800pci_bbp_write(rt2x00dev, 25, 0x90); + rt2800_bbp_write(rt2x00dev, 25, 0x90); msleep(1); - rt2800pci_bbp_read(rt2x00dev, 55, &stopband); + rt2800_bbp_read(rt2x00dev, 55, &stopband); if ((passband - stopband) <= filter_target) { rfcsr24++; @@ -1905,7 +1917,7 @@ static int rt2800pci_init_rfcsr(struct rt2x00_dev *rt2x00dev) /* * Set back to initial state */ - rt2800pci_bbp_write(rt2x00dev, 24, 0); + rt2800_bbp_write(rt2x00dev, 24, 0); rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); @@ -1914,9 +1926,9 @@ static int rt2800pci_init_rfcsr(struct rt2x00_dev *rt2x00dev) /* * set BBP back to BW20 */ - rt2800pci_bbp_read(rt2x00dev, 4, &bbp); + rt2800_bbp_read(rt2x00dev, 4, &bbp); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0); - rt2800pci_bbp_write(rt2x00dev, 4, bbp); + rt2800_bbp_write(rt2x00dev, 4, bbp); return 0; } -- cgit v1.2.3 From e91fea9b38b2208113dd540f436ce2aba7ab29fd Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:34:04 +0100 Subject: rt2800usb: add rt2800_rfcsr_[read,write]() wrappers Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 96 ++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 42 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index d26e1ea4105a..8cfb5573b883 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -189,6 +189,18 @@ static void rt2800usb_rfcsr_read(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } +static inline void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + rt2800usb_rfcsr_write(rt2x00dev, word, value); +} + +static inline void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + rt2800usb_rfcsr_read(rt2x00dev, word, value); +} + static void rt2800usb_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { @@ -762,28 +774,28 @@ static void rt2800usb_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, { u8 rfcsr; - rt2800usb_rfcsr_write(rt2x00dev, 2, rf->rf1); - rt2800usb_rfcsr_write(rt2x00dev, 2, rf->rf3); + rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); + rt2800_rfcsr_write(rt2x00dev, 2, rf->rf3); - rt2800usb_rfcsr_read(rt2x00dev, 6, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); - rt2800usb_rfcsr_write(rt2x00dev, 6, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800usb_rfcsr_read(rt2x00dev, 12, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, TXPOWER_G_TO_DEV(info->tx_power1)); - rt2800usb_rfcsr_write(rt2x00dev, 12, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); - rt2800usb_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); - rt2800usb_rfcsr_write(rt2x00dev, 23, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); - rt2800usb_rfcsr_write(rt2x00dev, 24, + rt2800_rfcsr_write(rt2x00dev, 24, rt2x00dev->calibration[conf_is_ht40(conf)]); - rt2800usb_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); - rt2800usb_rfcsr_write(rt2x00dev, 23, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); } static void rt2800usb_config_channel(struct rt2x00_dev *rt2x00dev, @@ -1656,15 +1668,15 @@ static u8 rt2800usb_init_rx_filter(struct rt2x00_dev *rt2x00dev, u8 stopband; u8 overtuned = 0; - rt2800usb_rfcsr_write(rt2x00dev, 24, rfcsr24); + rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); rt2800_bbp_read(rt2x00dev, 4, &bbp); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); rt2800_bbp_write(rt2x00dev, 4, bbp); - rt2800usb_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); - rt2800usb_rfcsr_write(rt2x00dev, 22, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); /* * Set power & frequency of passband test tone @@ -1697,12 +1709,12 @@ static u8 rt2800usb_init_rx_filter(struct rt2x00_dev *rt2x00dev, } else break; - rt2800usb_rfcsr_write(rt2x00dev, 24, rfcsr24); + rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); } rfcsr24 -= !!overtuned; - rt2800usb_rfcsr_write(rt2x00dev, 24, rfcsr24); + rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); return rfcsr24; } @@ -1717,33 +1729,33 @@ static int rt2800usb_init_rfcsr(struct rt2x00_dev *rt2x00dev) /* * Init RF calibration. */ - rt2800usb_rfcsr_read(rt2x00dev, 30, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); - rt2800usb_rfcsr_write(rt2x00dev, 30, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); msleep(1); rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); - rt2800usb_rfcsr_write(rt2x00dev, 30, rfcsr); - - rt2800usb_rfcsr_write(rt2x00dev, 4, 0x40); - rt2800usb_rfcsr_write(rt2x00dev, 5, 0x03); - rt2800usb_rfcsr_write(rt2x00dev, 6, 0x02); - rt2800usb_rfcsr_write(rt2x00dev, 7, 0x70); - rt2800usb_rfcsr_write(rt2x00dev, 9, 0x0f); - rt2800usb_rfcsr_write(rt2x00dev, 10, 0x71); - rt2800usb_rfcsr_write(rt2x00dev, 11, 0x21); - rt2800usb_rfcsr_write(rt2x00dev, 12, 0x7b); - rt2800usb_rfcsr_write(rt2x00dev, 14, 0x90); - rt2800usb_rfcsr_write(rt2x00dev, 15, 0x58); - rt2800usb_rfcsr_write(rt2x00dev, 16, 0xb3); - rt2800usb_rfcsr_write(rt2x00dev, 17, 0x92); - rt2800usb_rfcsr_write(rt2x00dev, 18, 0x2c); - rt2800usb_rfcsr_write(rt2x00dev, 19, 0x02); - rt2800usb_rfcsr_write(rt2x00dev, 20, 0xba); - rt2800usb_rfcsr_write(rt2x00dev, 21, 0xdb); - rt2800usb_rfcsr_write(rt2x00dev, 24, 0x16); - rt2800usb_rfcsr_write(rt2x00dev, 25, 0x01); - rt2800usb_rfcsr_write(rt2x00dev, 27, 0x03); - rt2800usb_rfcsr_write(rt2x00dev, 29, 0x1f); + rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); + + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800_rfcsr_write(rt2x00dev, 5, 0x03); + rt2800_rfcsr_write(rt2x00dev, 6, 0x02); + rt2800_rfcsr_write(rt2x00dev, 7, 0x70); + rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 10, 0x71); + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800_rfcsr_write(rt2x00dev, 12, 0x7b); + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800_rfcsr_write(rt2x00dev, 15, 0x58); + rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); + rt2800_rfcsr_write(rt2x00dev, 17, 0x92); + rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800_rfcsr_write(rt2x00dev, 20, 0xba); + rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 24, 0x16); + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); + rt2800_rfcsr_write(rt2x00dev, 27, 0x03); + rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); /* * Set RX Filter calibration for 20MHz and 40MHz @@ -1758,9 +1770,9 @@ static int rt2800usb_init_rfcsr(struct rt2x00_dev *rt2x00dev) */ rt2800_bbp_write(rt2x00dev, 24, 0); - rt2800usb_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); - rt2800usb_rfcsr_write(rt2x00dev, 22, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); /* * set BBP back to BW20 -- cgit v1.2.3 From 1af68f75a808d02997ad0c6dde9e37f43b7dfcb4 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:34:11 +0100 Subject: rt2800pci: add rt2800_rfcsr_[read,write]() wrappers Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 116 ++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 52 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 12344fd02b3b..37a55527a48f 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -202,6 +202,18 @@ static void rt2800pci_rfcsr_read(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } +static inline void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + rt2800pci_rfcsr_write(rt2x00dev, word, value); +} + +static inline void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + rt2800pci_rfcsr_read(rt2x00dev, word, value); +} + static void rt2800pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { @@ -915,28 +927,28 @@ static void rt2800pci_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, { u8 rfcsr; - rt2800pci_rfcsr_write(rt2x00dev, 2, rf->rf1); - rt2800pci_rfcsr_write(rt2x00dev, 2, rf->rf3); + rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); + rt2800_rfcsr_write(rt2x00dev, 2, rf->rf3); - rt2800pci_rfcsr_read(rt2x00dev, 6, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); - rt2800pci_rfcsr_write(rt2x00dev, 6, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - rt2800pci_rfcsr_read(rt2x00dev, 12, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, TXPOWER_G_TO_DEV(info->tx_power1)); - rt2800pci_rfcsr_write(rt2x00dev, 12, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); - rt2800pci_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); - rt2800pci_rfcsr_write(rt2x00dev, 23, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); - rt2800pci_rfcsr_write(rt2x00dev, 24, + rt2800_rfcsr_write(rt2x00dev, 24, rt2x00dev->calibration[conf_is_ht40(conf)]); - rt2800pci_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); - rt2800pci_rfcsr_write(rt2x00dev, 23, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); } static void rt2800pci_config_channel(struct rt2x00_dev *rt2x00dev, @@ -1805,15 +1817,15 @@ static u8 rt2800pci_init_rx_filter(struct rt2x00_dev *rt2x00dev, u8 stopband; u8 overtuned = 0; - rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24); + rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); rt2800_bbp_read(rt2x00dev, 4, &bbp); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); rt2800_bbp_write(rt2x00dev, 4, bbp); - rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); - rt2800pci_rfcsr_write(rt2x00dev, 22, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); /* * Set power & frequency of passband test tone @@ -1846,12 +1858,12 @@ static u8 rt2800pci_init_rx_filter(struct rt2x00_dev *rt2x00dev, } else break; - rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24); + rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); } rfcsr24 -= !!overtuned; - rt2800pci_rfcsr_write(rt2x00dev, 24, rfcsr24); + rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); return rfcsr24; } @@ -1868,43 +1880,43 @@ static int rt2800pci_init_rfcsr(struct rt2x00_dev *rt2x00dev) /* * Init RF calibration. */ - rt2800pci_rfcsr_read(rt2x00dev, 30, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); - rt2800pci_rfcsr_write(rt2x00dev, 30, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); msleep(1); rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); - rt2800pci_rfcsr_write(rt2x00dev, 30, rfcsr); - - rt2800pci_rfcsr_write(rt2x00dev, 0, 0x50); - rt2800pci_rfcsr_write(rt2x00dev, 1, 0x01); - rt2800pci_rfcsr_write(rt2x00dev, 2, 0xf7); - rt2800pci_rfcsr_write(rt2x00dev, 3, 0x75); - rt2800pci_rfcsr_write(rt2x00dev, 4, 0x40); - rt2800pci_rfcsr_write(rt2x00dev, 5, 0x03); - rt2800pci_rfcsr_write(rt2x00dev, 6, 0x02); - rt2800pci_rfcsr_write(rt2x00dev, 7, 0x50); - rt2800pci_rfcsr_write(rt2x00dev, 8, 0x39); - rt2800pci_rfcsr_write(rt2x00dev, 9, 0x0f); - rt2800pci_rfcsr_write(rt2x00dev, 10, 0x60); - rt2800pci_rfcsr_write(rt2x00dev, 11, 0x21); - rt2800pci_rfcsr_write(rt2x00dev, 12, 0x75); - rt2800pci_rfcsr_write(rt2x00dev, 13, 0x75); - rt2800pci_rfcsr_write(rt2x00dev, 14, 0x90); - rt2800pci_rfcsr_write(rt2x00dev, 15, 0x58); - rt2800pci_rfcsr_write(rt2x00dev, 16, 0xb3); - rt2800pci_rfcsr_write(rt2x00dev, 17, 0x92); - rt2800pci_rfcsr_write(rt2x00dev, 18, 0x2c); - rt2800pci_rfcsr_write(rt2x00dev, 19, 0x02); - rt2800pci_rfcsr_write(rt2x00dev, 20, 0xba); - rt2800pci_rfcsr_write(rt2x00dev, 21, 0xdb); - rt2800pci_rfcsr_write(rt2x00dev, 22, 0x00); - rt2800pci_rfcsr_write(rt2x00dev, 23, 0x31); - rt2800pci_rfcsr_write(rt2x00dev, 24, 0x08); - rt2800pci_rfcsr_write(rt2x00dev, 25, 0x01); - rt2800pci_rfcsr_write(rt2x00dev, 26, 0x25); - rt2800pci_rfcsr_write(rt2x00dev, 27, 0x23); - rt2800pci_rfcsr_write(rt2x00dev, 28, 0x13); - rt2800pci_rfcsr_write(rt2x00dev, 29, 0x83); + rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); + + rt2800_rfcsr_write(rt2x00dev, 0, 0x50); + rt2800_rfcsr_write(rt2x00dev, 1, 0x01); + rt2800_rfcsr_write(rt2x00dev, 2, 0xf7); + rt2800_rfcsr_write(rt2x00dev, 3, 0x75); + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800_rfcsr_write(rt2x00dev, 5, 0x03); + rt2800_rfcsr_write(rt2x00dev, 6, 0x02); + rt2800_rfcsr_write(rt2x00dev, 7, 0x50); + rt2800_rfcsr_write(rt2x00dev, 8, 0x39); + rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 10, 0x60); + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800_rfcsr_write(rt2x00dev, 12, 0x75); + rt2800_rfcsr_write(rt2x00dev, 13, 0x75); + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800_rfcsr_write(rt2x00dev, 15, 0x58); + rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); + rt2800_rfcsr_write(rt2x00dev, 17, 0x92); + rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800_rfcsr_write(rt2x00dev, 20, 0xba); + rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); + rt2800_rfcsr_write(rt2x00dev, 23, 0x31); + rt2800_rfcsr_write(rt2x00dev, 24, 0x08); + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); + rt2800_rfcsr_write(rt2x00dev, 26, 0x25); + rt2800_rfcsr_write(rt2x00dev, 27, 0x23); + rt2800_rfcsr_write(rt2x00dev, 28, 0x13); + rt2800_rfcsr_write(rt2x00dev, 29, 0x83); /* * Set RX Filter calibration for 20MHz and 40MHz @@ -1919,9 +1931,9 @@ static int rt2800pci_init_rfcsr(struct rt2x00_dev *rt2x00dev) */ rt2800_bbp_write(rt2x00dev, 24, 0); - rt2800pci_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); - rt2800pci_rfcsr_write(rt2x00dev, 22, rfcsr); + rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); /* * set BBP back to BW20 -- cgit v1.2.3 From 5c70e5bb36584a1c1d5be85e40aabac3a8f68d83 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:34:18 +0100 Subject: rt2800usb: add rt2800_rf_[read,write]() wrappers Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 8cfb5573b883..15aed2916e0c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -226,6 +226,12 @@ static void rt2800usb_rf_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } +static inline void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + rt2800usb_rf_write(rt2x00dev, word, value); +} + static void rt2800usb_mcu_request(struct rt2x00_dev *rt2x00dev, const u8 command, const u8 token, const u8 arg0, const u8 arg1) @@ -280,7 +286,7 @@ static const struct rt2x00debug rt2800usb_rt2x00debug = { }, .rf = { .read = rt2x00_rf_read, - .write = rt2800usb_rf_write, + .write = rt2800_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), @@ -747,24 +753,24 @@ static void rt2800usb_config_channel_rt2x(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); - rt2800usb_rf_write(rt2x00dev, 1, rf->rf1); - rt2800usb_rf_write(rt2x00dev, 2, rf->rf2); - rt2800usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt2800usb_rf_write(rt2x00dev, 4, rf->rf4); + rt2800_rf_write(rt2x00dev, 1, rf->rf1); + rt2800_rf_write(rt2x00dev, 2, rf->rf2); + rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800_rf_write(rt2x00dev, 4, rf->rf4); udelay(200); - rt2800usb_rf_write(rt2x00dev, 1, rf->rf1); - rt2800usb_rf_write(rt2x00dev, 2, rf->rf2); - rt2800usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); - rt2800usb_rf_write(rt2x00dev, 4, rf->rf4); + rt2800_rf_write(rt2x00dev, 1, rf->rf1); + rt2800_rf_write(rt2x00dev, 2, rf->rf2); + rt2800_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt2800_rf_write(rt2x00dev, 4, rf->rf4); udelay(200); - rt2800usb_rf_write(rt2x00dev, 1, rf->rf1); - rt2800usb_rf_write(rt2x00dev, 2, rf->rf2); - rt2800usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt2800usb_rf_write(rt2x00dev, 4, rf->rf4); + rt2800_rf_write(rt2x00dev, 1, rf->rf1); + rt2800_rf_write(rt2x00dev, 2, rf->rf2); + rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800_rf_write(rt2x00dev, 4, rf->rf4); } static void rt2800usb_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, -- cgit v1.2.3 From ada0394cede08702b604a4c8ee13409a4109e773 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:34:25 +0100 Subject: rt2800pci: add rt2800_rf_[read,write]() wrappers Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 37a55527a48f..83fe1babd5bb 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -239,6 +239,12 @@ static void rt2800pci_rf_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } +static inline void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + rt2800pci_rf_write(rt2x00dev, word, value); +} + static void rt2800pci_mcu_request(struct rt2x00_dev *rt2x00dev, const u8 command, const u8 token, const u8 arg0, const u8 arg1) @@ -431,7 +437,7 @@ static const struct rt2x00debug rt2800pci_rt2x00debug = { }, .rf = { .read = rt2x00_rf_read, - .write = rt2800pci_rf_write, + .write = rt2800_rf_write, .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), @@ -900,24 +906,24 @@ static void rt2800pci_config_channel_rt2x(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); - rt2800pci_rf_write(rt2x00dev, 1, rf->rf1); - rt2800pci_rf_write(rt2x00dev, 2, rf->rf2); - rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt2800pci_rf_write(rt2x00dev, 4, rf->rf4); + rt2800_rf_write(rt2x00dev, 1, rf->rf1); + rt2800_rf_write(rt2x00dev, 2, rf->rf2); + rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800_rf_write(rt2x00dev, 4, rf->rf4); udelay(200); - rt2800pci_rf_write(rt2x00dev, 1, rf->rf1); - rt2800pci_rf_write(rt2x00dev, 2, rf->rf2); - rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); - rt2800pci_rf_write(rt2x00dev, 4, rf->rf4); + rt2800_rf_write(rt2x00dev, 1, rf->rf1); + rt2800_rf_write(rt2x00dev, 2, rf->rf2); + rt2800_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt2800_rf_write(rt2x00dev, 4, rf->rf4); udelay(200); - rt2800pci_rf_write(rt2x00dev, 1, rf->rf1); - rt2800pci_rf_write(rt2x00dev, 2, rf->rf2); - rt2800pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt2800pci_rf_write(rt2x00dev, 4, rf->rf4); + rt2800_rf_write(rt2x00dev, 1, rf->rf1); + rt2800_rf_write(rt2x00dev, 2, rf->rf2); + rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800_rf_write(rt2x00dev, 4, rf->rf4); } static void rt2800pci_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, -- cgit v1.2.3 From 4f2c53268ad1bdc7d6d12ca8bd110bb288a14300 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:34:32 +0100 Subject: rt2800usb: add rt2800_mcu_request() wrapper Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 15aed2916e0c..3783fdc4251f 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -259,6 +259,13 @@ static void rt2800usb_mcu_request(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } +static inline void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, + const u8 command, const u8 token, + const u8 arg0, const u8 arg1) +{ + rt2800usb_mcu_request(rt2x00dev, command, token, arg0, arg1); +} + #ifdef CONFIG_RT2X00_LIB_DEBUGFS static const struct rt2x00debug rt2800usb_rt2x00debug = { .owner = THIS_MODULE, @@ -319,10 +326,10 @@ static void rt2800usb_brightness_set(struct led_classdev *led_cdev, EEPROM_FREQ_LED_MODE); if (led->type == LED_TYPE_RADIO) { - rt2800usb_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, enabled ? 0x20 : 0); } else if (led->type == LED_TYPE_ASSOC) { - rt2800usb_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); } else if (led->type == LED_TYPE_QUALITY) { /* @@ -333,7 +340,7 @@ static void rt2800usb_brightness_set(struct led_classdev *led_cdev, * work with bitshifting: * (1 << level) - 1 */ - rt2800usb_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, + rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, (1 << brightness / (LED_FULL / 6)) - 1, polarity); } @@ -1233,13 +1240,13 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, /* * Send signal to firmware during boot time. */ - rt2800usb_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0); + rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0); if ((chipset == 0x3070) || (chipset == 0x3071) || (chipset == 0x3572)) { udelay(200); - rt2800usb_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0); + rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0); udelay(10); } @@ -1875,15 +1882,15 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) * Initialize LED control */ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); - rt2800usb_mcu_request(rt2x00dev, MCU_LED_1, 0xff, + rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff, word & 0xff, (word >> 8) & 0xff); rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); - rt2800usb_mcu_request(rt2x00dev, MCU_LED_2, 0xff, + rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff, word & 0xff, (word >> 8) & 0xff); rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); - rt2800usb_mcu_request(rt2x00dev, MCU_LED_3, 0xff, + rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff, word & 0xff, (word >> 8) & 0xff); return 0; @@ -1912,9 +1919,9 @@ static int rt2800usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) { if (state == STATE_AWAKE) - rt2800usb_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); + rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); else - rt2800usb_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2); + rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2); return 0; } -- cgit v1.2.3 From 3a9e5b0fff63bb87dd6e0f9c60626e16d81192af Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:34:39 +0100 Subject: rt2800pci: add rt2800_mcu_request() wrapper Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 83fe1babd5bb..8f8f8d85f2cf 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -279,6 +279,13 @@ static void rt2800pci_mcu_request(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } +static inline void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, + const u8 command, const u8 token, + const u8 arg0, const u8 arg1) +{ + rt2800pci_mcu_request(rt2x00dev, command, token, arg0, arg1); +} + static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) { unsigned int i; @@ -470,10 +477,10 @@ static void rt2800pci_brightness_set(struct led_classdev *led_cdev, EEPROM_FREQ_LED_MODE); if (led->type == LED_TYPE_RADIO) { - rt2800pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, enabled ? 0x20 : 0); } else if (led->type == LED_TYPE_ASSOC) { - rt2800pci_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); } else if (led->type == LED_TYPE_QUALITY) { /* @@ -484,7 +491,7 @@ static void rt2800pci_brightness_set(struct led_classdev *led_cdev, * work with bitshifting: * (1 << level) - 1 */ - rt2800pci_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, + rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, (1 << brightness / (LED_FULL / 6)) - 1, polarity); } @@ -2040,7 +2047,7 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Send signal to firmware during boot time. */ - rt2800pci_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0); + rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0); /* * Enable RX. @@ -2066,15 +2073,15 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) * Initialize LED control */ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); - rt2800pci_mcu_request(rt2x00dev, MCU_LED_1, 0xff, + rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff, word & 0xff, (word >> 8) & 0xff); rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); - rt2800pci_mcu_request(rt2x00dev, MCU_LED_2, 0xff, + rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff, word & 0xff, (word >> 8) & 0xff); rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); - rt2800pci_mcu_request(rt2x00dev, MCU_LED_3, 0xff, + rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff, word & 0xff, (word >> 8) & 0xff); return 0; @@ -2123,10 +2130,10 @@ static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, * if the device is booting and wasn't asleep it will return * failure when attempting to wakeup. */ - rt2800pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2); + rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2); if (state == STATE_AWAKE) { - rt2800pci_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0); + rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0); rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP); } -- cgit v1.2.3 From ee134fcc552e17e708346a183076db21b8c49188 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:34:46 +0100 Subject: rt2x00: add driver private field to struct rt2x00_dev Enhance rt2x00 infrastructure by adding driver specific field to struct rt2x00_dev. The new field will be used by rt2800 drivers for chipset registers access abstraction layer. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 196de8ab8153..c14b0f505b7f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -842,6 +842,11 @@ struct rt2x00_dev { * Firmware image. */ const struct firmware *fw; + + /* + * Driver specific data. + */ + void *priv; }; /* -- cgit v1.2.3 From 7a345d3d2512769ca693d4844b215ae2cc267dce Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:34:53 +0100 Subject: rt2800usb: convert to use struct rt2800_ops methods Add chipset registers access abstraction layer and prepare for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 13 ++++++++++ drivers/net/wireless/rt2x00/rt2800usb.h | 44 ++++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3783fdc4251f..a3ec97a4c744 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2627,10 +2627,23 @@ static int rt2800usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) return 0; } +static const struct rt2800_ops rt2800usb_rt2800_ops = { + .register_read = rt2x00usb_register_read, + .register_write = rt2x00usb_register_write, + .register_write_lock = rt2x00usb_register_write_lock, + + .register_multiread = rt2x00usb_register_multiread, + .register_multiwrite = rt2x00usb_register_multiwrite, + + .regbusy_read = rt2x00usb_regbusy_read, +}; + static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + rt2x00dev->priv = (void *)&rt2800usb_rt2800_ops; + /* * Allocate eeprom data. */ diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 180dfce41b20..6524d72631cd 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -27,39 +27,69 @@ #ifndef RT2800USB_H #define RT2800USB_H +struct rt2800_ops { + void (*register_read)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 *value); + void (*register_write)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 value); + void (*register_write_lock)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 value); + + void (*register_multiread)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length); + void (*register_multiwrite)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length); + + int (*regbusy_read)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field32 field, u32 *reg); +}; + static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 *value) { - rt2x00usb_register_read(rt2x00dev, offset, value); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_read(rt2x00dev, offset, value); } static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 value) { - rt2x00usb_register_write(rt2x00dev, offset, value); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_write(rt2x00dev, offset, value); } static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 value) { - rt2x00usb_register_write_lock(rt2x00dev, offset, value); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_write_lock(rt2x00dev, offset, value); } static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u32 length) { - rt2x00usb_register_multiread(rt2x00dev, offset, value, length); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_multiread(rt2x00dev, offset, value, length); } static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u32 length) { - rt2x00usb_register_multiwrite(rt2x00dev, offset, value, length); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_multiwrite(rt2x00dev, offset, value, length); } static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, @@ -67,7 +97,9 @@ static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, struct rt2x00_field32 field, u32 *reg) { - return rt2x00usb_regbusy_read(rt2x00dev, offset, field, reg); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg); } /* -- cgit v1.2.3 From b0a1edabd31a18de3c6380022af0804592bded14 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:35:00 +0100 Subject: rt2800pci: convert to use struct rt2800_ops methods Add chipset registers access abstraction layer and prepare for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 13 ++++++++++ drivers/net/wireless/rt2x00/rt2800pci.h | 44 ++++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 8f8f8d85f2cf..fde722caab94 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -2988,10 +2988,23 @@ static int rt2800pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) return 0; } +static const struct rt2800_ops rt2800pci_rt2800_ops = { + .register_read = rt2x00pci_register_read, + .register_write = rt2x00pci_register_write, + .register_write_lock = rt2x00pci_register_write, /* same for PCI */ + + .register_multiread = rt2x00pci_register_multiread, + .register_multiwrite = rt2x00pci_register_multiwrite, + + .regbusy_read = rt2x00pci_regbusy_read, +}; + static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + rt2x00dev->priv = (void *)&rt2800pci_rt2800_ops; + /* * Allocate eeprom data. */ diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index 392f580cbb60..fecb71c05c1e 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -27,32 +27,60 @@ #ifndef RT2800PCI_H #define RT2800PCI_H +struct rt2800_ops { + void (*register_read)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 *value); + void (*register_write)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 value); + void (*register_write_lock)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 value); + + void (*register_multiread)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u16 length); + void (*register_multiwrite)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const void *value, const u16 length); + + int (*regbusy_read)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const struct rt2x00_field32 field, u32 *reg); +}; + static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 *value) { - rt2x00pci_register_read(rt2x00dev, offset, value); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_read(rt2x00dev, offset, value); } static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 value) { - rt2x00pci_register_write(rt2x00dev, offset, value); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_write(rt2x00dev, offset, value); } static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 value) { - rt2x00pci_register_write(rt2x00dev, offset, value); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_write_lock(rt2x00dev, offset, value); } static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u16 length) { - rt2x00pci_register_multiread(rt2x00dev, offset, value, length); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_multiread(rt2x00dev, offset, value, length); } static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev, @@ -60,7 +88,9 @@ static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev, const void *value, const u16 length) { - rt2x00pci_register_multiwrite(rt2x00dev, offset, value, length); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_multiwrite(rt2x00dev, offset, value, length); } static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, @@ -68,7 +98,9 @@ static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, const struct rt2x00_field32 field, u32 *reg) { - return rt2x00pci_regbusy_read(rt2x00dev, offset, field, reg); + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg); } /* -- cgit v1.2.3 From 5b10b09898bf00350a68af4cdaf96c393b252591 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:35:10 +0100 Subject: rt2x00: fix rt2x00usb_register_multiwrite() arguments Add const to 'value' argument of rt2x00usb_register_multiwrite() (all arguments match rt2x00pci_register_multiwrite() ones now). Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.h | 2 +- drivers/net/wireless/rt2x00/rt2x00usb.h | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 6524d72631cd..8c88690c1537 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -40,7 +40,7 @@ struct rt2800_ops { void *value, const u32 length); void (*register_multiwrite)(struct rt2x00_dev *rt2x00dev, const unsigned int offset, - void *value, const u32 length); + const void *value, const u32 length); int (*regbusy_read)(struct rt2x00_dev *rt2x00dev, const unsigned int offset, diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 9093516d9af1..f6fb58f2ca72 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -340,12 +340,13 @@ static inline void rt2x00usb_register_write_lock(struct rt2x00_dev *rt2x00dev, * through rt2x00usb_vendor_request_buff(). */ static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length) + const unsigned int offset, + const void *value, + const u32 length) { rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - value, length, + (void *)value, length, REGISTER_TIMEOUT32(length)); } -- cgit v1.2.3 From f255b92b570325dfbd4c4a791a0eda7999e67fe7 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:35:18 +0100 Subject: rt2x00: fix rt2x00usb_regbusy_read() arguments Add const to 'field' argument of rt2x00usb_regbusy_read() (all arguments match rt2x00pci_regbusy_read() ones now). Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.h | 2 +- drivers/net/wireless/rt2x00/rt2x00usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00usb.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 8c88690c1537..0a525a722a74 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -44,7 +44,7 @@ struct rt2800_ops { int (*regbusy_read)(struct rt2x00_dev *rt2x00dev, const unsigned int offset, - struct rt2x00_field32 field, u32 *reg); + const struct rt2x00_field32 field, u32 *reg); }; static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 501544882c2c..b34d4b6badd0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -156,7 +156,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff); int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, const unsigned int offset, - struct rt2x00_field32 field, + const struct rt2x00_field32 field, u32 *reg) { unsigned int i; diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index f6fb58f2ca72..212dec47119e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -365,7 +365,7 @@ static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, */ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, const unsigned int offset, - struct rt2x00_field32 field, + const struct rt2x00_field32 field, u32 *reg); /* -- cgit v1.2.3 From 473196bd9935f0efd4c5f1cda28229e7dcff564c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:35:25 +0100 Subject: rt2x00: fix rt2x00pci_register_multi[read,write]() arguments Change type of 'length' argument from u16 to u32 (all arguments match rt2x00usb_register_multi[read,write]() ones now). Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.h | 8 ++++---- drivers/net/wireless/rt2x00/rt2x00pci.h | 15 +++++++-------- 2 files changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index fecb71c05c1e..586eb81ad76a 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -37,10 +37,10 @@ struct rt2800_ops { void (*register_multiread)(struct rt2x00_dev *rt2x00dev, const unsigned int offset, - void *value, const u16 length); + void *value, const u32 length); void (*register_multiwrite)(struct rt2x00_dev *rt2x00dev, const unsigned int offset, - const void *value, const u16 length); + const void *value, const u32 length); int (*regbusy_read)(struct rt2x00_dev *rt2x00dev, const unsigned int offset, @@ -76,7 +76,7 @@ static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev, static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned int offset, - void *value, const u16 length) + void *value, const u32 length) { const struct rt2800_ops *rt2800ops = rt2x00dev->priv; @@ -86,7 +86,7 @@ static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev, static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev, const unsigned int offset, const void *value, - const u16 length) + const u32 length) { const struct rt2800_ops *rt2800ops = rt2x00dev->priv; diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 15a12487e04b..f5af4b40308d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -53,10 +53,9 @@ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, *value = readl(rt2x00dev->csr.base + offset); } -static inline void -rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u16 length) +static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) { memcpy_fromio(value, rt2x00dev->csr.base + offset, length); } @@ -68,10 +67,10 @@ static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, writel(value, rt2x00dev->csr.base + offset); } -static inline void -rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - const void *value, const u16 length) +static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const void *value, + const u32 length) { memcpy_toio(rt2x00dev->csr.base + offset, value, length); } -- cgit v1.2.3 From 7ef5cc92bac940419f022e11115a28daea53814f Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:35:32 +0100 Subject: rt2800: add rt2800lib.h Code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.h | 99 +++++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800pci.c | 1 + drivers/net/wireless/rt2x00/rt2800pci.h | 76 ------------------------- drivers/net/wireless/rt2x00/rt2800usb.c | 1 + drivers/net/wireless/rt2x00/rt2800usb.h | 75 ------------------------- 5 files changed, 101 insertions(+), 151 deletions(-) create mode 100644 drivers/net/wireless/rt2x00/rt2800lib.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h new file mode 100644 index 000000000000..17e91fb1a77a --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -0,0 +1,99 @@ +/* + Copyright (C) 2009 Bartlomiej Zolnierkiewicz + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef RT2800LIB_H +#define RT2800LIB_H + +struct rt2800_ops { + void (*register_read)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 *value); + void (*register_write)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 value); + void (*register_write_lock)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 value); + + void (*register_multiread)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length); + void (*register_multiwrite)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const void *value, const u32 length); + + int (*regbusy_read)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const struct rt2x00_field32 field, u32 *reg); +}; + +static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) +{ + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_read(rt2x00dev, offset, value); +} + +static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_write(rt2x00dev, offset, value); +} + +static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_write_lock(rt2x00dev, offset, value); +} + +static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_multiread(rt2x00dev, offset, value, length); +} + +static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const void *value, + const u32 length) +{ + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_multiwrite(rt2x00dev, offset, value, length); +} + +static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const struct rt2x00_field32 field, + u32 *reg) +{ + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg); +} + +#endif /* RT2800LIB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index fde722caab94..9017ea64d011 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -37,6 +37,7 @@ #include "rt2x00.h" #include "rt2x00pci.h" #include "rt2x00soc.h" +#include "rt2800lib.h" #include "rt2800pci.h" #ifdef CONFIG_RT2800PCI_PCI_MODULE diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index 586eb81ad76a..856908815221 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -27,82 +27,6 @@ #ifndef RT2800PCI_H #define RT2800PCI_H -struct rt2800_ops { - void (*register_read)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value); - void (*register_write)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 value); - void (*register_write_lock)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 value); - - void (*register_multiread)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length); - void (*register_multiwrite)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - const void *value, const u32 length); - - int (*regbusy_read)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - const struct rt2x00_field32 field, u32 *reg); -}; - -static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - rt2800ops->register_read(rt2x00dev, offset, value); -} - -static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 value) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - rt2800ops->register_write(rt2x00dev, offset, value); -} - -static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 value) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - rt2800ops->register_write_lock(rt2x00dev, offset, value); -} - -static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - rt2800ops->register_multiread(rt2x00dev, offset, value, length); -} - -static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - const void *value, - const u32 length) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - rt2800ops->register_multiwrite(rt2x00dev, offset, value, length); -} - -static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - const struct rt2x00_field32 field, - u32 *reg) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg); -} - /* * RF chip defines. * diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index a3ec97a4c744..a3e505034fce 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -34,6 +34,7 @@ #include "rt2x00.h" #include "rt2x00usb.h" +#include "rt2800lib.h" #include "rt2800usb.h" /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 0a525a722a74..7b1130a22c55 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -27,81 +27,6 @@ #ifndef RT2800USB_H #define RT2800USB_H -struct rt2800_ops { - void (*register_read)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value); - void (*register_write)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 value); - void (*register_write_lock)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 value); - - void (*register_multiread)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length); - void (*register_multiwrite)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - const void *value, const u32 length); - - int (*regbusy_read)(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - const struct rt2x00_field32 field, u32 *reg); -}; - -static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 *value) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - rt2800ops->register_read(rt2x00dev, offset, value); -} - -static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 value) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - rt2800ops->register_write(rt2x00dev, offset, value); -} - -static inline void rt2800_register_write_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - u32 value) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - rt2800ops->register_write_lock(rt2x00dev, offset, value); -} - -static inline void rt2800_register_multiread(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - rt2800ops->register_multiread(rt2x00dev, offset, value, length); -} - -static inline void rt2800_register_multiwrite(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - rt2800ops->register_multiwrite(rt2x00dev, offset, value, length); -} - -static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - struct rt2x00_field32 field, - u32 *reg) -{ - const struct rt2800_ops *rt2800ops = rt2x00dev->priv; - - return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg); -} - /* * RF chip defines. * -- cgit v1.2.3 From d42c8d86ca52185c053f3352c57b46857573307a Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:35:47 +0100 Subject: rt2800usb: add RXINFO_DESC_SIZE definition Add RXINFO_DESC_SIZE definition and use it instead of abusing RXD_DESC_SIZE one (TXD_DESC_SIZE and RXD_DESC_SIZE are specific to PCI version of the chipset). Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 4 ++-- drivers/net/wireless/rt2x00/rt2800usb.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index a3e505034fce..0851dc672a8c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -2152,7 +2152,7 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, */ memcpy(skbdesc->desc, rxd, skbdesc->desc_len); rxd = (__le32 *)skbdesc->desc; - rxwi = &rxd[RXD_DESC_SIZE / sizeof(__le32)]; + rxwi = &rxd[RXINFO_DESC_SIZE / sizeof(__le32)]; /* * It is now safe to read the descriptor on all architectures. @@ -2874,7 +2874,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { static const struct data_queue_desc rt2800usb_queue_rx = { .entry_num = RX_ENTRIES, .data_size = AGGREGATION_SIZE, - .desc_size = RXD_DESC_SIZE + RXWI_DESC_SIZE, + .desc_size = RXINFO_DESC_SIZE + RXWI_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb), }; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 7b1130a22c55..9d7bb54999cc 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -1747,7 +1747,8 @@ struct mac_iveiv_entry { #define TXD_DESC_SIZE ( 4 * sizeof(__le32) ) #define TXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) #define TXWI_DESC_SIZE ( 4 * sizeof(__le32) ) -#define RXD_DESC_SIZE ( 1 * sizeof(__le32) ) +#define RXD_DESC_SIZE ( 4 * sizeof(__le32) ) +#define RXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) #define RXWI_DESC_SIZE ( 4 * sizeof(__le32) ) /* -- cgit v1.2.3 From b54f78a8b7a108a4abc81d88d641769726be23c1 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:35:54 +0100 Subject: rt2800: fix duplication in header files Updated debugging scripts are located here: http://www.kernel.org/pub/linux/kernel/people/bart/rt2800/scripts/ (they also work fine with older drivers) Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 1819 ++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800pci.c | 1 + drivers/net/wireless/rt2x00/rt2800pci.h | 1844 +----------------------------- drivers/net/wireless/rt2x00/rt2800usb.c | 1 + drivers/net/wireless/rt2x00/rt2800usb.h | 1873 +------------------------------ 5 files changed, 1881 insertions(+), 3657 deletions(-) create mode 100644 drivers/net/wireless/rt2x00/rt2800.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h new file mode 100644 index 000000000000..c5a56bac3bb5 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -0,0 +1,1819 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2800 + Abstract: Data structures and registers for the rt2800 modules. + Supported chipsets: RT2800E, RT2800ED & RT2800U. + */ + +#ifndef RT2800_H +#define RT2800_H + +/* + * RF chip defines. + * + * RF2820 2.4G 2T3R + * RF2850 2.4G/5G 2T3R + * RF2720 2.4G 1T2R + * RF2750 2.4G/5G 1T2R + * RF3020 2.4G 1T1R + * RF2020 2.4G B/G + * RF3021 2.4G 1T2R + * RF3022 2.4G 2T2R + * RF3052 2.4G 2T2R + */ +#define RF2820 0x0001 +#define RF2850 0x0002 +#define RF2720 0x0003 +#define RF2750 0x0004 +#define RF3020 0x0005 +#define RF2020 0x0006 +#define RF3021 0x0007 +#define RF3022 0x0008 +#define RF3052 0x0009 + +/* + * Chipset version. + */ +#define RT2860C_VERSION 0x28600100 +#define RT2860D_VERSION 0x28600101 +#define RT2880E_VERSION 0x28720200 +#define RT2883_VERSION 0x28830300 +#define RT3070_VERSION 0x30700200 + +/* + * Signal information. + * Default offset is required for RSSI <-> dBm conversion. + */ +#define DEFAULT_RSSI_OFFSET 120 /* FIXME */ + +/* + * Register layout information. + */ +#define CSR_REG_BASE 0x1000 +#define CSR_REG_SIZE 0x0800 +#define EEPROM_BASE 0x0000 +#define EEPROM_SIZE 0x0110 +#define BBP_BASE 0x0000 +#define BBP_SIZE 0x0080 +#define RF_BASE 0x0004 +#define RF_SIZE 0x0010 + +/* + * Number of TX queues. + */ +#define NUM_TX_QUEUES 4 + +/* + * USB registers. + */ + +/* + * INT_SOURCE_CSR: Interrupt source register. + * Write one to clear corresponding bit. + * TX_FIFO_STATUS: FIFO Statistics is full, sw should read 0x171c + */ +#define INT_SOURCE_CSR 0x0200 +#define INT_SOURCE_CSR_RXDELAYINT FIELD32(0x00000001) +#define INT_SOURCE_CSR_TXDELAYINT FIELD32(0x00000002) +#define INT_SOURCE_CSR_RX_DONE FIELD32(0x00000004) +#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00000008) +#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00000010) +#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00000020) +#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00000040) +#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00000080) +#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00000100) +#define INT_SOURCE_CSR_MCU_COMMAND FIELD32(0x00000200) +#define INT_SOURCE_CSR_RXTX_COHERENT FIELD32(0x00000400) +#define INT_SOURCE_CSR_TBTT FIELD32(0x00000800) +#define INT_SOURCE_CSR_PRE_TBTT FIELD32(0x00001000) +#define INT_SOURCE_CSR_TX_FIFO_STATUS FIELD32(0x00002000) +#define INT_SOURCE_CSR_AUTO_WAKEUP FIELD32(0x00004000) +#define INT_SOURCE_CSR_GPTIMER FIELD32(0x00008000) +#define INT_SOURCE_CSR_RX_COHERENT FIELD32(0x00010000) +#define INT_SOURCE_CSR_TX_COHERENT FIELD32(0x00020000) + +/* + * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF. + */ +#define INT_MASK_CSR 0x0204 +#define INT_MASK_CSR_RXDELAYINT FIELD32(0x00000001) +#define INT_MASK_CSR_TXDELAYINT FIELD32(0x00000002) +#define INT_MASK_CSR_RX_DONE FIELD32(0x00000004) +#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00000008) +#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00000010) +#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00000020) +#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00000040) +#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00000080) +#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00000100) +#define INT_MASK_CSR_MCU_COMMAND FIELD32(0x00000200) +#define INT_MASK_CSR_RXTX_COHERENT FIELD32(0x00000400) +#define INT_MASK_CSR_TBTT FIELD32(0x00000800) +#define INT_MASK_CSR_PRE_TBTT FIELD32(0x00001000) +#define INT_MASK_CSR_TX_FIFO_STATUS FIELD32(0x00002000) +#define INT_MASK_CSR_AUTO_WAKEUP FIELD32(0x00004000) +#define INT_MASK_CSR_GPTIMER FIELD32(0x00008000) +#define INT_MASK_CSR_RX_COHERENT FIELD32(0x00010000) +#define INT_MASK_CSR_TX_COHERENT FIELD32(0x00020000) + +/* + * WPDMA_GLO_CFG + */ +#define WPDMA_GLO_CFG 0x0208 +#define WPDMA_GLO_CFG_ENABLE_TX_DMA FIELD32(0x00000001) +#define WPDMA_GLO_CFG_TX_DMA_BUSY FIELD32(0x00000002) +#define WPDMA_GLO_CFG_ENABLE_RX_DMA FIELD32(0x00000004) +#define WPDMA_GLO_CFG_RX_DMA_BUSY FIELD32(0x00000008) +#define WPDMA_GLO_CFG_WP_DMA_BURST_SIZE FIELD32(0x00000030) +#define WPDMA_GLO_CFG_TX_WRITEBACK_DONE FIELD32(0x00000040) +#define WPDMA_GLO_CFG_BIG_ENDIAN FIELD32(0x00000080) +#define WPDMA_GLO_CFG_RX_HDR_SCATTER FIELD32(0x0000ff00) +#define WPDMA_GLO_CFG_HDR_SEG_LEN FIELD32(0xffff0000) + +/* + * WPDMA_RST_IDX + */ +#define WPDMA_RST_IDX 0x020c +#define WPDMA_RST_IDX_DTX_IDX0 FIELD32(0x00000001) +#define WPDMA_RST_IDX_DTX_IDX1 FIELD32(0x00000002) +#define WPDMA_RST_IDX_DTX_IDX2 FIELD32(0x00000004) +#define WPDMA_RST_IDX_DTX_IDX3 FIELD32(0x00000008) +#define WPDMA_RST_IDX_DTX_IDX4 FIELD32(0x00000010) +#define WPDMA_RST_IDX_DTX_IDX5 FIELD32(0x00000020) +#define WPDMA_RST_IDX_DRX_IDX0 FIELD32(0x00010000) + +/* + * DELAY_INT_CFG + */ +#define DELAY_INT_CFG 0x0210 +#define DELAY_INT_CFG_RXMAX_PTIME FIELD32(0x000000ff) +#define DELAY_INT_CFG_RXMAX_PINT FIELD32(0x00007f00) +#define DELAY_INT_CFG_RXDLY_INT_EN FIELD32(0x00008000) +#define DELAY_INT_CFG_TXMAX_PTIME FIELD32(0x00ff0000) +#define DELAY_INT_CFG_TXMAX_PINT FIELD32(0x7f000000) +#define DELAY_INT_CFG_TXDLY_INT_EN FIELD32(0x80000000) + +/* + * WMM_AIFSN_CFG: Aifsn for each EDCA AC + * AIFSN0: AC_BE + * AIFSN1: AC_BK + * AIFSN1: AC_VI + * AIFSN1: AC_VO + */ +#define WMM_AIFSN_CFG 0x0214 +#define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f) +#define WMM_AIFSN_CFG_AIFSN1 FIELD32(0x000000f0) +#define WMM_AIFSN_CFG_AIFSN2 FIELD32(0x00000f00) +#define WMM_AIFSN_CFG_AIFSN3 FIELD32(0x0000f000) + +/* + * WMM_CWMIN_CSR: CWmin for each EDCA AC + * CWMIN0: AC_BE + * CWMIN1: AC_BK + * CWMIN1: AC_VI + * CWMIN1: AC_VO + */ +#define WMM_CWMIN_CFG 0x0218 +#define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f) +#define WMM_CWMIN_CFG_CWMIN1 FIELD32(0x000000f0) +#define WMM_CWMIN_CFG_CWMIN2 FIELD32(0x00000f00) +#define WMM_CWMIN_CFG_CWMIN3 FIELD32(0x0000f000) + +/* + * WMM_CWMAX_CSR: CWmax for each EDCA AC + * CWMAX0: AC_BE + * CWMAX1: AC_BK + * CWMAX1: AC_VI + * CWMAX1: AC_VO + */ +#define WMM_CWMAX_CFG 0x021c +#define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f) +#define WMM_CWMAX_CFG_CWMAX1 FIELD32(0x000000f0) +#define WMM_CWMAX_CFG_CWMAX2 FIELD32(0x00000f00) +#define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000) + +/* + * AC_TXOP0: AC_BK/AC_BE TXOP register + * AC0TXOP: AC_BK in unit of 32us + * AC1TXOP: AC_BE in unit of 32us + */ +#define WMM_TXOP0_CFG 0x0220 +#define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff) +#define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000) + +/* + * AC_TXOP1: AC_VO/AC_VI TXOP register + * AC2TXOP: AC_VI in unit of 32us + * AC3TXOP: AC_VO in unit of 32us + */ +#define WMM_TXOP1_CFG 0x0224 +#define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff) +#define WMM_TXOP1_CFG_AC3TXOP FIELD32(0xffff0000) + +/* + * GPIO_CTRL_CFG: + */ +#define GPIO_CTRL_CFG 0x0228 +#define GPIO_CTRL_CFG_BIT0 FIELD32(0x00000001) +#define GPIO_CTRL_CFG_BIT1 FIELD32(0x00000002) +#define GPIO_CTRL_CFG_BIT2 FIELD32(0x00000004) +#define GPIO_CTRL_CFG_BIT3 FIELD32(0x00000008) +#define GPIO_CTRL_CFG_BIT4 FIELD32(0x00000010) +#define GPIO_CTRL_CFG_BIT5 FIELD32(0x00000020) +#define GPIO_CTRL_CFG_BIT6 FIELD32(0x00000040) +#define GPIO_CTRL_CFG_BIT7 FIELD32(0x00000080) +#define GPIO_CTRL_CFG_BIT8 FIELD32(0x00000100) + +/* + * MCU_CMD_CFG + */ +#define MCU_CMD_CFG 0x022c + +/* + * AC_BK register offsets + */ +#define TX_BASE_PTR0 0x0230 +#define TX_MAX_CNT0 0x0234 +#define TX_CTX_IDX0 0x0238 +#define TX_DTX_IDX0 0x023c + +/* + * AC_BE register offsets + */ +#define TX_BASE_PTR1 0x0240 +#define TX_MAX_CNT1 0x0244 +#define TX_CTX_IDX1 0x0248 +#define TX_DTX_IDX1 0x024c + +/* + * AC_VI register offsets + */ +#define TX_BASE_PTR2 0x0250 +#define TX_MAX_CNT2 0x0254 +#define TX_CTX_IDX2 0x0258 +#define TX_DTX_IDX2 0x025c + +/* + * AC_VO register offsets + */ +#define TX_BASE_PTR3 0x0260 +#define TX_MAX_CNT3 0x0264 +#define TX_CTX_IDX3 0x0268 +#define TX_DTX_IDX3 0x026c + +/* + * HCCA register offsets + */ +#define TX_BASE_PTR4 0x0270 +#define TX_MAX_CNT4 0x0274 +#define TX_CTX_IDX4 0x0278 +#define TX_DTX_IDX4 0x027c + +/* + * MGMT register offsets + */ +#define TX_BASE_PTR5 0x0280 +#define TX_MAX_CNT5 0x0284 +#define TX_CTX_IDX5 0x0288 +#define TX_DTX_IDX5 0x028c + +/* + * RX register offsets + */ +#define RX_BASE_PTR 0x0290 +#define RX_MAX_CNT 0x0294 +#define RX_CRX_IDX 0x0298 +#define RX_DRX_IDX 0x029c + +/* + * PBF_SYS_CTRL + * HOST_RAM_WRITE: enable Host program ram write selection + */ +#define PBF_SYS_CTRL 0x0400 +#define PBF_SYS_CTRL_READY FIELD32(0x00000080) +#define PBF_SYS_CTRL_HOST_RAM_WRITE FIELD32(0x00010000) + +/* + * HOST-MCU shared memory + */ +#define HOST_CMD_CSR 0x0404 +#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x000000ff) + +/* + * PBF registers + * Most are for debug. Driver doesn't touch PBF register. + */ +#define PBF_CFG 0x0408 +#define PBF_MAX_PCNT 0x040c +#define PBF_CTRL 0x0410 +#define PBF_INT_STA 0x0414 +#define PBF_INT_ENA 0x0418 + +/* + * BCN_OFFSET0: + */ +#define BCN_OFFSET0 0x042c +#define BCN_OFFSET0_BCN0 FIELD32(0x000000ff) +#define BCN_OFFSET0_BCN1 FIELD32(0x0000ff00) +#define BCN_OFFSET0_BCN2 FIELD32(0x00ff0000) +#define BCN_OFFSET0_BCN3 FIELD32(0xff000000) + +/* + * BCN_OFFSET1: + */ +#define BCN_OFFSET1 0x0430 +#define BCN_OFFSET1_BCN4 FIELD32(0x000000ff) +#define BCN_OFFSET1_BCN5 FIELD32(0x0000ff00) +#define BCN_OFFSET1_BCN6 FIELD32(0x00ff0000) +#define BCN_OFFSET1_BCN7 FIELD32(0xff000000) + +/* + * PBF registers + * Most are for debug. Driver doesn't touch PBF register. + */ +#define TXRXQ_PCNT 0x0438 +#define PBF_DBG 0x043c + +/* + * RF registers + */ +#define RF_CSR_CFG 0x0500 +#define RF_CSR_CFG_DATA FIELD32(0x000000ff) +#define RF_CSR_CFG_REGNUM FIELD32(0x00001f00) +#define RF_CSR_CFG_WRITE FIELD32(0x00010000) +#define RF_CSR_CFG_BUSY FIELD32(0x00020000) + +/* + * MAC Control/Status Registers(CSR). + * Some values are set in TU, whereas 1 TU == 1024 us. + */ + +/* + * MAC_CSR0: ASIC revision number. + * ASIC_REV: 0 + * ASIC_VER: 2860 or 2870 + */ +#define MAC_CSR0 0x1000 +#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff) +#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000) + +/* + * MAC_SYS_CTRL: + */ +#define MAC_SYS_CTRL 0x1004 +#define MAC_SYS_CTRL_RESET_CSR FIELD32(0x00000001) +#define MAC_SYS_CTRL_RESET_BBP FIELD32(0x00000002) +#define MAC_SYS_CTRL_ENABLE_TX FIELD32(0x00000004) +#define MAC_SYS_CTRL_ENABLE_RX FIELD32(0x00000008) +#define MAC_SYS_CTRL_CONTINUOUS_TX FIELD32(0x00000010) +#define MAC_SYS_CTRL_LOOPBACK FIELD32(0x00000020) +#define MAC_SYS_CTRL_WLAN_HALT FIELD32(0x00000040) +#define MAC_SYS_CTRL_RX_TIMESTAMP FIELD32(0x00000080) + +/* + * MAC_ADDR_DW0: STA MAC register 0 + */ +#define MAC_ADDR_DW0 0x1008 +#define MAC_ADDR_DW0_BYTE0 FIELD32(0x000000ff) +#define MAC_ADDR_DW0_BYTE1 FIELD32(0x0000ff00) +#define MAC_ADDR_DW0_BYTE2 FIELD32(0x00ff0000) +#define MAC_ADDR_DW0_BYTE3 FIELD32(0xff000000) + +/* + * MAC_ADDR_DW1: STA MAC register 1 + * UNICAST_TO_ME_MASK: + * Used to mask off bits from byte 5 of the MAC address + * to determine the UNICAST_TO_ME bit for RX frames. + * The full mask is complemented by BSS_ID_MASK: + * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK + */ +#define MAC_ADDR_DW1 0x100c +#define MAC_ADDR_DW1_BYTE4 FIELD32(0x000000ff) +#define MAC_ADDR_DW1_BYTE5 FIELD32(0x0000ff00) +#define MAC_ADDR_DW1_UNICAST_TO_ME_MASK FIELD32(0x00ff0000) + +/* + * MAC_BSSID_DW0: BSSID register 0 + */ +#define MAC_BSSID_DW0 0x1010 +#define MAC_BSSID_DW0_BYTE0 FIELD32(0x000000ff) +#define MAC_BSSID_DW0_BYTE1 FIELD32(0x0000ff00) +#define MAC_BSSID_DW0_BYTE2 FIELD32(0x00ff0000) +#define MAC_BSSID_DW0_BYTE3 FIELD32(0xff000000) + +/* + * MAC_BSSID_DW1: BSSID register 1 + * BSS_ID_MASK: + * 0: 1-BSSID mode (BSS index = 0) + * 1: 2-BSSID mode (BSS index: Byte5, bit 0) + * 2: 4-BSSID mode (BSS index: byte5, bit 0 - 1) + * 3: 8-BSSID mode (BSS index: byte5, bit 0 - 2) + * This mask is used to mask off bits 0, 1 and 2 of byte 5 of the + * BSSID. This will make sure that those bits will be ignored + * when determining the MY_BSS of RX frames. + */ +#define MAC_BSSID_DW1 0x1014 +#define MAC_BSSID_DW1_BYTE4 FIELD32(0x000000ff) +#define MAC_BSSID_DW1_BYTE5 FIELD32(0x0000ff00) +#define MAC_BSSID_DW1_BSS_ID_MASK FIELD32(0x00030000) +#define MAC_BSSID_DW1_BSS_BCN_NUM FIELD32(0x001c0000) + +/* + * MAX_LEN_CFG: Maximum frame length register. + * MAX_MPDU: rt2860b max 16k bytes + * MAX_PSDU: Maximum PSDU length + * (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 + */ +#define MAX_LEN_CFG 0x1018 +#define MAX_LEN_CFG_MAX_MPDU FIELD32(0x00000fff) +#define MAX_LEN_CFG_MAX_PSDU FIELD32(0x00003000) +#define MAX_LEN_CFG_MIN_PSDU FIELD32(0x0000c000) +#define MAX_LEN_CFG_MIN_MPDU FIELD32(0x000f0000) + +/* + * BBP_CSR_CFG: BBP serial control register + * VALUE: Register value to program into BBP + * REG_NUM: Selected BBP register + * READ_CONTROL: 0 write BBP, 1 read BBP + * BUSY: ASIC is busy executing BBP commands + * BBP_PAR_DUR: 0 4 MAC clocks, 1 8 MAC clocks + * BBP_RW_MODE: 0 serial, 1 paralell + */ +#define BBP_CSR_CFG 0x101c +#define BBP_CSR_CFG_VALUE FIELD32(0x000000ff) +#define BBP_CSR_CFG_REGNUM FIELD32(0x0000ff00) +#define BBP_CSR_CFG_READ_CONTROL FIELD32(0x00010000) +#define BBP_CSR_CFG_BUSY FIELD32(0x00020000) +#define BBP_CSR_CFG_BBP_PAR_DUR FIELD32(0x00040000) +#define BBP_CSR_CFG_BBP_RW_MODE FIELD32(0x00080000) + +/* + * RF_CSR_CFG0: RF control register + * REGID_AND_VALUE: Register value to program into RF + * BITWIDTH: Selected RF register + * STANDBYMODE: 0 high when standby, 1 low when standby + * SEL: 0 RF_LE0 activate, 1 RF_LE1 activate + * BUSY: ASIC is busy executing RF commands + */ +#define RF_CSR_CFG0 0x1020 +#define RF_CSR_CFG0_REGID_AND_VALUE FIELD32(0x00ffffff) +#define RF_CSR_CFG0_BITWIDTH FIELD32(0x1f000000) +#define RF_CSR_CFG0_REG_VALUE_BW FIELD32(0x1fffffff) +#define RF_CSR_CFG0_STANDBYMODE FIELD32(0x20000000) +#define RF_CSR_CFG0_SEL FIELD32(0x40000000) +#define RF_CSR_CFG0_BUSY FIELD32(0x80000000) + +/* + * RF_CSR_CFG1: RF control register + * REGID_AND_VALUE: Register value to program into RF + * RFGAP: Gap between BB_CONTROL_RF and RF_LE + * 0: 3 system clock cycle (37.5usec) + * 1: 5 system clock cycle (62.5usec) + */ +#define RF_CSR_CFG1 0x1024 +#define RF_CSR_CFG1_REGID_AND_VALUE FIELD32(0x00ffffff) +#define RF_CSR_CFG1_RFGAP FIELD32(0x1f000000) + +/* + * RF_CSR_CFG2: RF control register + * VALUE: Register value to program into RF + * RFGAP: Gap between BB_CONTROL_RF and RF_LE + * 0: 3 system clock cycle (37.5usec) + * 1: 5 system clock cycle (62.5usec) + */ +#define RF_CSR_CFG2 0x1028 +#define RF_CSR_CFG2_VALUE FIELD32(0x00ffffff) + +/* + * LED_CFG: LED control + * color LED's: + * 0: off + * 1: blinking upon TX2 + * 2: periodic slow blinking + * 3: always on + * LED polarity: + * 0: active low + * 1: active high + */ +#define LED_CFG 0x102c +#define LED_CFG_ON_PERIOD FIELD32(0x000000ff) +#define LED_CFG_OFF_PERIOD FIELD32(0x0000ff00) +#define LED_CFG_SLOW_BLINK_PERIOD FIELD32(0x003f0000) +#define LED_CFG_R_LED_MODE FIELD32(0x03000000) +#define LED_CFG_G_LED_MODE FIELD32(0x0c000000) +#define LED_CFG_Y_LED_MODE FIELD32(0x30000000) +#define LED_CFG_LED_POLAR FIELD32(0x40000000) + +/* + * XIFS_TIME_CFG: MAC timing + * CCKM_SIFS_TIME: unit 1us. Applied after CCK RX/TX + * OFDM_SIFS_TIME: unit 1us. Applied after OFDM RX/TX + * OFDM_XIFS_TIME: unit 1us. Applied after OFDM RX + * when MAC doesn't reference BBP signal BBRXEND + * EIFS: unit 1us + * BB_RXEND_ENABLE: reference RXEND signal to begin XIFS defer + * + */ +#define XIFS_TIME_CFG 0x1100 +#define XIFS_TIME_CFG_CCKM_SIFS_TIME FIELD32(0x000000ff) +#define XIFS_TIME_CFG_OFDM_SIFS_TIME FIELD32(0x0000ff00) +#define XIFS_TIME_CFG_OFDM_XIFS_TIME FIELD32(0x000f0000) +#define XIFS_TIME_CFG_EIFS FIELD32(0x1ff00000) +#define XIFS_TIME_CFG_BB_RXEND_ENABLE FIELD32(0x20000000) + +/* + * BKOFF_SLOT_CFG: + */ +#define BKOFF_SLOT_CFG 0x1104 +#define BKOFF_SLOT_CFG_SLOT_TIME FIELD32(0x000000ff) +#define BKOFF_SLOT_CFG_CC_DELAY_TIME FIELD32(0x0000ff00) + +/* + * NAV_TIME_CFG: + */ +#define NAV_TIME_CFG 0x1108 +#define NAV_TIME_CFG_SIFS FIELD32(0x000000ff) +#define NAV_TIME_CFG_SLOT_TIME FIELD32(0x0000ff00) +#define NAV_TIME_CFG_EIFS FIELD32(0x01ff0000) +#define NAV_TIME_ZERO_SIFS FIELD32(0x02000000) + +/* + * CH_TIME_CFG: count as channel busy + */ +#define CH_TIME_CFG 0x110c + +/* + * PBF_LIFE_TIMER: TX/RX MPDU timestamp timer (free run) Unit: 1us + */ +#define PBF_LIFE_TIMER 0x1110 + +/* + * BCN_TIME_CFG: + * BEACON_INTERVAL: in unit of 1/16 TU + * TSF_TICKING: Enable TSF auto counting + * TSF_SYNC: Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode + * BEACON_GEN: Enable beacon generator + */ +#define BCN_TIME_CFG 0x1114 +#define BCN_TIME_CFG_BEACON_INTERVAL FIELD32(0x0000ffff) +#define BCN_TIME_CFG_TSF_TICKING FIELD32(0x00010000) +#define BCN_TIME_CFG_TSF_SYNC FIELD32(0x00060000) +#define BCN_TIME_CFG_TBTT_ENABLE FIELD32(0x00080000) +#define BCN_TIME_CFG_BEACON_GEN FIELD32(0x00100000) +#define BCN_TIME_CFG_TX_TIME_COMPENSATE FIELD32(0xf0000000) + +/* + * TBTT_SYNC_CFG: + */ +#define TBTT_SYNC_CFG 0x1118 + +/* + * TSF_TIMER_DW0: Local lsb TSF timer, read-only + */ +#define TSF_TIMER_DW0 0x111c +#define TSF_TIMER_DW0_LOW_WORD FIELD32(0xffffffff) + +/* + * TSF_TIMER_DW1: Local msb TSF timer, read-only + */ +#define TSF_TIMER_DW1 0x1120 +#define TSF_TIMER_DW1_HIGH_WORD FIELD32(0xffffffff) + +/* + * TBTT_TIMER: TImer remains till next TBTT, read-only + */ +#define TBTT_TIMER 0x1124 + +/* + * INT_TIMER_CFG: + */ +#define INT_TIMER_CFG 0x1128 + +/* + * INT_TIMER_EN: GP-timer and pre-tbtt Int enable + */ +#define INT_TIMER_EN 0x112c + +/* + * CH_IDLE_STA: channel idle time + */ +#define CH_IDLE_STA 0x1130 + +/* + * CH_BUSY_STA: channel busy time + */ +#define CH_BUSY_STA 0x1134 + +/* + * MAC_STATUS_CFG: + * BBP_RF_BUSY: When set to 0, BBP and RF are stable. + * if 1 or higher one of the 2 registers is busy. + */ +#define MAC_STATUS_CFG 0x1200 +#define MAC_STATUS_CFG_BBP_RF_BUSY FIELD32(0x00000003) + +/* + * PWR_PIN_CFG: + */ +#define PWR_PIN_CFG 0x1204 + +/* + * AUTOWAKEUP_CFG: Manual power control / status register + * TBCN_BEFORE_WAKE: ForceWake has high privilege than PutToSleep when both set + * AUTOWAKE: 0:sleep, 1:awake + */ +#define AUTOWAKEUP_CFG 0x1208 +#define AUTOWAKEUP_CFG_AUTO_LEAD_TIME FIELD32(0x000000ff) +#define AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE FIELD32(0x00007f00) +#define AUTOWAKEUP_CFG_AUTOWAKE FIELD32(0x00008000) + +/* + * EDCA_AC0_CFG: + */ +#define EDCA_AC0_CFG 0x1300 +#define EDCA_AC0_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC0_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC0_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC0_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC1_CFG: + */ +#define EDCA_AC1_CFG 0x1304 +#define EDCA_AC1_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC1_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC1_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC1_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC2_CFG: + */ +#define EDCA_AC2_CFG 0x1308 +#define EDCA_AC2_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC2_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC2_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC2_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_AC3_CFG: + */ +#define EDCA_AC3_CFG 0x130c +#define EDCA_AC3_CFG_TX_OP FIELD32(0x000000ff) +#define EDCA_AC3_CFG_AIFSN FIELD32(0x00000f00) +#define EDCA_AC3_CFG_CWMIN FIELD32(0x0000f000) +#define EDCA_AC3_CFG_CWMAX FIELD32(0x000f0000) + +/* + * EDCA_TID_AC_MAP: + */ +#define EDCA_TID_AC_MAP 0x1310 + +/* + * TX_PWR_CFG_0: + */ +#define TX_PWR_CFG_0 0x1314 +#define TX_PWR_CFG_0_1MBS FIELD32(0x0000000f) +#define TX_PWR_CFG_0_2MBS FIELD32(0x000000f0) +#define TX_PWR_CFG_0_55MBS FIELD32(0x00000f00) +#define TX_PWR_CFG_0_11MBS FIELD32(0x0000f000) +#define TX_PWR_CFG_0_6MBS FIELD32(0x000f0000) +#define TX_PWR_CFG_0_9MBS FIELD32(0x00f00000) +#define TX_PWR_CFG_0_12MBS FIELD32(0x0f000000) +#define TX_PWR_CFG_0_18MBS FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_1: + */ +#define TX_PWR_CFG_1 0x1318 +#define TX_PWR_CFG_1_24MBS FIELD32(0x0000000f) +#define TX_PWR_CFG_1_36MBS FIELD32(0x000000f0) +#define TX_PWR_CFG_1_48MBS FIELD32(0x00000f00) +#define TX_PWR_CFG_1_54MBS FIELD32(0x0000f000) +#define TX_PWR_CFG_1_MCS0 FIELD32(0x000f0000) +#define TX_PWR_CFG_1_MCS1 FIELD32(0x00f00000) +#define TX_PWR_CFG_1_MCS2 FIELD32(0x0f000000) +#define TX_PWR_CFG_1_MCS3 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_2: + */ +#define TX_PWR_CFG_2 0x131c +#define TX_PWR_CFG_2_MCS4 FIELD32(0x0000000f) +#define TX_PWR_CFG_2_MCS5 FIELD32(0x000000f0) +#define TX_PWR_CFG_2_MCS6 FIELD32(0x00000f00) +#define TX_PWR_CFG_2_MCS7 FIELD32(0x0000f000) +#define TX_PWR_CFG_2_MCS8 FIELD32(0x000f0000) +#define TX_PWR_CFG_2_MCS9 FIELD32(0x00f00000) +#define TX_PWR_CFG_2_MCS10 FIELD32(0x0f000000) +#define TX_PWR_CFG_2_MCS11 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_3: + */ +#define TX_PWR_CFG_3 0x1320 +#define TX_PWR_CFG_3_MCS12 FIELD32(0x0000000f) +#define TX_PWR_CFG_3_MCS13 FIELD32(0x000000f0) +#define TX_PWR_CFG_3_MCS14 FIELD32(0x00000f00) +#define TX_PWR_CFG_3_MCS15 FIELD32(0x0000f000) +#define TX_PWR_CFG_3_UKNOWN1 FIELD32(0x000f0000) +#define TX_PWR_CFG_3_UKNOWN2 FIELD32(0x00f00000) +#define TX_PWR_CFG_3_UKNOWN3 FIELD32(0x0f000000) +#define TX_PWR_CFG_3_UKNOWN4 FIELD32(0xf0000000) + +/* + * TX_PWR_CFG_4: + */ +#define TX_PWR_CFG_4 0x1324 +#define TX_PWR_CFG_4_UKNOWN5 FIELD32(0x0000000f) +#define TX_PWR_CFG_4_UKNOWN6 FIELD32(0x000000f0) +#define TX_PWR_CFG_4_UKNOWN7 FIELD32(0x00000f00) +#define TX_PWR_CFG_4_UKNOWN8 FIELD32(0x0000f000) + +/* + * TX_PIN_CFG: + */ +#define TX_PIN_CFG 0x1328 +#define TX_PIN_CFG_PA_PE_A0_EN FIELD32(0x00000001) +#define TX_PIN_CFG_PA_PE_G0_EN FIELD32(0x00000002) +#define TX_PIN_CFG_PA_PE_A1_EN FIELD32(0x00000004) +#define TX_PIN_CFG_PA_PE_G1_EN FIELD32(0x00000008) +#define TX_PIN_CFG_PA_PE_A0_POL FIELD32(0x00000010) +#define TX_PIN_CFG_PA_PE_G0_POL FIELD32(0x00000020) +#define TX_PIN_CFG_PA_PE_A1_POL FIELD32(0x00000040) +#define TX_PIN_CFG_PA_PE_G1_POL FIELD32(0x00000080) +#define TX_PIN_CFG_LNA_PE_A0_EN FIELD32(0x00000100) +#define TX_PIN_CFG_LNA_PE_G0_EN FIELD32(0x00000200) +#define TX_PIN_CFG_LNA_PE_A1_EN FIELD32(0x00000400) +#define TX_PIN_CFG_LNA_PE_G1_EN FIELD32(0x00000800) +#define TX_PIN_CFG_LNA_PE_A0_POL FIELD32(0x00001000) +#define TX_PIN_CFG_LNA_PE_G0_POL FIELD32(0x00002000) +#define TX_PIN_CFG_LNA_PE_A1_POL FIELD32(0x00004000) +#define TX_PIN_CFG_LNA_PE_G1_POL FIELD32(0x00008000) +#define TX_PIN_CFG_RFTR_EN FIELD32(0x00010000) +#define TX_PIN_CFG_RFTR_POL FIELD32(0x00020000) +#define TX_PIN_CFG_TRSW_EN FIELD32(0x00040000) +#define TX_PIN_CFG_TRSW_POL FIELD32(0x00080000) + +/* + * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz + */ +#define TX_BAND_CFG 0x132c +#define TX_BAND_CFG_HT40_PLUS FIELD32(0x00000001) +#define TX_BAND_CFG_A FIELD32(0x00000002) +#define TX_BAND_CFG_BG FIELD32(0x00000004) + +/* + * TX_SW_CFG0: + */ +#define TX_SW_CFG0 0x1330 + +/* + * TX_SW_CFG1: + */ +#define TX_SW_CFG1 0x1334 + +/* + * TX_SW_CFG2: + */ +#define TX_SW_CFG2 0x1338 + +/* + * TXOP_THRES_CFG: + */ +#define TXOP_THRES_CFG 0x133c + +/* + * TXOP_CTRL_CFG: + */ +#define TXOP_CTRL_CFG 0x1340 + +/* + * TX_RTS_CFG: + * RTS_THRES: unit:byte + * RTS_FBK_EN: enable rts rate fallback + */ +#define TX_RTS_CFG 0x1344 +#define TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT FIELD32(0x000000ff) +#define TX_RTS_CFG_RTS_THRES FIELD32(0x00ffff00) +#define TX_RTS_CFG_RTS_FBK_EN FIELD32(0x01000000) + +/* + * TX_TIMEOUT_CFG: + * MPDU_LIFETIME: expiration time = 2^(9+MPDU LIFE TIME) us + * RX_ACK_TIMEOUT: unit:slot. Used for TX procedure + * TX_OP_TIMEOUT: TXOP timeout value for TXOP truncation. + * it is recommended that: + * (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) + */ +#define TX_TIMEOUT_CFG 0x1348 +#define TX_TIMEOUT_CFG_MPDU_LIFETIME FIELD32(0x000000f0) +#define TX_TIMEOUT_CFG_RX_ACK_TIMEOUT FIELD32(0x0000ff00) +#define TX_TIMEOUT_CFG_TX_OP_TIMEOUT FIELD32(0x00ff0000) + +/* + * TX_RTY_CFG: + * SHORT_RTY_LIMIT: short retry limit + * LONG_RTY_LIMIT: long retry limit + * LONG_RTY_THRE: Long retry threshoold + * NON_AGG_RTY_MODE: Non-Aggregate MPDU retry mode + * 0:expired by retry limit, 1: expired by mpdu life timer + * AGG_RTY_MODE: Aggregate MPDU retry mode + * 0:expired by retry limit, 1: expired by mpdu life timer + * TX_AUTO_FB_ENABLE: Tx retry PHY rate auto fallback enable + */ +#define TX_RTY_CFG 0x134c +#define TX_RTY_CFG_SHORT_RTY_LIMIT FIELD32(0x000000ff) +#define TX_RTY_CFG_LONG_RTY_LIMIT FIELD32(0x0000ff00) +#define TX_RTY_CFG_LONG_RTY_THRE FIELD32(0x0fff0000) +#define TX_RTY_CFG_NON_AGG_RTY_MODE FIELD32(0x10000000) +#define TX_RTY_CFG_AGG_RTY_MODE FIELD32(0x20000000) +#define TX_RTY_CFG_TX_AUTO_FB_ENABLE FIELD32(0x40000000) + +/* + * TX_LINK_CFG: + * REMOTE_MFB_LIFETIME: remote MFB life time. unit: 32us + * MFB_ENABLE: TX apply remote MFB 1:enable + * REMOTE_UMFS_ENABLE: remote unsolicit MFB enable + * 0: not apply remote remote unsolicit (MFS=7) + * TX_MRQ_EN: MCS request TX enable + * TX_RDG_EN: RDG TX enable + * TX_CF_ACK_EN: Piggyback CF-ACK enable + * REMOTE_MFB: remote MCS feedback + * REMOTE_MFS: remote MCS feedback sequence number + */ +#define TX_LINK_CFG 0x1350 +#define TX_LINK_CFG_REMOTE_MFB_LIFETIME FIELD32(0x000000ff) +#define TX_LINK_CFG_MFB_ENABLE FIELD32(0x00000100) +#define TX_LINK_CFG_REMOTE_UMFS_ENABLE FIELD32(0x00000200) +#define TX_LINK_CFG_TX_MRQ_EN FIELD32(0x00000400) +#define TX_LINK_CFG_TX_RDG_EN FIELD32(0x00000800) +#define TX_LINK_CFG_TX_CF_ACK_EN FIELD32(0x00001000) +#define TX_LINK_CFG_REMOTE_MFB FIELD32(0x00ff0000) +#define TX_LINK_CFG_REMOTE_MFS FIELD32(0xff000000) + +/* + * HT_FBK_CFG0: + */ +#define HT_FBK_CFG0 0x1354 +#define HT_FBK_CFG0_HTMCS0FBK FIELD32(0x0000000f) +#define HT_FBK_CFG0_HTMCS1FBK FIELD32(0x000000f0) +#define HT_FBK_CFG0_HTMCS2FBK FIELD32(0x00000f00) +#define HT_FBK_CFG0_HTMCS3FBK FIELD32(0x0000f000) +#define HT_FBK_CFG0_HTMCS4FBK FIELD32(0x000f0000) +#define HT_FBK_CFG0_HTMCS5FBK FIELD32(0x00f00000) +#define HT_FBK_CFG0_HTMCS6FBK FIELD32(0x0f000000) +#define HT_FBK_CFG0_HTMCS7FBK FIELD32(0xf0000000) + +/* + * HT_FBK_CFG1: + */ +#define HT_FBK_CFG1 0x1358 +#define HT_FBK_CFG1_HTMCS8FBK FIELD32(0x0000000f) +#define HT_FBK_CFG1_HTMCS9FBK FIELD32(0x000000f0) +#define HT_FBK_CFG1_HTMCS10FBK FIELD32(0x00000f00) +#define HT_FBK_CFG1_HTMCS11FBK FIELD32(0x0000f000) +#define HT_FBK_CFG1_HTMCS12FBK FIELD32(0x000f0000) +#define HT_FBK_CFG1_HTMCS13FBK FIELD32(0x00f00000) +#define HT_FBK_CFG1_HTMCS14FBK FIELD32(0x0f000000) +#define HT_FBK_CFG1_HTMCS15FBK FIELD32(0xf0000000) + +/* + * LG_FBK_CFG0: + */ +#define LG_FBK_CFG0 0x135c +#define LG_FBK_CFG0_OFDMMCS0FBK FIELD32(0x0000000f) +#define LG_FBK_CFG0_OFDMMCS1FBK FIELD32(0x000000f0) +#define LG_FBK_CFG0_OFDMMCS2FBK FIELD32(0x00000f00) +#define LG_FBK_CFG0_OFDMMCS3FBK FIELD32(0x0000f000) +#define LG_FBK_CFG0_OFDMMCS4FBK FIELD32(0x000f0000) +#define LG_FBK_CFG0_OFDMMCS5FBK FIELD32(0x00f00000) +#define LG_FBK_CFG0_OFDMMCS6FBK FIELD32(0x0f000000) +#define LG_FBK_CFG0_OFDMMCS7FBK FIELD32(0xf0000000) + +/* + * LG_FBK_CFG1: + */ +#define LG_FBK_CFG1 0x1360 +#define LG_FBK_CFG0_CCKMCS0FBK FIELD32(0x0000000f) +#define LG_FBK_CFG0_CCKMCS1FBK FIELD32(0x000000f0) +#define LG_FBK_CFG0_CCKMCS2FBK FIELD32(0x00000f00) +#define LG_FBK_CFG0_CCKMCS3FBK FIELD32(0x0000f000) + +/* + * CCK_PROT_CFG: CCK Protection + * PROTECT_RATE: Protection control frame rate for CCK TX(RTS/CTS/CFEnd) + * PROTECT_CTRL: Protection control frame type for CCK TX + * 0:none, 1:RTS/CTS, 2:CTS-to-self + * PROTECT_NAV: TXOP protection type for CCK TX + * 0:none, 1:ShortNAVprotect, 2:LongNAVProtect + * TX_OP_ALLOW_CCK: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_OFDM: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_MM20: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_MM40: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_GF20: CCK TXOP allowance, 0:disallow + * TX_OP_ALLOW_GF40: CCK TXOP allowance, 0:disallow + * RTS_TH_EN: RTS threshold enable on CCK TX + */ +#define CCK_PROT_CFG 0x1364 +#define CCK_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define CCK_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define CCK_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define CCK_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define CCK_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define CCK_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define CCK_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define CCK_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define CCK_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define CCK_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * OFDM_PROT_CFG: OFDM Protection + */ +#define OFDM_PROT_CFG 0x1368 +#define OFDM_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define OFDM_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define OFDM_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define OFDM_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define OFDM_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * MM20_PROT_CFG: MM20 Protection + */ +#define MM20_PROT_CFG 0x136c +#define MM20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define MM20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define MM20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define MM20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define MM20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define MM20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define MM20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define MM20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define MM20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define MM20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * MM40_PROT_CFG: MM40 Protection + */ +#define MM40_PROT_CFG 0x1370 +#define MM40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define MM40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define MM40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define MM40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define MM40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define MM40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define MM40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define MM40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define MM40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define MM40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * GF20_PROT_CFG: GF20 Protection + */ +#define GF20_PROT_CFG 0x1374 +#define GF20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define GF20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define GF20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define GF20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define GF20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define GF20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define GF20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define GF20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define GF20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define GF20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * GF40_PROT_CFG: GF40 Protection + */ +#define GF40_PROT_CFG 0x1378 +#define GF40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) +#define GF40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) +#define GF40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) +#define GF40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) +#define GF40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) +#define GF40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) +#define GF40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) +#define GF40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) +#define GF40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) +#define GF40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) + +/* + * EXP_CTS_TIME: + */ +#define EXP_CTS_TIME 0x137c + +/* + * EXP_ACK_TIME: + */ +#define EXP_ACK_TIME 0x1380 + +/* + * RX_FILTER_CFG: RX configuration register. + */ +#define RX_FILTER_CFG 0x1400 +#define RX_FILTER_CFG_DROP_CRC_ERROR FIELD32(0x00000001) +#define RX_FILTER_CFG_DROP_PHY_ERROR FIELD32(0x00000002) +#define RX_FILTER_CFG_DROP_NOT_TO_ME FIELD32(0x00000004) +#define RX_FILTER_CFG_DROP_NOT_MY_BSSD FIELD32(0x00000008) +#define RX_FILTER_CFG_DROP_VER_ERROR FIELD32(0x00000010) +#define RX_FILTER_CFG_DROP_MULTICAST FIELD32(0x00000020) +#define RX_FILTER_CFG_DROP_BROADCAST FIELD32(0x00000040) +#define RX_FILTER_CFG_DROP_DUPLICATE FIELD32(0x00000080) +#define RX_FILTER_CFG_DROP_CF_END_ACK FIELD32(0x00000100) +#define RX_FILTER_CFG_DROP_CF_END FIELD32(0x00000200) +#define RX_FILTER_CFG_DROP_ACK FIELD32(0x00000400) +#define RX_FILTER_CFG_DROP_CTS FIELD32(0x00000800) +#define RX_FILTER_CFG_DROP_RTS FIELD32(0x00001000) +#define RX_FILTER_CFG_DROP_PSPOLL FIELD32(0x00002000) +#define RX_FILTER_CFG_DROP_BA FIELD32(0x00004000) +#define RX_FILTER_CFG_DROP_BAR FIELD32(0x00008000) +#define RX_FILTER_CFG_DROP_CNTL FIELD32(0x00010000) + +/* + * AUTO_RSP_CFG: + * AUTORESPONDER: 0: disable, 1: enable + * BAC_ACK_POLICY: 0:long, 1:short preamble + * CTS_40_MMODE: Response CTS 40MHz duplicate mode + * CTS_40_MREF: Response CTS 40MHz duplicate mode + * AR_PREAMBLE: Auto responder preamble 0:long, 1:short preamble + * DUAL_CTS_EN: Power bit value in control frame + * ACK_CTS_PSM_BIT:Power bit value in control frame + */ +#define AUTO_RSP_CFG 0x1404 +#define AUTO_RSP_CFG_AUTORESPONDER FIELD32(0x00000001) +#define AUTO_RSP_CFG_BAC_ACK_POLICY FIELD32(0x00000002) +#define AUTO_RSP_CFG_CTS_40_MMODE FIELD32(0x00000004) +#define AUTO_RSP_CFG_CTS_40_MREF FIELD32(0x00000008) +#define AUTO_RSP_CFG_AR_PREAMBLE FIELD32(0x00000010) +#define AUTO_RSP_CFG_DUAL_CTS_EN FIELD32(0x00000040) +#define AUTO_RSP_CFG_ACK_CTS_PSM_BIT FIELD32(0x00000080) + +/* + * LEGACY_BASIC_RATE: + */ +#define LEGACY_BASIC_RATE 0x1408 + +/* + * HT_BASIC_RATE: + */ +#define HT_BASIC_RATE 0x140c + +/* + * HT_CTRL_CFG: + */ +#define HT_CTRL_CFG 0x1410 + +/* + * SIFS_COST_CFG: + */ +#define SIFS_COST_CFG 0x1414 + +/* + * RX_PARSER_CFG: + * Set NAV for all received frames + */ +#define RX_PARSER_CFG 0x1418 + +/* + * TX_SEC_CNT0: + */ +#define TX_SEC_CNT0 0x1500 + +/* + * RX_SEC_CNT0: + */ +#define RX_SEC_CNT0 0x1504 + +/* + * CCMP_FC_MUTE: + */ +#define CCMP_FC_MUTE 0x1508 + +/* + * TXOP_HLDR_ADDR0: + */ +#define TXOP_HLDR_ADDR0 0x1600 + +/* + * TXOP_HLDR_ADDR1: + */ +#define TXOP_HLDR_ADDR1 0x1604 + +/* + * TXOP_HLDR_ET: + */ +#define TXOP_HLDR_ET 0x1608 + +/* + * QOS_CFPOLL_RA_DW0: + */ +#define QOS_CFPOLL_RA_DW0 0x160c + +/* + * QOS_CFPOLL_RA_DW1: + */ +#define QOS_CFPOLL_RA_DW1 0x1610 + +/* + * QOS_CFPOLL_QC: + */ +#define QOS_CFPOLL_QC 0x1614 + +/* + * RX_STA_CNT0: RX PLCP error count & RX CRC error count + */ +#define RX_STA_CNT0 0x1700 +#define RX_STA_CNT0_CRC_ERR FIELD32(0x0000ffff) +#define RX_STA_CNT0_PHY_ERR FIELD32(0xffff0000) + +/* + * RX_STA_CNT1: RX False CCA count & RX LONG frame count + */ +#define RX_STA_CNT1 0x1704 +#define RX_STA_CNT1_FALSE_CCA FIELD32(0x0000ffff) +#define RX_STA_CNT1_PLCP_ERR FIELD32(0xffff0000) + +/* + * RX_STA_CNT2: + */ +#define RX_STA_CNT2 0x1708 +#define RX_STA_CNT2_RX_DUPLI_COUNT FIELD32(0x0000ffff) +#define RX_STA_CNT2_RX_FIFO_OVERFLOW FIELD32(0xffff0000) + +/* + * TX_STA_CNT0: TX Beacon count + */ +#define TX_STA_CNT0 0x170c +#define TX_STA_CNT0_TX_FAIL_COUNT FIELD32(0x0000ffff) +#define TX_STA_CNT0_TX_BEACON_COUNT FIELD32(0xffff0000) + +/* + * TX_STA_CNT1: TX tx count + */ +#define TX_STA_CNT1 0x1710 +#define TX_STA_CNT1_TX_SUCCESS FIELD32(0x0000ffff) +#define TX_STA_CNT1_TX_RETRANSMIT FIELD32(0xffff0000) + +/* + * TX_STA_CNT2: TX tx count + */ +#define TX_STA_CNT2 0x1714 +#define TX_STA_CNT2_TX_ZERO_LEN_COUNT FIELD32(0x0000ffff) +#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000) + +/* + * TX_STA_FIFO: TX Result for specific PID status fifo register + */ +#define TX_STA_FIFO 0x1718 +#define TX_STA_FIFO_VALID FIELD32(0x00000001) +#define TX_STA_FIFO_PID_TYPE FIELD32(0x0000001e) +#define TX_STA_FIFO_TX_SUCCESS FIELD32(0x00000020) +#define TX_STA_FIFO_TX_AGGRE FIELD32(0x00000040) +#define TX_STA_FIFO_TX_ACK_REQUIRED FIELD32(0x00000080) +#define TX_STA_FIFO_WCID FIELD32(0x0000ff00) +#define TX_STA_FIFO_SUCCESS_RATE FIELD32(0xffff0000) +#define TX_STA_FIFO_MCS FIELD32(0x007f0000) +#define TX_STA_FIFO_PHYMODE FIELD32(0xc0000000) + +/* + * TX_AGG_CNT: Debug counter + */ +#define TX_AGG_CNT 0x171c +#define TX_AGG_CNT_NON_AGG_TX_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT_AGG_TX_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT0: + */ +#define TX_AGG_CNT0 0x1720 +#define TX_AGG_CNT0_AGG_SIZE_1_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT0_AGG_SIZE_2_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT1: + */ +#define TX_AGG_CNT1 0x1724 +#define TX_AGG_CNT1_AGG_SIZE_3_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT1_AGG_SIZE_4_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT2: + */ +#define TX_AGG_CNT2 0x1728 +#define TX_AGG_CNT2_AGG_SIZE_5_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT2_AGG_SIZE_6_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT3: + */ +#define TX_AGG_CNT3 0x172c +#define TX_AGG_CNT3_AGG_SIZE_7_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT3_AGG_SIZE_8_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT4: + */ +#define TX_AGG_CNT4 0x1730 +#define TX_AGG_CNT4_AGG_SIZE_9_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT4_AGG_SIZE_10_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT5: + */ +#define TX_AGG_CNT5 0x1734 +#define TX_AGG_CNT5_AGG_SIZE_11_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT5_AGG_SIZE_12_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT6: + */ +#define TX_AGG_CNT6 0x1738 +#define TX_AGG_CNT6_AGG_SIZE_13_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT6_AGG_SIZE_14_COUNT FIELD32(0xffff0000) + +/* + * TX_AGG_CNT7: + */ +#define TX_AGG_CNT7 0x173c +#define TX_AGG_CNT7_AGG_SIZE_15_COUNT FIELD32(0x0000ffff) +#define TX_AGG_CNT7_AGG_SIZE_16_COUNT FIELD32(0xffff0000) + +/* + * MPDU_DENSITY_CNT: + * TX_ZERO_DEL: TX zero length delimiter count + * RX_ZERO_DEL: RX zero length delimiter count + */ +#define MPDU_DENSITY_CNT 0x1740 +#define MPDU_DENSITY_CNT_TX_ZERO_DEL FIELD32(0x0000ffff) +#define MPDU_DENSITY_CNT_RX_ZERO_DEL FIELD32(0xffff0000) + +/* + * Security key table memory. + * MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry + * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry + * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry + * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry + * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry + * SHARED_KEY_MODE_BASE: 4 bits * 32-entry + */ +#define MAC_WCID_BASE 0x1800 +#define PAIRWISE_KEY_TABLE_BASE 0x4000 +#define MAC_IVEIV_TABLE_BASE 0x6000 +#define MAC_WCID_ATTRIBUTE_BASE 0x6800 +#define SHARED_KEY_TABLE_BASE 0x6c00 +#define SHARED_KEY_MODE_BASE 0x7000 + +#define MAC_WCID_ENTRY(__idx) \ + ( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) ) +#define PAIRWISE_KEY_ENTRY(__idx) \ + ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) +#define MAC_IVEIV_ENTRY(__idx) \ + ( MAC_IVEIV_TABLE_BASE + ((__idx) & sizeof(struct mac_iveiv_entry)) ) +#define MAC_WCID_ATTR_ENTRY(__idx) \ + ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) ) +#define SHARED_KEY_ENTRY(__idx) \ + ( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) +#define SHARED_KEY_MODE_ENTRY(__idx) \ + ( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) ) + +struct mac_wcid_entry { + u8 mac[6]; + u8 reserved[2]; +} __attribute__ ((packed)); + +struct hw_key_entry { + u8 key[16]; + u8 tx_mic[8]; + u8 rx_mic[8]; +} __attribute__ ((packed)); + +struct mac_iveiv_entry { + u8 iv[8]; +} __attribute__ ((packed)); + +/* + * MAC_WCID_ATTRIBUTE: + */ +#define MAC_WCID_ATTRIBUTE_KEYTAB FIELD32(0x00000001) +#define MAC_WCID_ATTRIBUTE_CIPHER FIELD32(0x0000000e) +#define MAC_WCID_ATTRIBUTE_BSS_IDX FIELD32(0x00000070) +#define MAC_WCID_ATTRIBUTE_RX_WIUDF FIELD32(0x00000380) + +/* + * SHARED_KEY_MODE: + */ +#define SHARED_KEY_MODE_BSS0_KEY0 FIELD32(0x00000007) +#define SHARED_KEY_MODE_BSS0_KEY1 FIELD32(0x00000070) +#define SHARED_KEY_MODE_BSS0_KEY2 FIELD32(0x00000700) +#define SHARED_KEY_MODE_BSS0_KEY3 FIELD32(0x00007000) +#define SHARED_KEY_MODE_BSS1_KEY0 FIELD32(0x00070000) +#define SHARED_KEY_MODE_BSS1_KEY1 FIELD32(0x00700000) +#define SHARED_KEY_MODE_BSS1_KEY2 FIELD32(0x07000000) +#define SHARED_KEY_MODE_BSS1_KEY3 FIELD32(0x70000000) + +/* + * HOST-MCU communication + */ + +/* + * H2M_MAILBOX_CSR: Host-to-MCU Mailbox. + */ +#define H2M_MAILBOX_CSR 0x7010 +#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff) +#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00) +#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000) +#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000) + +/* + * H2M_MAILBOX_CID: + */ +#define H2M_MAILBOX_CID 0x7014 +#define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff) +#define H2M_MAILBOX_CID_CMD1 FIELD32(0x0000ff00) +#define H2M_MAILBOX_CID_CMD2 FIELD32(0x00ff0000) +#define H2M_MAILBOX_CID_CMD3 FIELD32(0xff000000) + +/* + * H2M_MAILBOX_STATUS: + */ +#define H2M_MAILBOX_STATUS 0x701c + +/* + * H2M_INT_SRC: + */ +#define H2M_INT_SRC 0x7024 + +/* + * H2M_BBP_AGENT: + */ +#define H2M_BBP_AGENT 0x7028 + +/* + * MCU_LEDCS: LED control for MCU Mailbox. + */ +#define MCU_LEDCS_LED_MODE FIELD8(0x1f) +#define MCU_LEDCS_POLARITY FIELD8(0x01) + +/* + * HW_CS_CTS_BASE: + * Carrier-sense CTS frame base address. + * It's where mac stores carrier-sense frame for carrier-sense function. + */ +#define HW_CS_CTS_BASE 0x7700 + +/* + * HW_DFS_CTS_BASE: + * FS CTS frame base address. It's where mac stores CTS frame for DFS. + */ +#define HW_DFS_CTS_BASE 0x7780 + +/* + * TXRX control registers - base address 0x3000 + */ + +/* + * TXRX_CSR1: + * rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first.. + */ +#define TXRX_CSR1 0x77d0 + +/* + * HW_DEBUG_SETTING_BASE: + * since NULL frame won't be that long (256 byte) + * We steal 16 tail bytes to save debugging settings + */ +#define HW_DEBUG_SETTING_BASE 0x77f0 +#define HW_DEBUG_SETTING_BASE2 0x7770 + +/* + * HW_BEACON_BASE + * In order to support maximum 8 MBSS and its maximum length + * is 512 bytes for each beacon + * Three section discontinue memory segments will be used. + * 1. The original region for BCN 0~3 + * 2. Extract memory from FCE table for BCN 4~5 + * 3. Extract memory from Pair-wise key table for BCN 6~7 + * It occupied those memory of wcid 238~253 for BCN 6 + * and wcid 222~237 for BCN 7 + * + * IMPORTANT NOTE: Not sure why legacy driver does this, + * but HW_BEACON_BASE7 is 0x0200 bytes below HW_BEACON_BASE6. + */ +#define HW_BEACON_BASE0 0x7800 +#define HW_BEACON_BASE1 0x7a00 +#define HW_BEACON_BASE2 0x7c00 +#define HW_BEACON_BASE3 0x7e00 +#define HW_BEACON_BASE4 0x7200 +#define HW_BEACON_BASE5 0x7400 +#define HW_BEACON_BASE6 0x5dc0 +#define HW_BEACON_BASE7 0x5bc0 + +#define HW_BEACON_OFFSET(__index) \ + ( ((__index) < 4) ? ( HW_BEACON_BASE0 + (__index * 0x0200) ) : \ + (((__index) < 6) ? ( HW_BEACON_BASE4 + ((__index - 4) * 0x0200) ) : \ + (HW_BEACON_BASE6 - ((__index - 6) * 0x0200))) ) + +/* + * BBP registers. + * The wordsize of the BBP is 8 bits. + */ + +/* + * BBP 1: TX Antenna + */ +#define BBP1_TX_POWER FIELD8(0x07) +#define BBP1_TX_ANTENNA FIELD8(0x18) + +/* + * BBP 3: RX Antenna + */ +#define BBP3_RX_ANTENNA FIELD8(0x18) +#define BBP3_HT40_PLUS FIELD8(0x20) + +/* + * BBP 4: Bandwidth + */ +#define BBP4_TX_BF FIELD8(0x01) +#define BBP4_BANDWIDTH FIELD8(0x18) + +/* + * RFCSR registers + * The wordsize of the RFCSR is 8 bits. + */ + +/* + * RFCSR 6: + */ +#define RFCSR6_R FIELD8(0x03) + +/* + * RFCSR 7: + */ +#define RFCSR7_RF_TUNING FIELD8(0x01) + +/* + * RFCSR 12: + */ +#define RFCSR12_TX_POWER FIELD8(0x1f) + +/* + * RFCSR 22: + */ +#define RFCSR22_BASEBAND_LOOPBACK FIELD8(0x01) + +/* + * RFCSR 23: + */ +#define RFCSR23_FREQ_OFFSET FIELD8(0x7f) + +/* + * RFCSR 30: + */ +#define RFCSR30_RF_CALIBRATION FIELD8(0x80) + +/* + * RF registers + */ + +/* + * RF 2 + */ +#define RF2_ANTENNA_RX2 FIELD32(0x00000040) +#define RF2_ANTENNA_TX1 FIELD32(0x00004000) +#define RF2_ANTENNA_RX1 FIELD32(0x00020000) + +/* + * RF 3 + */ +#define RF3_TXPOWER_G FIELD32(0x00003e00) +#define RF3_TXPOWER_A_7DBM_BOOST FIELD32(0x00000200) +#define RF3_TXPOWER_A FIELD32(0x00003c00) + +/* + * RF 4 + */ +#define RF4_TXPOWER_G FIELD32(0x000007c0) +#define RF4_TXPOWER_A_7DBM_BOOST FIELD32(0x00000040) +#define RF4_TXPOWER_A FIELD32(0x00000780) +#define RF4_FREQ_OFFSET FIELD32(0x001f8000) +#define RF4_HT40 FIELD32(0x00200000) + +/* + * EEPROM content. + * The wordsize of the EEPROM is 16 bits. + */ + +/* + * EEPROM Version + */ +#define EEPROM_VERSION 0x0001 +#define EEPROM_VERSION_FAE FIELD16(0x00ff) +#define EEPROM_VERSION_VERSION FIELD16(0xff00) + +/* + * HW MAC address. + */ +#define EEPROM_MAC_ADDR_0 0x0002 +#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_1 0x0003 +#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) +#define EEPROM_MAC_ADDR_2 0x0004 +#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) +#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) + +/* + * EEPROM ANTENNA config + * RXPATH: 1: 1R, 2: 2R, 3: 3R + * TXPATH: 1: 1T, 2: 2T + */ +#define EEPROM_ANTENNA 0x001a +#define EEPROM_ANTENNA_RXPATH FIELD16(0x000f) +#define EEPROM_ANTENNA_TXPATH FIELD16(0x00f0) +#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0f00) + +/* + * EEPROM NIC config + * CARDBUS_ACCEL: 0 - enable, 1 - disable + */ +#define EEPROM_NIC 0x001b +#define EEPROM_NIC_HW_RADIO FIELD16(0x0001) +#define EEPROM_NIC_DYNAMIC_TX_AGC FIELD16(0x0002) +#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0004) +#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0008) +#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0010) +#define EEPROM_NIC_BW40M_SB_BG FIELD16(0x0020) +#define EEPROM_NIC_BW40M_SB_A FIELD16(0x0040) +#define EEPROM_NIC_WPS_PBC FIELD16(0x0080) +#define EEPROM_NIC_BW40M_BG FIELD16(0x0100) +#define EEPROM_NIC_BW40M_A FIELD16(0x0200) + +/* + * EEPROM frequency + */ +#define EEPROM_FREQ 0x001d +#define EEPROM_FREQ_OFFSET FIELD16(0x00ff) +#define EEPROM_FREQ_LED_MODE FIELD16(0x7f00) +#define EEPROM_FREQ_LED_POLARITY FIELD16(0x1000) + +/* + * EEPROM LED + * POLARITY_RDY_G: Polarity RDY_G setting. + * POLARITY_RDY_A: Polarity RDY_A setting. + * POLARITY_ACT: Polarity ACT setting. + * POLARITY_GPIO_0: Polarity GPIO0 setting. + * POLARITY_GPIO_1: Polarity GPIO1 setting. + * POLARITY_GPIO_2: Polarity GPIO2 setting. + * POLARITY_GPIO_3: Polarity GPIO3 setting. + * POLARITY_GPIO_4: Polarity GPIO4 setting. + * LED_MODE: Led mode. + */ +#define EEPROM_LED1 0x001e +#define EEPROM_LED2 0x001f +#define EEPROM_LED3 0x0020 +#define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001) +#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002) +#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004) +#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008) +#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010) +#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020) +#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040) +#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080) +#define EEPROM_LED_LED_MODE FIELD16(0x1f00) + +/* + * EEPROM LNA + */ +#define EEPROM_LNA 0x0022 +#define EEPROM_LNA_BG FIELD16(0x00ff) +#define EEPROM_LNA_A0 FIELD16(0xff00) + +/* + * EEPROM RSSI BG offset + */ +#define EEPROM_RSSI_BG 0x0023 +#define EEPROM_RSSI_BG_OFFSET0 FIELD16(0x00ff) +#define EEPROM_RSSI_BG_OFFSET1 FIELD16(0xff00) + +/* + * EEPROM RSSI BG2 offset + */ +#define EEPROM_RSSI_BG2 0x0024 +#define EEPROM_RSSI_BG2_OFFSET2 FIELD16(0x00ff) +#define EEPROM_RSSI_BG2_LNA_A1 FIELD16(0xff00) + +/* + * EEPROM RSSI A offset + */ +#define EEPROM_RSSI_A 0x0025 +#define EEPROM_RSSI_A_OFFSET0 FIELD16(0x00ff) +#define EEPROM_RSSI_A_OFFSET1 FIELD16(0xff00) + +/* + * EEPROM RSSI A2 offset + */ +#define EEPROM_RSSI_A2 0x0026 +#define EEPROM_RSSI_A2_OFFSET2 FIELD16(0x00ff) +#define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00) + +/* + * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power. + * This is delta in 40MHZ. + * VALUE: Tx Power dalta value (MAX=4) + * TYPE: 1: Plus the delta value, 0: minus the delta value + * TXPOWER: Enable: + */ +#define EEPROM_TXPOWER_DELTA 0x0028 +#define EEPROM_TXPOWER_DELTA_VALUE FIELD16(0x003f) +#define EEPROM_TXPOWER_DELTA_TYPE FIELD16(0x0040) +#define EEPROM_TXPOWER_DELTA_TXPOWER FIELD16(0x0080) + +/* + * EEPROM TXPOWER 802.11BG + */ +#define EEPROM_TXPOWER_BG1 0x0029 +#define EEPROM_TXPOWER_BG2 0x0030 +#define EEPROM_TXPOWER_BG_SIZE 7 +#define EEPROM_TXPOWER_BG_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) + +/* + * EEPROM TXPOWER 802.11A + */ +#define EEPROM_TXPOWER_A1 0x003c +#define EEPROM_TXPOWER_A2 0x0053 +#define EEPROM_TXPOWER_A_SIZE 6 +#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) +#define EEPROM_TXPOWER_A_2 FIELD16(0xff00) + +/* + * EEPROM TXpower byrate: 20MHZ power + */ +#define EEPROM_TXPOWER_BYRATE 0x006f + +/* + * EEPROM BBP. + */ +#define EEPROM_BBP_START 0x0078 +#define EEPROM_BBP_SIZE 16 +#define EEPROM_BBP_VALUE FIELD16(0x00ff) +#define EEPROM_BBP_REG_ID FIELD16(0xff00) + +/* + * MCU mailbox commands. + */ +#define MCU_SLEEP 0x30 +#define MCU_WAKEUP 0x31 +#define MCU_RADIO_OFF 0x35 +#define MCU_CURRENT 0x36 +#define MCU_LED 0x50 +#define MCU_LED_STRENGTH 0x51 +#define MCU_LED_1 0x52 +#define MCU_LED_2 0x53 +#define MCU_LED_3 0x54 +#define MCU_RADAR 0x60 +#define MCU_BOOT_SIGNAL 0x72 +#define MCU_BBP_SIGNAL 0x80 +#define MCU_POWER_SAVE 0x83 + +/* + * MCU mailbox tokens + */ +#define TOKEN_WAKUP 3 + +/* + * DMA descriptor defines. + */ +#define TXWI_DESC_SIZE ( 4 * sizeof(__le32) ) +#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) ) + +/* + * TX WI structure + */ + +/* + * Word0 + * FRAG: 1 To inform TKIP engine this is a fragment. + * MIMO_PS: The remote peer is in dynamic MIMO-PS mode + * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs + * BW: Channel bandwidth 20MHz or 40 MHz + * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED + */ +#define TXWI_W0_FRAG FIELD32(0x00000001) +#define TXWI_W0_MIMO_PS FIELD32(0x00000002) +#define TXWI_W0_CF_ACK FIELD32(0x00000004) +#define TXWI_W0_TS FIELD32(0x00000008) +#define TXWI_W0_AMPDU FIELD32(0x00000010) +#define TXWI_W0_MPDU_DENSITY FIELD32(0x000000e0) +#define TXWI_W0_TX_OP FIELD32(0x00000300) +#define TXWI_W0_MCS FIELD32(0x007f0000) +#define TXWI_W0_BW FIELD32(0x00800000) +#define TXWI_W0_SHORT_GI FIELD32(0x01000000) +#define TXWI_W0_STBC FIELD32(0x06000000) +#define TXWI_W0_IFS FIELD32(0x08000000) +#define TXWI_W0_PHYMODE FIELD32(0xc0000000) + +/* + * Word1 + */ +#define TXWI_W1_ACK FIELD32(0x00000001) +#define TXWI_W1_NSEQ FIELD32(0x00000002) +#define TXWI_W1_BW_WIN_SIZE FIELD32(0x000000fc) +#define TXWI_W1_WIRELESS_CLI_ID FIELD32(0x0000ff00) +#define TXWI_W1_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) +#define TXWI_W1_PACKETID FIELD32(0xf0000000) + +/* + * Word2 + */ +#define TXWI_W2_IV FIELD32(0xffffffff) + +/* + * Word3 + */ +#define TXWI_W3_EIV FIELD32(0xffffffff) + +/* + * RX WI structure + */ + +/* + * Word0 + */ +#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff) +#define RXWI_W0_KEY_INDEX FIELD32(0x00000300) +#define RXWI_W0_BSSID FIELD32(0x00001c00) +#define RXWI_W0_UDF FIELD32(0x0000e000) +#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) +#define RXWI_W0_TID FIELD32(0xf0000000) + +/* + * Word1 + */ +#define RXWI_W1_FRAG FIELD32(0x0000000f) +#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0) +#define RXWI_W1_MCS FIELD32(0x007f0000) +#define RXWI_W1_BW FIELD32(0x00800000) +#define RXWI_W1_SHORT_GI FIELD32(0x01000000) +#define RXWI_W1_STBC FIELD32(0x06000000) +#define RXWI_W1_PHYMODE FIELD32(0xc0000000) + +/* + * Word2 + */ +#define RXWI_W2_RSSI0 FIELD32(0x000000ff) +#define RXWI_W2_RSSI1 FIELD32(0x0000ff00) +#define RXWI_W2_RSSI2 FIELD32(0x00ff0000) + +/* + * Word3 + */ +#define RXWI_W3_SNR0 FIELD32(0x000000ff) +#define RXWI_W3_SNR1 FIELD32(0x0000ff00) + +/* + * Macros for converting txpower from EEPROM to mac80211 value + * and from mac80211 value to register value. + */ +#define MIN_G_TXPOWER 0 +#define MIN_A_TXPOWER -7 +#define MAX_G_TXPOWER 31 +#define MAX_A_TXPOWER 15 +#define DEFAULT_TXPOWER 5 + +#define TXPOWER_G_FROM_DEV(__txpower) \ + ((__txpower) > MAX_G_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_G_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_G_TXPOWER, MAX_G_TXPOWER) + +#define TXPOWER_A_FROM_DEV(__txpower) \ + ((__txpower) > MAX_A_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) + +#define TXPOWER_A_TO_DEV(__txpower) \ + clamp_t(char, __txpower, MIN_A_TXPOWER, MAX_A_TXPOWER) + +#endif /* RT2800_H */ diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 9017ea64d011..cae772ea5686 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -38,6 +38,7 @@ #include "rt2x00pci.h" #include "rt2x00soc.h" #include "rt2800lib.h" +#include "rt2800.h" #include "rt2800pci.h" #ifdef CONFIG_RT2800PCI_PCI_MODULE diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index 856908815221..1dbf13270cda 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -28,1463 +28,60 @@ #define RT2800PCI_H /* - * RF chip defines. - * - * RF2820 2.4G 2T3R - * RF2850 2.4G/5G 2T3R - * RF2720 2.4G 1T2R - * RF2750 2.4G/5G 1T2R - * RF3020 2.4G 1T1R - * RF2020 2.4G B/G - * RF3021 2.4G 1T2R - * RF3022 2.4G 2T2R - * RF3052 2.4G 2T2R - */ -#define RF2820 0x0001 -#define RF2850 0x0002 -#define RF2720 0x0003 -#define RF2750 0x0004 -#define RF3020 0x0005 -#define RF2020 0x0006 -#define RF3021 0x0007 -#define RF3022 0x0008 -#define RF3052 0x0009 - -/* - * RT2860 version - */ -#define RT2860C_VERSION 0x28600100 -#define RT2860D_VERSION 0x28600101 -#define RT2880E_VERSION 0x28720200 -#define RT2883_VERSION 0x28830300 -#define RT3070_VERSION 0x30700200 - -/* - * Signal information. - * Default offset is required for RSSI <-> dBm conversion. - */ -#define DEFAULT_RSSI_OFFSET 120 /* FIXME */ - -/* - * Register layout information. - */ -#define CSR_REG_BASE 0x1000 -#define CSR_REG_SIZE 0x0800 -#define EEPROM_BASE 0x0000 -#define EEPROM_SIZE 0x0110 -#define BBP_BASE 0x0000 -#define BBP_SIZE 0x0080 -#define RF_BASE 0x0004 -#define RF_SIZE 0x0010 - -/* - * Number of TX queues. - */ -#define NUM_TX_QUEUES 4 - -/* - * PCI registers. - */ - -/* - * E2PROM_CSR: EEPROM control register. - * RELOAD: Write 1 to reload eeprom content. - * TYPE: 0: 93c46, 1:93c66. - * LOAD_STATUS: 1:loading, 0:done. - */ -#define E2PROM_CSR 0x0004 -#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000001) -#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000002) -#define E2PROM_CSR_DATA_IN FIELD32(0x00000004) -#define E2PROM_CSR_DATA_OUT FIELD32(0x00000008) -#define E2PROM_CSR_TYPE FIELD32(0x00000030) -#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040) -#define E2PROM_CSR_RELOAD FIELD32(0x00000080) - -/* - * INT_SOURCE_CSR: Interrupt source register. - * Write one to clear corresponding bit. - * TX_FIFO_STATUS: FIFO Statistics is full, sw should read 0x171c - */ -#define INT_SOURCE_CSR 0x0200 -#define INT_SOURCE_CSR_RXDELAYINT FIELD32(0x00000001) -#define INT_SOURCE_CSR_TXDELAYINT FIELD32(0x00000002) -#define INT_SOURCE_CSR_RX_DONE FIELD32(0x00000004) -#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00000008) -#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00000010) -#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00000020) -#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00000040) -#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00000080) -#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00000100) -#define INT_SOURCE_CSR_MCU_COMMAND FIELD32(0x00000200) -#define INT_SOURCE_CSR_RXTX_COHERENT FIELD32(0x00000400) -#define INT_SOURCE_CSR_TBTT FIELD32(0x00000800) -#define INT_SOURCE_CSR_PRE_TBTT FIELD32(0x00001000) -#define INT_SOURCE_CSR_TX_FIFO_STATUS FIELD32(0x00002000) -#define INT_SOURCE_CSR_AUTO_WAKEUP FIELD32(0x00004000) -#define INT_SOURCE_CSR_GPTIMER FIELD32(0x00008000) -#define INT_SOURCE_CSR_RX_COHERENT FIELD32(0x00010000) -#define INT_SOURCE_CSR_TX_COHERENT FIELD32(0x00020000) - -/* - * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF. - */ -#define INT_MASK_CSR 0x0204 -#define INT_MASK_CSR_RXDELAYINT FIELD32(0x00000001) -#define INT_MASK_CSR_TXDELAYINT FIELD32(0x00000002) -#define INT_MASK_CSR_RX_DONE FIELD32(0x00000004) -#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00000008) -#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00000010) -#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00000020) -#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00000040) -#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00000080) -#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00000100) -#define INT_MASK_CSR_MCU_COMMAND FIELD32(0x00000200) -#define INT_MASK_CSR_RXTX_COHERENT FIELD32(0x00000400) -#define INT_MASK_CSR_TBTT FIELD32(0x00000800) -#define INT_MASK_CSR_PRE_TBTT FIELD32(0x00001000) -#define INT_MASK_CSR_TX_FIFO_STATUS FIELD32(0x00002000) -#define INT_MASK_CSR_AUTO_WAKEUP FIELD32(0x00004000) -#define INT_MASK_CSR_GPTIMER FIELD32(0x00008000) -#define INT_MASK_CSR_RX_COHERENT FIELD32(0x00010000) -#define INT_MASK_CSR_TX_COHERENT FIELD32(0x00020000) - -/* - * WPDMA_GLO_CFG - */ -#define WPDMA_GLO_CFG 0x0208 -#define WPDMA_GLO_CFG_ENABLE_TX_DMA FIELD32(0x00000001) -#define WPDMA_GLO_CFG_TX_DMA_BUSY FIELD32(0x00000002) -#define WPDMA_GLO_CFG_ENABLE_RX_DMA FIELD32(0x00000004) -#define WPDMA_GLO_CFG_RX_DMA_BUSY FIELD32(0x00000008) -#define WPDMA_GLO_CFG_WP_DMA_BURST_SIZE FIELD32(0x00000030) -#define WPDMA_GLO_CFG_TX_WRITEBACK_DONE FIELD32(0x00000040) -#define WPDMA_GLO_CFG_BIG_ENDIAN FIELD32(0x00000080) -#define WPDMA_GLO_CFG_RX_HDR_SCATTER FIELD32(0x0000ff00) -#define WPDMA_GLO_CFG_HDR_SEG_LEN FIELD32(0xffff0000) - -/* - * WPDMA_RST_IDX - */ -#define WPDMA_RST_IDX 0x020c -#define WPDMA_RST_IDX_DTX_IDX0 FIELD32(0x00000001) -#define WPDMA_RST_IDX_DTX_IDX1 FIELD32(0x00000002) -#define WPDMA_RST_IDX_DTX_IDX2 FIELD32(0x00000004) -#define WPDMA_RST_IDX_DTX_IDX3 FIELD32(0x00000008) -#define WPDMA_RST_IDX_DTX_IDX4 FIELD32(0x00000010) -#define WPDMA_RST_IDX_DTX_IDX5 FIELD32(0x00000020) -#define WPDMA_RST_IDX_DRX_IDX0 FIELD32(0x00010000) - -/* - * DELAY_INT_CFG - */ -#define DELAY_INT_CFG 0x0210 -#define DELAY_INT_CFG_RXMAX_PTIME FIELD32(0x000000ff) -#define DELAY_INT_CFG_RXMAX_PINT FIELD32(0x00007f00) -#define DELAY_INT_CFG_RXDLY_INT_EN FIELD32(0x00008000) -#define DELAY_INT_CFG_TXMAX_PTIME FIELD32(0x00ff0000) -#define DELAY_INT_CFG_TXMAX_PINT FIELD32(0x7f000000) -#define DELAY_INT_CFG_TXDLY_INT_EN FIELD32(0x80000000) - -/* - * WMM_AIFSN_CFG: Aifsn for each EDCA AC - * AIFSN0: AC_BE - * AIFSN1: AC_BK - * AIFSN1: AC_VI - * AIFSN1: AC_VO - */ -#define WMM_AIFSN_CFG 0x0214 -#define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f) -#define WMM_AIFSN_CFG_AIFSN1 FIELD32(0x000000f0) -#define WMM_AIFSN_CFG_AIFSN2 FIELD32(0x00000f00) -#define WMM_AIFSN_CFG_AIFSN3 FIELD32(0x0000f000) - -/* - * WMM_CWMIN_CSR: CWmin for each EDCA AC - * CWMIN0: AC_BE - * CWMIN1: AC_BK - * CWMIN1: AC_VI - * CWMIN1: AC_VO - */ -#define WMM_CWMIN_CFG 0x0218 -#define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f) -#define WMM_CWMIN_CFG_CWMIN1 FIELD32(0x000000f0) -#define WMM_CWMIN_CFG_CWMIN2 FIELD32(0x00000f00) -#define WMM_CWMIN_CFG_CWMIN3 FIELD32(0x0000f000) - -/* - * WMM_CWMAX_CSR: CWmax for each EDCA AC - * CWMAX0: AC_BE - * CWMAX1: AC_BK - * CWMAX1: AC_VI - * CWMAX1: AC_VO - */ -#define WMM_CWMAX_CFG 0x021c -#define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f) -#define WMM_CWMAX_CFG_CWMAX1 FIELD32(0x000000f0) -#define WMM_CWMAX_CFG_CWMAX2 FIELD32(0x00000f00) -#define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000) - -/* - * AC_TXOP0: AC_BK/AC_BE TXOP register - * AC0TXOP: AC_BK in unit of 32us - * AC1TXOP: AC_BE in unit of 32us - */ -#define WMM_TXOP0_CFG 0x0220 -#define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff) -#define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000) - -/* - * AC_TXOP1: AC_VO/AC_VI TXOP register - * AC2TXOP: AC_VI in unit of 32us - * AC3TXOP: AC_VO in unit of 32us - */ -#define WMM_TXOP1_CFG 0x0224 -#define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff) -#define WMM_TXOP1_CFG_AC3TXOP FIELD32(0xffff0000) - -/* - * GPIO_CTRL_CFG: - */ -#define GPIO_CTRL_CFG 0x0228 -#define GPIO_CTRL_CFG_BIT0 FIELD32(0x00000001) -#define GPIO_CTRL_CFG_BIT1 FIELD32(0x00000002) -#define GPIO_CTRL_CFG_BIT2 FIELD32(0x00000004) -#define GPIO_CTRL_CFG_BIT3 FIELD32(0x00000008) -#define GPIO_CTRL_CFG_BIT4 FIELD32(0x00000010) -#define GPIO_CTRL_CFG_BIT5 FIELD32(0x00000020) -#define GPIO_CTRL_CFG_BIT6 FIELD32(0x00000040) -#define GPIO_CTRL_CFG_BIT7 FIELD32(0x00000080) -#define GPIO_CTRL_CFG_BIT8 FIELD32(0x00000100) - -/* - * MCU_CMD_CFG - */ -#define MCU_CMD_CFG 0x022c - -/* - * AC_BK register offsets - */ -#define TX_BASE_PTR0 0x0230 -#define TX_MAX_CNT0 0x0234 -#define TX_CTX_IDX0 0x0238 -#define TX_DTX_IDX0 0x023c - -/* - * AC_BE register offsets - */ -#define TX_BASE_PTR1 0x0240 -#define TX_MAX_CNT1 0x0244 -#define TX_CTX_IDX1 0x0248 -#define TX_DTX_IDX1 0x024c - -/* - * AC_VI register offsets - */ -#define TX_BASE_PTR2 0x0250 -#define TX_MAX_CNT2 0x0254 -#define TX_CTX_IDX2 0x0258 -#define TX_DTX_IDX2 0x025c - -/* - * AC_VO register offsets - */ -#define TX_BASE_PTR3 0x0260 -#define TX_MAX_CNT3 0x0264 -#define TX_CTX_IDX3 0x0268 -#define TX_DTX_IDX3 0x026c - -/* - * HCCA register offsets - */ -#define TX_BASE_PTR4 0x0270 -#define TX_MAX_CNT4 0x0274 -#define TX_CTX_IDX4 0x0278 -#define TX_DTX_IDX4 0x027c - -/* - * MGMT register offsets - */ -#define TX_BASE_PTR5 0x0280 -#define TX_MAX_CNT5 0x0284 -#define TX_CTX_IDX5 0x0288 -#define TX_DTX_IDX5 0x028c - -/* - * Queue register offset macros - */ -#define TX_QUEUE_REG_OFFSET 0x10 -#define TX_BASE_PTR(__x) TX_BASE_PTR0 + ((__x) * TX_QUEUE_REG_OFFSET) -#define TX_MAX_CNT(__x) TX_MAX_CNT0 + ((__x) * TX_QUEUE_REG_OFFSET) -#define TX_CTX_IDX(__x) TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) -#define TX_DTX_IDX(__x) TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) - -/* - * RX register offsets - */ -#define RX_BASE_PTR 0x0290 -#define RX_MAX_CNT 0x0294 -#define RX_CRX_IDX 0x0298 -#define RX_DRX_IDX 0x029c - -/* - * PBF_SYS_CTRL - * HOST_RAM_WRITE: enable Host program ram write selection - */ -#define PBF_SYS_CTRL 0x0400 -#define PBF_SYS_CTRL_READY FIELD32(0x00000080) -#define PBF_SYS_CTRL_HOST_RAM_WRITE FIELD32(0x00010000) - -/* - * HOST-MCU shared memory - */ -#define HOST_CMD_CSR 0x0404 -#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x000000ff) - -/* - * PBF registers - * Most are for debug. Driver doesn't touch PBF register. - */ -#define PBF_CFG 0x0408 -#define PBF_MAX_PCNT 0x040c -#define PBF_CTRL 0x0410 -#define PBF_INT_STA 0x0414 -#define PBF_INT_ENA 0x0418 - -/* - * BCN_OFFSET0: - */ -#define BCN_OFFSET0 0x042c -#define BCN_OFFSET0_BCN0 FIELD32(0x000000ff) -#define BCN_OFFSET0_BCN1 FIELD32(0x0000ff00) -#define BCN_OFFSET0_BCN2 FIELD32(0x00ff0000) -#define BCN_OFFSET0_BCN3 FIELD32(0xff000000) - -/* - * BCN_OFFSET1: - */ -#define BCN_OFFSET1 0x0430 -#define BCN_OFFSET1_BCN4 FIELD32(0x000000ff) -#define BCN_OFFSET1_BCN5 FIELD32(0x0000ff00) -#define BCN_OFFSET1_BCN6 FIELD32(0x00ff0000) -#define BCN_OFFSET1_BCN7 FIELD32(0xff000000) - -/* - * PBF registers - * Most are for debug. Driver doesn't touch PBF register. - */ -#define TXRXQ_PCNT 0x0438 -#define PBF_DBG 0x043c - -/* - * RF registers - */ -#define RF_CSR_CFG 0x0500 -#define RF_CSR_CFG_DATA FIELD32(0x000000ff) -#define RF_CSR_CFG_REGNUM FIELD32(0x00001f00) -#define RF_CSR_CFG_WRITE FIELD32(0x00010000) -#define RF_CSR_CFG_BUSY FIELD32(0x00020000) - -/* - * EFUSE_CSR: RT3090 EEPROM - */ -#define EFUSE_CTRL 0x0580 -#define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000) -#define EFUSE_CTRL_MODE FIELD32(0x000000c0) -#define EFUSE_CTRL_KICK FIELD32(0x40000000) - -/* - * EFUSE_DATA0 - */ -#define EFUSE_DATA0 0x0590 - -/* - * EFUSE_DATA1 - */ -#define EFUSE_DATA1 0x0594 - -/* - * EFUSE_DATA2 - */ -#define EFUSE_DATA2 0x0598 - -/* - * EFUSE_DATA3 - */ -#define EFUSE_DATA3 0x059c - -/* - * MAC Control/Status Registers(CSR). - * Some values are set in TU, whereas 1 TU == 1024 us. - */ - -/* - * MAC_CSR0: ASIC revision number. - * ASIC_REV: 0 - * ASIC_VER: 2860 - */ -#define MAC_CSR0 0x1000 -#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff) -#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000) - -/* - * MAC_SYS_CTRL: - */ -#define MAC_SYS_CTRL 0x1004 -#define MAC_SYS_CTRL_RESET_CSR FIELD32(0x00000001) -#define MAC_SYS_CTRL_RESET_BBP FIELD32(0x00000002) -#define MAC_SYS_CTRL_ENABLE_TX FIELD32(0x00000004) -#define MAC_SYS_CTRL_ENABLE_RX FIELD32(0x00000008) -#define MAC_SYS_CTRL_CONTINUOUS_TX FIELD32(0x00000010) -#define MAC_SYS_CTRL_LOOPBACK FIELD32(0x00000020) -#define MAC_SYS_CTRL_WLAN_HALT FIELD32(0x00000040) -#define MAC_SYS_CTRL_RX_TIMESTAMP FIELD32(0x00000080) - -/* - * MAC_ADDR_DW0: STA MAC register 0 - */ -#define MAC_ADDR_DW0 0x1008 -#define MAC_ADDR_DW0_BYTE0 FIELD32(0x000000ff) -#define MAC_ADDR_DW0_BYTE1 FIELD32(0x0000ff00) -#define MAC_ADDR_DW0_BYTE2 FIELD32(0x00ff0000) -#define MAC_ADDR_DW0_BYTE3 FIELD32(0xff000000) - -/* - * MAC_ADDR_DW1: STA MAC register 1 - * UNICAST_TO_ME_MASK: - * Used to mask off bits from byte 5 of the MAC address - * to determine the UNICAST_TO_ME bit for RX frames. - * The full mask is complemented by BSS_ID_MASK: - * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK - */ -#define MAC_ADDR_DW1 0x100c -#define MAC_ADDR_DW1_BYTE4 FIELD32(0x000000ff) -#define MAC_ADDR_DW1_BYTE5 FIELD32(0x0000ff00) -#define MAC_ADDR_DW1_UNICAST_TO_ME_MASK FIELD32(0x00ff0000) - -/* - * MAC_BSSID_DW0: BSSID register 0 - */ -#define MAC_BSSID_DW0 0x1010 -#define MAC_BSSID_DW0_BYTE0 FIELD32(0x000000ff) -#define MAC_BSSID_DW0_BYTE1 FIELD32(0x0000ff00) -#define MAC_BSSID_DW0_BYTE2 FIELD32(0x00ff0000) -#define MAC_BSSID_DW0_BYTE3 FIELD32(0xff000000) - -/* - * MAC_BSSID_DW1: BSSID register 1 - * BSS_ID_MASK: - * 0: 1-BSSID mode (BSS index = 0) - * 1: 2-BSSID mode (BSS index: Byte5, bit 0) - * 2: 4-BSSID mode (BSS index: byte5, bit 0 - 1) - * 3: 8-BSSID mode (BSS index: byte5, bit 0 - 2) - * This mask is used to mask off bits 0, 1 and 2 of byte 5 of the - * BSSID. This will make sure that those bits will be ignored - * when determining the MY_BSS of RX frames. - */ -#define MAC_BSSID_DW1 0x1014 -#define MAC_BSSID_DW1_BYTE4 FIELD32(0x000000ff) -#define MAC_BSSID_DW1_BYTE5 FIELD32(0x0000ff00) -#define MAC_BSSID_DW1_BSS_ID_MASK FIELD32(0x00030000) -#define MAC_BSSID_DW1_BSS_BCN_NUM FIELD32(0x001c0000) - -/* - * MAX_LEN_CFG: Maximum frame length register. - * MAX_MPDU: rt2860b max 16k bytes - * MAX_PSDU: Maximum PSDU length - * (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 - */ -#define MAX_LEN_CFG 0x1018 -#define MAX_LEN_CFG_MAX_MPDU FIELD32(0x00000fff) -#define MAX_LEN_CFG_MAX_PSDU FIELD32(0x00003000) -#define MAX_LEN_CFG_MIN_PSDU FIELD32(0x0000c000) -#define MAX_LEN_CFG_MIN_MPDU FIELD32(0x000f0000) - -/* - * BBP_CSR_CFG: BBP serial control register - * VALUE: Register value to program into BBP - * REG_NUM: Selected BBP register - * READ_CONTROL: 0 write BBP, 1 read BBP - * BUSY: ASIC is busy executing BBP commands - * BBP_PAR_DUR: 0 4 MAC clocks, 1 8 MAC clocks - * BBP_RW_MODE: 0 serial, 1 paralell - */ -#define BBP_CSR_CFG 0x101c -#define BBP_CSR_CFG_VALUE FIELD32(0x000000ff) -#define BBP_CSR_CFG_REGNUM FIELD32(0x0000ff00) -#define BBP_CSR_CFG_READ_CONTROL FIELD32(0x00010000) -#define BBP_CSR_CFG_BUSY FIELD32(0x00020000) -#define BBP_CSR_CFG_BBP_PAR_DUR FIELD32(0x00040000) -#define BBP_CSR_CFG_BBP_RW_MODE FIELD32(0x00080000) - -/* - * RF_CSR_CFG0: RF control register - * REGID_AND_VALUE: Register value to program into RF - * BITWIDTH: Selected RF register - * STANDBYMODE: 0 high when standby, 1 low when standby - * SEL: 0 RF_LE0 activate, 1 RF_LE1 activate - * BUSY: ASIC is busy executing RF commands - */ -#define RF_CSR_CFG0 0x1020 -#define RF_CSR_CFG0_REGID_AND_VALUE FIELD32(0x00ffffff) -#define RF_CSR_CFG0_BITWIDTH FIELD32(0x1f000000) -#define RF_CSR_CFG0_REG_VALUE_BW FIELD32(0x1fffffff) -#define RF_CSR_CFG0_STANDBYMODE FIELD32(0x20000000) -#define RF_CSR_CFG0_SEL FIELD32(0x40000000) -#define RF_CSR_CFG0_BUSY FIELD32(0x80000000) - -/* - * RF_CSR_CFG1: RF control register - * REGID_AND_VALUE: Register value to program into RF - * RFGAP: Gap between BB_CONTROL_RF and RF_LE - * 0: 3 system clock cycle (37.5usec) - * 1: 5 system clock cycle (62.5usec) - */ -#define RF_CSR_CFG1 0x1024 -#define RF_CSR_CFG1_REGID_AND_VALUE FIELD32(0x00ffffff) -#define RF_CSR_CFG1_RFGAP FIELD32(0x1f000000) - -/* - * RF_CSR_CFG2: RF control register - * VALUE: Register value to program into RF - * RFGAP: Gap between BB_CONTROL_RF and RF_LE - * 0: 3 system clock cycle (37.5usec) - * 1: 5 system clock cycle (62.5usec) - */ -#define RF_CSR_CFG2 0x1028 -#define RF_CSR_CFG2_VALUE FIELD32(0x00ffffff) - -/* - * LED_CFG: LED control - * color LED's: - * 0: off - * 1: blinking upon TX2 - * 2: periodic slow blinking - * 3: always on - * LED polarity: - * 0: active low - * 1: active high - */ -#define LED_CFG 0x102c -#define LED_CFG_ON_PERIOD FIELD32(0x000000ff) -#define LED_CFG_OFF_PERIOD FIELD32(0x0000ff00) -#define LED_CFG_SLOW_BLINK_PERIOD FIELD32(0x003f0000) -#define LED_CFG_R_LED_MODE FIELD32(0x03000000) -#define LED_CFG_G_LED_MODE FIELD32(0x0c000000) -#define LED_CFG_Y_LED_MODE FIELD32(0x30000000) -#define LED_CFG_LED_POLAR FIELD32(0x40000000) - -/* - * XIFS_TIME_CFG: MAC timing - * CCKM_SIFS_TIME: unit 1us. Applied after CCK RX/TX - * OFDM_SIFS_TIME: unit 1us. Applied after OFDM RX/TX - * OFDM_XIFS_TIME: unit 1us. Applied after OFDM RX - * when MAC doesn't reference BBP signal BBRXEND - * EIFS: unit 1us - * BB_RXEND_ENABLE: reference RXEND signal to begin XIFS defer - * - */ -#define XIFS_TIME_CFG 0x1100 -#define XIFS_TIME_CFG_CCKM_SIFS_TIME FIELD32(0x000000ff) -#define XIFS_TIME_CFG_OFDM_SIFS_TIME FIELD32(0x0000ff00) -#define XIFS_TIME_CFG_OFDM_XIFS_TIME FIELD32(0x000f0000) -#define XIFS_TIME_CFG_EIFS FIELD32(0x1ff00000) -#define XIFS_TIME_CFG_BB_RXEND_ENABLE FIELD32(0x20000000) - -/* - * BKOFF_SLOT_CFG: - */ -#define BKOFF_SLOT_CFG 0x1104 -#define BKOFF_SLOT_CFG_SLOT_TIME FIELD32(0x000000ff) -#define BKOFF_SLOT_CFG_CC_DELAY_TIME FIELD32(0x0000ff00) - -/* - * NAV_TIME_CFG: - */ -#define NAV_TIME_CFG 0x1108 -#define NAV_TIME_CFG_SIFS FIELD32(0x000000ff) -#define NAV_TIME_CFG_SLOT_TIME FIELD32(0x0000ff00) -#define NAV_TIME_CFG_EIFS FIELD32(0x01ff0000) -#define NAV_TIME_ZERO_SIFS FIELD32(0x02000000) - -/* - * CH_TIME_CFG: count as channel busy - */ -#define CH_TIME_CFG 0x110c - -/* - * PBF_LIFE_TIMER: TX/RX MPDU timestamp timer (free run) Unit: 1us - */ -#define PBF_LIFE_TIMER 0x1110 - -/* - * BCN_TIME_CFG: - * BEACON_INTERVAL: in unit of 1/16 TU - * TSF_TICKING: Enable TSF auto counting - * TSF_SYNC: Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode - * BEACON_GEN: Enable beacon generator - */ -#define BCN_TIME_CFG 0x1114 -#define BCN_TIME_CFG_BEACON_INTERVAL FIELD32(0x0000ffff) -#define BCN_TIME_CFG_TSF_TICKING FIELD32(0x00010000) -#define BCN_TIME_CFG_TSF_SYNC FIELD32(0x00060000) -#define BCN_TIME_CFG_TBTT_ENABLE FIELD32(0x00080000) -#define BCN_TIME_CFG_BEACON_GEN FIELD32(0x00100000) -#define BCN_TIME_CFG_TX_TIME_COMPENSATE FIELD32(0xf0000000) - -/* - * TBTT_SYNC_CFG: - */ -#define TBTT_SYNC_CFG 0x1118 - -/* - * TSF_TIMER_DW0: Local lsb TSF timer, read-only - */ -#define TSF_TIMER_DW0 0x111c -#define TSF_TIMER_DW0_LOW_WORD FIELD32(0xffffffff) - -/* - * TSF_TIMER_DW1: Local msb TSF timer, read-only - */ -#define TSF_TIMER_DW1 0x1120 -#define TSF_TIMER_DW1_HIGH_WORD FIELD32(0xffffffff) - -/* - * TBTT_TIMER: TImer remains till next TBTT, read-only - */ -#define TBTT_TIMER 0x1124 - -/* - * INT_TIMER_CFG: - */ -#define INT_TIMER_CFG 0x1128 - -/* - * INT_TIMER_EN: GP-timer and pre-tbtt Int enable - */ -#define INT_TIMER_EN 0x112c - -/* - * CH_IDLE_STA: channel idle time - */ -#define CH_IDLE_STA 0x1130 - -/* - * CH_BUSY_STA: channel busy time - */ -#define CH_BUSY_STA 0x1134 - -/* - * MAC_STATUS_CFG: - * BBP_RF_BUSY: When set to 0, BBP and RF are stable. - * if 1 or higher one of the 2 registers is busy. - */ -#define MAC_STATUS_CFG 0x1200 -#define MAC_STATUS_CFG_BBP_RF_BUSY FIELD32(0x00000003) - -/* - * PWR_PIN_CFG: - */ -#define PWR_PIN_CFG 0x1204 - -/* - * AUTOWAKEUP_CFG: Manual power control / status register - * TBCN_BEFORE_WAKE: ForceWake has high privilege than PutToSleep when both set - * AUTOWAKE: 0:sleep, 1:awake - */ -#define AUTOWAKEUP_CFG 0x1208 -#define AUTOWAKEUP_CFG_AUTO_LEAD_TIME FIELD32(0x000000ff) -#define AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE FIELD32(0x00007f00) -#define AUTOWAKEUP_CFG_AUTOWAKE FIELD32(0x00008000) - -/* - * EDCA_AC0_CFG: - */ -#define EDCA_AC0_CFG 0x1300 -#define EDCA_AC0_CFG_TX_OP FIELD32(0x000000ff) -#define EDCA_AC0_CFG_AIFSN FIELD32(0x00000f00) -#define EDCA_AC0_CFG_CWMIN FIELD32(0x0000f000) -#define EDCA_AC0_CFG_CWMAX FIELD32(0x000f0000) - -/* - * EDCA_AC1_CFG: - */ -#define EDCA_AC1_CFG 0x1304 -#define EDCA_AC1_CFG_TX_OP FIELD32(0x000000ff) -#define EDCA_AC1_CFG_AIFSN FIELD32(0x00000f00) -#define EDCA_AC1_CFG_CWMIN FIELD32(0x0000f000) -#define EDCA_AC1_CFG_CWMAX FIELD32(0x000f0000) - -/* - * EDCA_AC2_CFG: - */ -#define EDCA_AC2_CFG 0x1308 -#define EDCA_AC2_CFG_TX_OP FIELD32(0x000000ff) -#define EDCA_AC2_CFG_AIFSN FIELD32(0x00000f00) -#define EDCA_AC2_CFG_CWMIN FIELD32(0x0000f000) -#define EDCA_AC2_CFG_CWMAX FIELD32(0x000f0000) - -/* - * EDCA_AC3_CFG: - */ -#define EDCA_AC3_CFG 0x130c -#define EDCA_AC3_CFG_TX_OP FIELD32(0x000000ff) -#define EDCA_AC3_CFG_AIFSN FIELD32(0x00000f00) -#define EDCA_AC3_CFG_CWMIN FIELD32(0x0000f000) -#define EDCA_AC3_CFG_CWMAX FIELD32(0x000f0000) - -/* - * EDCA_TID_AC_MAP: - */ -#define EDCA_TID_AC_MAP 0x1310 - -/* - * TX_PWR_CFG_0: - */ -#define TX_PWR_CFG_0 0x1314 -#define TX_PWR_CFG_0_1MBS FIELD32(0x0000000f) -#define TX_PWR_CFG_0_2MBS FIELD32(0x000000f0) -#define TX_PWR_CFG_0_55MBS FIELD32(0x00000f00) -#define TX_PWR_CFG_0_11MBS FIELD32(0x0000f000) -#define TX_PWR_CFG_0_6MBS FIELD32(0x000f0000) -#define TX_PWR_CFG_0_9MBS FIELD32(0x00f00000) -#define TX_PWR_CFG_0_12MBS FIELD32(0x0f000000) -#define TX_PWR_CFG_0_18MBS FIELD32(0xf0000000) - -/* - * TX_PWR_CFG_1: - */ -#define TX_PWR_CFG_1 0x1318 -#define TX_PWR_CFG_1_24MBS FIELD32(0x0000000f) -#define TX_PWR_CFG_1_36MBS FIELD32(0x000000f0) -#define TX_PWR_CFG_1_48MBS FIELD32(0x00000f00) -#define TX_PWR_CFG_1_54MBS FIELD32(0x0000f000) -#define TX_PWR_CFG_1_MCS0 FIELD32(0x000f0000) -#define TX_PWR_CFG_1_MCS1 FIELD32(0x00f00000) -#define TX_PWR_CFG_1_MCS2 FIELD32(0x0f000000) -#define TX_PWR_CFG_1_MCS3 FIELD32(0xf0000000) - -/* - * TX_PWR_CFG_2: - */ -#define TX_PWR_CFG_2 0x131c -#define TX_PWR_CFG_2_MCS4 FIELD32(0x0000000f) -#define TX_PWR_CFG_2_MCS5 FIELD32(0x000000f0) -#define TX_PWR_CFG_2_MCS6 FIELD32(0x00000f00) -#define TX_PWR_CFG_2_MCS7 FIELD32(0x0000f000) -#define TX_PWR_CFG_2_MCS8 FIELD32(0x000f0000) -#define TX_PWR_CFG_2_MCS9 FIELD32(0x00f00000) -#define TX_PWR_CFG_2_MCS10 FIELD32(0x0f000000) -#define TX_PWR_CFG_2_MCS11 FIELD32(0xf0000000) - -/* - * TX_PWR_CFG_3: - */ -#define TX_PWR_CFG_3 0x1320 -#define TX_PWR_CFG_3_MCS12 FIELD32(0x0000000f) -#define TX_PWR_CFG_3_MCS13 FIELD32(0x000000f0) -#define TX_PWR_CFG_3_MCS14 FIELD32(0x00000f00) -#define TX_PWR_CFG_3_MCS15 FIELD32(0x0000f000) -#define TX_PWR_CFG_3_UKNOWN1 FIELD32(0x000f0000) -#define TX_PWR_CFG_3_UKNOWN2 FIELD32(0x00f00000) -#define TX_PWR_CFG_3_UKNOWN3 FIELD32(0x0f000000) -#define TX_PWR_CFG_3_UKNOWN4 FIELD32(0xf0000000) - -/* - * TX_PWR_CFG_4: - */ -#define TX_PWR_CFG_4 0x1324 -#define TX_PWR_CFG_4_UKNOWN5 FIELD32(0x0000000f) -#define TX_PWR_CFG_4_UKNOWN6 FIELD32(0x000000f0) -#define TX_PWR_CFG_4_UKNOWN7 FIELD32(0x00000f00) -#define TX_PWR_CFG_4_UKNOWN8 FIELD32(0x0000f000) - -/* - * TX_PIN_CFG: - */ -#define TX_PIN_CFG 0x1328 -#define TX_PIN_CFG_PA_PE_A0_EN FIELD32(0x00000001) -#define TX_PIN_CFG_PA_PE_G0_EN FIELD32(0x00000002) -#define TX_PIN_CFG_PA_PE_A1_EN FIELD32(0x00000004) -#define TX_PIN_CFG_PA_PE_G1_EN FIELD32(0x00000008) -#define TX_PIN_CFG_PA_PE_A0_POL FIELD32(0x00000010) -#define TX_PIN_CFG_PA_PE_G0_POL FIELD32(0x00000020) -#define TX_PIN_CFG_PA_PE_A1_POL FIELD32(0x00000040) -#define TX_PIN_CFG_PA_PE_G1_POL FIELD32(0x00000080) -#define TX_PIN_CFG_LNA_PE_A0_EN FIELD32(0x00000100) -#define TX_PIN_CFG_LNA_PE_G0_EN FIELD32(0x00000200) -#define TX_PIN_CFG_LNA_PE_A1_EN FIELD32(0x00000400) -#define TX_PIN_CFG_LNA_PE_G1_EN FIELD32(0x00000800) -#define TX_PIN_CFG_LNA_PE_A0_POL FIELD32(0x00001000) -#define TX_PIN_CFG_LNA_PE_G0_POL FIELD32(0x00002000) -#define TX_PIN_CFG_LNA_PE_A1_POL FIELD32(0x00004000) -#define TX_PIN_CFG_LNA_PE_G1_POL FIELD32(0x00008000) -#define TX_PIN_CFG_RFTR_EN FIELD32(0x00010000) -#define TX_PIN_CFG_RFTR_POL FIELD32(0x00020000) -#define TX_PIN_CFG_TRSW_EN FIELD32(0x00040000) -#define TX_PIN_CFG_TRSW_POL FIELD32(0x00080000) - -/* - * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz - */ -#define TX_BAND_CFG 0x132c -#define TX_BAND_CFG_HT40_PLUS FIELD32(0x00000001) -#define TX_BAND_CFG_A FIELD32(0x00000002) -#define TX_BAND_CFG_BG FIELD32(0x00000004) - -/* - * TX_SW_CFG0: - */ -#define TX_SW_CFG0 0x1330 - -/* - * TX_SW_CFG1: - */ -#define TX_SW_CFG1 0x1334 - -/* - * TX_SW_CFG2: - */ -#define TX_SW_CFG2 0x1338 - -/* - * TXOP_THRES_CFG: - */ -#define TXOP_THRES_CFG 0x133c - -/* - * TXOP_CTRL_CFG: - */ -#define TXOP_CTRL_CFG 0x1340 - -/* - * TX_RTS_CFG: - * RTS_THRES: unit:byte - * RTS_FBK_EN: enable rts rate fallback - */ -#define TX_RTS_CFG 0x1344 -#define TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT FIELD32(0x000000ff) -#define TX_RTS_CFG_RTS_THRES FIELD32(0x00ffff00) -#define TX_RTS_CFG_RTS_FBK_EN FIELD32(0x01000000) - -/* - * TX_TIMEOUT_CFG: - * MPDU_LIFETIME: expiration time = 2^(9+MPDU LIFE TIME) us - * RX_ACK_TIMEOUT: unit:slot. Used for TX procedure - * TX_OP_TIMEOUT: TXOP timeout value for TXOP truncation. - * it is recommended that: - * (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) - */ -#define TX_TIMEOUT_CFG 0x1348 -#define TX_TIMEOUT_CFG_MPDU_LIFETIME FIELD32(0x000000f0) -#define TX_TIMEOUT_CFG_RX_ACK_TIMEOUT FIELD32(0x0000ff00) -#define TX_TIMEOUT_CFG_TX_OP_TIMEOUT FIELD32(0x00ff0000) - -/* - * TX_RTY_CFG: - * SHORT_RTY_LIMIT: short retry limit - * LONG_RTY_LIMIT: long retry limit - * LONG_RTY_THRE: Long retry threshoold - * NON_AGG_RTY_MODE: Non-Aggregate MPDU retry mode - * 0:expired by retry limit, 1: expired by mpdu life timer - * AGG_RTY_MODE: Aggregate MPDU retry mode - * 0:expired by retry limit, 1: expired by mpdu life timer - * TX_AUTO_FB_ENABLE: Tx retry PHY rate auto fallback enable - */ -#define TX_RTY_CFG 0x134c -#define TX_RTY_CFG_SHORT_RTY_LIMIT FIELD32(0x000000ff) -#define TX_RTY_CFG_LONG_RTY_LIMIT FIELD32(0x0000ff00) -#define TX_RTY_CFG_LONG_RTY_THRE FIELD32(0x0fff0000) -#define TX_RTY_CFG_NON_AGG_RTY_MODE FIELD32(0x10000000) -#define TX_RTY_CFG_AGG_RTY_MODE FIELD32(0x20000000) -#define TX_RTY_CFG_TX_AUTO_FB_ENABLE FIELD32(0x40000000) - -/* - * TX_LINK_CFG: - * REMOTE_MFB_LIFETIME: remote MFB life time. unit: 32us - * MFB_ENABLE: TX apply remote MFB 1:enable - * REMOTE_UMFS_ENABLE: remote unsolicit MFB enable - * 0: not apply remote remote unsolicit (MFS=7) - * TX_MRQ_EN: MCS request TX enable - * TX_RDG_EN: RDG TX enable - * TX_CF_ACK_EN: Piggyback CF-ACK enable - * REMOTE_MFB: remote MCS feedback - * REMOTE_MFS: remote MCS feedback sequence number - */ -#define TX_LINK_CFG 0x1350 -#define TX_LINK_CFG_REMOTE_MFB_LIFETIME FIELD32(0x000000ff) -#define TX_LINK_CFG_MFB_ENABLE FIELD32(0x00000100) -#define TX_LINK_CFG_REMOTE_UMFS_ENABLE FIELD32(0x00000200) -#define TX_LINK_CFG_TX_MRQ_EN FIELD32(0x00000400) -#define TX_LINK_CFG_TX_RDG_EN FIELD32(0x00000800) -#define TX_LINK_CFG_TX_CF_ACK_EN FIELD32(0x00001000) -#define TX_LINK_CFG_REMOTE_MFB FIELD32(0x00ff0000) -#define TX_LINK_CFG_REMOTE_MFS FIELD32(0xff000000) - -/* - * HT_FBK_CFG0: - */ -#define HT_FBK_CFG0 0x1354 -#define HT_FBK_CFG0_HTMCS0FBK FIELD32(0x0000000f) -#define HT_FBK_CFG0_HTMCS1FBK FIELD32(0x000000f0) -#define HT_FBK_CFG0_HTMCS2FBK FIELD32(0x00000f00) -#define HT_FBK_CFG0_HTMCS3FBK FIELD32(0x0000f000) -#define HT_FBK_CFG0_HTMCS4FBK FIELD32(0x000f0000) -#define HT_FBK_CFG0_HTMCS5FBK FIELD32(0x00f00000) -#define HT_FBK_CFG0_HTMCS6FBK FIELD32(0x0f000000) -#define HT_FBK_CFG0_HTMCS7FBK FIELD32(0xf0000000) - -/* - * HT_FBK_CFG1: - */ -#define HT_FBK_CFG1 0x1358 -#define HT_FBK_CFG1_HTMCS8FBK FIELD32(0x0000000f) -#define HT_FBK_CFG1_HTMCS9FBK FIELD32(0x000000f0) -#define HT_FBK_CFG1_HTMCS10FBK FIELD32(0x00000f00) -#define HT_FBK_CFG1_HTMCS11FBK FIELD32(0x0000f000) -#define HT_FBK_CFG1_HTMCS12FBK FIELD32(0x000f0000) -#define HT_FBK_CFG1_HTMCS13FBK FIELD32(0x00f00000) -#define HT_FBK_CFG1_HTMCS14FBK FIELD32(0x0f000000) -#define HT_FBK_CFG1_HTMCS15FBK FIELD32(0xf0000000) - -/* - * LG_FBK_CFG0: - */ -#define LG_FBK_CFG0 0x135c -#define LG_FBK_CFG0_OFDMMCS0FBK FIELD32(0x0000000f) -#define LG_FBK_CFG0_OFDMMCS1FBK FIELD32(0x000000f0) -#define LG_FBK_CFG0_OFDMMCS2FBK FIELD32(0x00000f00) -#define LG_FBK_CFG0_OFDMMCS3FBK FIELD32(0x0000f000) -#define LG_FBK_CFG0_OFDMMCS4FBK FIELD32(0x000f0000) -#define LG_FBK_CFG0_OFDMMCS5FBK FIELD32(0x00f00000) -#define LG_FBK_CFG0_OFDMMCS6FBK FIELD32(0x0f000000) -#define LG_FBK_CFG0_OFDMMCS7FBK FIELD32(0xf0000000) - -/* - * LG_FBK_CFG1: - */ -#define LG_FBK_CFG1 0x1360 -#define LG_FBK_CFG0_CCKMCS0FBK FIELD32(0x0000000f) -#define LG_FBK_CFG0_CCKMCS1FBK FIELD32(0x000000f0) -#define LG_FBK_CFG0_CCKMCS2FBK FIELD32(0x00000f00) -#define LG_FBK_CFG0_CCKMCS3FBK FIELD32(0x0000f000) - -/* - * CCK_PROT_CFG: CCK Protection - * PROTECT_RATE: Protection control frame rate for CCK TX(RTS/CTS/CFEnd) - * PROTECT_CTRL: Protection control frame type for CCK TX - * 0:none, 1:RTS/CTS, 2:CTS-to-self - * PROTECT_NAV: TXOP protection type for CCK TX - * 0:none, 1:ShortNAVprotect, 2:LongNAVProtect - * TX_OP_ALLOW_CCK: CCK TXOP allowance, 0:disallow - * TX_OP_ALLOW_OFDM: CCK TXOP allowance, 0:disallow - * TX_OP_ALLOW_MM20: CCK TXOP allowance, 0:disallow - * TX_OP_ALLOW_MM40: CCK TXOP allowance, 0:disallow - * TX_OP_ALLOW_GF20: CCK TXOP allowance, 0:disallow - * TX_OP_ALLOW_GF40: CCK TXOP allowance, 0:disallow - * RTS_TH_EN: RTS threshold enable on CCK TX - */ -#define CCK_PROT_CFG 0x1364 -#define CCK_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define CCK_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define CCK_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define CCK_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define CCK_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define CCK_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define CCK_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define CCK_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define CCK_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define CCK_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * OFDM_PROT_CFG: OFDM Protection - */ -#define OFDM_PROT_CFG 0x1368 -#define OFDM_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define OFDM_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define OFDM_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define OFDM_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * MM20_PROT_CFG: MM20 Protection - */ -#define MM20_PROT_CFG 0x136c -#define MM20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define MM20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define MM20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define MM20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define MM20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define MM20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define MM20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define MM20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define MM20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define MM20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * MM40_PROT_CFG: MM40 Protection - */ -#define MM40_PROT_CFG 0x1370 -#define MM40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define MM40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define MM40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define MM40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define MM40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define MM40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define MM40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define MM40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define MM40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define MM40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * GF20_PROT_CFG: GF20 Protection - */ -#define GF20_PROT_CFG 0x1374 -#define GF20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define GF20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define GF20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define GF20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define GF20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define GF20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define GF20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define GF20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define GF20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define GF20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * GF40_PROT_CFG: GF40 Protection - */ -#define GF40_PROT_CFG 0x1378 -#define GF40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define GF40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define GF40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define GF40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define GF40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define GF40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define GF40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define GF40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define GF40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define GF40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * EXP_CTS_TIME: - */ -#define EXP_CTS_TIME 0x137c - -/* - * EXP_ACK_TIME: - */ -#define EXP_ACK_TIME 0x1380 - -/* - * RX_FILTER_CFG: RX configuration register. - */ -#define RX_FILTER_CFG 0x1400 -#define RX_FILTER_CFG_DROP_CRC_ERROR FIELD32(0x00000001) -#define RX_FILTER_CFG_DROP_PHY_ERROR FIELD32(0x00000002) -#define RX_FILTER_CFG_DROP_NOT_TO_ME FIELD32(0x00000004) -#define RX_FILTER_CFG_DROP_NOT_MY_BSSD FIELD32(0x00000008) -#define RX_FILTER_CFG_DROP_VER_ERROR FIELD32(0x00000010) -#define RX_FILTER_CFG_DROP_MULTICAST FIELD32(0x00000020) -#define RX_FILTER_CFG_DROP_BROADCAST FIELD32(0x00000040) -#define RX_FILTER_CFG_DROP_DUPLICATE FIELD32(0x00000080) -#define RX_FILTER_CFG_DROP_CF_END_ACK FIELD32(0x00000100) -#define RX_FILTER_CFG_DROP_CF_END FIELD32(0x00000200) -#define RX_FILTER_CFG_DROP_ACK FIELD32(0x00000400) -#define RX_FILTER_CFG_DROP_CTS FIELD32(0x00000800) -#define RX_FILTER_CFG_DROP_RTS FIELD32(0x00001000) -#define RX_FILTER_CFG_DROP_PSPOLL FIELD32(0x00002000) -#define RX_FILTER_CFG_DROP_BA FIELD32(0x00004000) -#define RX_FILTER_CFG_DROP_BAR FIELD32(0x00008000) -#define RX_FILTER_CFG_DROP_CNTL FIELD32(0x00010000) - -/* - * AUTO_RSP_CFG: - * AUTORESPONDER: 0: disable, 1: enable - * BAC_ACK_POLICY: 0:long, 1:short preamble - * CTS_40_MMODE: Response CTS 40MHz duplicate mode - * CTS_40_MREF: Response CTS 40MHz duplicate mode - * AR_PREAMBLE: Auto responder preamble 0:long, 1:short preamble - * DUAL_CTS_EN: Power bit value in control frame - * ACK_CTS_PSM_BIT:Power bit value in control frame - */ -#define AUTO_RSP_CFG 0x1404 -#define AUTO_RSP_CFG_AUTORESPONDER FIELD32(0x00000001) -#define AUTO_RSP_CFG_BAC_ACK_POLICY FIELD32(0x00000002) -#define AUTO_RSP_CFG_CTS_40_MMODE FIELD32(0x00000004) -#define AUTO_RSP_CFG_CTS_40_MREF FIELD32(0x00000008) -#define AUTO_RSP_CFG_AR_PREAMBLE FIELD32(0x00000010) -#define AUTO_RSP_CFG_DUAL_CTS_EN FIELD32(0x00000040) -#define AUTO_RSP_CFG_ACK_CTS_PSM_BIT FIELD32(0x00000080) - -/* - * LEGACY_BASIC_RATE: - */ -#define LEGACY_BASIC_RATE 0x1408 - -/* - * HT_BASIC_RATE: - */ -#define HT_BASIC_RATE 0x140c - -/* - * HT_CTRL_CFG: - */ -#define HT_CTRL_CFG 0x1410 - -/* - * SIFS_COST_CFG: - */ -#define SIFS_COST_CFG 0x1414 - -/* - * RX_PARSER_CFG: - * Set NAV for all received frames - */ -#define RX_PARSER_CFG 0x1418 - -/* - * TX_SEC_CNT0: - */ -#define TX_SEC_CNT0 0x1500 - -/* - * RX_SEC_CNT0: - */ -#define RX_SEC_CNT0 0x1504 - -/* - * CCMP_FC_MUTE: - */ -#define CCMP_FC_MUTE 0x1508 - -/* - * TXOP_HLDR_ADDR0: - */ -#define TXOP_HLDR_ADDR0 0x1600 - -/* - * TXOP_HLDR_ADDR1: - */ -#define TXOP_HLDR_ADDR1 0x1604 - -/* - * TXOP_HLDR_ET: - */ -#define TXOP_HLDR_ET 0x1608 - -/* - * QOS_CFPOLL_RA_DW0: - */ -#define QOS_CFPOLL_RA_DW0 0x160c - -/* - * QOS_CFPOLL_RA_DW1: - */ -#define QOS_CFPOLL_RA_DW1 0x1610 - -/* - * QOS_CFPOLL_QC: - */ -#define QOS_CFPOLL_QC 0x1614 - -/* - * RX_STA_CNT0: RX PLCP error count & RX CRC error count - */ -#define RX_STA_CNT0 0x1700 -#define RX_STA_CNT0_CRC_ERR FIELD32(0x0000ffff) -#define RX_STA_CNT0_PHY_ERR FIELD32(0xffff0000) - -/* - * RX_STA_CNT1: RX False CCA count & RX LONG frame count - */ -#define RX_STA_CNT1 0x1704 -#define RX_STA_CNT1_FALSE_CCA FIELD32(0x0000ffff) -#define RX_STA_CNT1_PLCP_ERR FIELD32(0xffff0000) - -/* - * RX_STA_CNT2: - */ -#define RX_STA_CNT2 0x1708 -#define RX_STA_CNT2_RX_DUPLI_COUNT FIELD32(0x0000ffff) -#define RX_STA_CNT2_RX_FIFO_OVERFLOW FIELD32(0xffff0000) - -/* - * TX_STA_CNT0: TX Beacon count - */ -#define TX_STA_CNT0 0x170c -#define TX_STA_CNT0_TX_FAIL_COUNT FIELD32(0x0000ffff) -#define TX_STA_CNT0_TX_BEACON_COUNT FIELD32(0xffff0000) - -/* - * TX_STA_CNT1: TX tx count - */ -#define TX_STA_CNT1 0x1710 -#define TX_STA_CNT1_TX_SUCCESS FIELD32(0x0000ffff) -#define TX_STA_CNT1_TX_RETRANSMIT FIELD32(0xffff0000) - -/* - * TX_STA_CNT2: TX tx count - */ -#define TX_STA_CNT2 0x1714 -#define TX_STA_CNT2_TX_ZERO_LEN_COUNT FIELD32(0x0000ffff) -#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000) - -/* - * TX_STA_FIFO: TX Result for specific PID status fifo register - */ -#define TX_STA_FIFO 0x1718 -#define TX_STA_FIFO_VALID FIELD32(0x00000001) -#define TX_STA_FIFO_PID_TYPE FIELD32(0x0000001e) -#define TX_STA_FIFO_TX_SUCCESS FIELD32(0x00000020) -#define TX_STA_FIFO_TX_AGGRE FIELD32(0x00000040) -#define TX_STA_FIFO_TX_ACK_REQUIRED FIELD32(0x00000080) -#define TX_STA_FIFO_WCID FIELD32(0x0000ff00) -#define TX_STA_FIFO_MCS FIELD32(0x007f0000) -#define TX_STA_FIFO_PHYMODE FIELD32(0xc0000000) - -/* - * TX_AGG_CNT: Debug counter - */ -#define TX_AGG_CNT 0x171c -#define TX_AGG_CNT_NON_AGG_TX_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT_AGG_TX_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT0: - */ -#define TX_AGG_CNT0 0x1720 -#define TX_AGG_CNT0_AGG_SIZE_1_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT0_AGG_SIZE_2_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT1: - */ -#define TX_AGG_CNT1 0x1724 -#define TX_AGG_CNT1_AGG_SIZE_3_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT1_AGG_SIZE_4_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT2: - */ -#define TX_AGG_CNT2 0x1728 -#define TX_AGG_CNT2_AGG_SIZE_5_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT2_AGG_SIZE_6_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT3: - */ -#define TX_AGG_CNT3 0x172c -#define TX_AGG_CNT3_AGG_SIZE_7_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT3_AGG_SIZE_8_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT4: - */ -#define TX_AGG_CNT4 0x1730 -#define TX_AGG_CNT4_AGG_SIZE_9_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT4_AGG_SIZE_10_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT5: - */ -#define TX_AGG_CNT5 0x1734 -#define TX_AGG_CNT5_AGG_SIZE_11_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT5_AGG_SIZE_12_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT6: - */ -#define TX_AGG_CNT6 0x1738 -#define TX_AGG_CNT6_AGG_SIZE_13_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT6_AGG_SIZE_14_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT7: - */ -#define TX_AGG_CNT7 0x173c -#define TX_AGG_CNT7_AGG_SIZE_15_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT7_AGG_SIZE_16_COUNT FIELD32(0xffff0000) - -/* - * MPDU_DENSITY_CNT: - * TX_ZERO_DEL: TX zero length delimiter count - * RX_ZERO_DEL: RX zero length delimiter count - */ -#define MPDU_DENSITY_CNT 0x1740 -#define MPDU_DENSITY_CNT_TX_ZERO_DEL FIELD32(0x0000ffff) -#define MPDU_DENSITY_CNT_RX_ZERO_DEL FIELD32(0xffff0000) - -/* - * Security key table memory. - * MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry - * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry - * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry - * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry - * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry - * SHARED_KEY_MODE_BASE: 4 bits * 32-entry - */ -#define MAC_WCID_BASE 0x1800 -#define PAIRWISE_KEY_TABLE_BASE 0x4000 -#define MAC_IVEIV_TABLE_BASE 0x6000 -#define MAC_WCID_ATTRIBUTE_BASE 0x6800 -#define SHARED_KEY_TABLE_BASE 0x6c00 -#define SHARED_KEY_MODE_BASE 0x7000 - -#define MAC_WCID_ENTRY(__idx) \ - ( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) ) -#define PAIRWISE_KEY_ENTRY(__idx) \ - ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) -#define MAC_IVEIV_ENTRY(__idx) \ - ( MAC_IVEIV_TABLE_BASE + ((__idx) & sizeof(struct mac_iveiv_entry)) ) -#define MAC_WCID_ATTR_ENTRY(__idx) \ - ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) ) -#define SHARED_KEY_ENTRY(__idx) \ - ( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) -#define SHARED_KEY_MODE_ENTRY(__idx) \ - ( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) ) - -struct mac_wcid_entry { - u8 mac[6]; - u8 reserved[2]; -} __attribute__ ((packed)); - -struct hw_key_entry { - u8 key[16]; - u8 tx_mic[8]; - u8 rx_mic[8]; -} __attribute__ ((packed)); - -struct mac_iveiv_entry { - u8 iv[8]; -} __attribute__ ((packed)); - -/* - * MAC_WCID_ATTRIBUTE: - */ -#define MAC_WCID_ATTRIBUTE_KEYTAB FIELD32(0x00000001) -#define MAC_WCID_ATTRIBUTE_CIPHER FIELD32(0x0000000e) -#define MAC_WCID_ATTRIBUTE_BSS_IDX FIELD32(0x00000070) -#define MAC_WCID_ATTRIBUTE_RX_WIUDF FIELD32(0x00000380) - -/* - * SHARED_KEY_MODE: - */ -#define SHARED_KEY_MODE_BSS0_KEY0 FIELD32(0x00000007) -#define SHARED_KEY_MODE_BSS0_KEY1 FIELD32(0x00000070) -#define SHARED_KEY_MODE_BSS0_KEY2 FIELD32(0x00000700) -#define SHARED_KEY_MODE_BSS0_KEY3 FIELD32(0x00007000) -#define SHARED_KEY_MODE_BSS1_KEY0 FIELD32(0x00070000) -#define SHARED_KEY_MODE_BSS1_KEY1 FIELD32(0x00700000) -#define SHARED_KEY_MODE_BSS1_KEY2 FIELD32(0x07000000) -#define SHARED_KEY_MODE_BSS1_KEY3 FIELD32(0x70000000) - -/* - * HOST-MCU communication - */ - -/* - * H2M_MAILBOX_CSR: Host-to-MCU Mailbox. - */ -#define H2M_MAILBOX_CSR 0x7010 -#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff) -#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00) -#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000) -#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000) - -/* - * H2M_MAILBOX_CID: - */ -#define H2M_MAILBOX_CID 0x7014 -#define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff) -#define H2M_MAILBOX_CID_CMD1 FIELD32(0x0000ff00) -#define H2M_MAILBOX_CID_CMD2 FIELD32(0x00ff0000) -#define H2M_MAILBOX_CID_CMD3 FIELD32(0xff000000) - -/* - * H2M_MAILBOX_STATUS: - */ -#define H2M_MAILBOX_STATUS 0x701c - -/* - * H2M_INT_SRC: - */ -#define H2M_INT_SRC 0x7024 - -/* - * H2M_BBP_AGENT: + * PCI registers. */ -#define H2M_BBP_AGENT 0x7028 /* - * MCU_LEDCS: LED control for MCU Mailbox. + * E2PROM_CSR: EEPROM control register. + * RELOAD: Write 1 to reload eeprom content. + * TYPE: 0: 93c46, 1:93c66. + * LOAD_STATUS: 1:loading, 0:done. */ -#define MCU_LEDCS_LED_MODE FIELD8(0x1f) -#define MCU_LEDCS_POLARITY FIELD8(0x01) +#define E2PROM_CSR 0x0004 +#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000001) +#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000002) +#define E2PROM_CSR_DATA_IN FIELD32(0x00000004) +#define E2PROM_CSR_DATA_OUT FIELD32(0x00000008) +#define E2PROM_CSR_TYPE FIELD32(0x00000030) +#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040) +#define E2PROM_CSR_RELOAD FIELD32(0x00000080) /* - * HW_CS_CTS_BASE: - * Carrier-sense CTS frame base address. - * It's where mac stores carrier-sense frame for carrier-sense function. + * Queue register offset macros */ -#define HW_CS_CTS_BASE 0x7700 +#define TX_QUEUE_REG_OFFSET 0x10 +#define TX_BASE_PTR(__x) TX_BASE_PTR0 + ((__x) * TX_QUEUE_REG_OFFSET) +#define TX_MAX_CNT(__x) TX_MAX_CNT0 + ((__x) * TX_QUEUE_REG_OFFSET) +#define TX_CTX_IDX(__x) TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) +#define TX_DTX_IDX(__x) TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) /* - * HW_DFS_CTS_BASE: - * FS CTS frame base address. It's where mac stores CTS frame for DFS. + * EFUSE_CSR: RT3090 EEPROM */ -#define HW_DFS_CTS_BASE 0x7780 +#define EFUSE_CTRL 0x0580 +#define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000) +#define EFUSE_CTRL_MODE FIELD32(0x000000c0) +#define EFUSE_CTRL_KICK FIELD32(0x40000000) /* - * TXRX control registers - base address 0x3000 + * EFUSE_DATA0 */ +#define EFUSE_DATA0 0x0590 /* - * TXRX_CSR1: - * rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first.. + * EFUSE_DATA1 */ -#define TXRX_CSR1 0x77d0 +#define EFUSE_DATA1 0x0594 /* - * HW_DEBUG_SETTING_BASE: - * since NULL frame won't be that long (256 byte) - * We steal 16 tail bytes to save debugging settings + * EFUSE_DATA2 */ -#define HW_DEBUG_SETTING_BASE 0x77f0 -#define HW_DEBUG_SETTING_BASE2 0x7770 +#define EFUSE_DATA2 0x0598 /* - * HW_BEACON_BASE - * In order to support maximum 8 MBSS and its maximum length - * is 512 bytes for each beacon - * Three section discontinue memory segments will be used. - * 1. The original region for BCN 0~3 - * 2. Extract memory from FCE table for BCN 4~5 - * 3. Extract memory from Pair-wise key table for BCN 6~7 - * It occupied those memory of wcid 238~253 for BCN 6 - * and wcid 222~237 for BCN 7 - * - * IMPORTANT NOTE: Not sure why legacy driver does this, - * but HW_BEACON_BASE7 is 0x0200 bytes below HW_BEACON_BASE6. + * EFUSE_DATA3 */ -#define HW_BEACON_BASE0 0x7800 -#define HW_BEACON_BASE1 0x7a00 -#define HW_BEACON_BASE2 0x7c00 -#define HW_BEACON_BASE3 0x7e00 -#define HW_BEACON_BASE4 0x7200 -#define HW_BEACON_BASE5 0x7400 -#define HW_BEACON_BASE6 0x5dc0 -#define HW_BEACON_BASE7 0x5bc0 - -#define HW_BEACON_OFFSET(__index) \ - ( ((__index) < 4) ? ( HW_BEACON_BASE0 + (__index * 0x0200) ) : \ - (((__index) < 6) ? ( HW_BEACON_BASE4 + ((__index - 4) * 0x0200) ) : \ - (HW_BEACON_BASE6 - ((__index - 6) * 0x0200))) ) +#define EFUSE_DATA3 0x059c /* * 8051 firmware image. @@ -1492,282 +89,11 @@ struct mac_iveiv_entry { #define FIRMWARE_RT2860 "rt2860.bin" #define FIRMWARE_IMAGE_BASE 0x2000 -/* - * BBP registers. - * The wordsize of the BBP is 8 bits. - */ - -/* - * BBP 1: TX Antenna - */ -#define BBP1_TX_POWER FIELD8(0x07) -#define BBP1_TX_ANTENNA FIELD8(0x18) - -/* - * BBP 3: RX Antenna - */ -#define BBP3_RX_ANTENNA FIELD8(0x18) -#define BBP3_HT40_PLUS FIELD8(0x20) - -/* - * BBP 4: Bandwidth - */ -#define BBP4_TX_BF FIELD8(0x01) -#define BBP4_BANDWIDTH FIELD8(0x18) - -/* - * RFCSR registers - * The wordsize of the RFCSR is 8 bits. - */ - -/* - * RFCSR 6: - */ -#define RFCSR6_R FIELD8(0x03) - -/* - * RFCSR 7: - */ -#define RFCSR7_RF_TUNING FIELD8(0x01) - -/* - * RFCSR 12: - */ -#define RFCSR12_TX_POWER FIELD8(0x1f) - -/* - * RFCSR 22: - */ -#define RFCSR22_BASEBAND_LOOPBACK FIELD8(0x01) - -/* - * RFCSR 23: - */ -#define RFCSR23_FREQ_OFFSET FIELD8(0x7f) - -/* - * RFCSR 30: - */ -#define RFCSR30_RF_CALIBRATION FIELD8(0x80) - -/* - * RF registers - */ - -/* - * RF 2 - */ -#define RF2_ANTENNA_RX2 FIELD32(0x00000040) -#define RF2_ANTENNA_TX1 FIELD32(0x00004000) -#define RF2_ANTENNA_RX1 FIELD32(0x00020000) - -/* - * RF 3 - */ -#define RF3_TXPOWER_G FIELD32(0x00003e00) -#define RF3_TXPOWER_A_7DBM_BOOST FIELD32(0x00000200) -#define RF3_TXPOWER_A FIELD32(0x00003c00) - -/* - * RF 4 - */ -#define RF4_TXPOWER_G FIELD32(0x000007c0) -#define RF4_TXPOWER_A_7DBM_BOOST FIELD32(0x00000040) -#define RF4_TXPOWER_A FIELD32(0x00000780) -#define RF4_FREQ_OFFSET FIELD32(0x001f8000) -#define RF4_HT40 FIELD32(0x00200000) - -/* - * EEPROM content. - * The wordsize of the EEPROM is 16 bits. - */ - -/* - * EEPROM Version - */ -#define EEPROM_VERSION 0x0001 -#define EEPROM_VERSION_FAE FIELD16(0x00ff) -#define EEPROM_VERSION_VERSION FIELD16(0xff00) - -/* - * HW MAC address. - */ -#define EEPROM_MAC_ADDR_0 0x0002 -#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) -#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) -#define EEPROM_MAC_ADDR_1 0x0003 -#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) -#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) -#define EEPROM_MAC_ADDR_2 0x0004 -#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) -#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) - -/* - * EEPROM ANTENNA config - * RXPATH: 1: 1R, 2: 2R, 3: 3R - * TXPATH: 1: 1T, 2: 2T - */ -#define EEPROM_ANTENNA 0x001a -#define EEPROM_ANTENNA_RXPATH FIELD16(0x000f) -#define EEPROM_ANTENNA_TXPATH FIELD16(0x00f0) -#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0f00) - -/* - * EEPROM NIC config - * CARDBUS_ACCEL: 0 - enable, 1 - disable - */ -#define EEPROM_NIC 0x001b -#define EEPROM_NIC_HW_RADIO FIELD16(0x0001) -#define EEPROM_NIC_DYNAMIC_TX_AGC FIELD16(0x0002) -#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0004) -#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0008) -#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0010) -#define EEPROM_NIC_BW40M_SB_BG FIELD16(0x0020) -#define EEPROM_NIC_BW40M_SB_A FIELD16(0x0040) -#define EEPROM_NIC_WPS_PBC FIELD16(0x0080) -#define EEPROM_NIC_BW40M_BG FIELD16(0x0100) -#define EEPROM_NIC_BW40M_A FIELD16(0x0200) - -/* - * EEPROM frequency - */ -#define EEPROM_FREQ 0x001d -#define EEPROM_FREQ_OFFSET FIELD16(0x00ff) -#define EEPROM_FREQ_LED_MODE FIELD16(0x7f00) -#define EEPROM_FREQ_LED_POLARITY FIELD16(0x1000) - -/* - * EEPROM LED - * POLARITY_RDY_G: Polarity RDY_G setting. - * POLARITY_RDY_A: Polarity RDY_A setting. - * POLARITY_ACT: Polarity ACT setting. - * POLARITY_GPIO_0: Polarity GPIO0 setting. - * POLARITY_GPIO_1: Polarity GPIO1 setting. - * POLARITY_GPIO_2: Polarity GPIO2 setting. - * POLARITY_GPIO_3: Polarity GPIO3 setting. - * POLARITY_GPIO_4: Polarity GPIO4 setting. - * LED_MODE: Led mode. - */ -#define EEPROM_LED1 0x001e -#define EEPROM_LED2 0x001f -#define EEPROM_LED3 0x0020 -#define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001) -#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002) -#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004) -#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008) -#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010) -#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020) -#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040) -#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080) -#define EEPROM_LED_LED_MODE FIELD16(0x1f00) - -/* - * EEPROM LNA - */ -#define EEPROM_LNA 0x0022 -#define EEPROM_LNA_BG FIELD16(0x00ff) -#define EEPROM_LNA_A0 FIELD16(0xff00) - -/* - * EEPROM RSSI BG offset - */ -#define EEPROM_RSSI_BG 0x0023 -#define EEPROM_RSSI_BG_OFFSET0 FIELD16(0x00ff) -#define EEPROM_RSSI_BG_OFFSET1 FIELD16(0xff00) - -/* - * EEPROM RSSI BG2 offset - */ -#define EEPROM_RSSI_BG2 0x0024 -#define EEPROM_RSSI_BG2_OFFSET2 FIELD16(0x00ff) -#define EEPROM_RSSI_BG2_LNA_A1 FIELD16(0xff00) - -/* - * EEPROM RSSI A offset - */ -#define EEPROM_RSSI_A 0x0025 -#define EEPROM_RSSI_A_OFFSET0 FIELD16(0x00ff) -#define EEPROM_RSSI_A_OFFSET1 FIELD16(0xff00) - -/* - * EEPROM RSSI A2 offset - */ -#define EEPROM_RSSI_A2 0x0026 -#define EEPROM_RSSI_A2_OFFSET2 FIELD16(0x00ff) -#define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00) - -/* - * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power. - * This is delta in 40MHZ. - * VALUE: Tx Power dalta value (MAX=4) - * TYPE: 1: Plus the delta value, 0: minus the delta value - * TXPOWER: Enable: - */ -#define EEPROM_TXPOWER_DELTA 0x0028 -#define EEPROM_TXPOWER_DELTA_VALUE FIELD16(0x003f) -#define EEPROM_TXPOWER_DELTA_TYPE FIELD16(0x0040) -#define EEPROM_TXPOWER_DELTA_TXPOWER FIELD16(0x0080) - -/* - * EEPROM TXPOWER 802.11BG - */ -#define EEPROM_TXPOWER_BG1 0x0029 -#define EEPROM_TXPOWER_BG2 0x0030 -#define EEPROM_TXPOWER_BG_SIZE 7 -#define EEPROM_TXPOWER_BG_1 FIELD16(0x00ff) -#define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) - -/* - * EEPROM TXPOWER 802.11A - */ -#define EEPROM_TXPOWER_A1 0x003c -#define EEPROM_TXPOWER_A2 0x0053 -#define EEPROM_TXPOWER_A_SIZE 6 -#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) -#define EEPROM_TXPOWER_A_2 FIELD16(0xff00) - -/* - * EEPROM TXpower byrate: 20MHZ power - */ -#define EEPROM_TXPOWER_BYRATE 0x006f - -/* - * EEPROM BBP. - */ -#define EEPROM_BBP_START 0x0078 -#define EEPROM_BBP_SIZE 16 -#define EEPROM_BBP_VALUE FIELD16(0x00ff) -#define EEPROM_BBP_REG_ID FIELD16(0xff00) - -/* - * MCU mailbox commands. - */ -#define MCU_SLEEP 0x30 -#define MCU_WAKEUP 0x31 -#define MCU_RADIO_OFF 0x35 -#define MCU_CURRENT 0x36 -#define MCU_LED 0x50 -#define MCU_LED_STRENGTH 0x51 -#define MCU_LED_1 0x52 -#define MCU_LED_2 0x53 -#define MCU_LED_3 0x54 -#define MCU_RADAR 0x60 -#define MCU_BOOT_SIGNAL 0x72 -#define MCU_BBP_SIGNAL 0x80 -#define MCU_POWER_SAVE 0x83 - -/* - * MCU mailbox tokens - */ -#define TOKEN_WAKUP 3 - /* * DMA descriptor defines. */ #define TXD_DESC_SIZE ( 4 * sizeof(__le32) ) -#define TXWI_DESC_SIZE ( 4 * sizeof(__le32) ) #define RXD_DESC_SIZE ( 4 * sizeof(__le32) ) -#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) ) /* * TX descriptor format for TX, PRIO and Beacon Ring. @@ -1805,52 +131,6 @@ struct mac_iveiv_entry { #define TXD_W3_UCO FIELD32(0x40000000) #define TXD_W3_ICO FIELD32(0x80000000) -/* - * TX WI structure - */ - -/* - * Word0 - * FRAG: 1 To inform TKIP engine this is a fragment. - * MIMO_PS: The remote peer is in dynamic MIMO-PS mode - * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs - * BW: Channel bandwidth 20MHz or 40 MHz - * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED - */ -#define TXWI_W0_FRAG FIELD32(0x00000001) -#define TXWI_W0_MIMO_PS FIELD32(0x00000002) -#define TXWI_W0_CF_ACK FIELD32(0x00000004) -#define TXWI_W0_TS FIELD32(0x00000008) -#define TXWI_W0_AMPDU FIELD32(0x00000010) -#define TXWI_W0_MPDU_DENSITY FIELD32(0x000000e0) -#define TXWI_W0_TX_OP FIELD32(0x00000300) -#define TXWI_W0_MCS FIELD32(0x007f0000) -#define TXWI_W0_BW FIELD32(0x00800000) -#define TXWI_W0_SHORT_GI FIELD32(0x01000000) -#define TXWI_W0_STBC FIELD32(0x06000000) -#define TXWI_W0_IFS FIELD32(0x08000000) -#define TXWI_W0_PHYMODE FIELD32(0xc0000000) - -/* - * Word1 - */ -#define TXWI_W1_ACK FIELD32(0x00000001) -#define TXWI_W1_NSEQ FIELD32(0x00000002) -#define TXWI_W1_BW_WIN_SIZE FIELD32(0x000000fc) -#define TXWI_W1_WIRELESS_CLI_ID FIELD32(0x0000ff00) -#define TXWI_W1_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) -#define TXWI_W1_PACKETID FIELD32(0xf0000000) - -/* - * Word2 - */ -#define TXWI_W2_IV FIELD32(0xffffffff) - -/* - * Word3 - */ -#define TXWI_W3_EIV FIELD32(0xffffffff) - /* * RX descriptor format for RX Ring. */ @@ -1897,64 +177,4 @@ struct mac_iveiv_entry { #define RXD_W3_PLCP_SIGNAL FIELD32(0x00020000) #define RXD_W3_PLCP_RSSI FIELD32(0x00040000) -/* - * RX WI structure - */ - -/* - * Word0 - */ -#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff) -#define RXWI_W0_KEY_INDEX FIELD32(0x00000300) -#define RXWI_W0_BSSID FIELD32(0x00001c00) -#define RXWI_W0_UDF FIELD32(0x0000e000) -#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) -#define RXWI_W0_TID FIELD32(0xf0000000) - -/* - * Word1 - */ -#define RXWI_W1_FRAG FIELD32(0x0000000f) -#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0) -#define RXWI_W1_MCS FIELD32(0x007f0000) -#define RXWI_W1_BW FIELD32(0x00800000) -#define RXWI_W1_SHORT_GI FIELD32(0x01000000) -#define RXWI_W1_STBC FIELD32(0x06000000) -#define RXWI_W1_PHYMODE FIELD32(0xc0000000) - -/* - * Word2 - */ -#define RXWI_W2_RSSI0 FIELD32(0x000000ff) -#define RXWI_W2_RSSI1 FIELD32(0x0000ff00) -#define RXWI_W2_RSSI2 FIELD32(0x00ff0000) - -/* - * Word3 - */ -#define RXWI_W3_SNR0 FIELD32(0x000000ff) -#define RXWI_W3_SNR1 FIELD32(0x0000ff00) - -/* - * Macros for converting txpower from EEPROM to mac80211 value - * and from mac80211 value to register value. - */ -#define MIN_G_TXPOWER 0 -#define MIN_A_TXPOWER -7 -#define MAX_G_TXPOWER 31 -#define MAX_A_TXPOWER 15 -#define DEFAULT_TXPOWER 5 - -#define TXPOWER_G_FROM_DEV(__txpower) \ - ((__txpower) > MAX_G_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) - -#define TXPOWER_G_TO_DEV(__txpower) \ - clamp_t(char, __txpower, MIN_G_TXPOWER, MAX_G_TXPOWER) - -#define TXPOWER_A_FROM_DEV(__txpower) \ - ((__txpower) > MAX_A_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) - -#define TXPOWER_A_TO_DEV(__txpower) \ - clamp_t(char, __txpower, MIN_A_TXPOWER, MAX_A_TXPOWER) - #endif /* RT2800PCI_H */ diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 0851dc672a8c..1383e55ff8ec 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -35,6 +35,7 @@ #include "rt2x00.h" #include "rt2x00usb.h" #include "rt2800lib.h" +#include "rt2800.h" #include "rt2800usb.h" /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 9d7bb54999cc..c9d7d40ee5fb 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -28,1443 +28,41 @@ #define RT2800USB_H /* - * RF chip defines. - * - * RF2820 2.4G 2T3R - * RF2850 2.4G/5G 2T3R - * RF2720 2.4G 1T2R - * RF2750 2.4G/5G 1T2R - * RF3020 2.4G 1T1R - * RF2020 2.4G B/G - * RF3021 2.4G 1T2R - * RF3022 2.4G 2T2R - * RF3052 2.4G 2T2R - */ -#define RF2820 0x0001 -#define RF2850 0x0002 -#define RF2720 0x0003 -#define RF2750 0x0004 -#define RF3020 0x0005 -#define RF2020 0x0006 -#define RF3021 0x0007 -#define RF3022 0x0008 -#define RF3052 0x0009 - -/* - * RT2870 version - */ -#define RT2860C_VERSION 0x28600100 -#define RT2860D_VERSION 0x28600101 -#define RT2880E_VERSION 0x28720200 -#define RT2883_VERSION 0x28830300 -#define RT3070_VERSION 0x30700200 - -/* - * Signal information. - * Default offset is required for RSSI <-> dBm conversion. - */ -#define DEFAULT_RSSI_OFFSET 120 /* FIXME */ - -/* - * Register layout information. - */ -#define CSR_REG_BASE 0x1000 -#define CSR_REG_SIZE 0x0800 -#define EEPROM_BASE 0x0000 -#define EEPROM_SIZE 0x0110 -#define BBP_BASE 0x0000 -#define BBP_SIZE 0x0080 -#define RF_BASE 0x0004 -#define RF_SIZE 0x0010 - -/* - * Number of TX queues. - */ -#define NUM_TX_QUEUES 4 - -/* - * USB registers. - */ - -/* - * INT_SOURCE_CSR: Interrupt source register. - * Write one to clear corresponding bit. - * TX_FIFO_STATUS: FIFO Statistics is full, sw should read 0x171c - */ -#define INT_SOURCE_CSR 0x0200 -#define INT_SOURCE_CSR_RXDELAYINT FIELD32(0x00000001) -#define INT_SOURCE_CSR_TXDELAYINT FIELD32(0x00000002) -#define INT_SOURCE_CSR_RX_DONE FIELD32(0x00000004) -#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00000008) -#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00000010) -#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00000020) -#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00000040) -#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00000080) -#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00000100) -#define INT_SOURCE_CSR_MCU_COMMAND FIELD32(0x00000200) -#define INT_SOURCE_CSR_RXTX_COHERENT FIELD32(0x00000400) -#define INT_SOURCE_CSR_TBTT FIELD32(0x00000800) -#define INT_SOURCE_CSR_PRE_TBTT FIELD32(0x00001000) -#define INT_SOURCE_CSR_TX_FIFO_STATUS FIELD32(0x00002000) -#define INT_SOURCE_CSR_AUTO_WAKEUP FIELD32(0x00004000) -#define INT_SOURCE_CSR_GPTIMER FIELD32(0x00008000) -#define INT_SOURCE_CSR_RX_COHERENT FIELD32(0x00010000) -#define INT_SOURCE_CSR_TX_COHERENT FIELD32(0x00020000) - -/* - * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF. - */ -#define INT_MASK_CSR 0x0204 -#define INT_MASK_CSR_RXDELAYINT FIELD32(0x00000001) -#define INT_MASK_CSR_TXDELAYINT FIELD32(0x00000002) -#define INT_MASK_CSR_RX_DONE FIELD32(0x00000004) -#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00000008) -#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00000010) -#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00000020) -#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00000040) -#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00000080) -#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00000100) -#define INT_MASK_CSR_MCU_COMMAND FIELD32(0x00000200) -#define INT_MASK_CSR_RXTX_COHERENT FIELD32(0x00000400) -#define INT_MASK_CSR_TBTT FIELD32(0x00000800) -#define INT_MASK_CSR_PRE_TBTT FIELD32(0x00001000) -#define INT_MASK_CSR_TX_FIFO_STATUS FIELD32(0x00002000) -#define INT_MASK_CSR_AUTO_WAKEUP FIELD32(0x00004000) -#define INT_MASK_CSR_GPTIMER FIELD32(0x00008000) -#define INT_MASK_CSR_RX_COHERENT FIELD32(0x00010000) -#define INT_MASK_CSR_TX_COHERENT FIELD32(0x00020000) - -/* - * WPDMA_GLO_CFG - */ -#define WPDMA_GLO_CFG 0x0208 -#define WPDMA_GLO_CFG_ENABLE_TX_DMA FIELD32(0x00000001) -#define WPDMA_GLO_CFG_TX_DMA_BUSY FIELD32(0x00000002) -#define WPDMA_GLO_CFG_ENABLE_RX_DMA FIELD32(0x00000004) -#define WPDMA_GLO_CFG_RX_DMA_BUSY FIELD32(0x00000008) -#define WPDMA_GLO_CFG_WP_DMA_BURST_SIZE FIELD32(0x00000030) -#define WPDMA_GLO_CFG_TX_WRITEBACK_DONE FIELD32(0x00000040) -#define WPDMA_GLO_CFG_BIG_ENDIAN FIELD32(0x00000080) -#define WPDMA_GLO_CFG_RX_HDR_SCATTER FIELD32(0x0000ff00) -#define WPDMA_GLO_CFG_HDR_SEG_LEN FIELD32(0xffff0000) - -/* - * WPDMA_RST_IDX - */ -#define WPDMA_RST_IDX 0x020c -#define WPDMA_RST_IDX_DTX_IDX0 FIELD32(0x00000001) -#define WPDMA_RST_IDX_DTX_IDX1 FIELD32(0x00000002) -#define WPDMA_RST_IDX_DTX_IDX2 FIELD32(0x00000004) -#define WPDMA_RST_IDX_DTX_IDX3 FIELD32(0x00000008) -#define WPDMA_RST_IDX_DTX_IDX4 FIELD32(0x00000010) -#define WPDMA_RST_IDX_DTX_IDX5 FIELD32(0x00000020) -#define WPDMA_RST_IDX_DRX_IDX0 FIELD32(0x00010000) - -/* - * DELAY_INT_CFG - */ -#define DELAY_INT_CFG 0x0210 -#define DELAY_INT_CFG_RXMAX_PTIME FIELD32(0x000000ff) -#define DELAY_INT_CFG_RXMAX_PINT FIELD32(0x00007f00) -#define DELAY_INT_CFG_RXDLY_INT_EN FIELD32(0x00008000) -#define DELAY_INT_CFG_TXMAX_PTIME FIELD32(0x00ff0000) -#define DELAY_INT_CFG_TXMAX_PINT FIELD32(0x7f000000) -#define DELAY_INT_CFG_TXDLY_INT_EN FIELD32(0x80000000) - -/* - * WMM_AIFSN_CFG: Aifsn for each EDCA AC - * AIFSN0: AC_BE - * AIFSN1: AC_BK - * AIFSN1: AC_VI - * AIFSN1: AC_VO - */ -#define WMM_AIFSN_CFG 0x0214 -#define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f) -#define WMM_AIFSN_CFG_AIFSN1 FIELD32(0x000000f0) -#define WMM_AIFSN_CFG_AIFSN2 FIELD32(0x00000f00) -#define WMM_AIFSN_CFG_AIFSN3 FIELD32(0x0000f000) - -/* - * WMM_CWMIN_CSR: CWmin for each EDCA AC - * CWMIN0: AC_BE - * CWMIN1: AC_BK - * CWMIN1: AC_VI - * CWMIN1: AC_VO - */ -#define WMM_CWMIN_CFG 0x0218 -#define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f) -#define WMM_CWMIN_CFG_CWMIN1 FIELD32(0x000000f0) -#define WMM_CWMIN_CFG_CWMIN2 FIELD32(0x00000f00) -#define WMM_CWMIN_CFG_CWMIN3 FIELD32(0x0000f000) - -/* - * WMM_CWMAX_CSR: CWmax for each EDCA AC - * CWMAX0: AC_BE - * CWMAX1: AC_BK - * CWMAX1: AC_VI - * CWMAX1: AC_VO - */ -#define WMM_CWMAX_CFG 0x021c -#define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f) -#define WMM_CWMAX_CFG_CWMAX1 FIELD32(0x000000f0) -#define WMM_CWMAX_CFG_CWMAX2 FIELD32(0x00000f00) -#define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000) - -/* - * AC_TXOP0: AC_BK/AC_BE TXOP register - * AC0TXOP: AC_BK in unit of 32us - * AC1TXOP: AC_BE in unit of 32us - */ -#define WMM_TXOP0_CFG 0x0220 -#define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff) -#define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000) - -/* - * AC_TXOP1: AC_VO/AC_VI TXOP register - * AC2TXOP: AC_VI in unit of 32us - * AC3TXOP: AC_VO in unit of 32us - */ -#define WMM_TXOP1_CFG 0x0224 -#define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff) -#define WMM_TXOP1_CFG_AC3TXOP FIELD32(0xffff0000) - -/* - * GPIO_CTRL_CFG: - */ -#define GPIO_CTRL_CFG 0x0228 -#define GPIO_CTRL_CFG_BIT0 FIELD32(0x00000001) -#define GPIO_CTRL_CFG_BIT1 FIELD32(0x00000002) -#define GPIO_CTRL_CFG_BIT2 FIELD32(0x00000004) -#define GPIO_CTRL_CFG_BIT3 FIELD32(0x00000008) -#define GPIO_CTRL_CFG_BIT4 FIELD32(0x00000010) -#define GPIO_CTRL_CFG_BIT5 FIELD32(0x00000020) -#define GPIO_CTRL_CFG_BIT6 FIELD32(0x00000040) -#define GPIO_CTRL_CFG_BIT7 FIELD32(0x00000080) -#define GPIO_CTRL_CFG_BIT8 FIELD32(0x00000100) - -/* - * MCU_CMD_CFG - */ -#define MCU_CMD_CFG 0x022c - -/* - * AC_BK register offsets - */ -#define TX_BASE_PTR0 0x0230 -#define TX_MAX_CNT0 0x0234 -#define TX_CTX_IDX0 0x0238 -#define TX_DTX_IDX0 0x023c - -/* - * AC_BE register offsets - */ -#define TX_BASE_PTR1 0x0240 -#define TX_MAX_CNT1 0x0244 -#define TX_CTX_IDX1 0x0248 -#define TX_DTX_IDX1 0x024c - -/* - * AC_VI register offsets - */ -#define TX_BASE_PTR2 0x0250 -#define TX_MAX_CNT2 0x0254 -#define TX_CTX_IDX2 0x0258 -#define TX_DTX_IDX2 0x025c - -/* - * AC_VO register offsets - */ -#define TX_BASE_PTR3 0x0260 -#define TX_MAX_CNT3 0x0264 -#define TX_CTX_IDX3 0x0268 -#define TX_DTX_IDX3 0x026c - -/* - * HCCA register offsets - */ -#define TX_BASE_PTR4 0x0270 -#define TX_MAX_CNT4 0x0274 -#define TX_CTX_IDX4 0x0278 -#define TX_DTX_IDX4 0x027c - -/* - * MGMT register offsets - */ -#define TX_BASE_PTR5 0x0280 -#define TX_MAX_CNT5 0x0284 -#define TX_CTX_IDX5 0x0288 -#define TX_DTX_IDX5 0x028c - -/* - * RX register offsets - */ -#define RX_BASE_PTR 0x0290 -#define RX_MAX_CNT 0x0294 -#define RX_CRX_IDX 0x0298 -#define RX_DRX_IDX 0x029c - -/* - * USB_DMA_CFG - * RX_BULK_AGG_TIMEOUT: Rx Bulk Aggregation TimeOut in unit of 33ns. - * RX_BULK_AGG_LIMIT: Rx Bulk Aggregation Limit in unit of 256 bytes. - * PHY_CLEAR: phy watch dog enable. - * TX_CLEAR: Clear USB DMA TX path. - * TXOP_HALT: Halt TXOP count down when TX buffer is full. - * RX_BULK_AGG_EN: Enable Rx Bulk Aggregation. - * RX_BULK_EN: Enable USB DMA Rx. - * TX_BULK_EN: Enable USB DMA Tx. - * EP_OUT_VALID: OUT endpoint data valid. - * RX_BUSY: USB DMA RX FSM busy. - * TX_BUSY: USB DMA TX FSM busy. - */ -#define USB_DMA_CFG 0x02a0 -#define USB_DMA_CFG_RX_BULK_AGG_TIMEOUT FIELD32(0x000000ff) -#define USB_DMA_CFG_RX_BULK_AGG_LIMIT FIELD32(0x0000ff00) -#define USB_DMA_CFG_PHY_CLEAR FIELD32(0x00010000) -#define USB_DMA_CFG_TX_CLEAR FIELD32(0x00080000) -#define USB_DMA_CFG_TXOP_HALT FIELD32(0x00100000) -#define USB_DMA_CFG_RX_BULK_AGG_EN FIELD32(0x00200000) -#define USB_DMA_CFG_RX_BULK_EN FIELD32(0x00400000) -#define USB_DMA_CFG_TX_BULK_EN FIELD32(0x00800000) -#define USB_DMA_CFG_EP_OUT_VALID FIELD32(0x3f000000) -#define USB_DMA_CFG_RX_BUSY FIELD32(0x40000000) -#define USB_DMA_CFG_TX_BUSY FIELD32(0x80000000) - -/* - * USB_CYC_CFG - */ -#define USB_CYC_CFG 0x02a4 -#define USB_CYC_CFG_CLOCK_CYCLE FIELD32(0x000000ff) - -/* - * PBF_SYS_CTRL - * HOST_RAM_WRITE: enable Host program ram write selection - */ -#define PBF_SYS_CTRL 0x0400 -#define PBF_SYS_CTRL_READY FIELD32(0x00000080) -#define PBF_SYS_CTRL_HOST_RAM_WRITE FIELD32(0x00010000) - -/* - * HOST-MCU shared memory - */ -#define HOST_CMD_CSR 0x0404 -#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x000000ff) - -/* - * PBF registers - * Most are for debug. Driver doesn't touch PBF register. - */ -#define PBF_CFG 0x0408 -#define PBF_MAX_PCNT 0x040c -#define PBF_CTRL 0x0410 -#define PBF_INT_STA 0x0414 -#define PBF_INT_ENA 0x0418 - -/* - * BCN_OFFSET0: - */ -#define BCN_OFFSET0 0x042c -#define BCN_OFFSET0_BCN0 FIELD32(0x000000ff) -#define BCN_OFFSET0_BCN1 FIELD32(0x0000ff00) -#define BCN_OFFSET0_BCN2 FIELD32(0x00ff0000) -#define BCN_OFFSET0_BCN3 FIELD32(0xff000000) - -/* - * BCN_OFFSET1: - */ -#define BCN_OFFSET1 0x0430 -#define BCN_OFFSET1_BCN4 FIELD32(0x000000ff) -#define BCN_OFFSET1_BCN5 FIELD32(0x0000ff00) -#define BCN_OFFSET1_BCN6 FIELD32(0x00ff0000) -#define BCN_OFFSET1_BCN7 FIELD32(0xff000000) - -/* - * PBF registers - * Most are for debug. Driver doesn't touch PBF register. - */ -#define TXRXQ_PCNT 0x0438 -#define PBF_DBG 0x043c - -/* - * RF registers - */ -#define RF_CSR_CFG 0x0500 -#define RF_CSR_CFG_DATA FIELD32(0x000000ff) -#define RF_CSR_CFG_REGNUM FIELD32(0x00001f00) -#define RF_CSR_CFG_WRITE FIELD32(0x00010000) -#define RF_CSR_CFG_BUSY FIELD32(0x00020000) - -/* - * MAC Control/Status Registers(CSR). - * Some values are set in TU, whereas 1 TU == 1024 us. - */ - -/* - * MAC_CSR0: ASIC revision number. - * ASIC_REV: 0 - * ASIC_VER: 2870 - */ -#define MAC_CSR0 0x1000 -#define MAC_CSR0_ASIC_REV FIELD32(0x0000ffff) -#define MAC_CSR0_ASIC_VER FIELD32(0xffff0000) - -/* - * MAC_SYS_CTRL: - */ -#define MAC_SYS_CTRL 0x1004 -#define MAC_SYS_CTRL_RESET_CSR FIELD32(0x00000001) -#define MAC_SYS_CTRL_RESET_BBP FIELD32(0x00000002) -#define MAC_SYS_CTRL_ENABLE_TX FIELD32(0x00000004) -#define MAC_SYS_CTRL_ENABLE_RX FIELD32(0x00000008) -#define MAC_SYS_CTRL_CONTINUOUS_TX FIELD32(0x00000010) -#define MAC_SYS_CTRL_LOOPBACK FIELD32(0x00000020) -#define MAC_SYS_CTRL_WLAN_HALT FIELD32(0x00000040) -#define MAC_SYS_CTRL_RX_TIMESTAMP FIELD32(0x00000080) - -/* - * MAC_ADDR_DW0: STA MAC register 0 - */ -#define MAC_ADDR_DW0 0x1008 -#define MAC_ADDR_DW0_BYTE0 FIELD32(0x000000ff) -#define MAC_ADDR_DW0_BYTE1 FIELD32(0x0000ff00) -#define MAC_ADDR_DW0_BYTE2 FIELD32(0x00ff0000) -#define MAC_ADDR_DW0_BYTE3 FIELD32(0xff000000) - -/* - * MAC_ADDR_DW1: STA MAC register 1 - * UNICAST_TO_ME_MASK: - * Used to mask off bits from byte 5 of the MAC address - * to determine the UNICAST_TO_ME bit for RX frames. - * The full mask is complemented by BSS_ID_MASK: - * MASK = BSS_ID_MASK & UNICAST_TO_ME_MASK - */ -#define MAC_ADDR_DW1 0x100c -#define MAC_ADDR_DW1_BYTE4 FIELD32(0x000000ff) -#define MAC_ADDR_DW1_BYTE5 FIELD32(0x0000ff00) -#define MAC_ADDR_DW1_UNICAST_TO_ME_MASK FIELD32(0x00ff0000) - -/* - * MAC_BSSID_DW0: BSSID register 0 - */ -#define MAC_BSSID_DW0 0x1010 -#define MAC_BSSID_DW0_BYTE0 FIELD32(0x000000ff) -#define MAC_BSSID_DW0_BYTE1 FIELD32(0x0000ff00) -#define MAC_BSSID_DW0_BYTE2 FIELD32(0x00ff0000) -#define MAC_BSSID_DW0_BYTE3 FIELD32(0xff000000) - -/* - * MAC_BSSID_DW1: BSSID register 1 - * BSS_ID_MASK: - * 0: 1-BSSID mode (BSS index = 0) - * 1: 2-BSSID mode (BSS index: Byte5, bit 0) - * 2: 4-BSSID mode (BSS index: byte5, bit 0 - 1) - * 3: 8-BSSID mode (BSS index: byte5, bit 0 - 2) - * This mask is used to mask off bits 0, 1 and 2 of byte 5 of the - * BSSID. This will make sure that those bits will be ignored - * when determining the MY_BSS of RX frames. - */ -#define MAC_BSSID_DW1 0x1014 -#define MAC_BSSID_DW1_BYTE4 FIELD32(0x000000ff) -#define MAC_BSSID_DW1_BYTE5 FIELD32(0x0000ff00) -#define MAC_BSSID_DW1_BSS_ID_MASK FIELD32(0x00030000) -#define MAC_BSSID_DW1_BSS_BCN_NUM FIELD32(0x001c0000) - -/* - * MAX_LEN_CFG: Maximum frame length register. - * MAX_MPDU: rt2860b max 16k bytes - * MAX_PSDU: Maximum PSDU length - * (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 - */ -#define MAX_LEN_CFG 0x1018 -#define MAX_LEN_CFG_MAX_MPDU FIELD32(0x00000fff) -#define MAX_LEN_CFG_MAX_PSDU FIELD32(0x00003000) -#define MAX_LEN_CFG_MIN_PSDU FIELD32(0x0000c000) -#define MAX_LEN_CFG_MIN_MPDU FIELD32(0x000f0000) - -/* - * BBP_CSR_CFG: BBP serial control register - * VALUE: Register value to program into BBP - * REG_NUM: Selected BBP register - * READ_CONTROL: 0 write BBP, 1 read BBP - * BUSY: ASIC is busy executing BBP commands - * BBP_PAR_DUR: 0 4 MAC clocks, 1 8 MAC clocks - * BBP_RW_MODE: 0 serial, 1 paralell - */ -#define BBP_CSR_CFG 0x101c -#define BBP_CSR_CFG_VALUE FIELD32(0x000000ff) -#define BBP_CSR_CFG_REGNUM FIELD32(0x0000ff00) -#define BBP_CSR_CFG_READ_CONTROL FIELD32(0x00010000) -#define BBP_CSR_CFG_BUSY FIELD32(0x00020000) -#define BBP_CSR_CFG_BBP_PAR_DUR FIELD32(0x00040000) -#define BBP_CSR_CFG_BBP_RW_MODE FIELD32(0x00080000) - -/* - * RF_CSR_CFG0: RF control register - * REGID_AND_VALUE: Register value to program into RF - * BITWIDTH: Selected RF register - * STANDBYMODE: 0 high when standby, 1 low when standby - * SEL: 0 RF_LE0 activate, 1 RF_LE1 activate - * BUSY: ASIC is busy executing RF commands - */ -#define RF_CSR_CFG0 0x1020 -#define RF_CSR_CFG0_REGID_AND_VALUE FIELD32(0x00ffffff) -#define RF_CSR_CFG0_BITWIDTH FIELD32(0x1f000000) -#define RF_CSR_CFG0_REG_VALUE_BW FIELD32(0x1fffffff) -#define RF_CSR_CFG0_STANDBYMODE FIELD32(0x20000000) -#define RF_CSR_CFG0_SEL FIELD32(0x40000000) -#define RF_CSR_CFG0_BUSY FIELD32(0x80000000) - -/* - * RF_CSR_CFG1: RF control register - * REGID_AND_VALUE: Register value to program into RF - * RFGAP: Gap between BB_CONTROL_RF and RF_LE - * 0: 3 system clock cycle (37.5usec) - * 1: 5 system clock cycle (62.5usec) - */ -#define RF_CSR_CFG1 0x1024 -#define RF_CSR_CFG1_REGID_AND_VALUE FIELD32(0x00ffffff) -#define RF_CSR_CFG1_RFGAP FIELD32(0x1f000000) - -/* - * RF_CSR_CFG2: RF control register - * VALUE: Register value to program into RF - * RFGAP: Gap between BB_CONTROL_RF and RF_LE - * 0: 3 system clock cycle (37.5usec) - * 1: 5 system clock cycle (62.5usec) - */ -#define RF_CSR_CFG2 0x1028 -#define RF_CSR_CFG2_VALUE FIELD32(0x00ffffff) - -/* - * LED_CFG: LED control - * color LED's: - * 0: off - * 1: blinking upon TX2 - * 2: periodic slow blinking - * 3: always on - * LED polarity: - * 0: active low - * 1: active high - */ -#define LED_CFG 0x102c -#define LED_CFG_ON_PERIOD FIELD32(0x000000ff) -#define LED_CFG_OFF_PERIOD FIELD32(0x0000ff00) -#define LED_CFG_SLOW_BLINK_PERIOD FIELD32(0x003f0000) -#define LED_CFG_R_LED_MODE FIELD32(0x03000000) -#define LED_CFG_G_LED_MODE FIELD32(0x0c000000) -#define LED_CFG_Y_LED_MODE FIELD32(0x30000000) -#define LED_CFG_LED_POLAR FIELD32(0x40000000) - -/* - * XIFS_TIME_CFG: MAC timing - * CCKM_SIFS_TIME: unit 1us. Applied after CCK RX/TX - * OFDM_SIFS_TIME: unit 1us. Applied after OFDM RX/TX - * OFDM_XIFS_TIME: unit 1us. Applied after OFDM RX - * when MAC doesn't reference BBP signal BBRXEND - * EIFS: unit 1us - * BB_RXEND_ENABLE: reference RXEND signal to begin XIFS defer - * - */ -#define XIFS_TIME_CFG 0x1100 -#define XIFS_TIME_CFG_CCKM_SIFS_TIME FIELD32(0x000000ff) -#define XIFS_TIME_CFG_OFDM_SIFS_TIME FIELD32(0x0000ff00) -#define XIFS_TIME_CFG_OFDM_XIFS_TIME FIELD32(0x000f0000) -#define XIFS_TIME_CFG_EIFS FIELD32(0x1ff00000) -#define XIFS_TIME_CFG_BB_RXEND_ENABLE FIELD32(0x20000000) - -/* - * BKOFF_SLOT_CFG: - */ -#define BKOFF_SLOT_CFG 0x1104 -#define BKOFF_SLOT_CFG_SLOT_TIME FIELD32(0x000000ff) -#define BKOFF_SLOT_CFG_CC_DELAY_TIME FIELD32(0x0000ff00) - -/* - * NAV_TIME_CFG: - */ -#define NAV_TIME_CFG 0x1108 -#define NAV_TIME_CFG_SIFS FIELD32(0x000000ff) -#define NAV_TIME_CFG_SLOT_TIME FIELD32(0x0000ff00) -#define NAV_TIME_CFG_EIFS FIELD32(0x01ff0000) -#define NAV_TIME_ZERO_SIFS FIELD32(0x02000000) - -/* - * CH_TIME_CFG: count as channel busy - */ -#define CH_TIME_CFG 0x110c - -/* - * PBF_LIFE_TIMER: TX/RX MPDU timestamp timer (free run) Unit: 1us - */ -#define PBF_LIFE_TIMER 0x1110 - -/* - * BCN_TIME_CFG: - * BEACON_INTERVAL: in unit of 1/16 TU - * TSF_TICKING: Enable TSF auto counting - * TSF_SYNC: Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode - * BEACON_GEN: Enable beacon generator - */ -#define BCN_TIME_CFG 0x1114 -#define BCN_TIME_CFG_BEACON_INTERVAL FIELD32(0x0000ffff) -#define BCN_TIME_CFG_TSF_TICKING FIELD32(0x00010000) -#define BCN_TIME_CFG_TSF_SYNC FIELD32(0x00060000) -#define BCN_TIME_CFG_TBTT_ENABLE FIELD32(0x00080000) -#define BCN_TIME_CFG_BEACON_GEN FIELD32(0x00100000) -#define BCN_TIME_CFG_TX_TIME_COMPENSATE FIELD32(0xf0000000) - -/* - * TBTT_SYNC_CFG: - */ -#define TBTT_SYNC_CFG 0x1118 - -/* - * TSF_TIMER_DW0: Local lsb TSF timer, read-only - */ -#define TSF_TIMER_DW0 0x111c -#define TSF_TIMER_DW0_LOW_WORD FIELD32(0xffffffff) - -/* - * TSF_TIMER_DW1: Local msb TSF timer, read-only - */ -#define TSF_TIMER_DW1 0x1120 -#define TSF_TIMER_DW1_HIGH_WORD FIELD32(0xffffffff) - -/* - * TBTT_TIMER: TImer remains till next TBTT, read-only - */ -#define TBTT_TIMER 0x1124 - -/* - * INT_TIMER_CFG: - */ -#define INT_TIMER_CFG 0x1128 - -/* - * INT_TIMER_EN: GP-timer and pre-tbtt Int enable - */ -#define INT_TIMER_EN 0x112c - -/* - * CH_IDLE_STA: channel idle time - */ -#define CH_IDLE_STA 0x1130 - -/* - * CH_BUSY_STA: channel busy time - */ -#define CH_BUSY_STA 0x1134 - -/* - * MAC_STATUS_CFG: - * BBP_RF_BUSY: When set to 0, BBP and RF are stable. - * if 1 or higher one of the 2 registers is busy. - */ -#define MAC_STATUS_CFG 0x1200 -#define MAC_STATUS_CFG_BBP_RF_BUSY FIELD32(0x00000003) - -/* - * PWR_PIN_CFG: - */ -#define PWR_PIN_CFG 0x1204 - -/* - * AUTOWAKEUP_CFG: Manual power control / status register - * TBCN_BEFORE_WAKE: ForceWake has high privilege than PutToSleep when both set - * AUTOWAKE: 0:sleep, 1:awake - */ -#define AUTOWAKEUP_CFG 0x1208 -#define AUTOWAKEUP_CFG_AUTO_LEAD_TIME FIELD32(0x000000ff) -#define AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE FIELD32(0x00007f00) -#define AUTOWAKEUP_CFG_AUTOWAKE FIELD32(0x00008000) - -/* - * EDCA_AC0_CFG: - */ -#define EDCA_AC0_CFG 0x1300 -#define EDCA_AC0_CFG_TX_OP FIELD32(0x000000ff) -#define EDCA_AC0_CFG_AIFSN FIELD32(0x00000f00) -#define EDCA_AC0_CFG_CWMIN FIELD32(0x0000f000) -#define EDCA_AC0_CFG_CWMAX FIELD32(0x000f0000) - -/* - * EDCA_AC1_CFG: - */ -#define EDCA_AC1_CFG 0x1304 -#define EDCA_AC1_CFG_TX_OP FIELD32(0x000000ff) -#define EDCA_AC1_CFG_AIFSN FIELD32(0x00000f00) -#define EDCA_AC1_CFG_CWMIN FIELD32(0x0000f000) -#define EDCA_AC1_CFG_CWMAX FIELD32(0x000f0000) - -/* - * EDCA_AC2_CFG: - */ -#define EDCA_AC2_CFG 0x1308 -#define EDCA_AC2_CFG_TX_OP FIELD32(0x000000ff) -#define EDCA_AC2_CFG_AIFSN FIELD32(0x00000f00) -#define EDCA_AC2_CFG_CWMIN FIELD32(0x0000f000) -#define EDCA_AC2_CFG_CWMAX FIELD32(0x000f0000) - -/* - * EDCA_AC3_CFG: - */ -#define EDCA_AC3_CFG 0x130c -#define EDCA_AC3_CFG_TX_OP FIELD32(0x000000ff) -#define EDCA_AC3_CFG_AIFSN FIELD32(0x00000f00) -#define EDCA_AC3_CFG_CWMIN FIELD32(0x0000f000) -#define EDCA_AC3_CFG_CWMAX FIELD32(0x000f0000) - -/* - * EDCA_TID_AC_MAP: - */ -#define EDCA_TID_AC_MAP 0x1310 - -/* - * TX_PWR_CFG_0: - */ -#define TX_PWR_CFG_0 0x1314 -#define TX_PWR_CFG_0_1MBS FIELD32(0x0000000f) -#define TX_PWR_CFG_0_2MBS FIELD32(0x000000f0) -#define TX_PWR_CFG_0_55MBS FIELD32(0x00000f00) -#define TX_PWR_CFG_0_11MBS FIELD32(0x0000f000) -#define TX_PWR_CFG_0_6MBS FIELD32(0x000f0000) -#define TX_PWR_CFG_0_9MBS FIELD32(0x00f00000) -#define TX_PWR_CFG_0_12MBS FIELD32(0x0f000000) -#define TX_PWR_CFG_0_18MBS FIELD32(0xf0000000) - -/* - * TX_PWR_CFG_1: - */ -#define TX_PWR_CFG_1 0x1318 -#define TX_PWR_CFG_1_24MBS FIELD32(0x0000000f) -#define TX_PWR_CFG_1_36MBS FIELD32(0x000000f0) -#define TX_PWR_CFG_1_48MBS FIELD32(0x00000f00) -#define TX_PWR_CFG_1_54MBS FIELD32(0x0000f000) -#define TX_PWR_CFG_1_MCS0 FIELD32(0x000f0000) -#define TX_PWR_CFG_1_MCS1 FIELD32(0x00f00000) -#define TX_PWR_CFG_1_MCS2 FIELD32(0x0f000000) -#define TX_PWR_CFG_1_MCS3 FIELD32(0xf0000000) - -/* - * TX_PWR_CFG_2: - */ -#define TX_PWR_CFG_2 0x131c -#define TX_PWR_CFG_2_MCS4 FIELD32(0x0000000f) -#define TX_PWR_CFG_2_MCS5 FIELD32(0x000000f0) -#define TX_PWR_CFG_2_MCS6 FIELD32(0x00000f00) -#define TX_PWR_CFG_2_MCS7 FIELD32(0x0000f000) -#define TX_PWR_CFG_2_MCS8 FIELD32(0x000f0000) -#define TX_PWR_CFG_2_MCS9 FIELD32(0x00f00000) -#define TX_PWR_CFG_2_MCS10 FIELD32(0x0f000000) -#define TX_PWR_CFG_2_MCS11 FIELD32(0xf0000000) - -/* - * TX_PWR_CFG_3: - */ -#define TX_PWR_CFG_3 0x1320 -#define TX_PWR_CFG_3_MCS12 FIELD32(0x0000000f) -#define TX_PWR_CFG_3_MCS13 FIELD32(0x000000f0) -#define TX_PWR_CFG_3_MCS14 FIELD32(0x00000f00) -#define TX_PWR_CFG_3_MCS15 FIELD32(0x0000f000) -#define TX_PWR_CFG_3_UKNOWN1 FIELD32(0x000f0000) -#define TX_PWR_CFG_3_UKNOWN2 FIELD32(0x00f00000) -#define TX_PWR_CFG_3_UKNOWN3 FIELD32(0x0f000000) -#define TX_PWR_CFG_3_UKNOWN4 FIELD32(0xf0000000) - -/* - * TX_PWR_CFG_4: - */ -#define TX_PWR_CFG_4 0x1324 -#define TX_PWR_CFG_4_UKNOWN5 FIELD32(0x0000000f) -#define TX_PWR_CFG_4_UKNOWN6 FIELD32(0x000000f0) -#define TX_PWR_CFG_4_UKNOWN7 FIELD32(0x00000f00) -#define TX_PWR_CFG_4_UKNOWN8 FIELD32(0x0000f000) - -/* - * TX_PIN_CFG: - */ -#define TX_PIN_CFG 0x1328 -#define TX_PIN_CFG_PA_PE_A0_EN FIELD32(0x00000001) -#define TX_PIN_CFG_PA_PE_G0_EN FIELD32(0x00000002) -#define TX_PIN_CFG_PA_PE_A1_EN FIELD32(0x00000004) -#define TX_PIN_CFG_PA_PE_G1_EN FIELD32(0x00000008) -#define TX_PIN_CFG_PA_PE_A0_POL FIELD32(0x00000010) -#define TX_PIN_CFG_PA_PE_G0_POL FIELD32(0x00000020) -#define TX_PIN_CFG_PA_PE_A1_POL FIELD32(0x00000040) -#define TX_PIN_CFG_PA_PE_G1_POL FIELD32(0x00000080) -#define TX_PIN_CFG_LNA_PE_A0_EN FIELD32(0x00000100) -#define TX_PIN_CFG_LNA_PE_G0_EN FIELD32(0x00000200) -#define TX_PIN_CFG_LNA_PE_A1_EN FIELD32(0x00000400) -#define TX_PIN_CFG_LNA_PE_G1_EN FIELD32(0x00000800) -#define TX_PIN_CFG_LNA_PE_A0_POL FIELD32(0x00001000) -#define TX_PIN_CFG_LNA_PE_G0_POL FIELD32(0x00002000) -#define TX_PIN_CFG_LNA_PE_A1_POL FIELD32(0x00004000) -#define TX_PIN_CFG_LNA_PE_G1_POL FIELD32(0x00008000) -#define TX_PIN_CFG_RFTR_EN FIELD32(0x00010000) -#define TX_PIN_CFG_RFTR_POL FIELD32(0x00020000) -#define TX_PIN_CFG_TRSW_EN FIELD32(0x00040000) -#define TX_PIN_CFG_TRSW_POL FIELD32(0x00080000) - -/* - * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz - */ -#define TX_BAND_CFG 0x132c -#define TX_BAND_CFG_HT40_PLUS FIELD32(0x00000001) -#define TX_BAND_CFG_A FIELD32(0x00000002) -#define TX_BAND_CFG_BG FIELD32(0x00000004) - -/* - * TX_SW_CFG0: - */ -#define TX_SW_CFG0 0x1330 - -/* - * TX_SW_CFG1: - */ -#define TX_SW_CFG1 0x1334 - -/* - * TX_SW_CFG2: - */ -#define TX_SW_CFG2 0x1338 - -/* - * TXOP_THRES_CFG: - */ -#define TXOP_THRES_CFG 0x133c - -/* - * TXOP_CTRL_CFG: - */ -#define TXOP_CTRL_CFG 0x1340 - -/* - * TX_RTS_CFG: - * RTS_THRES: unit:byte - * RTS_FBK_EN: enable rts rate fallback - */ -#define TX_RTS_CFG 0x1344 -#define TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT FIELD32(0x000000ff) -#define TX_RTS_CFG_RTS_THRES FIELD32(0x00ffff00) -#define TX_RTS_CFG_RTS_FBK_EN FIELD32(0x01000000) - -/* - * TX_TIMEOUT_CFG: - * MPDU_LIFETIME: expiration time = 2^(9+MPDU LIFE TIME) us - * RX_ACK_TIMEOUT: unit:slot. Used for TX procedure - * TX_OP_TIMEOUT: TXOP timeout value for TXOP truncation. - * it is recommended that: - * (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) - */ -#define TX_TIMEOUT_CFG 0x1348 -#define TX_TIMEOUT_CFG_MPDU_LIFETIME FIELD32(0x000000f0) -#define TX_TIMEOUT_CFG_RX_ACK_TIMEOUT FIELD32(0x0000ff00) -#define TX_TIMEOUT_CFG_TX_OP_TIMEOUT FIELD32(0x00ff0000) - -/* - * TX_RTY_CFG: - * SHORT_RTY_LIMIT: short retry limit - * LONG_RTY_LIMIT: long retry limit - * LONG_RTY_THRE: Long retry threshoold - * NON_AGG_RTY_MODE: Non-Aggregate MPDU retry mode - * 0:expired by retry limit, 1: expired by mpdu life timer - * AGG_RTY_MODE: Aggregate MPDU retry mode - * 0:expired by retry limit, 1: expired by mpdu life timer - * TX_AUTO_FB_ENABLE: Tx retry PHY rate auto fallback enable - */ -#define TX_RTY_CFG 0x134c -#define TX_RTY_CFG_SHORT_RTY_LIMIT FIELD32(0x000000ff) -#define TX_RTY_CFG_LONG_RTY_LIMIT FIELD32(0x0000ff00) -#define TX_RTY_CFG_LONG_RTY_THRE FIELD32(0x0fff0000) -#define TX_RTY_CFG_NON_AGG_RTY_MODE FIELD32(0x10000000) -#define TX_RTY_CFG_AGG_RTY_MODE FIELD32(0x20000000) -#define TX_RTY_CFG_TX_AUTO_FB_ENABLE FIELD32(0x40000000) - -/* - * TX_LINK_CFG: - * REMOTE_MFB_LIFETIME: remote MFB life time. unit: 32us - * MFB_ENABLE: TX apply remote MFB 1:enable - * REMOTE_UMFS_ENABLE: remote unsolicit MFB enable - * 0: not apply remote remote unsolicit (MFS=7) - * TX_MRQ_EN: MCS request TX enable - * TX_RDG_EN: RDG TX enable - * TX_CF_ACK_EN: Piggyback CF-ACK enable - * REMOTE_MFB: remote MCS feedback - * REMOTE_MFS: remote MCS feedback sequence number - */ -#define TX_LINK_CFG 0x1350 -#define TX_LINK_CFG_REMOTE_MFB_LIFETIME FIELD32(0x000000ff) -#define TX_LINK_CFG_MFB_ENABLE FIELD32(0x00000100) -#define TX_LINK_CFG_REMOTE_UMFS_ENABLE FIELD32(0x00000200) -#define TX_LINK_CFG_TX_MRQ_EN FIELD32(0x00000400) -#define TX_LINK_CFG_TX_RDG_EN FIELD32(0x00000800) -#define TX_LINK_CFG_TX_CF_ACK_EN FIELD32(0x00001000) -#define TX_LINK_CFG_REMOTE_MFB FIELD32(0x00ff0000) -#define TX_LINK_CFG_REMOTE_MFS FIELD32(0xff000000) - -/* - * HT_FBK_CFG0: - */ -#define HT_FBK_CFG0 0x1354 -#define HT_FBK_CFG0_HTMCS0FBK FIELD32(0x0000000f) -#define HT_FBK_CFG0_HTMCS1FBK FIELD32(0x000000f0) -#define HT_FBK_CFG0_HTMCS2FBK FIELD32(0x00000f00) -#define HT_FBK_CFG0_HTMCS3FBK FIELD32(0x0000f000) -#define HT_FBK_CFG0_HTMCS4FBK FIELD32(0x000f0000) -#define HT_FBK_CFG0_HTMCS5FBK FIELD32(0x00f00000) -#define HT_FBK_CFG0_HTMCS6FBK FIELD32(0x0f000000) -#define HT_FBK_CFG0_HTMCS7FBK FIELD32(0xf0000000) - -/* - * HT_FBK_CFG1: - */ -#define HT_FBK_CFG1 0x1358 -#define HT_FBK_CFG1_HTMCS8FBK FIELD32(0x0000000f) -#define HT_FBK_CFG1_HTMCS9FBK FIELD32(0x000000f0) -#define HT_FBK_CFG1_HTMCS10FBK FIELD32(0x00000f00) -#define HT_FBK_CFG1_HTMCS11FBK FIELD32(0x0000f000) -#define HT_FBK_CFG1_HTMCS12FBK FIELD32(0x000f0000) -#define HT_FBK_CFG1_HTMCS13FBK FIELD32(0x00f00000) -#define HT_FBK_CFG1_HTMCS14FBK FIELD32(0x0f000000) -#define HT_FBK_CFG1_HTMCS15FBK FIELD32(0xf0000000) - -/* - * LG_FBK_CFG0: - */ -#define LG_FBK_CFG0 0x135c -#define LG_FBK_CFG0_OFDMMCS0FBK FIELD32(0x0000000f) -#define LG_FBK_CFG0_OFDMMCS1FBK FIELD32(0x000000f0) -#define LG_FBK_CFG0_OFDMMCS2FBK FIELD32(0x00000f00) -#define LG_FBK_CFG0_OFDMMCS3FBK FIELD32(0x0000f000) -#define LG_FBK_CFG0_OFDMMCS4FBK FIELD32(0x000f0000) -#define LG_FBK_CFG0_OFDMMCS5FBK FIELD32(0x00f00000) -#define LG_FBK_CFG0_OFDMMCS6FBK FIELD32(0x0f000000) -#define LG_FBK_CFG0_OFDMMCS7FBK FIELD32(0xf0000000) - -/* - * LG_FBK_CFG1: - */ -#define LG_FBK_CFG1 0x1360 -#define LG_FBK_CFG0_CCKMCS0FBK FIELD32(0x0000000f) -#define LG_FBK_CFG0_CCKMCS1FBK FIELD32(0x000000f0) -#define LG_FBK_CFG0_CCKMCS2FBK FIELD32(0x00000f00) -#define LG_FBK_CFG0_CCKMCS3FBK FIELD32(0x0000f000) - -/* - * CCK_PROT_CFG: CCK Protection - * PROTECT_RATE: Protection control frame rate for CCK TX(RTS/CTS/CFEnd) - * PROTECT_CTRL: Protection control frame type for CCK TX - * 0:none, 1:RTS/CTS, 2:CTS-to-self - * PROTECT_NAV: TXOP protection type for CCK TX - * 0:none, 1:ShortNAVprotect, 2:LongNAVProtect - * TX_OP_ALLOW_CCK: CCK TXOP allowance, 0:disallow - * TX_OP_ALLOW_OFDM: CCK TXOP allowance, 0:disallow - * TX_OP_ALLOW_MM20: CCK TXOP allowance, 0:disallow - * TX_OP_ALLOW_MM40: CCK TXOP allowance, 0:disallow - * TX_OP_ALLOW_GF20: CCK TXOP allowance, 0:disallow - * TX_OP_ALLOW_GF40: CCK TXOP allowance, 0:disallow - * RTS_TH_EN: RTS threshold enable on CCK TX - */ -#define CCK_PROT_CFG 0x1364 -#define CCK_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define CCK_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define CCK_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define CCK_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define CCK_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define CCK_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define CCK_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define CCK_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define CCK_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define CCK_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * OFDM_PROT_CFG: OFDM Protection - */ -#define OFDM_PROT_CFG 0x1368 -#define OFDM_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define OFDM_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define OFDM_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define OFDM_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define OFDM_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * MM20_PROT_CFG: MM20 Protection - */ -#define MM20_PROT_CFG 0x136c -#define MM20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define MM20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define MM20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define MM20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define MM20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define MM20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define MM20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define MM20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define MM20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define MM20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * MM40_PROT_CFG: MM40 Protection - */ -#define MM40_PROT_CFG 0x1370 -#define MM40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define MM40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define MM40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define MM40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define MM40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define MM40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define MM40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define MM40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define MM40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define MM40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * GF20_PROT_CFG: GF20 Protection - */ -#define GF20_PROT_CFG 0x1374 -#define GF20_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define GF20_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define GF20_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define GF20_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define GF20_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define GF20_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define GF20_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define GF20_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define GF20_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define GF20_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * GF40_PROT_CFG: GF40 Protection - */ -#define GF40_PROT_CFG 0x1378 -#define GF40_PROT_CFG_PROTECT_RATE FIELD32(0x0000ffff) -#define GF40_PROT_CFG_PROTECT_CTRL FIELD32(0x00030000) -#define GF40_PROT_CFG_PROTECT_NAV FIELD32(0x000c0000) -#define GF40_PROT_CFG_TX_OP_ALLOW_CCK FIELD32(0x00100000) -#define GF40_PROT_CFG_TX_OP_ALLOW_OFDM FIELD32(0x00200000) -#define GF40_PROT_CFG_TX_OP_ALLOW_MM20 FIELD32(0x00400000) -#define GF40_PROT_CFG_TX_OP_ALLOW_MM40 FIELD32(0x00800000) -#define GF40_PROT_CFG_TX_OP_ALLOW_GF20 FIELD32(0x01000000) -#define GF40_PROT_CFG_TX_OP_ALLOW_GF40 FIELD32(0x02000000) -#define GF40_PROT_CFG_RTS_TH_EN FIELD32(0x04000000) - -/* - * EXP_CTS_TIME: - */ -#define EXP_CTS_TIME 0x137c - -/* - * EXP_ACK_TIME: - */ -#define EXP_ACK_TIME 0x1380 - -/* - * RX_FILTER_CFG: RX configuration register. - */ -#define RX_FILTER_CFG 0x1400 -#define RX_FILTER_CFG_DROP_CRC_ERROR FIELD32(0x00000001) -#define RX_FILTER_CFG_DROP_PHY_ERROR FIELD32(0x00000002) -#define RX_FILTER_CFG_DROP_NOT_TO_ME FIELD32(0x00000004) -#define RX_FILTER_CFG_DROP_NOT_MY_BSSD FIELD32(0x00000008) -#define RX_FILTER_CFG_DROP_VER_ERROR FIELD32(0x00000010) -#define RX_FILTER_CFG_DROP_MULTICAST FIELD32(0x00000020) -#define RX_FILTER_CFG_DROP_BROADCAST FIELD32(0x00000040) -#define RX_FILTER_CFG_DROP_DUPLICATE FIELD32(0x00000080) -#define RX_FILTER_CFG_DROP_CF_END_ACK FIELD32(0x00000100) -#define RX_FILTER_CFG_DROP_CF_END FIELD32(0x00000200) -#define RX_FILTER_CFG_DROP_ACK FIELD32(0x00000400) -#define RX_FILTER_CFG_DROP_CTS FIELD32(0x00000800) -#define RX_FILTER_CFG_DROP_RTS FIELD32(0x00001000) -#define RX_FILTER_CFG_DROP_PSPOLL FIELD32(0x00002000) -#define RX_FILTER_CFG_DROP_BA FIELD32(0x00004000) -#define RX_FILTER_CFG_DROP_BAR FIELD32(0x00008000) -#define RX_FILTER_CFG_DROP_CNTL FIELD32(0x00010000) - -/* - * AUTO_RSP_CFG: - * AUTORESPONDER: 0: disable, 1: enable - * BAC_ACK_POLICY: 0:long, 1:short preamble - * CTS_40_MMODE: Response CTS 40MHz duplicate mode - * CTS_40_MREF: Response CTS 40MHz duplicate mode - * AR_PREAMBLE: Auto responder preamble 0:long, 1:short preamble - * DUAL_CTS_EN: Power bit value in control frame - * ACK_CTS_PSM_BIT:Power bit value in control frame - */ -#define AUTO_RSP_CFG 0x1404 -#define AUTO_RSP_CFG_AUTORESPONDER FIELD32(0x00000001) -#define AUTO_RSP_CFG_BAC_ACK_POLICY FIELD32(0x00000002) -#define AUTO_RSP_CFG_CTS_40_MMODE FIELD32(0x00000004) -#define AUTO_RSP_CFG_CTS_40_MREF FIELD32(0x00000008) -#define AUTO_RSP_CFG_AR_PREAMBLE FIELD32(0x00000010) -#define AUTO_RSP_CFG_DUAL_CTS_EN FIELD32(0x00000040) -#define AUTO_RSP_CFG_ACK_CTS_PSM_BIT FIELD32(0x00000080) - -/* - * LEGACY_BASIC_RATE: - */ -#define LEGACY_BASIC_RATE 0x1408 - -/* - * HT_BASIC_RATE: - */ -#define HT_BASIC_RATE 0x140c - -/* - * HT_CTRL_CFG: - */ -#define HT_CTRL_CFG 0x1410 - -/* - * SIFS_COST_CFG: - */ -#define SIFS_COST_CFG 0x1414 - -/* - * RX_PARSER_CFG: - * Set NAV for all received frames - */ -#define RX_PARSER_CFG 0x1418 - -/* - * TX_SEC_CNT0: - */ -#define TX_SEC_CNT0 0x1500 - -/* - * RX_SEC_CNT0: - */ -#define RX_SEC_CNT0 0x1504 - -/* - * CCMP_FC_MUTE: - */ -#define CCMP_FC_MUTE 0x1508 - -/* - * TXOP_HLDR_ADDR0: - */ -#define TXOP_HLDR_ADDR0 0x1600 - -/* - * TXOP_HLDR_ADDR1: - */ -#define TXOP_HLDR_ADDR1 0x1604 - -/* - * TXOP_HLDR_ET: - */ -#define TXOP_HLDR_ET 0x1608 - -/* - * QOS_CFPOLL_RA_DW0: - */ -#define QOS_CFPOLL_RA_DW0 0x160c - -/* - * QOS_CFPOLL_RA_DW1: - */ -#define QOS_CFPOLL_RA_DW1 0x1610 - -/* - * QOS_CFPOLL_QC: - */ -#define QOS_CFPOLL_QC 0x1614 - -/* - * RX_STA_CNT0: RX PLCP error count & RX CRC error count - */ -#define RX_STA_CNT0 0x1700 -#define RX_STA_CNT0_CRC_ERR FIELD32(0x0000ffff) -#define RX_STA_CNT0_PHY_ERR FIELD32(0xffff0000) - -/* - * RX_STA_CNT1: RX False CCA count & RX LONG frame count - */ -#define RX_STA_CNT1 0x1704 -#define RX_STA_CNT1_FALSE_CCA FIELD32(0x0000ffff) -#define RX_STA_CNT1_PLCP_ERR FIELD32(0xffff0000) - -/* - * RX_STA_CNT2: - */ -#define RX_STA_CNT2 0x1708 -#define RX_STA_CNT2_RX_DUPLI_COUNT FIELD32(0x0000ffff) -#define RX_STA_CNT2_RX_FIFO_OVERFLOW FIELD32(0xffff0000) - -/* - * TX_STA_CNT0: TX Beacon count - */ -#define TX_STA_CNT0 0x170c -#define TX_STA_CNT0_TX_FAIL_COUNT FIELD32(0x0000ffff) -#define TX_STA_CNT0_TX_BEACON_COUNT FIELD32(0xffff0000) - -/* - * TX_STA_CNT1: TX tx count - */ -#define TX_STA_CNT1 0x1710 -#define TX_STA_CNT1_TX_SUCCESS FIELD32(0x0000ffff) -#define TX_STA_CNT1_TX_RETRANSMIT FIELD32(0xffff0000) - -/* - * TX_STA_CNT2: TX tx count - */ -#define TX_STA_CNT2 0x1714 -#define TX_STA_CNT2_TX_ZERO_LEN_COUNT FIELD32(0x0000ffff) -#define TX_STA_CNT2_TX_UNDER_FLOW_COUNT FIELD32(0xffff0000) - -/* - * TX_STA_FIFO: TX Result for specific PID status fifo register - */ -#define TX_STA_FIFO 0x1718 -#define TX_STA_FIFO_VALID FIELD32(0x00000001) -#define TX_STA_FIFO_PID_TYPE FIELD32(0x0000001e) -#define TX_STA_FIFO_TX_SUCCESS FIELD32(0x00000020) -#define TX_STA_FIFO_TX_AGGRE FIELD32(0x00000040) -#define TX_STA_FIFO_TX_ACK_REQUIRED FIELD32(0x00000080) -#define TX_STA_FIFO_WCID FIELD32(0x0000ff00) -#define TX_STA_FIFO_SUCCESS_RATE FIELD32(0xffff0000) - -/* - * TX_AGG_CNT: Debug counter - */ -#define TX_AGG_CNT 0x171c -#define TX_AGG_CNT_NON_AGG_TX_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT_AGG_TX_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT0: - */ -#define TX_AGG_CNT0 0x1720 -#define TX_AGG_CNT0_AGG_SIZE_1_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT0_AGG_SIZE_2_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT1: - */ -#define TX_AGG_CNT1 0x1724 -#define TX_AGG_CNT1_AGG_SIZE_3_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT1_AGG_SIZE_4_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT2: - */ -#define TX_AGG_CNT2 0x1728 -#define TX_AGG_CNT2_AGG_SIZE_5_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT2_AGG_SIZE_6_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT3: - */ -#define TX_AGG_CNT3 0x172c -#define TX_AGG_CNT3_AGG_SIZE_7_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT3_AGG_SIZE_8_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT4: - */ -#define TX_AGG_CNT4 0x1730 -#define TX_AGG_CNT4_AGG_SIZE_9_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT4_AGG_SIZE_10_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT5: - */ -#define TX_AGG_CNT5 0x1734 -#define TX_AGG_CNT5_AGG_SIZE_11_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT5_AGG_SIZE_12_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT6: - */ -#define TX_AGG_CNT6 0x1738 -#define TX_AGG_CNT6_AGG_SIZE_13_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT6_AGG_SIZE_14_COUNT FIELD32(0xffff0000) - -/* - * TX_AGG_CNT7: - */ -#define TX_AGG_CNT7 0x173c -#define TX_AGG_CNT7_AGG_SIZE_15_COUNT FIELD32(0x0000ffff) -#define TX_AGG_CNT7_AGG_SIZE_16_COUNT FIELD32(0xffff0000) - -/* - * MPDU_DENSITY_CNT: - * TX_ZERO_DEL: TX zero length delimiter count - * RX_ZERO_DEL: RX zero length delimiter count - */ -#define MPDU_DENSITY_CNT 0x1740 -#define MPDU_DENSITY_CNT_TX_ZERO_DEL FIELD32(0x0000ffff) -#define MPDU_DENSITY_CNT_RX_ZERO_DEL FIELD32(0xffff0000) - -/* - * Security key table memory. - * MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry - * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry - * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry - * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry - * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry - * SHARED_KEY_MODE_BASE: 4 bits * 32-entry - */ -#define MAC_WCID_BASE 0x1800 -#define PAIRWISE_KEY_TABLE_BASE 0x4000 -#define MAC_IVEIV_TABLE_BASE 0x6000 -#define MAC_WCID_ATTRIBUTE_BASE 0x6800 -#define SHARED_KEY_TABLE_BASE 0x6c00 -#define SHARED_KEY_MODE_BASE 0x7000 - -#define MAC_WCID_ENTRY(__idx) \ - ( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) ) -#define PAIRWISE_KEY_ENTRY(__idx) \ - ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) -#define MAC_IVEIV_ENTRY(__idx) \ - ( MAC_IVEIV_TABLE_BASE + ((__idx) & sizeof(struct mac_iveiv_entry)) ) -#define MAC_WCID_ATTR_ENTRY(__idx) \ - ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) ) -#define SHARED_KEY_ENTRY(__idx) \ - ( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) -#define SHARED_KEY_MODE_ENTRY(__idx) \ - ( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) ) - -struct mac_wcid_entry { - u8 mac[6]; - u8 reserved[2]; -} __attribute__ ((packed)); - -struct hw_key_entry { - u8 key[16]; - u8 tx_mic[8]; - u8 rx_mic[8]; -} __attribute__ ((packed)); - -struct mac_iveiv_entry { - u8 iv[8]; -} __attribute__ ((packed)); - -/* - * MAC_WCID_ATTRIBUTE: - */ -#define MAC_WCID_ATTRIBUTE_KEYTAB FIELD32(0x00000001) -#define MAC_WCID_ATTRIBUTE_CIPHER FIELD32(0x0000000e) -#define MAC_WCID_ATTRIBUTE_BSS_IDX FIELD32(0x00000070) -#define MAC_WCID_ATTRIBUTE_RX_WIUDF FIELD32(0x00000380) - -/* - * SHARED_KEY_MODE: - */ -#define SHARED_KEY_MODE_BSS0_KEY0 FIELD32(0x00000007) -#define SHARED_KEY_MODE_BSS0_KEY1 FIELD32(0x00000070) -#define SHARED_KEY_MODE_BSS0_KEY2 FIELD32(0x00000700) -#define SHARED_KEY_MODE_BSS0_KEY3 FIELD32(0x00007000) -#define SHARED_KEY_MODE_BSS1_KEY0 FIELD32(0x00070000) -#define SHARED_KEY_MODE_BSS1_KEY1 FIELD32(0x00700000) -#define SHARED_KEY_MODE_BSS1_KEY2 FIELD32(0x07000000) -#define SHARED_KEY_MODE_BSS1_KEY3 FIELD32(0x70000000) - -/* - * HOST-MCU communication - */ - -/* - * H2M_MAILBOX_CSR: Host-to-MCU Mailbox. - */ -#define H2M_MAILBOX_CSR 0x7010 -#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff) -#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00) -#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000) -#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000) - -/* - * H2M_MAILBOX_CID: - */ -#define H2M_MAILBOX_CID 0x7014 -#define H2M_MAILBOX_CID_CMD0 FIELD32(0x000000ff) -#define H2M_MAILBOX_CID_CMD1 FIELD32(0x0000ff00) -#define H2M_MAILBOX_CID_CMD2 FIELD32(0x00ff0000) -#define H2M_MAILBOX_CID_CMD3 FIELD32(0xff000000) - -/* - * H2M_MAILBOX_STATUS: - */ -#define H2M_MAILBOX_STATUS 0x701c - -/* - * H2M_INT_SRC: - */ -#define H2M_INT_SRC 0x7024 - -/* - * H2M_BBP_AGENT: - */ -#define H2M_BBP_AGENT 0x7028 - -/* - * MCU_LEDCS: LED control for MCU Mailbox. - */ -#define MCU_LEDCS_LED_MODE FIELD8(0x1f) -#define MCU_LEDCS_POLARITY FIELD8(0x01) - -/* - * HW_CS_CTS_BASE: - * Carrier-sense CTS frame base address. - * It's where mac stores carrier-sense frame for carrier-sense function. - */ -#define HW_CS_CTS_BASE 0x7700 - -/* - * HW_DFS_CTS_BASE: - * FS CTS frame base address. It's where mac stores CTS frame for DFS. - */ -#define HW_DFS_CTS_BASE 0x7780 - -/* - * TXRX control registers - base address 0x3000 - */ - -/* - * TXRX_CSR1: - * rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first.. + * USB registers. */ -#define TXRX_CSR1 0x77d0 /* - * HW_DEBUG_SETTING_BASE: - * since NULL frame won't be that long (256 byte) - * We steal 16 tail bytes to save debugging settings + * USB_DMA_CFG + * RX_BULK_AGG_TIMEOUT: Rx Bulk Aggregation TimeOut in unit of 33ns. + * RX_BULK_AGG_LIMIT: Rx Bulk Aggregation Limit in unit of 256 bytes. + * PHY_CLEAR: phy watch dog enable. + * TX_CLEAR: Clear USB DMA TX path. + * TXOP_HALT: Halt TXOP count down when TX buffer is full. + * RX_BULK_AGG_EN: Enable Rx Bulk Aggregation. + * RX_BULK_EN: Enable USB DMA Rx. + * TX_BULK_EN: Enable USB DMA Tx. + * EP_OUT_VALID: OUT endpoint data valid. + * RX_BUSY: USB DMA RX FSM busy. + * TX_BUSY: USB DMA TX FSM busy. */ -#define HW_DEBUG_SETTING_BASE 0x77f0 -#define HW_DEBUG_SETTING_BASE2 0x7770 +#define USB_DMA_CFG 0x02a0 +#define USB_DMA_CFG_RX_BULK_AGG_TIMEOUT FIELD32(0x000000ff) +#define USB_DMA_CFG_RX_BULK_AGG_LIMIT FIELD32(0x0000ff00) +#define USB_DMA_CFG_PHY_CLEAR FIELD32(0x00010000) +#define USB_DMA_CFG_TX_CLEAR FIELD32(0x00080000) +#define USB_DMA_CFG_TXOP_HALT FIELD32(0x00100000) +#define USB_DMA_CFG_RX_BULK_AGG_EN FIELD32(0x00200000) +#define USB_DMA_CFG_RX_BULK_EN FIELD32(0x00400000) +#define USB_DMA_CFG_TX_BULK_EN FIELD32(0x00800000) +#define USB_DMA_CFG_EP_OUT_VALID FIELD32(0x3f000000) +#define USB_DMA_CFG_RX_BUSY FIELD32(0x40000000) +#define USB_DMA_CFG_TX_BUSY FIELD32(0x80000000) /* - * HW_BEACON_BASE - * In order to support maximum 8 MBSS and its maximum length - * is 512 bytes for each beacon - * Three section discontinue memory segments will be used. - * 1. The original region for BCN 0~3 - * 2. Extract memory from FCE table for BCN 4~5 - * 3. Extract memory from Pair-wise key table for BCN 6~7 - * It occupied those memory of wcid 238~253 for BCN 6 - * and wcid 222~237 for BCN 7 - * - * IMPORTANT NOTE: Not sure why legacy driver does this, - * but HW_BEACON_BASE7 is 0x0200 bytes below HW_BEACON_BASE6. + * USB_CYC_CFG */ -#define HW_BEACON_BASE0 0x7800 -#define HW_BEACON_BASE1 0x7a00 -#define HW_BEACON_BASE2 0x7c00 -#define HW_BEACON_BASE3 0x7e00 -#define HW_BEACON_BASE4 0x7200 -#define HW_BEACON_BASE5 0x7400 -#define HW_BEACON_BASE6 0x5dc0 -#define HW_BEACON_BASE7 0x5bc0 - -#define HW_BEACON_OFFSET(__index) \ - ( ((__index) < 4) ? ( HW_BEACON_BASE0 + (__index * 0x0200) ) : \ - (((__index) < 6) ? ( HW_BEACON_BASE4 + ((__index - 4) * 0x0200) ) : \ - (HW_BEACON_BASE6 - ((__index - 6) * 0x0200))) ) +#define USB_CYC_CFG 0x02a4 +#define USB_CYC_CFG_CLOCK_CYCLE FIELD32(0x000000ff) /* * 8051 firmware image. @@ -1472,320 +70,11 @@ struct mac_iveiv_entry { #define FIRMWARE_RT2870 "rt2870.bin" #define FIRMWARE_IMAGE_BASE 0x3000 -/* - * BBP registers. - * The wordsize of the BBP is 8 bits. - */ - -/* - * BBP 1: TX Antenna - */ -#define BBP1_TX_POWER FIELD8(0x07) -#define BBP1_TX_ANTENNA FIELD8(0x18) - -/* - * BBP 3: RX Antenna - */ -#define BBP3_RX_ANTENNA FIELD8(0x18) -#define BBP3_HT40_PLUS FIELD8(0x20) - -/* - * BBP 4: Bandwidth - */ -#define BBP4_TX_BF FIELD8(0x01) -#define BBP4_BANDWIDTH FIELD8(0x18) - -/* - * RFCSR registers - * The wordsize of the RFCSR is 8 bits. - */ - -/* - * RFCSR 6: - */ -#define RFCSR6_R FIELD8(0x03) - -/* - * RFCSR 7: - */ -#define RFCSR7_RF_TUNING FIELD8(0x01) - -/* - * RFCSR 12: - */ -#define RFCSR12_TX_POWER FIELD8(0x1f) - -/* - * RFCSR 22: - */ -#define RFCSR22_BASEBAND_LOOPBACK FIELD8(0x01) - -/* - * RFCSR 23: - */ -#define RFCSR23_FREQ_OFFSET FIELD8(0x7f) - -/* - * RFCSR 30: - */ -#define RFCSR30_RF_CALIBRATION FIELD8(0x80) - -/* - * RF registers - */ - -/* - * RF 2 - */ -#define RF2_ANTENNA_RX2 FIELD32(0x00000040) -#define RF2_ANTENNA_TX1 FIELD32(0x00004000) -#define RF2_ANTENNA_RX1 FIELD32(0x00020000) - -/* - * RF 3 - */ -#define RF3_TXPOWER_G FIELD32(0x00003e00) -#define RF3_TXPOWER_A_7DBM_BOOST FIELD32(0x00000200) -#define RF3_TXPOWER_A FIELD32(0x00003c00) - -/* - * RF 4 - */ -#define RF4_TXPOWER_G FIELD32(0x000007c0) -#define RF4_TXPOWER_A_7DBM_BOOST FIELD32(0x00000040) -#define RF4_TXPOWER_A FIELD32(0x00000780) -#define RF4_FREQ_OFFSET FIELD32(0x001f8000) -#define RF4_HT40 FIELD32(0x00200000) - -/* - * EEPROM content. - * The wordsize of the EEPROM is 16 bits. - */ - -/* - * EEPROM Version - */ -#define EEPROM_VERSION 0x0001 -#define EEPROM_VERSION_FAE FIELD16(0x00ff) -#define EEPROM_VERSION_VERSION FIELD16(0xff00) - -/* - * HW MAC address. - */ -#define EEPROM_MAC_ADDR_0 0x0002 -#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff) -#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00) -#define EEPROM_MAC_ADDR_1 0x0003 -#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff) -#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00) -#define EEPROM_MAC_ADDR_2 0x0004 -#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff) -#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00) - -/* - * EEPROM ANTENNA config - * RXPATH: 1: 1R, 2: 2R, 3: 3R - * TXPATH: 1: 1T, 2: 2T - */ -#define EEPROM_ANTENNA 0x001a -#define EEPROM_ANTENNA_RXPATH FIELD16(0x000f) -#define EEPROM_ANTENNA_TXPATH FIELD16(0x00f0) -#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0f00) - -/* - * EEPROM NIC config - * CARDBUS_ACCEL: 0 - enable, 1 - disable - */ -#define EEPROM_NIC 0x001b -#define EEPROM_NIC_HW_RADIO FIELD16(0x0001) -#define EEPROM_NIC_DYNAMIC_TX_AGC FIELD16(0x0002) -#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0004) -#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0008) -#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0010) -#define EEPROM_NIC_BW40M_SB_BG FIELD16(0x0020) -#define EEPROM_NIC_BW40M_SB_A FIELD16(0x0040) -#define EEPROM_NIC_WPS_PBC FIELD16(0x0080) -#define EEPROM_NIC_BW40M_BG FIELD16(0x0100) -#define EEPROM_NIC_BW40M_A FIELD16(0x0200) - -/* - * EEPROM frequency - */ -#define EEPROM_FREQ 0x001d -#define EEPROM_FREQ_OFFSET FIELD16(0x00ff) -#define EEPROM_FREQ_LED_MODE FIELD16(0x7f00) -#define EEPROM_FREQ_LED_POLARITY FIELD16(0x1000) - -/* - * EEPROM LED - * POLARITY_RDY_G: Polarity RDY_G setting. - * POLARITY_RDY_A: Polarity RDY_A setting. - * POLARITY_ACT: Polarity ACT setting. - * POLARITY_GPIO_0: Polarity GPIO0 setting. - * POLARITY_GPIO_1: Polarity GPIO1 setting. - * POLARITY_GPIO_2: Polarity GPIO2 setting. - * POLARITY_GPIO_3: Polarity GPIO3 setting. - * POLARITY_GPIO_4: Polarity GPIO4 setting. - * LED_MODE: Led mode. - */ -#define EEPROM_LED1 0x001e -#define EEPROM_LED2 0x001f -#define EEPROM_LED3 0x0020 -#define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001) -#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002) -#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004) -#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008) -#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010) -#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020) -#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040) -#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080) -#define EEPROM_LED_LED_MODE FIELD16(0x1f00) - -/* - * EEPROM LNA - */ -#define EEPROM_LNA 0x0022 -#define EEPROM_LNA_BG FIELD16(0x00ff) -#define EEPROM_LNA_A0 FIELD16(0xff00) - -/* - * EEPROM RSSI BG offset - */ -#define EEPROM_RSSI_BG 0x0023 -#define EEPROM_RSSI_BG_OFFSET0 FIELD16(0x00ff) -#define EEPROM_RSSI_BG_OFFSET1 FIELD16(0xff00) - -/* - * EEPROM RSSI BG2 offset - */ -#define EEPROM_RSSI_BG2 0x0024 -#define EEPROM_RSSI_BG2_OFFSET2 FIELD16(0x00ff) -#define EEPROM_RSSI_BG2_LNA_A1 FIELD16(0xff00) - -/* - * EEPROM RSSI A offset - */ -#define EEPROM_RSSI_A 0x0025 -#define EEPROM_RSSI_A_OFFSET0 FIELD16(0x00ff) -#define EEPROM_RSSI_A_OFFSET1 FIELD16(0xff00) - -/* - * EEPROM RSSI A2 offset - */ -#define EEPROM_RSSI_A2 0x0026 -#define EEPROM_RSSI_A2_OFFSET2 FIELD16(0x00ff) -#define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00) - -/* - * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power. - * This is delta in 40MHZ. - * VALUE: Tx Power dalta value (MAX=4) - * TYPE: 1: Plus the delta value, 0: minus the delta value - * TXPOWER: Enable: - */ -#define EEPROM_TXPOWER_DELTA 0x0028 -#define EEPROM_TXPOWER_DELTA_VALUE FIELD16(0x003f) -#define EEPROM_TXPOWER_DELTA_TYPE FIELD16(0x0040) -#define EEPROM_TXPOWER_DELTA_TXPOWER FIELD16(0x0080) - -/* - * EEPROM TXPOWER 802.11BG - */ -#define EEPROM_TXPOWER_BG1 0x0029 -#define EEPROM_TXPOWER_BG2 0x0030 -#define EEPROM_TXPOWER_BG_SIZE 7 -#define EEPROM_TXPOWER_BG_1 FIELD16(0x00ff) -#define EEPROM_TXPOWER_BG_2 FIELD16(0xff00) - -/* - * EEPROM TXPOWER 802.11A - */ -#define EEPROM_TXPOWER_A1 0x003c -#define EEPROM_TXPOWER_A2 0x0053 -#define EEPROM_TXPOWER_A_SIZE 6 -#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff) -#define EEPROM_TXPOWER_A_2 FIELD16(0xff00) - -/* - * EEPROM TXpower byrate: 20MHZ power - */ -#define EEPROM_TXPOWER_BYRATE 0x006f - -/* - * EEPROM BBP. - */ -#define EEPROM_BBP_START 0x0078 -#define EEPROM_BBP_SIZE 16 -#define EEPROM_BBP_VALUE FIELD16(0x00ff) -#define EEPROM_BBP_REG_ID FIELD16(0xff00) - -/* - * MCU mailbox commands. - */ -#define MCU_SLEEP 0x30 -#define MCU_WAKEUP 0x31 -#define MCU_RADIO_OFF 0x35 -#define MCU_CURRENT 0x36 -#define MCU_LED 0x50 -#define MCU_LED_STRENGTH 0x51 -#define MCU_LED_1 0x52 -#define MCU_LED_2 0x53 -#define MCU_LED_3 0x54 -#define MCU_RADAR 0x60 -#define MCU_BOOT_SIGNAL 0x72 -#define MCU_BBP_SIGNAL 0x80 -#define MCU_POWER_SAVE 0x83 - -/* - * MCU mailbox tokens - */ -#define TOKEN_WAKUP 3 - /* * DMA descriptor defines. */ -#define TXD_DESC_SIZE ( 4 * sizeof(__le32) ) #define TXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) -#define TXWI_DESC_SIZE ( 4 * sizeof(__le32) ) -#define RXD_DESC_SIZE ( 4 * sizeof(__le32) ) #define RXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) -#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) ) - -/* - * TX descriptor format for TX, PRIO and Beacon Ring. - */ - -/* - * Word0 - */ -#define TXD_W0_SD_PTR0 FIELD32(0xffffffff) - -/* - * Word1 - */ -#define TXD_W1_SD_LEN1 FIELD32(0x00003fff) -#define TXD_W1_LAST_SEC1 FIELD32(0x00004000) -#define TXD_W1_BURST FIELD32(0x00008000) -#define TXD_W1_SD_LEN0 FIELD32(0x3fff0000) -#define TXD_W1_LAST_SEC0 FIELD32(0x40000000) -#define TXD_W1_DMA_DONE FIELD32(0x80000000) - -/* - * Word2 - */ -#define TXD_W2_SD_PTR1 FIELD32(0xffffffff) - -/* - * Word3 - * WIV: Wireless Info Valid. 1: Driver filled WI, 0: DMA needs to copy WI - * QSEL: Select on-chip FIFO ID for 2nd-stage output scheduler. - * 0:MGMT, 1:HCCA 2:EDCA - */ -#define TXD_W3_WIV FIELD32(0x01000000) -#define TXD_W3_QSEL FIELD32(0x06000000) -#define TXD_W3_TCO FIELD32(0x20000000) -#define TXD_W3_UCO FIELD32(0x40000000) -#define TXD_W3_ICO FIELD32(0x80000000) /* * TX Info structure @@ -1807,52 +96,6 @@ struct mac_iveiv_entry { #define TXINFO_W0_USB_DMA_NEXT_VALID FIELD32(0x40000000) #define TXINFO_W0_USB_DMA_TX_BURST FIELD32(0x80000000) -/* - * TX WI structure - */ - -/* - * Word0 - * FRAG: 1 To inform TKIP engine this is a fragment. - * MIMO_PS: The remote peer is in dynamic MIMO-PS mode - * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs - * BW: Channel bandwidth 20MHz or 40 MHz - * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED - */ -#define TXWI_W0_FRAG FIELD32(0x00000001) -#define TXWI_W0_MIMO_PS FIELD32(0x00000002) -#define TXWI_W0_CF_ACK FIELD32(0x00000004) -#define TXWI_W0_TS FIELD32(0x00000008) -#define TXWI_W0_AMPDU FIELD32(0x00000010) -#define TXWI_W0_MPDU_DENSITY FIELD32(0x000000e0) -#define TXWI_W0_TX_OP FIELD32(0x00000300) -#define TXWI_W0_MCS FIELD32(0x007f0000) -#define TXWI_W0_BW FIELD32(0x00800000) -#define TXWI_W0_SHORT_GI FIELD32(0x01000000) -#define TXWI_W0_STBC FIELD32(0x06000000) -#define TXWI_W0_IFS FIELD32(0x08000000) -#define TXWI_W0_PHYMODE FIELD32(0xc0000000) - -/* - * Word1 - */ -#define TXWI_W1_ACK FIELD32(0x00000001) -#define TXWI_W1_NSEQ FIELD32(0x00000002) -#define TXWI_W1_BW_WIN_SIZE FIELD32(0x000000fc) -#define TXWI_W1_WIRELESS_CLI_ID FIELD32(0x0000ff00) -#define TXWI_W1_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) -#define TXWI_W1_PACKETID FIELD32(0xf0000000) - -/* - * Word2 - */ -#define TXWI_W2_IV FIELD32(0xffffffff) - -/* - * Word3 - */ -#define TXWI_W3_EIV FIELD32(0xffffffff) - /* * RX descriptor format for RX Ring. */ @@ -1889,64 +132,4 @@ struct mac_iveiv_entry { #define RXD_W0_LAST_AMSDU FIELD32(0x00080000) #define RXD_W0_PLCP_SIGNAL FIELD32(0xfff00000) -/* - * RX WI structure - */ - -/* - * Word0 - */ -#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff) -#define RXWI_W0_KEY_INDEX FIELD32(0x00000300) -#define RXWI_W0_BSSID FIELD32(0x00001c00) -#define RXWI_W0_UDF FIELD32(0x0000e000) -#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000) -#define RXWI_W0_TID FIELD32(0xf0000000) - -/* - * Word1 - */ -#define RXWI_W1_FRAG FIELD32(0x0000000f) -#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0) -#define RXWI_W1_MCS FIELD32(0x007f0000) -#define RXWI_W1_BW FIELD32(0x00800000) -#define RXWI_W1_SHORT_GI FIELD32(0x01000000) -#define RXWI_W1_STBC FIELD32(0x06000000) -#define RXWI_W1_PHYMODE FIELD32(0xc0000000) - -/* - * Word2 - */ -#define RXWI_W2_RSSI0 FIELD32(0x000000ff) -#define RXWI_W2_RSSI1 FIELD32(0x0000ff00) -#define RXWI_W2_RSSI2 FIELD32(0x00ff0000) - -/* - * Word3 - */ -#define RXWI_W3_SNR0 FIELD32(0x000000ff) -#define RXWI_W3_SNR1 FIELD32(0x0000ff00) - -/* - * Macros for converting txpower from EEPROM to mac80211 value - * and from mac80211 value to register value. - */ -#define MIN_G_TXPOWER 0 -#define MIN_A_TXPOWER -7 -#define MAX_G_TXPOWER 31 -#define MAX_A_TXPOWER 15 -#define DEFAULT_TXPOWER 5 - -#define TXPOWER_G_FROM_DEV(__txpower) \ - ((__txpower) > MAX_G_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) - -#define TXPOWER_G_TO_DEV(__txpower) \ - clamp_t(char, __txpower, MIN_G_TXPOWER, MAX_G_TXPOWER) - -#define TXPOWER_A_FROM_DEV(__txpower) \ - ((__txpower) > MAX_A_TXPOWER) ? DEFAULT_TXPOWER : (__txpower) - -#define TXPOWER_A_TO_DEV(__txpower) \ - clamp_t(char, __txpower, MIN_A_TXPOWER, MAX_A_TXPOWER) - #endif /* RT2800USB_H */ -- cgit v1.2.3 From a4385213883420f2f0f77e531fb96489ca001239 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:36:02 +0100 Subject: rt2800: fix comments in rt2800.h Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index c5a56bac3bb5..d9b6a72e6d27 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -175,8 +175,8 @@ * WMM_AIFSN_CFG: Aifsn for each EDCA AC * AIFSN0: AC_BE * AIFSN1: AC_BK - * AIFSN1: AC_VI - * AIFSN1: AC_VO + * AIFSN2: AC_VI + * AIFSN3: AC_VO */ #define WMM_AIFSN_CFG 0x0214 #define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f) @@ -188,8 +188,8 @@ * WMM_CWMIN_CSR: CWmin for each EDCA AC * CWMIN0: AC_BE * CWMIN1: AC_BK - * CWMIN1: AC_VI - * CWMIN1: AC_VO + * CWMIN2: AC_VI + * CWMIN3: AC_VO */ #define WMM_CWMIN_CFG 0x0218 #define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f) @@ -201,8 +201,8 @@ * WMM_CWMAX_CSR: CWmax for each EDCA AC * CWMAX0: AC_BE * CWMAX1: AC_BK - * CWMAX1: AC_VI - * CWMAX1: AC_VO + * CWMAX2: AC_VI + * CWMAX3: AC_VO */ #define WMM_CWMAX_CFG 0x021c #define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f) @@ -495,9 +495,6 @@ /* * RF_CSR_CFG2: RF control register * VALUE: Register value to program into RF - * RFGAP: Gap between BB_CONTROL_RF and RF_LE - * 0: 3 system clock cycle (37.5usec) - * 1: 5 system clock cycle (62.5usec) */ #define RF_CSR_CFG2 0x1028 #define RF_CSR_CFG2_VALUE FIELD32(0x00ffffff) @@ -1275,8 +1272,8 @@ * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry - * SHARED_KEY_TABLE_BASE: 32 bytes * 32-entry - * SHARED_KEY_MODE_BASE: 4 bits * 32-entry + * SHARED_KEY_TABLE_BASE: 32-byte * 16-entry + * SHARED_KEY_MODE_BASE: 4-byte * 16-entry */ #define MAC_WCID_BASE 0x1800 #define PAIRWISE_KEY_TABLE_BASE 0x4000 @@ -1385,7 +1382,7 @@ struct mac_iveiv_entry { /* * HW_DFS_CTS_BASE: - * FS CTS frame base address. It's where mac stores CTS frame for DFS. + * DFS CTS frame base address. It's where mac stores CTS frame for DFS. */ #define HW_DFS_CTS_BASE 0x7780 -- cgit v1.2.3 From 5822e0701d9c29291f16cf170417071b702edeee Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:36:10 +0100 Subject: rt2x00: add support for different chipset interfaces Enhance rt2x00 infrastructure by adding explicit information about used chipset interface to struct rt2x00_chip. The new field will be used by rt2800 drivers for rt2800 library. Also add commonly used rt2x00_intf_is_pci() and rt2x00_intf_is_usb() helpers to make code easier to read (noticed by Ivo van Doorn). Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index c14b0f505b7f..1ddda729a483 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -144,6 +144,11 @@ struct avg_val { int avg_weight; }; +enum rt2x00_chip_intf { + RT2X00_CHIP_INTF_PCI, + RT2X00_CHIP_INTF_USB, +}; + /* * Chipset identification * The chipset on the device is composed of a RT and RF chip. @@ -169,6 +174,8 @@ struct rt2x00_chip { u16 rf; u32 rev; + + enum rt2x00_chip_intf intf; }; /* @@ -937,6 +944,28 @@ static inline bool rt2x00_check_rev(const struct rt2x00_chip *chipset, return ((chipset->rev & mask) == rev); } +static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev, + enum rt2x00_chip_intf intf) +{ + rt2x00dev->chip.intf = intf; +} + +static inline bool rt2x00_intf(const struct rt2x00_chip *chipset, + enum rt2x00_chip_intf intf) +{ + return (chipset->intf == intf); +} + +static inline bool rt2x00_intf_is_pci(struct rt2x00_dev *rt2x00dev) +{ + return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_PCI); +} + +static inline bool rt2x00_intf_is_usb(struct rt2x00_dev *rt2x00dev) +{ + return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_USB); +} + /** * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. * @rt2x00dev: Pointer to &struct rt2x00_dev. -- cgit v1.2.3 From 4d6f8b9f17626da48d6badc6ba259fbacc1413c3 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:36:17 +0100 Subject: rt2800: prepare for rt2800lib addition Part of preparations for later code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 103 +++++++++++++----------- drivers/net/wireless/rt2x00/rt2800usb.c | 134 ++++++++++++++++++-------------- 2 files changed, 133 insertions(+), 104 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index cae772ea5686..938f198f3562 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -97,7 +97,8 @@ static void rt2800pci_bbp_write(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); - rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); + if (rt2x00_intf_is_pci(rt2x00dev)) + rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); } @@ -125,7 +126,8 @@ static void rt2800pci_bbp_read(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); - rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); + if (rt2x00_intf_is_pci(rt2x00dev)) + rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); @@ -253,12 +255,14 @@ static void rt2800pci_mcu_request(struct rt2x00_dev *rt2x00dev, { u32 reg; - /* - * RT2880 and RT3052 don't support MCU requests. - */ - if (rt2x00_rt(&rt2x00dev->chip, RT2880) || - rt2x00_rt(&rt2x00dev->chip, RT3052)) - return; + if (rt2x00_intf_is_pci(rt2x00dev)) { + /* + * RT2880 and RT3052 don't support MCU requests. + */ + if (rt2x00_rt(&rt2x00dev->chip, RT2880) || + rt2x00_rt(&rt2x00dev->chip, RT3052)) + return; + } mutex_lock(&rt2x00dev->csr_mutex); @@ -814,7 +818,8 @@ static void rt2800pci_config_ant(struct rt2x00_dev *rt2x00dev, switch ((int)ant->tx) { case 1: rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); - rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); + if (rt2x00_intf_is_pci(rt2x00dev)) + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); break; case 2: rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); @@ -1480,7 +1485,8 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) u32 reg; unsigned int i; - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + if (rt2x00_intf_is_pci(rt2x00dev)) + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); @@ -1803,7 +1809,8 @@ static int rt2800pci_init_bbp(struct rt2x00_dev *rt2x00dev) if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) rt2800_bbp_write(rt2x00dev, 84, 0x19); - if (rt2x00_rt(&rt2x00dev->chip, RT3052)) { + if (rt2x00_intf_is_pci(rt2x00dev) && + rt2x00_rt(&rt2x00dev->chip, RT3052)) { rt2800_bbp_write(rt2x00dev, 31, 0x08); rt2800_bbp_write(rt2x00dev, 78, 0x0e); rt2800_bbp_write(rt2x00dev, 80, 0x08); @@ -1887,10 +1894,12 @@ static int rt2800pci_init_rfcsr(struct rt2x00_dev *rt2x00dev) u8 rfcsr; u8 bbp; - if (!rt2x00_rf(&rt2x00dev->chip, RF3020) && - !rt2x00_rf(&rt2x00dev->chip, RF3021) && - !rt2x00_rf(&rt2x00dev->chip, RF3022)) - return 0; + if (rt2x00_intf_is_pci(rt2x00dev)) { + if (!rt2x00_rf(&rt2x00dev->chip, RF3020) && + !rt2x00_rf(&rt2x00dev->chip, RF3021) && + !rt2x00_rf(&rt2x00dev->chip, RF3022)) + return 0; + } /* * Init RF calibration. @@ -1902,36 +1911,38 @@ static int rt2800pci_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); - rt2800_rfcsr_write(rt2x00dev, 0, 0x50); - rt2800_rfcsr_write(rt2x00dev, 1, 0x01); - rt2800_rfcsr_write(rt2x00dev, 2, 0xf7); - rt2800_rfcsr_write(rt2x00dev, 3, 0x75); - rt2800_rfcsr_write(rt2x00dev, 4, 0x40); - rt2800_rfcsr_write(rt2x00dev, 5, 0x03); - rt2800_rfcsr_write(rt2x00dev, 6, 0x02); - rt2800_rfcsr_write(rt2x00dev, 7, 0x50); - rt2800_rfcsr_write(rt2x00dev, 8, 0x39); - rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); - rt2800_rfcsr_write(rt2x00dev, 10, 0x60); - rt2800_rfcsr_write(rt2x00dev, 11, 0x21); - rt2800_rfcsr_write(rt2x00dev, 12, 0x75); - rt2800_rfcsr_write(rt2x00dev, 13, 0x75); - rt2800_rfcsr_write(rt2x00dev, 14, 0x90); - rt2800_rfcsr_write(rt2x00dev, 15, 0x58); - rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); - rt2800_rfcsr_write(rt2x00dev, 17, 0x92); - rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); - rt2800_rfcsr_write(rt2x00dev, 19, 0x02); - rt2800_rfcsr_write(rt2x00dev, 20, 0xba); - rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); - rt2800_rfcsr_write(rt2x00dev, 22, 0x00); - rt2800_rfcsr_write(rt2x00dev, 23, 0x31); - rt2800_rfcsr_write(rt2x00dev, 24, 0x08); - rt2800_rfcsr_write(rt2x00dev, 25, 0x01); - rt2800_rfcsr_write(rt2x00dev, 26, 0x25); - rt2800_rfcsr_write(rt2x00dev, 27, 0x23); - rt2800_rfcsr_write(rt2x00dev, 28, 0x13); - rt2800_rfcsr_write(rt2x00dev, 29, 0x83); + if (rt2x00_intf_is_pci(rt2x00dev)) { + rt2800_rfcsr_write(rt2x00dev, 0, 0x50); + rt2800_rfcsr_write(rt2x00dev, 1, 0x01); + rt2800_rfcsr_write(rt2x00dev, 2, 0xf7); + rt2800_rfcsr_write(rt2x00dev, 3, 0x75); + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800_rfcsr_write(rt2x00dev, 5, 0x03); + rt2800_rfcsr_write(rt2x00dev, 6, 0x02); + rt2800_rfcsr_write(rt2x00dev, 7, 0x50); + rt2800_rfcsr_write(rt2x00dev, 8, 0x39); + rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 10, 0x60); + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800_rfcsr_write(rt2x00dev, 12, 0x75); + rt2800_rfcsr_write(rt2x00dev, 13, 0x75); + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800_rfcsr_write(rt2x00dev, 15, 0x58); + rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); + rt2800_rfcsr_write(rt2x00dev, 17, 0x92); + rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800_rfcsr_write(rt2x00dev, 20, 0xba); + rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); + rt2800_rfcsr_write(rt2x00dev, 23, 0x31); + rt2800_rfcsr_write(rt2x00dev, 24, 0x08); + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); + rt2800_rfcsr_write(rt2x00dev, 26, 0x25); + rt2800_rfcsr_write(rt2x00dev, 27, 0x23); + rt2800_rfcsr_write(rt2x00dev, 28, 0x13); + rt2800_rfcsr_write(rt2x00dev, 29, 0x83); + } /* * Set RX Filter calibration for 20MHz and 40MHz @@ -3005,6 +3016,8 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); + rt2x00dev->priv = (void *)&rt2800pci_rt2800_ops; /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 1383e55ff8ec..9aee3ab6589e 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1050,7 +1050,8 @@ static void rt2800usb_link_stats(struct rt2x00_dev *rt2x00dev, static u8 rt2800usb_get_default_vgc(struct rt2x00_dev *rt2x00dev) { if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { - if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) return 0x1c + (2 * rt2x00dev->lna_gain); else return 0x2e + rt2x00dev->lna_gain; @@ -1285,33 +1286,38 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) u32 reg; unsigned int i; - /* - * Wait untill BBP and RF are ready. - */ - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - if (reg && reg != ~0) - break; - msleep(1); - } + if (rt2x00_intf_is_usb(rt2x00dev)) { + /* + * Wait untill BBP and RF are ready. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg && reg != ~0) + break; + msleep(1); + } - if (i == REGISTER_BUSY_COUNT) { - ERROR(rt2x00dev, "Unstable hardware.\n"); - return -EBUSY; - } + if (i == REGISTER_BUSY_COUNT) { + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; + } - rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); + rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, + reg & ~0x00002000); + } rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); + if (rt2x00_intf_is_usb(rt2x00dev)) { + rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); - rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, - USB_MODE_RESET, REGISTER_TIMEOUT); + rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, + USB_MODE_RESET, REGISTER_TIMEOUT); + } rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); @@ -1343,7 +1349,8 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); - if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); @@ -1461,19 +1468,21 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1); rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); - rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); + if (rt2x00_intf_is_usb(rt2x00dev)) { + rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 3); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_BIG_ENDIAN, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_HDR_SCATTER, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_HDR_SEG_LEN, 0); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 3); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_BIG_ENDIAN, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_HDR_SCATTER, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_HDR_SEG_LEN, 0); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + } rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); @@ -1519,9 +1528,11 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0); rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0); - rt2800_register_read(rt2x00dev, USB_CYC_CFG, ®); - rt2x00_set_field32(®, USB_CYC_CFG_CLOCK_CYCLE, 30); - rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg); + if (rt2x00_intf_is_usb(rt2x00dev)) { + rt2800_register_read(rt2x00dev, USB_CYC_CFG, ®); + rt2x00_set_field32(®, USB_CYC_CFG_CLOCK_CYCLE, 30); + rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg); + } rt2800_register_read(rt2x00dev, HT_FBK_CFG0, ®); rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS0FBK, 0); @@ -1650,11 +1661,11 @@ static int rt2800usb_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 73, 0x12); } - if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) { + if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) rt2800_bbp_write(rt2x00dev, 84, 0x19); - } - if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { rt2800_bbp_write(rt2x00dev, 70, 0x0a); rt2800_bbp_write(rt2x00dev, 84, 0x99); rt2800_bbp_write(rt2x00dev, 105, 0x05); @@ -1738,7 +1749,8 @@ static int rt2800usb_init_rfcsr(struct rt2x00_dev *rt2x00dev) u8 rfcsr; u8 bbp; - if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) return 0; /* @@ -1751,26 +1763,28 @@ static int rt2800usb_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); - rt2800_rfcsr_write(rt2x00dev, 4, 0x40); - rt2800_rfcsr_write(rt2x00dev, 5, 0x03); - rt2800_rfcsr_write(rt2x00dev, 6, 0x02); - rt2800_rfcsr_write(rt2x00dev, 7, 0x70); - rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); - rt2800_rfcsr_write(rt2x00dev, 10, 0x71); - rt2800_rfcsr_write(rt2x00dev, 11, 0x21); - rt2800_rfcsr_write(rt2x00dev, 12, 0x7b); - rt2800_rfcsr_write(rt2x00dev, 14, 0x90); - rt2800_rfcsr_write(rt2x00dev, 15, 0x58); - rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); - rt2800_rfcsr_write(rt2x00dev, 17, 0x92); - rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); - rt2800_rfcsr_write(rt2x00dev, 19, 0x02); - rt2800_rfcsr_write(rt2x00dev, 20, 0xba); - rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); - rt2800_rfcsr_write(rt2x00dev, 24, 0x16); - rt2800_rfcsr_write(rt2x00dev, 25, 0x01); - rt2800_rfcsr_write(rt2x00dev, 27, 0x03); - rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); + if (rt2x00_intf_is_usb(rt2x00dev)) { + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800_rfcsr_write(rt2x00dev, 5, 0x03); + rt2800_rfcsr_write(rt2x00dev, 6, 0x02); + rt2800_rfcsr_write(rt2x00dev, 7, 0x70); + rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 10, 0x71); + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800_rfcsr_write(rt2x00dev, 12, 0x7b); + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800_rfcsr_write(rt2x00dev, 15, 0x58); + rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); + rt2800_rfcsr_write(rt2x00dev, 17, 0x92); + rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800_rfcsr_write(rt2x00dev, 20, 0xba); + rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 24, 0x16); + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); + rt2800_rfcsr_write(rt2x00dev, 27, 0x03); + rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); + } /* * Set RX Filter calibration for 20MHz and 40MHz @@ -2644,6 +2658,8 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB); + rt2x00dev->priv = (void *)&rt2800usb_rt2800_ops; /* -- cgit v1.2.3 From 89297425c2104b187c25d6260a41345c491c8f18 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:36:24 +0100 Subject: rt2800: add rt2800lib (part one) Code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/Kconfig | 5 + drivers/net/wireless/rt2x00/Makefile | 1 + drivers/net/wireless/rt2x00/rt2800lib.c | 244 ++++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800lib.h | 14 ++ drivers/net/wireless/rt2x00/rt2800pci.c | 236 ------------------------------ drivers/net/wireless/rt2x00/rt2800usb.c | 223 ----------------------------- 6 files changed, 264 insertions(+), 459 deletions(-) create mode 100644 drivers/net/wireless/rt2x00/rt2800lib.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 18e5b8e6c34f..bf60689aaabb 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -66,6 +66,7 @@ config RT2800PCI_SOC config RT2800PCI tristate "Ralink rt2800 (PCI/PCMCIA) support (VERY EXPERIMENTAL)" depends on (RT2800PCI_PCI || RT2800PCI_SOC) && EXPERIMENTAL + select RT2800_LIB select RT2X00_LIB_PCI if RT2800PCI_PCI select RT2X00_LIB_SOC if RT2800PCI_SOC select RT2X00_LIB_HT @@ -109,6 +110,7 @@ config RT73USB config RT2800USB tristate "Ralink rt2800 (USB) support (EXPERIMENTAL)" depends on USB && EXPERIMENTAL + select RT2800_LIB select RT2X00_LIB_USB select RT2X00_LIB_HT select RT2X00_LIB_FIRMWARE @@ -124,6 +126,9 @@ config RT2800USB When compiled as a module, this driver will be called "rt2800usb.ko". +config RT2800_LIB + tristate + config RT2X00_LIB_PCI tristate select RT2X00_LIB diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile index 912f5f67e159..971339858297 100644 --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o obj-$(CONFIG_RT2X00_LIB_SOC) += rt2x00soc.o obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o +obj-$(CONFIG_RT2800_LIB) += rt2800lib.o obj-$(CONFIG_RT2400PCI) += rt2400pci.o obj-$(CONFIG_RT2500PCI) += rt2500pci.o obj-$(CONFIG_RT61PCI) += rt61pci.o diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c new file mode 100644 index 000000000000..3cbe85434ce3 --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -0,0 +1,244 @@ +/* + Copyright (C) 2009 Bartlomiej Zolnierkiewicz + + Based on the original rt2800pci.c and rt2800usb.c: + + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Module: rt2800lib + Abstract: rt2800 generic device routines. + */ + +#include +#include + +#include "rt2x00.h" +#include "rt2800lib.h" +#include "rt2800.h" + +MODULE_AUTHOR("Bartlomiej Zolnierkiewicz"); +MODULE_DESCRIPTION("rt2800 library"); +MODULE_LICENSE("GPL"); + +/* + * Register access. + * All access to the CSR registers will go through the methods + * rt2800_register_read and rt2800_register_write. + * BBP and RF register require indirect register access, + * and use the CSR registers BBPCSR and RFCSR to achieve this. + * These indirect registers work with busy bits, + * and we will try maximal REGISTER_BUSY_COUNT times to access + * the register while taking a REGISTER_BUSY_DELAY us delay + * between each attampt. When the busy bit is still set at that time, + * the access attempt is considered to have failed, + * and we will print an error. + * The _lock versions must be used if you already hold the csr_mutex + */ +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2800_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) +#define WAIT_FOR_RFCSR(__dev, __reg) \ + rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2800_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) +#define WAIT_FOR_MCU(__dev, __reg) \ + rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \ + H2M_MAILBOX_CSR_OWNER, (__reg)) + +void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBP_CSR_CFG_VALUE, value); + rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); + rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); + if (rt2x00_intf_is_pci(rt2x00dev)) + rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); + + rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} +EXPORT_SYMBOL_GPL(rt2800_bbp_write); + +void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. + */ + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); + rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); + if (rt2x00_intf_is_pci(rt2x00dev)) + rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); + + rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); + + WAIT_FOR_BBP(rt2x00dev, ®); + } + + *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); +} +EXPORT_SYMBOL_GPL(rt2800_bbp_read); + +void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RFCSR becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG_DATA, value); + rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); + rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); + + rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} +EXPORT_SYMBOL_GPL(rt2800_rfcsr_write); + +void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RFCSR becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. + */ + if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); + rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); + rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); + + rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); + + WAIT_FOR_RFCSR(rt2x00dev, ®); + } + + *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); + + mutex_unlock(&rt2x00dev->csr_mutex); +} +EXPORT_SYMBOL_GPL(rt2800_rfcsr_read); + +void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) +{ + u32 reg; + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RF_CSR_CFG0_REG_VALUE_BW, value); + rt2x00_set_field32(®, RF_CSR_CFG0_STANDBYMODE, 0); + rt2x00_set_field32(®, RF_CSR_CFG0_SEL, 0); + rt2x00_set_field32(®, RF_CSR_CFG0_BUSY, 1); + + rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} +EXPORT_SYMBOL_GPL(rt2800_rf_write); + +void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, + const u8 command, const u8 token, + const u8 arg0, const u8 arg1) +{ + u32 reg; + + if (rt2x00_intf_is_pci(rt2x00dev)) { + /* + * RT2880 and RT3052 don't support MCU requests. + */ + if (rt2x00_rt(&rt2x00dev->chip, RT2880) || + rt2x00_rt(&rt2x00dev->chip, RT3052)) + return; + } + + mutex_lock(&rt2x00dev->csr_mutex); + + /* + * Wait until the MCU becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_MCU(rt2x00dev, ®)) { + rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); + rt2800_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg); + + reg = 0; + rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); + rt2800_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg); + } + + mutex_unlock(&rt2x00dev->csr_mutex); +} +EXPORT_SYMBOL_GPL(rt2800_mcu_request); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 17e91fb1a77a..40a7f72e87f5 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -96,4 +96,18 @@ static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg); } +void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value); +void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value); +void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value); +void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value); +void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value); +void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, + const u8 command, const u8 token, + const u8 arg0, const u8 arg1); + #endif /* RT2800LIB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 938f198f3562..90ada5d014fd 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -56,242 +56,6 @@ static int modparam_nohwcrypt = 1; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -/* - * Register access. - * All access to the CSR registers will go through the methods - * rt2800_register_read and rt2800_register_write. - * BBP and RF register require indirect register access, - * and use the CSR registers BBPCSR and RFCSR to achieve this. - * These indirect registers work with busy bits, - * and we will try maximal REGISTER_BUSY_COUNT times to access - * the register while taking a REGISTER_BUSY_DELAY us delay - * between each attampt. When the busy bit is still set at that time, - * the access attempt is considered to have failed, - * and we will print an error. - * The _lock versions must be used if you already hold the csr_mutex - */ -#define WAIT_FOR_BBP(__dev, __reg) \ - rt2800_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) -#define WAIT_FOR_RFCSR(__dev, __reg) \ - rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) -#define WAIT_FOR_RF(__dev, __reg) \ - rt2800_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) -#define WAIT_FOR_MCU(__dev, __reg) \ - rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \ - H2M_MAILBOX_CSR_OWNER, (__reg)) - -static void rt2800pci_bbp_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value) -{ - u32 reg; - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the BBP becomes available, afterwards we - * can safely write the new data into the register. - */ - if (WAIT_FOR_BBP(rt2x00dev, ®)) { - reg = 0; - rt2x00_set_field32(®, BBP_CSR_CFG_VALUE, value); - rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); - rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); - rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); - if (rt2x00_intf_is_pci(rt2x00dev)) - rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); - - rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); - } - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static void rt2800pci_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) -{ - u32 reg; - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the BBP becomes available, afterwards we - * can safely write the read request into the register. - * After the data has been written, we wait until hardware - * returns the correct value, if at any time the register - * doesn't become available in time, reg will be 0xffffffff - * which means we return 0xff to the caller. - */ - if (WAIT_FOR_BBP(rt2x00dev, ®)) { - reg = 0; - rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); - rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); - rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); - if (rt2x00_intf_is_pci(rt2x00dev)) - rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); - - rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); - - WAIT_FOR_BBP(rt2x00dev, ®); - } - - *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static inline void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value) -{ - rt2800pci_bbp_write(rt2x00dev, word, value); -} - -static inline void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) -{ - rt2800pci_bbp_read(rt2x00dev, word, value); -} - -static void rt2800pci_rfcsr_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value) -{ - u32 reg; - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the RFCSR becomes available, afterwards we - * can safely write the new data into the register. - */ - if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { - reg = 0; - rt2x00_set_field32(®, RF_CSR_CFG_DATA, value); - rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); - rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); - rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); - - rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); - } - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static void rt2800pci_rfcsr_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) -{ - u32 reg; - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the RFCSR becomes available, afterwards we - * can safely write the read request into the register. - * After the data has been written, we wait until hardware - * returns the correct value, if at any time the register - * doesn't become available in time, reg will be 0xffffffff - * which means we return 0xff to the caller. - */ - if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { - reg = 0; - rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); - rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); - rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); - - rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); - - WAIT_FOR_RFCSR(rt2x00dev, ®); - } - - *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static inline void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value) -{ - rt2800pci_rfcsr_write(rt2x00dev, word, value); -} - -static inline void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) -{ - rt2800pci_rfcsr_read(rt2x00dev, word, value); -} - -static void rt2800pci_rf_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u32 value) -{ - u32 reg; - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the RF becomes available, afterwards we - * can safely write the new data into the register. - */ - if (WAIT_FOR_RF(rt2x00dev, ®)) { - reg = 0; - rt2x00_set_field32(®, RF_CSR_CFG0_REG_VALUE_BW, value); - rt2x00_set_field32(®, RF_CSR_CFG0_STANDBYMODE, 0); - rt2x00_set_field32(®, RF_CSR_CFG0_SEL, 0); - rt2x00_set_field32(®, RF_CSR_CFG0_BUSY, 1); - - rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg); - rt2x00_rf_write(rt2x00dev, word, value); - } - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static inline void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u32 value) -{ - rt2800pci_rf_write(rt2x00dev, word, value); -} - -static void rt2800pci_mcu_request(struct rt2x00_dev *rt2x00dev, - const u8 command, const u8 token, - const u8 arg0, const u8 arg1) -{ - u32 reg; - - if (rt2x00_intf_is_pci(rt2x00dev)) { - /* - * RT2880 and RT3052 don't support MCU requests. - */ - if (rt2x00_rt(&rt2x00dev->chip, RT2880) || - rt2x00_rt(&rt2x00dev->chip, RT3052)) - return; - } - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the MCU becomes available, afterwards we - * can safely write the new data into the register. - */ - if (WAIT_FOR_MCU(rt2x00dev, ®)) { - rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); - rt2800_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg); - - reg = 0; - rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); - rt2800_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg); - } - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static inline void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, - const u8 command, const u8 token, - const u8 arg0, const u8 arg1) -{ - rt2800pci_mcu_request(rt2x00dev, command, token, arg0, arg1); -} - static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) { unsigned int i; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 9aee3ab6589e..6bd646a979af 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -45,229 +45,6 @@ static int modparam_nohwcrypt = 1; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -/* - * Register access. - * All access to the CSR registers will go through the methods - * rt2800_register_read and rt2800_register_write. - * BBP and RF register require indirect register access, - * and use the CSR registers BBPCSR and RFCSR to achieve this. - * These indirect registers work with busy bits, - * and we will try maximal REGISTER_BUSY_COUNT times to access - * the register while taking a REGISTER_BUSY_DELAY us delay - * between each attampt. When the busy bit is still set at that time, - * the access attempt is considered to have failed, - * and we will print an error. - * The _lock versions must be used if you already hold the csr_mutex - */ -#define WAIT_FOR_BBP(__dev, __reg) \ - rt2800_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) -#define WAIT_FOR_RFCSR(__dev, __reg) \ - rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) -#define WAIT_FOR_RF(__dev, __reg) \ - rt2800_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) -#define WAIT_FOR_MCU(__dev, __reg) \ - rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \ - H2M_MAILBOX_CSR_OWNER, (__reg)) - -static void rt2800usb_bbp_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value) -{ - u32 reg; - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the BBP becomes available, afterwards we - * can safely write the new data into the register. - */ - if (WAIT_FOR_BBP(rt2x00dev, ®)) { - reg = 0; - rt2x00_set_field32(®, BBP_CSR_CFG_VALUE, value); - rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); - rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); - rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); - - rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); - } - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static void rt2800usb_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) -{ - u32 reg; - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the BBP becomes available, afterwards we - * can safely write the read request into the register. - * After the data has been written, we wait until hardware - * returns the correct value, if at any time the register - * doesn't become available in time, reg will be 0xffffffff - * which means we return 0xff to the caller. - */ - if (WAIT_FOR_BBP(rt2x00dev, ®)) { - reg = 0; - rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); - rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); - rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); - - rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); - - WAIT_FOR_BBP(rt2x00dev, ®); - } - - *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static inline void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value) -{ - rt2800usb_bbp_write(rt2x00dev, word, value); -} - -static inline void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) -{ - rt2800usb_bbp_read(rt2x00dev, word, value); -} - -static void rt2800usb_rfcsr_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value) -{ - u32 reg; - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the RFCSR becomes available, afterwards we - * can safely write the new data into the register. - */ - if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { - reg = 0; - rt2x00_set_field32(®, RF_CSR_CFG_DATA, value); - rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); - rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); - rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); - - rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); - } - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static void rt2800usb_rfcsr_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) -{ - u32 reg; - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the RFCSR becomes available, afterwards we - * can safely write the read request into the register. - * After the data has been written, we wait until hardware - * returns the correct value, if at any time the register - * doesn't become available in time, reg will be 0xffffffff - * which means we return 0xff to the caller. - */ - if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { - reg = 0; - rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); - rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); - rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); - - rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); - - WAIT_FOR_RFCSR(rt2x00dev, ®); - } - - *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static inline void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value) -{ - rt2800usb_rfcsr_write(rt2x00dev, word, value); -} - -static inline void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) -{ - rt2800usb_rfcsr_read(rt2x00dev, word, value); -} - -static void rt2800usb_rf_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u32 value) -{ - u32 reg; - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the RF becomes available, afterwards we - * can safely write the new data into the register. - */ - if (WAIT_FOR_RF(rt2x00dev, ®)) { - reg = 0; - rt2x00_set_field32(®, RF_CSR_CFG0_REG_VALUE_BW, value); - rt2x00_set_field32(®, RF_CSR_CFG0_STANDBYMODE, 0); - rt2x00_set_field32(®, RF_CSR_CFG0_SEL, 0); - rt2x00_set_field32(®, RF_CSR_CFG0_BUSY, 1); - - rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg); - rt2x00_rf_write(rt2x00dev, word, value); - } - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static inline void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u32 value) -{ - rt2800usb_rf_write(rt2x00dev, word, value); -} - -static void rt2800usb_mcu_request(struct rt2x00_dev *rt2x00dev, - const u8 command, const u8 token, - const u8 arg0, const u8 arg1) -{ - u32 reg; - - mutex_lock(&rt2x00dev->csr_mutex); - - /* - * Wait until the MCU becomes available, afterwards we - * can safely write the new data into the register. - */ - if (WAIT_FOR_MCU(rt2x00dev, ®)) { - rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); - rt2800_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg); - - reg = 0; - rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); - rt2800_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg); - } - - mutex_unlock(&rt2x00dev->csr_mutex); -} - -static inline void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, - const u8 command, const u8 token, - const u8 arg0, const u8 arg1) -{ - rt2800usb_mcu_request(rt2x00dev, command, token, arg0, arg1); -} - #ifdef CONFIG_RT2X00_LIB_DEBUGFS static const struct rt2x00debug rt2800usb_rt2x00debug = { .owner = THIS_MODULE, -- cgit v1.2.3 From f445061630c7a4a85193fdef006234f94f71c366 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:36:40 +0100 Subject: rt2800: add rt2800lib (part two) Code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 832 +++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800lib.h | 25 + drivers/net/wireless/rt2x00/rt2800pci.c | 854 +------------------------------ drivers/net/wireless/rt2x00/rt2800usb.c | 856 +------------------------------- 4 files changed, 887 insertions(+), 1680 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 3cbe85434ce3..ba88d643edd3 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -242,3 +242,835 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } EXPORT_SYMBOL_GPL(rt2800_mcu_request); + +#ifdef CONFIG_RT2X00_LIB_DEBUGFS +const struct rt2x00debug rt2800_rt2x00debug = { + .owner = THIS_MODULE, + .csr = { + .read = rt2800_register_read, + .write = rt2800_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, + .word_size = sizeof(u32), + .word_count = CSR_REG_SIZE / sizeof(u32), + }, + .eeprom = { + .read = rt2x00_eeprom_read, + .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, + .word_size = sizeof(u16), + .word_count = EEPROM_SIZE / sizeof(u16), + }, + .bbp = { + .read = rt2800_bbp_read, + .write = rt2800_bbp_write, + .word_base = BBP_BASE, + .word_size = sizeof(u8), + .word_count = BBP_SIZE / sizeof(u8), + }, + .rf = { + .read = rt2x00_rf_read, + .write = rt2800_rf_write, + .word_base = RF_BASE, + .word_size = sizeof(u32), + .word_count = RF_SIZE / sizeof(u32), + }, +}; +EXPORT_SYMBOL_GPL(rt2800_rt2x00debug); +#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ + +int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); + return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); +} +EXPORT_SYMBOL_GPL(rt2800_rfkill_poll); + +#ifdef CONFIG_RT2X00_LIB_LEDS +static void rt2800_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + unsigned int enabled = brightness != LED_OFF; + unsigned int bg_mode = + (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); + unsigned int polarity = + rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, + EEPROM_FREQ_LED_POLARITY); + unsigned int ledmode = + rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, + EEPROM_FREQ_LED_MODE); + + if (led->type == LED_TYPE_RADIO) { + rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? 0x20 : 0); + } else if (led->type == LED_TYPE_ASSOC) { + rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, + enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); + } else if (led->type == LED_TYPE_QUALITY) { + /* + * The brightness is divided into 6 levels (0 - 5), + * The specs tell us the following levels: + * 0, 1 ,3, 7, 15, 31 + * to determine the level in a simple way we can simply + * work with bitshifting: + * (1 << level) - 1 + */ + rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, + (1 << brightness / (LED_FULL / 6)) - 1, + polarity); + } +} + +static int rt2800_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, unsigned long *delay_off) +{ + struct rt2x00_led *led = + container_of(led_cdev, struct rt2x00_led, led_dev); + u32 reg; + + rt2800_register_read(led->rt2x00dev, LED_CFG, ®); + rt2x00_set_field32(®, LED_CFG_ON_PERIOD, *delay_on); + rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); + rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); + rt2x00_set_field32(®, LED_CFG_R_LED_MODE, 3); + rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 12); + rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3); + rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1); + rt2800_register_write(led->rt2x00dev, LED_CFG, reg); + + return 0; +} + +void rt2800_init_led(struct rt2x00_dev *rt2x00dev, + struct rt2x00_led *led, enum led_type type) +{ + led->rt2x00dev = rt2x00dev; + led->type = type; + led->led_dev.brightness_set = rt2800_brightness_set; + led->led_dev.blink_set = rt2800_blink_set; + led->flags = LED_INITIALIZED; +} +EXPORT_SYMBOL_GPL(rt2800_init_led); +#endif /* CONFIG_RT2X00_LIB_LEDS */ + +/* + * Configuration handlers. + */ +static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct mac_wcid_entry wcid_entry; + struct mac_iveiv_entry iveiv_entry; + u32 offset; + u32 reg; + + offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); + + rt2800_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, + !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, + (crypto->cmd == SET_KEY) * crypto->cipher); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, + (crypto->cmd == SET_KEY) * crypto->bssidx); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); + rt2800_register_write(rt2x00dev, offset, reg); + + offset = MAC_IVEIV_ENTRY(key->hw_key_idx); + + memset(&iveiv_entry, 0, sizeof(iveiv_entry)); + if ((crypto->cipher == CIPHER_TKIP) || + (crypto->cipher == CIPHER_TKIP_NO_MIC) || + (crypto->cipher == CIPHER_AES)) + iveiv_entry.iv[3] |= 0x20; + iveiv_entry.iv[3] |= key->keyidx << 6; + rt2800_register_multiwrite(rt2x00dev, offset, + &iveiv_entry, sizeof(iveiv_entry)); + + offset = MAC_WCID_ENTRY(key->hw_key_idx); + + memset(&wcid_entry, 0, sizeof(wcid_entry)); + if (crypto->cmd == SET_KEY) + memcpy(&wcid_entry, crypto->address, ETH_ALEN); + rt2800_register_multiwrite(rt2x00dev, offset, + &wcid_entry, sizeof(wcid_entry)); +} + +int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + struct rt2x00_field32 field; + u32 offset; + u32 reg; + + if (crypto->cmd == SET_KEY) { + key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx; + + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + offset = SHARED_KEY_ENTRY(key->hw_key_idx); + rt2800_register_multiwrite(rt2x00dev, offset, + &key_entry, sizeof(key_entry)); + } + + /* + * The cipher types are stored over multiple registers + * starting with SHARED_KEY_MODE_BASE each word will have + * 32 bits and contains the cipher types for 2 bssidx each. + * Using the correct defines correctly will cause overhead, + * so just calculate the correct offset. + */ + field.bit_offset = 4 * (key->hw_key_idx % 8); + field.bit_mask = 0x7 << field.bit_offset; + + offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); + + rt2800_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, field, + (crypto->cmd == SET_KEY) * crypto->cipher); + rt2800_register_write(rt2x00dev, offset, reg); + + /* + * Update WCID information + */ + rt2800_config_wcid_attr(rt2x00dev, crypto, key); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_config_shared_key); + +int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + struct hw_key_entry key_entry; + u32 offset; + + if (crypto->cmd == SET_KEY) { + /* + * 1 pairwise key is possible per AID, this means that the AID + * equals our hw_key_idx. Make sure the WCID starts _after_ the + * last possible shared key entry. + */ + if (crypto->aid > (256 - 32)) + return -ENOSPC; + + key->hw_key_idx = 32 + crypto->aid; + + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, + sizeof(key_entry.tx_mic)); + memcpy(key_entry.rx_mic, crypto->rx_mic, + sizeof(key_entry.rx_mic)); + + offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx); + rt2800_register_multiwrite(rt2x00dev, offset, + &key_entry, sizeof(key_entry)); + } + + /* + * Update WCID information + */ + rt2800_config_wcid_attr(rt2x00dev, crypto, key); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_config_pairwise_key); + +void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter_flags) +{ + u32 reg; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2800_register_read(rt2x00dev, RX_FILTER_CFG, ®); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, + !(filter_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, + !(filter_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, + !(filter_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST, + !(filter_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BROADCAST, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_DUPLICATE, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END_ACK, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_ACK, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CTS, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, + !(filter_flags & FIF_PSPOLL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, + !(filter_flags & FIF_CONTROL)); + rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg); +} +EXPORT_SYMBOL_GPL(rt2800_config_filter); + +void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, const unsigned int flags) +{ + unsigned int beacon_base; + u32 reg; + + if (flags & CONFIG_UPDATE_TYPE) { + /* + * Clear current synchronisation setup. + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); + rt2800_register_write(rt2x00dev, beacon_base, 0); + + /* + * Enable synchronisation. + */ + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + } + + if (flags & CONFIG_UPDATE_MAC) { + reg = le32_to_cpu(conf->mac[1]); + rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); + conf->mac[1] = cpu_to_le32(reg); + + rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, + conf->mac, sizeof(conf->mac)); + } + + if (flags & CONFIG_UPDATE_BSSID) { + reg = le32_to_cpu(conf->bssid[1]); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 0); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); + conf->bssid[1] = cpu_to_le32(reg); + + rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, + conf->bssid, sizeof(conf->bssid)); + } +} +EXPORT_SYMBOL_GPL(rt2800_config_intf); + +void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp) +{ + u32 reg; + + rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20); + rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + + rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, + !!erp->short_preamble); + rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, + !!erp->short_preamble); + rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + + rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, + erp->cts_protection ? 2 : 0); + rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, + erp->basic_rates); + rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + + rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); + rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); + rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); + rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); + + rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); + rt2x00_set_field32(®, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4); + rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); + rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); + rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); + + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, + erp->beacon_int * 16); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); +} +EXPORT_SYMBOL_GPL(rt2800_config_erp); + +void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) +{ + u8 r1; + u8 r3; + + rt2800_bbp_read(rt2x00dev, 1, &r1); + rt2800_bbp_read(rt2x00dev, 3, &r3); + + /* + * Configure the TX antenna. + */ + switch ((int)ant->tx) { + case 1: + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); + if (rt2x00_intf_is_pci(rt2x00dev)) + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); + break; + case 2: + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); + break; + case 3: + /* Do nothing */ + break; + } + + /* + * Configure the RX antenna. + */ + switch ((int)ant->rx) { + case 1: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); + break; + case 2: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1); + break; + case 3: + rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2); + break; + } + + rt2800_bbp_write(rt2x00dev, 3, r3); + rt2800_bbp_write(rt2x00dev, 1, r1); +} +EXPORT_SYMBOL_GPL(rt2800_config_ant); + +static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain; + + if (libconf->rf.channel <= 14) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG); + } else if (libconf->rf.channel <= 64) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); + } else if (libconf->rf.channel <= 128) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); + lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2); + } + + rt2x00dev->lna_gain = lna_gain; +} + +static void rt2800_config_channel_rt2x(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + if (rt2x00dev->default_ant.tx == 1) + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1); + + if (rt2x00dev->default_ant.rx == 1) { + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1); + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); + } else if (rt2x00dev->default_ant.rx == 2) + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); + + if (rf->channel > 14) { + /* + * When TX power is below 0, we should increase it by 7 to + * make it a positive value (Minumum value is -7). + * However this means that values between 0 and 7 have + * double meaning, and we should set a 7DBm boost flag. + */ + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, + (info->tx_power1 >= 0)); + + if (info->tx_power1 < 0) + info->tx_power1 += 7; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, + TXPOWER_A_TO_DEV(info->tx_power1)); + + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, + (info->tx_power2 >= 0)); + + if (info->tx_power2 < 0) + info->tx_power2 += 7; + + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, + TXPOWER_A_TO_DEV(info->tx_power2)); + } else { + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, + TXPOWER_G_TO_DEV(info->tx_power1)); + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, + TXPOWER_G_TO_DEV(info->tx_power2)); + } + + rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); + + rt2800_rf_write(rt2x00dev, 1, rf->rf1); + rt2800_rf_write(rt2x00dev, 2, rf->rf2); + rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt2800_rf_write(rt2x00dev, 1, rf->rf1); + rt2800_rf_write(rt2x00dev, 2, rf->rf2); + rt2800_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt2800_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt2800_rf_write(rt2x00dev, 1, rf->rf1); + rt2800_rf_write(rt2x00dev, 2, rf->rf2); + rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt2800_rf_write(rt2x00dev, 4, rf->rf4); +} + +static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + u8 rfcsr; + + rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); + rt2800_rfcsr_write(rt2x00dev, 2, rf->rf3); + + rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); + rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, + TXPOWER_G_TO_DEV(info->tx_power1)); + rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); + rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); + + rt2800_rfcsr_write(rt2x00dev, 24, + rt2x00dev->calibration[conf_is_ht40(conf)]); + + rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); + rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); +} + +static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + u32 reg; + unsigned int tx_pin; + u8 bbp; + + if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) + rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info); + else + rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info); + + /* + * Change BBP settings + */ + rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 86, 0); + + if (rf->channel <= 14) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { + rt2800_bbp_write(rt2x00dev, 82, 0x62); + rt2800_bbp_write(rt2x00dev, 75, 0x46); + } else { + rt2800_bbp_write(rt2x00dev, 82, 0x84); + rt2800_bbp_write(rt2x00dev, 75, 0x50); + } + } else { + rt2800_bbp_write(rt2x00dev, 82, 0xf2); + + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + rt2800_bbp_write(rt2x00dev, 75, 0x46); + else + rt2800_bbp_write(rt2x00dev, 75, 0x50); + } + + rt2800_register_read(rt2x00dev, TX_BAND_CFG, ®); + rt2x00_set_field32(®, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf)); + rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); + rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); + rt2800_register_write(rt2x00dev, TX_BAND_CFG, reg); + + tx_pin = 0; + + /* Turn on unused PA or LNA when not using 1T or 1R */ + if (rt2x00dev->default_ant.tx != 1) { + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1); + } + + /* Turn on unused PA or LNA when not using 1T or 1R */ + if (rt2x00dev->default_ant.rx != 1) { + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1); + } + + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14); + rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14); + + rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); + + rt2800_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); + rt2800_bbp_write(rt2x00dev, 4, bbp); + + rt2800_bbp_read(rt2x00dev, 3, &bbp); + rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); + rt2800_bbp_write(rt2x00dev, 3, bbp); + + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { + if (conf_is_ht40(conf)) { + rt2800_bbp_write(rt2x00dev, 69, 0x1a); + rt2800_bbp_write(rt2x00dev, 70, 0x0a); + rt2800_bbp_write(rt2x00dev, 73, 0x16); + } else { + rt2800_bbp_write(rt2x00dev, 69, 0x16); + rt2800_bbp_write(rt2x00dev, 70, 0x08); + rt2800_bbp_write(rt2x00dev, 73, 0x11); + } + } + + msleep(1); +} + +static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + u32 reg; + u32 value = TXPOWER_G_TO_DEV(txpower); + u8 r1; + + rt2800_bbp_read(rt2x00dev, 1, &r1); + rt2x00_set_field8(®, BBP1_TX_POWER, 0); + rt2800_bbp_write(rt2x00dev, 1, r1); + + rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, ®); + rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_2MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_55MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_11MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_6MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_9MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_12MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_0_18MBS, value); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, reg); + + rt2800_register_read(rt2x00dev, TX_PWR_CFG_1, ®); + rt2x00_set_field32(®, TX_PWR_CFG_1_24MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_36MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_48MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_54MBS, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS0, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS1, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS2, value); + rt2x00_set_field32(®, TX_PWR_CFG_1_MCS3, value); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, reg); + + rt2800_register_read(rt2x00dev, TX_PWR_CFG_2, ®); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS4, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS5, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS6, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS7, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS8, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS9, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS10, value); + rt2x00_set_field32(®, TX_PWR_CFG_2_MCS11, value); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, reg); + + rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, ®); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS12, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS13, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS14, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_MCS15, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN1, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN2, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN3, value); + rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN4, value); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, reg); + + rt2800_register_read(rt2x00dev, TX_PWR_CFG_4, ®); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN5, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN6, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN7, value); + rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN8, value); + rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, reg); +} + +static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u32 reg; + + rt2800_register_read(rt2x00dev, TX_RTY_CFG, ®); + rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, + libconf->conf->short_frame_max_tx_count); + rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_THRE, 2000); + rt2x00_set_field32(®, TX_RTY_CFG_NON_AGG_RTY_MODE, 0); + rt2x00_set_field32(®, TX_RTY_CFG_AGG_RTY_MODE, 0); + rt2x00_set_field32(®, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1); + rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg); +} + +static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + enum dev_state state = + (libconf->conf->flags & IEEE80211_CONF_PS) ? + STATE_SLEEP : STATE_AWAKE; + u32 reg; + + if (state == STATE_SLEEP) { + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); + + rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, + libconf->conf->listen_interval - 1); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 1); + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + } else { + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + + rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); + rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); + } +} + +void rt2800_config(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf, + const unsigned int flags) +{ + /* Always recalculate LNA gain before changing configuration */ + rt2800_config_lna_gain(rt2x00dev, libconf); + + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) + rt2800_config_channel(rt2x00dev, libconf->conf, + &libconf->rf, &libconf->channel); + if (flags & IEEE80211_CONF_CHANGE_POWER) + rt2800_config_txpower(rt2x00dev, libconf->conf->power_level); + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt2800_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_PS) + rt2800_config_ps(rt2x00dev, libconf); +} +EXPORT_SYMBOL_GPL(rt2800_config); + +/* + * Link tuning + */ +void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual) +{ + u32 reg; + + /* + * Update FCS error count from register. + */ + rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); + qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); +} +EXPORT_SYMBOL_GPL(rt2800_link_stats); + +static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) +{ + if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) + return 0x1c + (2 * rt2x00dev->lna_gain); + else + return 0x2e + rt2x00dev->lna_gain; + } + + if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) + return 0x32 + (rt2x00dev->lna_gain * 5) / 3; + else + return 0x3a + (rt2x00dev->lna_gain * 5) / 3; +} + +static inline void rt2800_set_vgc(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual, u8 vgc_level) +{ + if (qual->vgc_level != vgc_level) { + rt2800_bbp_write(rt2x00dev, 66, vgc_level); + qual->vgc_level = vgc_level; + qual->vgc_level_reg = vgc_level; + } +} + +void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual) +{ + rt2800_set_vgc(rt2x00dev, qual, rt2800_get_default_vgc(rt2x00dev)); +} +EXPORT_SYMBOL_GPL(rt2800_reset_tuner); + +void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, + const u32 count) +{ + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) + return; + + /* + * When RSSI is better then -80 increase VGC level with 0x10 + */ + rt2800_set_vgc(rt2x00dev, qual, + rt2800_get_default_vgc(rt2x00dev) + + ((qual->rssi > -80) * 0x10)); +} +EXPORT_SYMBOL_GPL(rt2800_link_tuner); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 40a7f72e87f5..b07caba37817 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -110,4 +110,29 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, const u8 command, const u8 token, const u8 arg0, const u8 arg1); +extern const struct rt2x00debug rt2800_rt2x00debug; + +int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev); +void rt2800_init_led(struct rt2x00_dev *rt2x00dev, + struct rt2x00_led *led, enum led_type type); +int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key); +int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key); +void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, + const unsigned int filter_flags); +void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, + struct rt2x00intf_conf *conf, const unsigned int flags); +void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp); +void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant); +void rt2800_config(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf, + const unsigned int flags); +void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); +void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); +void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, + const u32 count); + #endif /* RT2800LIB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 90ada5d014fd..cbf8be3057ef 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -187,830 +187,6 @@ static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) } #endif /* CONFIG_RT2800PCI_PCI */ -#ifdef CONFIG_RT2X00_LIB_DEBUGFS -static const struct rt2x00debug rt2800pci_rt2x00debug = { - .owner = THIS_MODULE, - .csr = { - .read = rt2800_register_read, - .write = rt2800_register_write, - .flags = RT2X00DEBUGFS_OFFSET, - .word_base = CSR_REG_BASE, - .word_size = sizeof(u32), - .word_count = CSR_REG_SIZE / sizeof(u32), - }, - .eeprom = { - .read = rt2x00_eeprom_read, - .write = rt2x00_eeprom_write, - .word_base = EEPROM_BASE, - .word_size = sizeof(u16), - .word_count = EEPROM_SIZE / sizeof(u16), - }, - .bbp = { - .read = rt2800_bbp_read, - .write = rt2800_bbp_write, - .word_base = BBP_BASE, - .word_size = sizeof(u8), - .word_count = BBP_SIZE / sizeof(u8), - }, - .rf = { - .read = rt2x00_rf_read, - .write = rt2800_rf_write, - .word_base = RF_BASE, - .word_size = sizeof(u32), - .word_count = RF_SIZE / sizeof(u32), - }, -}; -#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ - -static int rt2800pci_rfkill_poll(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - - rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); - return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); -} - -#ifdef CONFIG_RT2X00_LIB_LEDS -static void rt2800pci_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct rt2x00_led *led = - container_of(led_cdev, struct rt2x00_led, led_dev); - unsigned int enabled = brightness != LED_OFF; - unsigned int bg_mode = - (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); - unsigned int polarity = - rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, - EEPROM_FREQ_LED_POLARITY); - unsigned int ledmode = - rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, - EEPROM_FREQ_LED_MODE); - - if (led->type == LED_TYPE_RADIO) { - rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, - enabled ? 0x20 : 0); - } else if (led->type == LED_TYPE_ASSOC) { - rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, - enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); - } else if (led->type == LED_TYPE_QUALITY) { - /* - * The brightness is divided into 6 levels (0 - 5), - * The specs tell us the following levels: - * 0, 1 ,3, 7, 15, 31 - * to determine the level in a simple way we can simply - * work with bitshifting: - * (1 << level) - 1 - */ - rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, - (1 << brightness / (LED_FULL / 6)) - 1, - polarity); - } -} - -static int rt2800pci_blink_set(struct led_classdev *led_cdev, - unsigned long *delay_on, - unsigned long *delay_off) -{ - struct rt2x00_led *led = - container_of(led_cdev, struct rt2x00_led, led_dev); - u32 reg; - - rt2800_register_read(led->rt2x00dev, LED_CFG, ®); - rt2x00_set_field32(®, LED_CFG_ON_PERIOD, *delay_on); - rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); - rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); - rt2x00_set_field32(®, LED_CFG_R_LED_MODE, 3); - rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 12); - rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3); - rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1); - rt2800_register_write(led->rt2x00dev, LED_CFG, reg); - - return 0; -} - -static void rt2800pci_init_led(struct rt2x00_dev *rt2x00dev, - struct rt2x00_led *led, - enum led_type type) -{ - led->rt2x00dev = rt2x00dev; - led->type = type; - led->led_dev.brightness_set = rt2800pci_brightness_set; - led->led_dev.blink_set = rt2800pci_blink_set; - led->flags = LED_INITIALIZED; -} -#endif /* CONFIG_RT2X00_LIB_LEDS */ - -/* - * Configuration handlers. - */ -static void rt2800pci_config_wcid_attr(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_crypto *crypto, - struct ieee80211_key_conf *key) -{ - struct mac_wcid_entry wcid_entry; - struct mac_iveiv_entry iveiv_entry; - u32 offset; - u32 reg; - - offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); - - rt2800_register_read(rt2x00dev, offset, ®); - rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, - !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); - rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, - (crypto->cmd == SET_KEY) * crypto->cipher); - rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, - (crypto->cmd == SET_KEY) * crypto->bssidx); - rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); - rt2800_register_write(rt2x00dev, offset, reg); - - offset = MAC_IVEIV_ENTRY(key->hw_key_idx); - - memset(&iveiv_entry, 0, sizeof(iveiv_entry)); - if ((crypto->cipher == CIPHER_TKIP) || - (crypto->cipher == CIPHER_TKIP_NO_MIC) || - (crypto->cipher == CIPHER_AES)) - iveiv_entry.iv[3] |= 0x20; - iveiv_entry.iv[3] |= key->keyidx << 6; - rt2800_register_multiwrite(rt2x00dev, offset, - &iveiv_entry, sizeof(iveiv_entry)); - - offset = MAC_WCID_ENTRY(key->hw_key_idx); - - memset(&wcid_entry, 0, sizeof(wcid_entry)); - if (crypto->cmd == SET_KEY) - memcpy(&wcid_entry, crypto->address, ETH_ALEN); - rt2800_register_multiwrite(rt2x00dev, offset, - &wcid_entry, sizeof(wcid_entry)); -} - -static int rt2800pci_config_shared_key(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_crypto *crypto, - struct ieee80211_key_conf *key) -{ - struct hw_key_entry key_entry; - struct rt2x00_field32 field; - u32 offset; - u32 reg; - - if (crypto->cmd == SET_KEY) { - key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx; - - memcpy(key_entry.key, crypto->key, - sizeof(key_entry.key)); - memcpy(key_entry.tx_mic, crypto->tx_mic, - sizeof(key_entry.tx_mic)); - memcpy(key_entry.rx_mic, crypto->rx_mic, - sizeof(key_entry.rx_mic)); - - offset = SHARED_KEY_ENTRY(key->hw_key_idx); - rt2800_register_multiwrite(rt2x00dev, offset, - &key_entry, sizeof(key_entry)); - } - - /* - * The cipher types are stored over multiple registers - * starting with SHARED_KEY_MODE_BASE each word will have - * 32 bits and contains the cipher types for 2 bssidx each. - * Using the correct defines correctly will cause overhead, - * so just calculate the correct offset. - */ - field.bit_offset = 4 * (key->hw_key_idx % 8); - field.bit_mask = 0x7 << field.bit_offset; - - offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); - - rt2800_register_read(rt2x00dev, offset, ®); - rt2x00_set_field32(®, field, - (crypto->cmd == SET_KEY) * crypto->cipher); - rt2800_register_write(rt2x00dev, offset, reg); - - /* - * Update WCID information - */ - rt2800pci_config_wcid_attr(rt2x00dev, crypto, key); - - return 0; -} - -static int rt2800pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_crypto *crypto, - struct ieee80211_key_conf *key) -{ - struct hw_key_entry key_entry; - u32 offset; - - if (crypto->cmd == SET_KEY) { - /* - * 1 pairwise key is possible per AID, this means that the AID - * equals our hw_key_idx. Make sure the WCID starts _after_ the - * last possible shared key entry. - */ - if (crypto->aid > (256 - 32)) - return -ENOSPC; - - key->hw_key_idx = 32 + crypto->aid; - - - memcpy(key_entry.key, crypto->key, - sizeof(key_entry.key)); - memcpy(key_entry.tx_mic, crypto->tx_mic, - sizeof(key_entry.tx_mic)); - memcpy(key_entry.rx_mic, crypto->rx_mic, - sizeof(key_entry.rx_mic)); - - offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx); - rt2800_register_multiwrite(rt2x00dev, offset, - &key_entry, sizeof(key_entry)); - } - - /* - * Update WCID information - */ - rt2800pci_config_wcid_attr(rt2x00dev, crypto, key); - - return 0; -} - -static void rt2800pci_config_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter_flags) -{ - u32 reg; - - /* - * Start configuration steps. - * Note that the version error will always be dropped - * and broadcast frames will always be accepted since - * there is no filter for it at this time. - */ - rt2800_register_read(rt2x00dev, RX_FILTER_CFG, ®); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, - !(filter_flags & FIF_FCSFAIL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, - !(filter_flags & FIF_PLCPFAIL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, - !(filter_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST, - !(filter_flags & FIF_ALLMULTI)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BROADCAST, 0); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_DUPLICATE, 1); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END_ACK, - !(filter_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END, - !(filter_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_ACK, - !(filter_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CTS, - !(filter_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, - !(filter_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, - !(filter_flags & FIF_PSPOLL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, - !(filter_flags & FIF_CONTROL)); - rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg); -} - -static void rt2800pci_config_intf(struct rt2x00_dev *rt2x00dev, - struct rt2x00_intf *intf, - struct rt2x00intf_conf *conf, - const unsigned int flags) -{ - unsigned int beacon_base; - u32 reg; - - if (flags & CONFIG_UPDATE_TYPE) { - /* - * Clear current synchronisation setup. - * For the Beacon base registers we only need to clear - * the first byte since that byte contains the VALID and OWNER - * bits which (when set to 0) will invalidate the entire beacon. - */ - beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - rt2800_register_write(rt2x00dev, beacon_base, 0); - - /* - * Enable synchronisation. - */ - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); - rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); - } - - if (flags & CONFIG_UPDATE_MAC) { - reg = le32_to_cpu(conf->mac[1]); - rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); - conf->mac[1] = cpu_to_le32(reg); - - rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, - conf->mac, sizeof(conf->mac)); - } - - if (flags & CONFIG_UPDATE_BSSID) { - reg = le32_to_cpu(conf->bssid[1]); - rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 0); - rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); - conf->bssid[1] = cpu_to_le32(reg); - - rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, - conf->bssid, sizeof(conf->bssid)); - } -} - -static void rt2800pci_config_erp(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_erp *erp) -{ - u32 reg; - - rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); - rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20); - rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); - - rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); - rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, - !!erp->short_preamble); - rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, - !!erp->short_preamble); - rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); - - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); - rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, - erp->cts_protection ? 2 : 0); - rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - - rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, - erp->basic_rates); - rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); - - rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); - rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); - rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); - rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); - - rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); - rt2x00_set_field32(®, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs); - rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs); - rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4); - rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); - rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); - rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); - - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); - rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, - erp->beacon_int * 16); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); -} - -static void rt2800pci_config_ant(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) -{ - u8 r1; - u8 r3; - - rt2800_bbp_read(rt2x00dev, 1, &r1); - rt2800_bbp_read(rt2x00dev, 3, &r3); - - /* - * Configure the TX antenna. - */ - switch ((int)ant->tx) { - case 1: - rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); - if (rt2x00_intf_is_pci(rt2x00dev)) - rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); - break; - case 2: - rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); - break; - case 3: - /* Do nothing */ - break; - } - - /* - * Configure the RX antenna. - */ - switch ((int)ant->rx) { - case 1: - rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); - break; - case 2: - rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1); - break; - case 3: - rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2); - break; - } - - rt2800_bbp_write(rt2x00dev, 3, r3); - rt2800_bbp_write(rt2x00dev, 1, r1); -} - -static void rt2800pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u16 eeprom; - short lna_gain; - - if (libconf->rf.channel <= 14) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); - lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG); - } else if (libconf->rf.channel <= 64) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); - lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); - } else if (libconf->rf.channel <= 128) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); - lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1); - } else { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); - lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2); - } - - rt2x00dev->lna_gain = lna_gain; -} - -static void rt2800pci_config_channel_rt2x(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf, - struct rf_channel *rf, - struct channel_info *info) -{ - rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - - if (rt2x00dev->default_ant.tx == 1) - rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1); - - if (rt2x00dev->default_ant.rx == 1) { - rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1); - rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); - } else if (rt2x00dev->default_ant.rx == 2) - rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); - - if (rf->channel > 14) { - /* - * When TX power is below 0, we should increase it by 7 to - * make it a positive value (Minumum value is -7). - * However this means that values between 0 and 7 have - * double meaning, and we should set a 7DBm boost flag. - */ - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, - (info->tx_power1 >= 0)); - - if (info->tx_power1 < 0) - info->tx_power1 += 7; - - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, - TXPOWER_A_TO_DEV(info->tx_power1)); - - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, - (info->tx_power2 >= 0)); - - if (info->tx_power2 < 0) - info->tx_power2 += 7; - - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, - TXPOWER_A_TO_DEV(info->tx_power2)); - } else { - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, - TXPOWER_G_TO_DEV(info->tx_power1)); - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, - TXPOWER_G_TO_DEV(info->tx_power2)); - } - - rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); - - rt2800_rf_write(rt2x00dev, 1, rf->rf1); - rt2800_rf_write(rt2x00dev, 2, rf->rf2); - rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt2800_rf_write(rt2x00dev, 4, rf->rf4); - - udelay(200); - - rt2800_rf_write(rt2x00dev, 1, rf->rf1); - rt2800_rf_write(rt2x00dev, 2, rf->rf2); - rt2800_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); - rt2800_rf_write(rt2x00dev, 4, rf->rf4); - - udelay(200); - - rt2800_rf_write(rt2x00dev, 1, rf->rf1); - rt2800_rf_write(rt2x00dev, 2, rf->rf2); - rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt2800_rf_write(rt2x00dev, 4, rf->rf4); -} - -static void rt2800pci_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf, - struct rf_channel *rf, - struct channel_info *info) -{ - u8 rfcsr; - - rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); - rt2800_rfcsr_write(rt2x00dev, 2, rf->rf3); - - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); - rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - - rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, - TXPOWER_G_TO_DEV(info->tx_power1)); - rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); - - rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); - rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); - - rt2800_rfcsr_write(rt2x00dev, 24, - rt2x00dev->calibration[conf_is_ht40(conf)]); - - rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); - rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); -} - -static void rt2800pci_config_channel(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf, - struct rf_channel *rf, - struct channel_info *info) -{ - u32 reg; - unsigned int tx_pin; - u8 bbp; - - if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) - rt2800pci_config_channel_rt2x(rt2x00dev, conf, rf, info); - else - rt2800pci_config_channel_rt3x(rt2x00dev, conf, rf, info); - - /* - * Change BBP settings - */ - rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); - rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); - rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); - rt2800_bbp_write(rt2x00dev, 86, 0); - - if (rf->channel <= 14) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { - rt2800_bbp_write(rt2x00dev, 82, 0x62); - rt2800_bbp_write(rt2x00dev, 75, 0x46); - } else { - rt2800_bbp_write(rt2x00dev, 82, 0x84); - rt2800_bbp_write(rt2x00dev, 75, 0x50); - } - } else { - rt2800_bbp_write(rt2x00dev, 82, 0xf2); - - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) - rt2800_bbp_write(rt2x00dev, 75, 0x46); - else - rt2800_bbp_write(rt2x00dev, 75, 0x50); - } - - rt2800_register_read(rt2x00dev, TX_BAND_CFG, ®); - rt2x00_set_field32(®, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf)); - rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); - rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); - rt2800_register_write(rt2x00dev, TX_BAND_CFG, reg); - - tx_pin = 0; - - /* Turn on unused PA or LNA when not using 1T or 1R */ - if (rt2x00dev->default_ant.tx != 1) { - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1); - } - - /* Turn on unused PA or LNA when not using 1T or 1R */ - if (rt2x00dev->default_ant.rx != 1) { - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1); - } - - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14); - - rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); - - rt2800_bbp_read(rt2x00dev, 4, &bbp); - rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); - rt2800_bbp_write(rt2x00dev, 4, bbp); - - rt2800_bbp_read(rt2x00dev, 3, &bbp); - rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); - rt2800_bbp_write(rt2x00dev, 3, bbp); - - if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { - if (conf_is_ht40(conf)) { - rt2800_bbp_write(rt2x00dev, 69, 0x1a); - rt2800_bbp_write(rt2x00dev, 70, 0x0a); - rt2800_bbp_write(rt2x00dev, 73, 0x16); - } else { - rt2800_bbp_write(rt2x00dev, 69, 0x16); - rt2800_bbp_write(rt2x00dev, 70, 0x08); - rt2800_bbp_write(rt2x00dev, 73, 0x11); - } - } - - msleep(1); -} - -static void rt2800pci_config_txpower(struct rt2x00_dev *rt2x00dev, - const int txpower) -{ - u32 reg; - u32 value = TXPOWER_G_TO_DEV(txpower); - u8 r1; - - rt2800_bbp_read(rt2x00dev, 1, &r1); - rt2x00_set_field8(®, BBP1_TX_POWER, 0); - rt2800_bbp_write(rt2x00dev, 1, r1); - - rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, ®); - rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_2MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_55MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_11MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_6MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_9MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_12MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_18MBS, value); - rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, reg); - - rt2800_register_read(rt2x00dev, TX_PWR_CFG_1, ®); - rt2x00_set_field32(®, TX_PWR_CFG_1_24MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_36MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_48MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_54MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_MCS0, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_MCS1, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_MCS2, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_MCS3, value); - rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, reg); - - rt2800_register_read(rt2x00dev, TX_PWR_CFG_2, ®); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS4, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS5, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS6, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS7, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS8, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS9, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS10, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS11, value); - rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, reg); - - rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, ®); - rt2x00_set_field32(®, TX_PWR_CFG_3_MCS12, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_MCS13, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_MCS14, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_MCS15, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN1, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN2, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN3, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN4, value); - rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, reg); - - rt2800_register_read(rt2x00dev, TX_PWR_CFG_4, ®); - rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN5, value); - rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN6, value); - rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN7, value); - rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN8, value); - rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, reg); -} - -static void rt2800pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u32 reg; - - rt2800_register_read(rt2x00dev, TX_RTY_CFG, ®); - rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, - libconf->conf->short_frame_max_tx_count); - rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, - libconf->conf->long_frame_max_tx_count); - rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_THRE, 2000); - rt2x00_set_field32(®, TX_RTY_CFG_NON_AGG_RTY_MODE, 0); - rt2x00_set_field32(®, TX_RTY_CFG_AGG_RTY_MODE, 0); - rt2x00_set_field32(®, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1); - rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg); -} - -static void rt2800pci_config_ps(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - enum dev_state state = - (libconf->conf->flags & IEEE80211_CONF_PS) ? - STATE_SLEEP : STATE_AWAKE; - u32 reg; - - if (state == STATE_SLEEP) { - rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); - - rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, - libconf->conf->listen_interval - 1); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 1); - rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); - - rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); - } else { - rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); - - rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); - rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); - } -} - -static void rt2800pci_config(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf, - const unsigned int flags) -{ - /* Always recalculate LNA gain before changing configuration */ - rt2800pci_config_lna_gain(rt2x00dev, libconf); - - if (flags & IEEE80211_CONF_CHANGE_CHANNEL) - rt2800pci_config_channel(rt2x00dev, libconf->conf, - &libconf->rf, &libconf->channel); - if (flags & IEEE80211_CONF_CHANGE_POWER) - rt2800pci_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) - rt2800pci_config_retry_limit(rt2x00dev, libconf); - if (flags & IEEE80211_CONF_CHANGE_PS) - rt2800pci_config_ps(rt2x00dev, libconf); -} - -/* - * Link tuning - */ -static void rt2800pci_link_stats(struct rt2x00_dev *rt2x00dev, - struct link_qual *qual) -{ - u32 reg; - - /* - * Update FCS error count from register. - */ - rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); - qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); -} - -static u8 rt2800pci_get_default_vgc(struct rt2x00_dev *rt2x00dev) -{ - if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) - return 0x2e + rt2x00dev->lna_gain; - - if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) - return 0x32 + (rt2x00dev->lna_gain * 5) / 3; - else - return 0x3a + (rt2x00dev->lna_gain * 5) / 3; -} - -static inline void rt2800pci_set_vgc(struct rt2x00_dev *rt2x00dev, - struct link_qual *qual, u8 vgc_level) -{ - if (qual->vgc_level != vgc_level) { - rt2800_bbp_write(rt2x00dev, 66, vgc_level); - qual->vgc_level = vgc_level; - qual->vgc_level_reg = vgc_level; - } -} - -static void rt2800pci_reset_tuner(struct rt2x00_dev *rt2x00dev, - struct link_qual *qual) -{ - rt2800pci_set_vgc(rt2x00dev, qual, - rt2800pci_get_default_vgc(rt2x00dev)); -} - -static void rt2800pci_link_tuner(struct rt2x00_dev *rt2x00dev, - struct link_qual *qual, const u32 count) -{ - if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) - return; - - /* - * When RSSI is better then -80 increase VGC level with 0x10 - */ - rt2800pci_set_vgc(rt2x00dev, qual, - rt2800pci_get_default_vgc(rt2x00dev) + - ((qual->rssi > -80) * 0x10)); -} - /* * Firmware functions */ @@ -2575,9 +1751,9 @@ static int rt2800pci_init_eeprom(struct rt2x00_dev *rt2x00dev) * Store led settings, for correct led behaviour. */ #ifdef CONFIG_RT2X00_LIB_LEDS - rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); - rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); - rt2800pci_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); + rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); + rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); + rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); #endif /* CONFIG_RT2X00_LIB_LEDS */ @@ -2994,23 +2170,23 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .get_entry_state = rt2800pci_get_entry_state, .clear_entry = rt2800pci_clear_entry, .set_device_state = rt2800pci_set_device_state, - .rfkill_poll = rt2800pci_rfkill_poll, - .link_stats = rt2800pci_link_stats, - .reset_tuner = rt2800pci_reset_tuner, - .link_tuner = rt2800pci_link_tuner, + .rfkill_poll = rt2800_rfkill_poll, + .link_stats = rt2800_link_stats, + .reset_tuner = rt2800_reset_tuner, + .link_tuner = rt2800_link_tuner, .write_tx_desc = rt2800pci_write_tx_desc, .write_tx_data = rt2x00pci_write_tx_data, .write_beacon = rt2800pci_write_beacon, .kick_tx_queue = rt2800pci_kick_tx_queue, .kill_tx_queue = rt2800pci_kill_tx_queue, .fill_rxdone = rt2800pci_fill_rxdone, - .config_shared_key = rt2800pci_config_shared_key, - .config_pairwise_key = rt2800pci_config_pairwise_key, - .config_filter = rt2800pci_config_filter, - .config_intf = rt2800pci_config_intf, - .config_erp = rt2800pci_config_erp, - .config_ant = rt2800pci_config_ant, - .config = rt2800pci_config, + .config_shared_key = rt2800_config_shared_key, + .config_pairwise_key = rt2800_config_pairwise_key, + .config_filter = rt2800_config_filter, + .config_intf = rt2800_config_intf, + .config_erp = rt2800_config_erp, + .config_ant = rt2800_config_ant, + .config = rt2800_config, }; static const struct data_queue_desc rt2800pci_queue_rx = { @@ -3047,7 +2223,7 @@ static const struct rt2x00_ops rt2800pci_ops = { .lib = &rt2800pci_rt2x00_ops, .hw = &rt2800pci_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS - .debugfs = &rt2800pci_rt2x00debug, + .debugfs = &rt2800_rt2x00debug, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 6bd646a979af..365f66fe7c68 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -45,832 +45,6 @@ static int modparam_nohwcrypt = 1; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -#ifdef CONFIG_RT2X00_LIB_DEBUGFS -static const struct rt2x00debug rt2800usb_rt2x00debug = { - .owner = THIS_MODULE, - .csr = { - .read = rt2800_register_read, - .write = rt2800_register_write, - .flags = RT2X00DEBUGFS_OFFSET, - .word_base = CSR_REG_BASE, - .word_size = sizeof(u32), - .word_count = CSR_REG_SIZE / sizeof(u32), - }, - .eeprom = { - .read = rt2x00_eeprom_read, - .write = rt2x00_eeprom_write, - .word_base = EEPROM_BASE, - .word_size = sizeof(u16), - .word_count = EEPROM_SIZE / sizeof(u16), - }, - .bbp = { - .read = rt2800_bbp_read, - .write = rt2800_bbp_write, - .word_base = BBP_BASE, - .word_size = sizeof(u8), - .word_count = BBP_SIZE / sizeof(u8), - }, - .rf = { - .read = rt2x00_rf_read, - .write = rt2800_rf_write, - .word_base = RF_BASE, - .word_size = sizeof(u32), - .word_count = RF_SIZE / sizeof(u32), - }, -}; -#endif /* CONFIG_RT2X00_LIB_DEBUGFS */ - -static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - - rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); - return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); -} - -#ifdef CONFIG_RT2X00_LIB_LEDS -static void rt2800usb_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct rt2x00_led *led = - container_of(led_cdev, struct rt2x00_led, led_dev); - unsigned int enabled = brightness != LED_OFF; - unsigned int bg_mode = - (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); - unsigned int polarity = - rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, - EEPROM_FREQ_LED_POLARITY); - unsigned int ledmode = - rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, - EEPROM_FREQ_LED_MODE); - - if (led->type == LED_TYPE_RADIO) { - rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, - enabled ? 0x20 : 0); - } else if (led->type == LED_TYPE_ASSOC) { - rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, - enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); - } else if (led->type == LED_TYPE_QUALITY) { - /* - * The brightness is divided into 6 levels (0 - 5), - * The specs tell us the following levels: - * 0, 1 ,3, 7, 15, 31 - * to determine the level in a simple way we can simply - * work with bitshifting: - * (1 << level) - 1 - */ - rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, - (1 << brightness / (LED_FULL / 6)) - 1, - polarity); - } -} - -static int rt2800usb_blink_set(struct led_classdev *led_cdev, - unsigned long *delay_on, - unsigned long *delay_off) -{ - struct rt2x00_led *led = - container_of(led_cdev, struct rt2x00_led, led_dev); - u32 reg; - - rt2800_register_read(led->rt2x00dev, LED_CFG, ®); - rt2x00_set_field32(®, LED_CFG_ON_PERIOD, *delay_on); - rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); - rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); - rt2x00_set_field32(®, LED_CFG_R_LED_MODE, 3); - rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 12); - rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3); - rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1); - rt2800_register_write(led->rt2x00dev, LED_CFG, reg); - - return 0; -} - -static void rt2800usb_init_led(struct rt2x00_dev *rt2x00dev, - struct rt2x00_led *led, - enum led_type type) -{ - led->rt2x00dev = rt2x00dev; - led->type = type; - led->led_dev.brightness_set = rt2800usb_brightness_set; - led->led_dev.blink_set = rt2800usb_blink_set; - led->flags = LED_INITIALIZED; -} -#endif /* CONFIG_RT2X00_LIB_LEDS */ - -/* - * Configuration handlers. - */ -static void rt2800usb_config_wcid_attr(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_crypto *crypto, - struct ieee80211_key_conf *key) -{ - struct mac_wcid_entry wcid_entry; - struct mac_iveiv_entry iveiv_entry; - u32 offset; - u32 reg; - - offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); - - rt2800_register_read(rt2x00dev, offset, ®); - rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, - !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); - rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, - (crypto->cmd == SET_KEY) * crypto->cipher); - rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, - (crypto->cmd == SET_KEY) * crypto->bssidx); - rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); - rt2800_register_write(rt2x00dev, offset, reg); - - offset = MAC_IVEIV_ENTRY(key->hw_key_idx); - - memset(&iveiv_entry, 0, sizeof(iveiv_entry)); - if ((crypto->cipher == CIPHER_TKIP) || - (crypto->cipher == CIPHER_TKIP_NO_MIC) || - (crypto->cipher == CIPHER_AES)) - iveiv_entry.iv[3] |= 0x20; - iveiv_entry.iv[3] |= key->keyidx << 6; - rt2800_register_multiwrite(rt2x00dev, offset, - &iveiv_entry, sizeof(iveiv_entry)); - - offset = MAC_WCID_ENTRY(key->hw_key_idx); - - memset(&wcid_entry, 0, sizeof(wcid_entry)); - if (crypto->cmd == SET_KEY) - memcpy(&wcid_entry, crypto->address, ETH_ALEN); - rt2800_register_multiwrite(rt2x00dev, offset, - &wcid_entry, sizeof(wcid_entry)); -} - -static int rt2800usb_config_shared_key(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_crypto *crypto, - struct ieee80211_key_conf *key) -{ - struct hw_key_entry key_entry; - struct rt2x00_field32 field; - u32 offset; - u32 reg; - - if (crypto->cmd == SET_KEY) { - key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx; - - memcpy(key_entry.key, crypto->key, - sizeof(key_entry.key)); - memcpy(key_entry.tx_mic, crypto->tx_mic, - sizeof(key_entry.tx_mic)); - memcpy(key_entry.rx_mic, crypto->rx_mic, - sizeof(key_entry.rx_mic)); - - offset = SHARED_KEY_ENTRY(key->hw_key_idx); - rt2800_register_multiwrite(rt2x00dev, offset, - &key_entry, sizeof(key_entry)); - } - - /* - * The cipher types are stored over multiple registers - * starting with SHARED_KEY_MODE_BASE each word will have - * 32 bits and contains the cipher types for 2 bssidx each. - * Using the correct defines correctly will cause overhead, - * so just calculate the correct offset. - */ - field.bit_offset = 4 * (key->hw_key_idx % 8); - field.bit_mask = 0x7 << field.bit_offset; - - offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); - - rt2800_register_read(rt2x00dev, offset, ®); - rt2x00_set_field32(®, field, - (crypto->cmd == SET_KEY) * crypto->cipher); - rt2800_register_write(rt2x00dev, offset, reg); - - /* - * Update WCID information - */ - rt2800usb_config_wcid_attr(rt2x00dev, crypto, key); - - return 0; -} - -static int rt2800usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_crypto *crypto, - struct ieee80211_key_conf *key) -{ - struct hw_key_entry key_entry; - u32 offset; - - if (crypto->cmd == SET_KEY) { - /* - * 1 pairwise key is possible per AID, this means that the AID - * equals our hw_key_idx. Make sure the WCID starts _after_ the - * last possible shared key entry. - */ - if (crypto->aid > (256 - 32)) - return -ENOSPC; - - key->hw_key_idx = 32 + crypto->aid; - - memcpy(key_entry.key, crypto->key, - sizeof(key_entry.key)); - memcpy(key_entry.tx_mic, crypto->tx_mic, - sizeof(key_entry.tx_mic)); - memcpy(key_entry.rx_mic, crypto->rx_mic, - sizeof(key_entry.rx_mic)); - - offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx); - rt2800_register_multiwrite(rt2x00dev, offset, - &key_entry, sizeof(key_entry)); - } - - /* - * Update WCID information - */ - rt2800usb_config_wcid_attr(rt2x00dev, crypto, key); - - return 0; -} - -static void rt2800usb_config_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter_flags) -{ - u32 reg; - - /* - * Start configuration steps. - * Note that the version error will always be dropped - * and broadcast frames will always be accepted since - * there is no filter for it at this time. - */ - rt2800_register_read(rt2x00dev, RX_FILTER_CFG, ®); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, - !(filter_flags & FIF_FCSFAIL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, - !(filter_flags & FIF_PLCPFAIL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, - !(filter_flags & FIF_PROMISC_IN_BSS)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST, - !(filter_flags & FIF_ALLMULTI)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BROADCAST, 0); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_DUPLICATE, 1); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END_ACK, - !(filter_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END, - !(filter_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_ACK, - !(filter_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CTS, - !(filter_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, - !(filter_flags & FIF_CONTROL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, - !(filter_flags & FIF_PSPOLL)); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); - rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, - !(filter_flags & FIF_CONTROL)); - rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg); -} - -static void rt2800usb_config_intf(struct rt2x00_dev *rt2x00dev, - struct rt2x00_intf *intf, - struct rt2x00intf_conf *conf, - const unsigned int flags) -{ - unsigned int beacon_base; - u32 reg; - - if (flags & CONFIG_UPDATE_TYPE) { - /* - * Clear current synchronisation setup. - * For the Beacon base registers we only need to clear - * the first byte since that byte contains the VALID and OWNER - * bits which (when set to 0) will invalidate the entire beacon. - */ - beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - rt2800_register_write(rt2x00dev, beacon_base, 0); - - /* - * Enable synchronisation. - */ - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); - rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); - } - - if (flags & CONFIG_UPDATE_MAC) { - reg = le32_to_cpu(conf->mac[1]); - rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); - conf->mac[1] = cpu_to_le32(reg); - - rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, - conf->mac, sizeof(conf->mac)); - } - - if (flags & CONFIG_UPDATE_BSSID) { - reg = le32_to_cpu(conf->bssid[1]); - rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 0); - rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); - conf->bssid[1] = cpu_to_le32(reg); - - rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, - conf->bssid, sizeof(conf->bssid)); - } -} - -static void rt2800usb_config_erp(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_erp *erp) -{ - u32 reg; - - rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); - rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20); - rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); - - rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); - rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, - !!erp->short_preamble); - rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, - !!erp->short_preamble); - rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); - - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); - rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, - erp->cts_protection ? 2 : 0); - rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - - rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, - erp->basic_rates); - rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); - - rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); - rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); - rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); - rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); - - rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); - rt2x00_set_field32(®, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs); - rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs); - rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4); - rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); - rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); - rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); - - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); - rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, - erp->beacon_int * 16); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); -} - -static void rt2800usb_config_ant(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) -{ - u8 r1; - u8 r3; - - rt2800_bbp_read(rt2x00dev, 1, &r1); - rt2800_bbp_read(rt2x00dev, 3, &r3); - - /* - * Configure the TX antenna. - */ - switch ((int)ant->tx) { - case 1: - rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); - break; - case 2: - rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); - break; - case 3: - /* Do nothing */ - break; - } - - /* - * Configure the RX antenna. - */ - switch ((int)ant->rx) { - case 1: - rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); - break; - case 2: - rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1); - break; - case 3: - rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2); - break; - } - - rt2800_bbp_write(rt2x00dev, 3, r3); - rt2800_bbp_write(rt2x00dev, 1, r1); -} - -static void rt2800usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u16 eeprom; - short lna_gain; - - if (libconf->rf.channel <= 14) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); - lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG); - } else if (libconf->rf.channel <= 64) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); - lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); - } else if (libconf->rf.channel <= 128) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); - lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1); - } else { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); - lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2); - } - - rt2x00dev->lna_gain = lna_gain; -} - -static void rt2800usb_config_channel_rt2x(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf, - struct rf_channel *rf, - struct channel_info *info) -{ - rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - - if (rt2x00dev->default_ant.tx == 1) - rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1); - - if (rt2x00dev->default_ant.rx == 1) { - rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1); - rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); - } else if (rt2x00dev->default_ant.rx == 2) - rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); - - if (rf->channel > 14) { - /* - * When TX power is below 0, we should increase it by 7 to - * make it a positive value (Minumum value is -7). - * However this means that values between 0 and 7 have - * double meaning, and we should set a 7DBm boost flag. - */ - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, - (info->tx_power1 >= 0)); - - if (info->tx_power1 < 0) - info->tx_power1 += 7; - - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, - TXPOWER_A_TO_DEV(info->tx_power1)); - - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, - (info->tx_power2 >= 0)); - - if (info->tx_power2 < 0) - info->tx_power2 += 7; - - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, - TXPOWER_A_TO_DEV(info->tx_power2)); - } else { - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, - TXPOWER_G_TO_DEV(info->tx_power1)); - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, - TXPOWER_G_TO_DEV(info->tx_power2)); - } - - rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); - - rt2800_rf_write(rt2x00dev, 1, rf->rf1); - rt2800_rf_write(rt2x00dev, 2, rf->rf2); - rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt2800_rf_write(rt2x00dev, 4, rf->rf4); - - udelay(200); - - rt2800_rf_write(rt2x00dev, 1, rf->rf1); - rt2800_rf_write(rt2x00dev, 2, rf->rf2); - rt2800_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); - rt2800_rf_write(rt2x00dev, 4, rf->rf4); - - udelay(200); - - rt2800_rf_write(rt2x00dev, 1, rf->rf1); - rt2800_rf_write(rt2x00dev, 2, rf->rf2); - rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt2800_rf_write(rt2x00dev, 4, rf->rf4); -} - -static void rt2800usb_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf, - struct rf_channel *rf, - struct channel_info *info) -{ - u8 rfcsr; - - rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); - rt2800_rfcsr_write(rt2x00dev, 2, rf->rf3); - - rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); - rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); - - rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, - TXPOWER_G_TO_DEV(info->tx_power1)); - rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); - - rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); - rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); - - rt2800_rfcsr_write(rt2x00dev, 24, - rt2x00dev->calibration[conf_is_ht40(conf)]); - - rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); - rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); -} - -static void rt2800usb_config_channel(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf, - struct rf_channel *rf, - struct channel_info *info) -{ - u32 reg; - unsigned int tx_pin; - u8 bbp; - - if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) - rt2800usb_config_channel_rt2x(rt2x00dev, conf, rf, info); - else - rt2800usb_config_channel_rt3x(rt2x00dev, conf, rf, info); - - /* - * Change BBP settings - */ - rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); - rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); - rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); - rt2800_bbp_write(rt2x00dev, 86, 0); - - if (rf->channel <= 14) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { - rt2800_bbp_write(rt2x00dev, 82, 0x62); - rt2800_bbp_write(rt2x00dev, 75, 0x46); - } else { - rt2800_bbp_write(rt2x00dev, 82, 0x84); - rt2800_bbp_write(rt2x00dev, 75, 0x50); - } - } else { - rt2800_bbp_write(rt2x00dev, 82, 0xf2); - - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) - rt2800_bbp_write(rt2x00dev, 75, 0x46); - else - rt2800_bbp_write(rt2x00dev, 75, 0x50); - } - - rt2800_register_read(rt2x00dev, TX_BAND_CFG, ®); - rt2x00_set_field32(®, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf)); - rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); - rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); - rt2800_register_write(rt2x00dev, TX_BAND_CFG, reg); - - tx_pin = 0; - - /* Turn on unused PA or LNA when not using 1T or 1R */ - if (rt2x00dev->default_ant.tx != 1) { - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1); - } - - /* Turn on unused PA or LNA when not using 1T or 1R */ - if (rt2x00dev->default_ant.rx != 1) { - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1); - } - - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14); - rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14); - - rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); - - rt2800_bbp_read(rt2x00dev, 4, &bbp); - rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); - rt2800_bbp_write(rt2x00dev, 4, bbp); - - rt2800_bbp_read(rt2x00dev, 3, &bbp); - rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); - rt2800_bbp_write(rt2x00dev, 3, bbp); - - if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { - if (conf_is_ht40(conf)) { - rt2800_bbp_write(rt2x00dev, 69, 0x1a); - rt2800_bbp_write(rt2x00dev, 70, 0x0a); - rt2800_bbp_write(rt2x00dev, 73, 0x16); - } else { - rt2800_bbp_write(rt2x00dev, 69, 0x16); - rt2800_bbp_write(rt2x00dev, 70, 0x08); - rt2800_bbp_write(rt2x00dev, 73, 0x11); - } - } - - msleep(1); -} - -static void rt2800usb_config_txpower(struct rt2x00_dev *rt2x00dev, - const int txpower) -{ - u32 reg; - u32 value = TXPOWER_G_TO_DEV(txpower); - u8 r1; - - rt2800_bbp_read(rt2x00dev, 1, &r1); - rt2x00_set_field8(®, BBP1_TX_POWER, 0); - rt2800_bbp_write(rt2x00dev, 1, r1); - - rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, ®); - rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_2MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_55MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_11MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_6MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_9MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_12MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_0_18MBS, value); - rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, reg); - - rt2800_register_read(rt2x00dev, TX_PWR_CFG_1, ®); - rt2x00_set_field32(®, TX_PWR_CFG_1_24MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_36MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_48MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_54MBS, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_MCS0, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_MCS1, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_MCS2, value); - rt2x00_set_field32(®, TX_PWR_CFG_1_MCS3, value); - rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, reg); - - rt2800_register_read(rt2x00dev, TX_PWR_CFG_2, ®); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS4, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS5, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS6, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS7, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS8, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS9, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS10, value); - rt2x00_set_field32(®, TX_PWR_CFG_2_MCS11, value); - rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, reg); - - rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, ®); - rt2x00_set_field32(®, TX_PWR_CFG_3_MCS12, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_MCS13, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_MCS14, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_MCS15, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN1, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN2, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN3, value); - rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN4, value); - rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, reg); - - rt2800_register_read(rt2x00dev, TX_PWR_CFG_4, ®); - rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN5, value); - rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN6, value); - rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN7, value); - rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN8, value); - rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, reg); -} - -static void rt2800usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u32 reg; - - rt2800_register_read(rt2x00dev, TX_RTY_CFG, ®); - rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, - libconf->conf->short_frame_max_tx_count); - rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, - libconf->conf->long_frame_max_tx_count); - rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_THRE, 2000); - rt2x00_set_field32(®, TX_RTY_CFG_NON_AGG_RTY_MODE, 0); - rt2x00_set_field32(®, TX_RTY_CFG_AGG_RTY_MODE, 0); - rt2x00_set_field32(®, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1); - rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg); -} - -static void rt2800usb_config_ps(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - enum dev_state state = - (libconf->conf->flags & IEEE80211_CONF_PS) ? - STATE_SLEEP : STATE_AWAKE; - u32 reg; - - if (state == STATE_SLEEP) { - rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); - - rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, - libconf->conf->listen_interval - 1); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 1); - rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); - - rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); - } else { - rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); - - rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); - rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); - rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); - } -} - -static void rt2800usb_config(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf, - const unsigned int flags) -{ - /* Always recalculate LNA gain before changing configuration */ - rt2800usb_config_lna_gain(rt2x00dev, libconf); - - if (flags & IEEE80211_CONF_CHANGE_CHANNEL) - rt2800usb_config_channel(rt2x00dev, libconf->conf, - &libconf->rf, &libconf->channel); - if (flags & IEEE80211_CONF_CHANGE_POWER) - rt2800usb_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) - rt2800usb_config_retry_limit(rt2x00dev, libconf); - if (flags & IEEE80211_CONF_CHANGE_PS) - rt2800usb_config_ps(rt2x00dev, libconf); -} - -/* - * Link tuning - */ -static void rt2800usb_link_stats(struct rt2x00_dev *rt2x00dev, - struct link_qual *qual) -{ - u32 reg; - - /* - * Update FCS error count from register. - */ - rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); - qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); -} - -static u8 rt2800usb_get_default_vgc(struct rt2x00_dev *rt2x00dev) -{ - if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { - if (rt2x00_intf_is_usb(rt2x00dev) && - rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) - return 0x1c + (2 * rt2x00dev->lna_gain); - else - return 0x2e + rt2x00dev->lna_gain; - } - - if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) - return 0x32 + (rt2x00dev->lna_gain * 5) / 3; - else - return 0x3a + (rt2x00dev->lna_gain * 5) / 3; -} - -static inline void rt2800usb_set_vgc(struct rt2x00_dev *rt2x00dev, - struct link_qual *qual, u8 vgc_level) -{ - if (qual->vgc_level != vgc_level) { - rt2800_bbp_write(rt2x00dev, 66, vgc_level); - qual->vgc_level = vgc_level; - qual->vgc_level_reg = vgc_level; - } -} - -static void rt2800usb_reset_tuner(struct rt2x00_dev *rt2x00dev, - struct link_qual *qual) -{ - rt2800usb_set_vgc(rt2x00dev, qual, - rt2800usb_get_default_vgc(rt2x00dev)); -} - -static void rt2800usb_link_tuner(struct rt2x00_dev *rt2x00dev, - struct link_qual *qual, const u32 count) -{ - if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) - return; - - /* - * When RSSI is better then -80 increase VGC level with 0x10 - */ - rt2800usb_set_vgc(rt2x00dev, qual, - rt2800usb_get_default_vgc(rt2x00dev) + - ((qual->rssi > -80) * 0x10)); -} - /* * Firmware functions */ @@ -2205,9 +1379,9 @@ static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Store led settings, for correct led behaviour. */ #ifdef CONFIG_RT2X00_LIB_LEDS - rt2800usb_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); - rt2800usb_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); - rt2800usb_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); + rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); + rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); + rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); @@ -2645,10 +1819,10 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .uninitialize = rt2x00usb_uninitialize, .clear_entry = rt2x00usb_clear_entry, .set_device_state = rt2800usb_set_device_state, - .rfkill_poll = rt2800usb_rfkill_poll, - .link_stats = rt2800usb_link_stats, - .reset_tuner = rt2800usb_reset_tuner, - .link_tuner = rt2800usb_link_tuner, + .rfkill_poll = rt2800_rfkill_poll, + .link_stats = rt2800_link_stats, + .reset_tuner = rt2800_reset_tuner, + .link_tuner = rt2800_link_tuner, .write_tx_desc = rt2800usb_write_tx_desc, .write_tx_data = rt2x00usb_write_tx_data, .write_beacon = rt2800usb_write_beacon, @@ -2656,13 +1830,13 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .kick_tx_queue = rt2800usb_kick_tx_queue, .kill_tx_queue = rt2x00usb_kill_tx_queue, .fill_rxdone = rt2800usb_fill_rxdone, - .config_shared_key = rt2800usb_config_shared_key, - .config_pairwise_key = rt2800usb_config_pairwise_key, - .config_filter = rt2800usb_config_filter, - .config_intf = rt2800usb_config_intf, - .config_erp = rt2800usb_config_erp, - .config_ant = rt2800usb_config_ant, - .config = rt2800usb_config, + .config_shared_key = rt2800_config_shared_key, + .config_pairwise_key = rt2800_config_pairwise_key, + .config_filter = rt2800_config_filter, + .config_intf = rt2800_config_intf, + .config_erp = rt2800_config_erp, + .config_ant = rt2800_config_ant, + .config = rt2800_config, }; static const struct data_queue_desc rt2800usb_queue_rx = { @@ -2699,7 +1873,7 @@ static const struct rt2x00_ops rt2800usb_ops = { .lib = &rt2800usb_rt2x00_ops, .hw = &rt2800usb_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS - .debugfs = &rt2800usb_rt2x00debug, + .debugfs = &rt2800_rt2x00debug, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; -- cgit v1.2.3 From 1f285f1423e456cfa14331987782edeca64d8e70 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:36:50 +0100 Subject: rt2x00: move REGISTER_BUSY_* definitions to rt2x00.h Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 9 +++++++++ drivers/net/wireless/rt2x00/rt2x00pci.h | 9 --------- drivers/net/wireless/rt2x00/rt2x00usb.h | 6 ------ 3 files changed, 9 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 1ddda729a483..c83dbaefd57a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -856,6 +856,15 @@ struct rt2x00_dev { void *priv; }; +/* + * Register defines. + * Some registers require multiple attempts before success, + * in those cases REGISTER_BUSY_COUNT attempts should be + * taken with a REGISTER_BUSY_DELAY interval. + */ +#define REGISTER_BUSY_COUNT 5 +#define REGISTER_BUSY_DELAY 100 + /* * Generic RF access. * The RF is being accessed by word index. diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index f5af4b40308d..ae33eebe9a6f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -34,15 +34,6 @@ */ #define PCI_DEVICE_DATA(__ops) .driver_data = (kernel_ulong_t)(__ops) -/* - * Register defines. - * Some registers require multiple attempts before success, - * in those cases REGISTER_BUSY_COUNT attempts should be - * taken with a REGISTER_BUSY_DELAY interval. - */ -#define REGISTER_BUSY_COUNT 5 -#define REGISTER_BUSY_DELAY 100 - /* * Register access. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 212dec47119e..9943e428bc21 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -39,17 +39,11 @@ #define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) /* - * Register defines. - * Some registers require multiple attempts before success, - * in those cases REGISTER_BUSY_COUNT attempts should be - * taken with a REGISTER_BUSY_DELAY interval. * For USB vendor requests we need to pass a timeout * time in ms, for this we use the REGISTER_TIMEOUT, * however when loading firmware a higher value is * required. In that case we use the REGISTER_TIMEOUT_FIRMWARE. */ -#define REGISTER_BUSY_COUNT 5 -#define REGISTER_BUSY_DELAY 100 #define REGISTER_TIMEOUT 500 #define REGISTER_TIMEOUT_FIRMWARE 1000 -- cgit v1.2.3 From fcf5154118849cca3cdf424e83f863225d8173e7 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:36:57 +0100 Subject: rt2800: add rt2800lib (part three) Code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 614 +++++++++++++++++++++++++++++++- drivers/net/wireless/rt2x00/rt2800lib.h | 14 +- drivers/net/wireless/rt2x00/rt2800pci.c | 497 +------------------------- drivers/net/wireless/rt2x00/rt2800usb.c | 541 +--------------------------- 4 files changed, 609 insertions(+), 1057 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index ba88d643edd3..ddd53c02be7a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -31,8 +31,12 @@ #include #include "rt2x00.h" +#ifdef CONFIG_RT2800USB +#include "rt2x00usb.h" +#endif #include "rt2800lib.h" #include "rt2800.h" +#include "rt2800usb.h" MODULE_AUTHOR("Bartlomiej Zolnierkiewicz"); MODULE_DESCRIPTION("rt2800 library"); @@ -62,8 +66,8 @@ MODULE_LICENSE("GPL"); rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \ H2M_MAILBOX_CSR_OWNER, (__reg)) -void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value) +static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) { u32 reg; @@ -87,10 +91,9 @@ void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -EXPORT_SYMBOL_GPL(rt2800_bbp_write); -void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) { u32 reg; @@ -121,10 +124,9 @@ void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -EXPORT_SYMBOL_GPL(rt2800_bbp_read); -void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value) +static void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u8 value) { u32 reg; @@ -146,10 +148,9 @@ void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -EXPORT_SYMBOL_GPL(rt2800_rfcsr_write); -void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value) +static void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, + const unsigned int word, u8 *value) { u32 reg; @@ -178,10 +179,9 @@ void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -EXPORT_SYMBOL_GPL(rt2800_rfcsr_read); -void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u32 value) +static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, + const unsigned int word, const u32 value) { u32 reg; @@ -204,7 +204,6 @@ void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, mutex_unlock(&rt2x00dev->csr_mutex); } -EXPORT_SYMBOL_GPL(rt2800_rf_write); void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, const u8 command, const u8 token, @@ -1074,3 +1073,588 @@ void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, ((qual->rssi > -80) * 0x10)); } EXPORT_SYMBOL_GPL(rt2800_link_tuner); + +/* + * Initialization functions. + */ +int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + unsigned int i; + + if (rt2x00_intf_is_usb(rt2x00dev)) { + /* + * Wait untill BBP and RF are ready. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg && reg != ~0) + break; + msleep(1); + } + + if (i == REGISTER_BUSY_COUNT) { + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; + } + + rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); + rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, + reg & ~0x00002000); + } else if (rt2x00_intf_is_pci(rt2x00dev)) + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + if (rt2x00_intf_is_usb(rt2x00dev)) { + rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); +#ifdef CONFIG_RT2800USB + rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, + USB_MODE_RESET, REGISTER_TIMEOUT); +#endif + } + + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + + rt2800_register_read(rt2x00dev, BCN_OFFSET0, ®); + rt2x00_set_field32(®, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */ + rt2x00_set_field32(®, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */ + rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg); + + rt2800_register_read(rt2x00dev, BCN_OFFSET1, ®); + rt2x00_set_field32(®, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */ + rt2x00_set_field32(®, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */ + rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg); + + rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); + rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); + + rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); + rt2x00_set_field32(®, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0); + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); + + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); + rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); + } else { + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); + } + + rt2800_register_read(rt2x00dev, TX_LINK_CFG, ®); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32); + rt2x00_set_field32(®, TX_LINK_CFG_MFB_ENABLE, 0); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_MRQ_EN, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_RDG_EN, 0); + rt2x00_set_field32(®, TX_LINK_CFG_TX_CF_ACK_EN, 1); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB, 0); + rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFS, 0); + rt2800_register_write(rt2x00dev, TX_LINK_CFG, reg); + + rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10); + rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + + rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); + if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION && + rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION) + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 2); + else + rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); + rt2x00_set_field32(®, MAX_LEN_CFG_MIN_PSDU, 0); + rt2x00_set_field32(®, MAX_LEN_CFG_MIN_MPDU, 0); + rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); + + rt2800_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); + + rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); + rt2x00_set_field32(®, AUTO_RSP_CFG_AUTORESPONDER, 1); + rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MMODE, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MREF, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_DUAL_CTS_EN, 0); + rt2x00_set_field32(®, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0); + rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + + rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, 0x4004); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0); + rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, 0x4004); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0); + rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, 0x4084); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM20, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); + + if (rt2x00_intf_is_usb(rt2x00dev)) { + rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); + + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 3); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_BIG_ENDIAN, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_HDR_SCATTER, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_HDR_SEG_LEN, 0); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + } + + rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); + rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); + + rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, + IEEE80211_MAX_RTS_THRESHOLD); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_FBK_EN, 0); + rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); + + rt2800_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca); + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + + /* + * ASIC will keep garbage value after boot, clear encryption keys. + */ + for (i = 0; i < 4; i++) + rt2800_register_write(rt2x00dev, + SHARED_KEY_MODE_ENTRY(i), 0); + + for (i = 0; i < 256; i++) { + u32 wcid[2] = { 0xffffffff, 0x00ffffff }; + rt2800_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), + wcid, sizeof(wcid)); + + rt2800_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); + rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); + } + + /* + * Clear all beacons + * For the Beacon base registers we only need to clear + * the first byte since that byte contains the VALID and OWNER + * bits which (when set to 0) will invalidate the entire beacon. + */ + rt2800_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE3, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE4, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE5, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0); + rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0); + + if (rt2x00_intf_is_usb(rt2x00dev)) { + rt2800_register_read(rt2x00dev, USB_CYC_CFG, ®); + rt2x00_set_field32(®, USB_CYC_CFG_CLOCK_CYCLE, 30); + rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg); + } + + rt2800_register_read(rt2x00dev, HT_FBK_CFG0, ®); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS0FBK, 0); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS1FBK, 0); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS2FBK, 1); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS3FBK, 2); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS4FBK, 3); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS5FBK, 4); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS6FBK, 5); + rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS7FBK, 6); + rt2800_register_write(rt2x00dev, HT_FBK_CFG0, reg); + + rt2800_register_read(rt2x00dev, HT_FBK_CFG1, ®); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS8FBK, 8); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS9FBK, 8); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS10FBK, 9); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS11FBK, 10); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS12FBK, 11); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS13FBK, 12); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS14FBK, 13); + rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS15FBK, 14); + rt2800_register_write(rt2x00dev, HT_FBK_CFG1, reg); + + rt2800_register_read(rt2x00dev, LG_FBK_CFG0, ®); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 9); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 10); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 11); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 13); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); + rt2800_register_write(rt2x00dev, LG_FBK_CFG0, reg); + + rt2800_register_read(rt2x00dev, LG_FBK_CFG1, ®); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS0FBK, 0); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS1FBK, 0); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS2FBK, 1); + rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS3FBK, 2); + rt2800_register_write(rt2x00dev, LG_FBK_CFG1, reg); + + /* + * We must clear the error counters. + * These registers are cleared on read, + * so we may pass a useless variable to store the value. + */ + rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); + rt2800_register_read(rt2x00dev, RX_STA_CNT1, ®); + rt2800_register_read(rt2x00dev, RX_STA_CNT2, ®); + rt2800_register_read(rt2x00dev, TX_STA_CNT0, ®); + rt2800_register_read(rt2x00dev, TX_STA_CNT1, ®); + rt2800_register_read(rt2x00dev, TX_STA_CNT2, ®); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_init_registers); + +static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, ®); + if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY)) + return 0; + + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP/RF register access failed, aborting.\n"); + return -EACCES; +} + +static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u8 value; + + /* + * BBP was enabled after firmware was loaded, + * but we need to reactivate it now. + */ + rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); + rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); + msleep(1); + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800_bbp_read(rt2x00dev, 0, &value); + if ((value != 0xff) && (value != 0x00)) + return 0; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); + return -EACCES; +} + +int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u16 eeprom; + u8 reg_id; + u8 value; + + if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev) || + rt2800_wait_bbp_ready(rt2x00dev))) + return -EACCES; + + rt2800_bbp_write(rt2x00dev, 65, 0x2c); + rt2800_bbp_write(rt2x00dev, 66, 0x38); + rt2800_bbp_write(rt2x00dev, 69, 0x12); + rt2800_bbp_write(rt2x00dev, 70, 0x0a); + rt2800_bbp_write(rt2x00dev, 73, 0x10); + rt2800_bbp_write(rt2x00dev, 81, 0x37); + rt2800_bbp_write(rt2x00dev, 82, 0x62); + rt2800_bbp_write(rt2x00dev, 83, 0x6a); + rt2800_bbp_write(rt2x00dev, 84, 0x99); + rt2800_bbp_write(rt2x00dev, 86, 0x00); + rt2800_bbp_write(rt2x00dev, 91, 0x04); + rt2800_bbp_write(rt2x00dev, 92, 0x00); + rt2800_bbp_write(rt2x00dev, 103, 0x00); + rt2800_bbp_write(rt2x00dev, 105, 0x05); + + if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { + rt2800_bbp_write(rt2x00dev, 69, 0x16); + rt2800_bbp_write(rt2x00dev, 73, 0x12); + } + + if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) + rt2800_bbp_write(rt2x00dev, 84, 0x19); + + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { + rt2800_bbp_write(rt2x00dev, 70, 0x0a); + rt2800_bbp_write(rt2x00dev, 84, 0x99); + rt2800_bbp_write(rt2x00dev, 105, 0x05); + } + + if (rt2x00_intf_is_pci(rt2x00dev) && + rt2x00_rt(&rt2x00dev->chip, RT3052)) { + rt2800_bbp_write(rt2x00dev, 31, 0x08); + rt2800_bbp_write(rt2x00dev, 78, 0x0e); + rt2800_bbp_write(rt2x00dev, 80, 0x08); + } + + for (i = 0; i < EEPROM_BBP_SIZE; i++) { + rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); + + if (eeprom != 0xffff && eeprom != 0x0000) { + reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); + value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); + rt2800_bbp_write(rt2x00dev, reg_id, value); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_init_bbp); + +static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, + bool bw40, u8 rfcsr24, u8 filter_target) +{ + unsigned int i; + u8 bbp; + u8 rfcsr; + u8 passband; + u8 stopband; + u8 overtuned = 0; + + rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); + + rt2800_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); + rt2800_bbp_write(rt2x00dev, 4, bbp); + + rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); + rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); + + /* + * Set power & frequency of passband test tone + */ + rt2800_bbp_write(rt2x00dev, 24, 0); + + for (i = 0; i < 100; i++) { + rt2800_bbp_write(rt2x00dev, 25, 0x90); + msleep(1); + + rt2800_bbp_read(rt2x00dev, 55, &passband); + if (passband) + break; + } + + /* + * Set power & frequency of stopband test tone + */ + rt2800_bbp_write(rt2x00dev, 24, 0x06); + + for (i = 0; i < 100; i++) { + rt2800_bbp_write(rt2x00dev, 25, 0x90); + msleep(1); + + rt2800_bbp_read(rt2x00dev, 55, &stopband); + + if ((passband - stopband) <= filter_target) { + rfcsr24++; + overtuned += ((passband - stopband) == filter_target); + } else + break; + + rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); + } + + rfcsr24 -= !!overtuned; + + rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); + return rfcsr24; +} + +int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) +{ + u8 rfcsr; + u8 bbp; + + if (rt2x00_intf_is_usb(rt2x00dev) && + rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) + return 0; + + if (rt2x00_intf_is_pci(rt2x00dev)) { + if (!rt2x00_rf(&rt2x00dev->chip, RF3020) && + !rt2x00_rf(&rt2x00dev->chip, RF3021) && + !rt2x00_rf(&rt2x00dev->chip, RF3022)) + return 0; + } + + /* + * Init RF calibration. + */ + rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); + rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); + msleep(1); + rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); + rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); + + if (rt2x00_intf_is_usb(rt2x00dev)) { + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800_rfcsr_write(rt2x00dev, 5, 0x03); + rt2800_rfcsr_write(rt2x00dev, 6, 0x02); + rt2800_rfcsr_write(rt2x00dev, 7, 0x70); + rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 10, 0x71); + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800_rfcsr_write(rt2x00dev, 12, 0x7b); + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800_rfcsr_write(rt2x00dev, 15, 0x58); + rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); + rt2800_rfcsr_write(rt2x00dev, 17, 0x92); + rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800_rfcsr_write(rt2x00dev, 20, 0xba); + rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 24, 0x16); + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); + rt2800_rfcsr_write(rt2x00dev, 27, 0x03); + rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); + } else if (rt2x00_intf_is_pci(rt2x00dev)) { + rt2800_rfcsr_write(rt2x00dev, 0, 0x50); + rt2800_rfcsr_write(rt2x00dev, 1, 0x01); + rt2800_rfcsr_write(rt2x00dev, 2, 0xf7); + rt2800_rfcsr_write(rt2x00dev, 3, 0x75); + rt2800_rfcsr_write(rt2x00dev, 4, 0x40); + rt2800_rfcsr_write(rt2x00dev, 5, 0x03); + rt2800_rfcsr_write(rt2x00dev, 6, 0x02); + rt2800_rfcsr_write(rt2x00dev, 7, 0x50); + rt2800_rfcsr_write(rt2x00dev, 8, 0x39); + rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 10, 0x60); + rt2800_rfcsr_write(rt2x00dev, 11, 0x21); + rt2800_rfcsr_write(rt2x00dev, 12, 0x75); + rt2800_rfcsr_write(rt2x00dev, 13, 0x75); + rt2800_rfcsr_write(rt2x00dev, 14, 0x90); + rt2800_rfcsr_write(rt2x00dev, 15, 0x58); + rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); + rt2800_rfcsr_write(rt2x00dev, 17, 0x92); + rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); + rt2800_rfcsr_write(rt2x00dev, 19, 0x02); + rt2800_rfcsr_write(rt2x00dev, 20, 0xba); + rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); + rt2800_rfcsr_write(rt2x00dev, 22, 0x00); + rt2800_rfcsr_write(rt2x00dev, 23, 0x31); + rt2800_rfcsr_write(rt2x00dev, 24, 0x08); + rt2800_rfcsr_write(rt2x00dev, 25, 0x01); + rt2800_rfcsr_write(rt2x00dev, 26, 0x25); + rt2800_rfcsr_write(rt2x00dev, 27, 0x23); + rt2800_rfcsr_write(rt2x00dev, 28, 0x13); + rt2800_rfcsr_write(rt2x00dev, 29, 0x83); + } + + /* + * Set RX Filter calibration for 20MHz and 40MHz + */ + rt2x00dev->calibration[0] = + rt2800_init_rx_filter(rt2x00dev, false, 0x07, 0x16); + rt2x00dev->calibration[1] = + rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x19); + + /* + * Set back to initial state + */ + rt2800_bbp_write(rt2x00dev, 24, 0); + + rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); + rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); + + /* + * set BBP back to BW20 + */ + rt2800_bbp_read(rt2x00dev, 4, &bbp); + rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0); + rt2800_bbp_write(rt2x00dev, 4, bbp); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_init_rfcsr); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index b07caba37817..2da8f79215fd 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -96,16 +96,6 @@ static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev, return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg); } -void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value); -void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value); -void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u8 value); -void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u8 *value); -void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, - const unsigned int word, const u32 value); void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, const u8 command, const u8 token, const u8 arg0, const u8 arg1); @@ -135,4 +125,8 @@ void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count); +int rt2800_init_registers(struct rt2x00_dev *rt2x00dev); +int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); +int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); + #endif /* RT2800LIB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index cbf8be3057ef..78086cce55ee 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -420,497 +420,6 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) return 0; } -static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - if (rt2x00_intf_is_pci(rt2x00dev)) - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); - - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); - rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); - rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); - - rt2800_register_read(rt2x00dev, BCN_OFFSET0, ®); - rt2x00_set_field32(®, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */ - rt2x00_set_field32(®, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */ - rt2x00_set_field32(®, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */ - rt2x00_set_field32(®, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */ - rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg); - - rt2800_register_read(rt2x00dev, BCN_OFFSET1, ®); - rt2x00_set_field32(®, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */ - rt2x00_set_field32(®, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */ - rt2x00_set_field32(®, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */ - rt2x00_set_field32(®, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */ - rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg); - - rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); - rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); - - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); - - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); - rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); - - rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); - rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); - - rt2800_register_read(rt2x00dev, TX_LINK_CFG, ®); - rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32); - rt2x00_set_field32(®, TX_LINK_CFG_MFB_ENABLE, 0); - rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0); - rt2x00_set_field32(®, TX_LINK_CFG_TX_MRQ_EN, 0); - rt2x00_set_field32(®, TX_LINK_CFG_TX_RDG_EN, 0); - rt2x00_set_field32(®, TX_LINK_CFG_TX_CF_ACK_EN, 1); - rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB, 0); - rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFS, 0); - rt2800_register_write(rt2x00dev, TX_LINK_CFG, reg); - - rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); - rt2x00_set_field32(®, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9); - rt2x00_set_field32(®, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10); - rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); - - rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); - rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); - if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION && - rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION) - rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 2); - else - rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); - rt2x00_set_field32(®, MAX_LEN_CFG_MIN_PSDU, 0); - rt2x00_set_field32(®, MAX_LEN_CFG_MIN_MPDU, 0); - rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); - - rt2800_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); - - rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); - rt2x00_set_field32(®, AUTO_RSP_CFG_AUTORESPONDER, 1); - rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MMODE, 0); - rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MREF, 0); - rt2x00_set_field32(®, AUTO_RSP_CFG_DUAL_CTS_EN, 0); - rt2x00_set_field32(®, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0); - rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); - - rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); - rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 8); - rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); - rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 8); - rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); - rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, 0x4004); - rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); - rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); - rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); - rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, 0x4004); - rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); - rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, 0x4084); - rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); - - rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); - rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); - - rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); - rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32); - rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, - IEEE80211_MAX_RTS_THRESHOLD); - rt2x00_set_field32(®, TX_RTS_CFG_RTS_FBK_EN, 0); - rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); - - rt2800_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca); - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); - - /* - * ASIC will keep garbage value after boot, clear encryption keys. - */ - for (i = 0; i < 4; i++) - rt2800_register_write(rt2x00dev, - SHARED_KEY_MODE_ENTRY(i), 0); - - for (i = 0; i < 256; i++) { - u32 wcid[2] = { 0xffffffff, 0x00ffffff }; - rt2800_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), - wcid, sizeof(wcid)); - - rt2800_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); - rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); - } - - /* - * Clear all beacons - * For the Beacon base registers we only need to clear - * the first byte since that byte contains the VALID and OWNER - * bits which (when set to 0) will invalidate the entire beacon. - */ - rt2800_register_write(rt2x00dev, HW_BEACON_BASE0, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE1, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE2, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE3, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE4, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE5, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0); - - rt2800_register_read(rt2x00dev, HT_FBK_CFG0, ®); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS0FBK, 0); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS1FBK, 0); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS2FBK, 1); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS3FBK, 2); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS4FBK, 3); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS5FBK, 4); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS6FBK, 5); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS7FBK, 6); - rt2800_register_write(rt2x00dev, HT_FBK_CFG0, reg); - - rt2800_register_read(rt2x00dev, HT_FBK_CFG1, ®); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS8FBK, 8); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS9FBK, 8); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS10FBK, 9); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS11FBK, 10); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS12FBK, 11); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS13FBK, 12); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS14FBK, 13); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS15FBK, 14); - rt2800_register_write(rt2x00dev, HT_FBK_CFG1, reg); - - rt2800_register_read(rt2x00dev, LG_FBK_CFG0, ®); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 9); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 10); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 11); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 13); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); - rt2800_register_write(rt2x00dev, LG_FBK_CFG0, reg); - - rt2800_register_read(rt2x00dev, LG_FBK_CFG1, ®); - rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS0FBK, 0); - rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS1FBK, 0); - rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS2FBK, 1); - rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS3FBK, 2); - rt2800_register_write(rt2x00dev, LG_FBK_CFG1, reg); - - /* - * We must clear the error counters. - * These registers are cleared on read, - * so we may pass a useless variable to store the value. - */ - rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); - rt2800_register_read(rt2x00dev, RX_STA_CNT1, ®); - rt2800_register_read(rt2x00dev, RX_STA_CNT2, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT0, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT1, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT2, ®); - - return 0; -} - -static int rt2800pci_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) -{ - unsigned int i; - u32 reg; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, ®); - if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY)) - return 0; - - udelay(REGISTER_BUSY_DELAY); - } - - ERROR(rt2x00dev, "BBP/RF register access failed, aborting.\n"); - return -EACCES; -} - -static int rt2800pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) -{ - unsigned int i; - u8 value; - - /* - * BBP was enabled after firmware was loaded, - * but we need to reactivate it now. - */ - rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); - msleep(1); - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_bbp_read(rt2x00dev, 0, &value); - if ((value != 0xff) && (value != 0x00)) - return 0; - udelay(REGISTER_BUSY_DELAY); - } - - ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); - return -EACCES; -} - -static int rt2800pci_init_bbp(struct rt2x00_dev *rt2x00dev) -{ - unsigned int i; - u16 eeprom; - u8 reg_id; - u8 value; - - if (unlikely(rt2800pci_wait_bbp_rf_ready(rt2x00dev) || - rt2800pci_wait_bbp_ready(rt2x00dev))) - return -EACCES; - - rt2800_bbp_write(rt2x00dev, 65, 0x2c); - rt2800_bbp_write(rt2x00dev, 66, 0x38); - rt2800_bbp_write(rt2x00dev, 69, 0x12); - rt2800_bbp_write(rt2x00dev, 70, 0x0a); - rt2800_bbp_write(rt2x00dev, 73, 0x10); - rt2800_bbp_write(rt2x00dev, 81, 0x37); - rt2800_bbp_write(rt2x00dev, 82, 0x62); - rt2800_bbp_write(rt2x00dev, 83, 0x6a); - rt2800_bbp_write(rt2x00dev, 84, 0x99); - rt2800_bbp_write(rt2x00dev, 86, 0x00); - rt2800_bbp_write(rt2x00dev, 91, 0x04); - rt2800_bbp_write(rt2x00dev, 92, 0x00); - rt2800_bbp_write(rt2x00dev, 103, 0x00); - rt2800_bbp_write(rt2x00dev, 105, 0x05); - - if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { - rt2800_bbp_write(rt2x00dev, 69, 0x16); - rt2800_bbp_write(rt2x00dev, 73, 0x12); - } - - if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) - rt2800_bbp_write(rt2x00dev, 84, 0x19); - - if (rt2x00_intf_is_pci(rt2x00dev) && - rt2x00_rt(&rt2x00dev->chip, RT3052)) { - rt2800_bbp_write(rt2x00dev, 31, 0x08); - rt2800_bbp_write(rt2x00dev, 78, 0x0e); - rt2800_bbp_write(rt2x00dev, 80, 0x08); - } - - for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); - - if (eeprom != 0xffff && eeprom != 0x0000) { - reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); - value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); - rt2800_bbp_write(rt2x00dev, reg_id, value); - } - } - - return 0; -} - -static u8 rt2800pci_init_rx_filter(struct rt2x00_dev *rt2x00dev, - bool bw40, u8 rfcsr24, u8 filter_target) -{ - unsigned int i; - u8 bbp; - u8 rfcsr; - u8 passband; - u8 stopband; - u8 overtuned = 0; - - rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); - - rt2800_bbp_read(rt2x00dev, 4, &bbp); - rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); - rt2800_bbp_write(rt2x00dev, 4, bbp); - - rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); - rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); - - /* - * Set power & frequency of passband test tone - */ - rt2800_bbp_write(rt2x00dev, 24, 0); - - for (i = 0; i < 100; i++) { - rt2800_bbp_write(rt2x00dev, 25, 0x90); - msleep(1); - - rt2800_bbp_read(rt2x00dev, 55, &passband); - if (passband) - break; - } - - /* - * Set power & frequency of stopband test tone - */ - rt2800_bbp_write(rt2x00dev, 24, 0x06); - - for (i = 0; i < 100; i++) { - rt2800_bbp_write(rt2x00dev, 25, 0x90); - msleep(1); - - rt2800_bbp_read(rt2x00dev, 55, &stopband); - - if ((passband - stopband) <= filter_target) { - rfcsr24++; - overtuned += ((passband - stopband) == filter_target); - } else - break; - - rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); - } - - rfcsr24 -= !!overtuned; - - rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); - return rfcsr24; -} - -static int rt2800pci_init_rfcsr(struct rt2x00_dev *rt2x00dev) -{ - u8 rfcsr; - u8 bbp; - - if (rt2x00_intf_is_pci(rt2x00dev)) { - if (!rt2x00_rf(&rt2x00dev->chip, RF3020) && - !rt2x00_rf(&rt2x00dev->chip, RF3021) && - !rt2x00_rf(&rt2x00dev->chip, RF3022)) - return 0; - } - - /* - * Init RF calibration. - */ - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); - rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); - msleep(1); - rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); - rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); - - if (rt2x00_intf_is_pci(rt2x00dev)) { - rt2800_rfcsr_write(rt2x00dev, 0, 0x50); - rt2800_rfcsr_write(rt2x00dev, 1, 0x01); - rt2800_rfcsr_write(rt2x00dev, 2, 0xf7); - rt2800_rfcsr_write(rt2x00dev, 3, 0x75); - rt2800_rfcsr_write(rt2x00dev, 4, 0x40); - rt2800_rfcsr_write(rt2x00dev, 5, 0x03); - rt2800_rfcsr_write(rt2x00dev, 6, 0x02); - rt2800_rfcsr_write(rt2x00dev, 7, 0x50); - rt2800_rfcsr_write(rt2x00dev, 8, 0x39); - rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); - rt2800_rfcsr_write(rt2x00dev, 10, 0x60); - rt2800_rfcsr_write(rt2x00dev, 11, 0x21); - rt2800_rfcsr_write(rt2x00dev, 12, 0x75); - rt2800_rfcsr_write(rt2x00dev, 13, 0x75); - rt2800_rfcsr_write(rt2x00dev, 14, 0x90); - rt2800_rfcsr_write(rt2x00dev, 15, 0x58); - rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); - rt2800_rfcsr_write(rt2x00dev, 17, 0x92); - rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); - rt2800_rfcsr_write(rt2x00dev, 19, 0x02); - rt2800_rfcsr_write(rt2x00dev, 20, 0xba); - rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); - rt2800_rfcsr_write(rt2x00dev, 22, 0x00); - rt2800_rfcsr_write(rt2x00dev, 23, 0x31); - rt2800_rfcsr_write(rt2x00dev, 24, 0x08); - rt2800_rfcsr_write(rt2x00dev, 25, 0x01); - rt2800_rfcsr_write(rt2x00dev, 26, 0x25); - rt2800_rfcsr_write(rt2x00dev, 27, 0x23); - rt2800_rfcsr_write(rt2x00dev, 28, 0x13); - rt2800_rfcsr_write(rt2x00dev, 29, 0x83); - } - - /* - * Set RX Filter calibration for 20MHz and 40MHz - */ - rt2x00dev->calibration[0] = - rt2800pci_init_rx_filter(rt2x00dev, false, 0x07, 0x16); - rt2x00dev->calibration[1] = - rt2800pci_init_rx_filter(rt2x00dev, true, 0x27, 0x19); - - /* - * Set back to initial state - */ - rt2800_bbp_write(rt2x00dev, 24, 0); - - rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); - rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); - - /* - * set BBP back to BW20 - */ - rt2800_bbp_read(rt2x00dev, 4, &bbp); - rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0); - rt2800_bbp_write(rt2x00dev, 4, bbp); - - return 0; -} - /* * Device state switch handlers. */ @@ -991,10 +500,10 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) */ if (unlikely(rt2800pci_wait_wpdma_ready(rt2x00dev) || rt2800pci_init_queues(rt2x00dev) || - rt2800pci_init_registers(rt2x00dev) || + rt2800_init_registers(rt2x00dev) || rt2800pci_wait_wpdma_ready(rt2x00dev) || - rt2800pci_init_bbp(rt2x00dev) || - rt2800pci_init_rfcsr(rt2x00dev))) + rt2800_init_bbp(rt2x00dev) || + rt2800_init_rfcsr(rt2x00dev))) return -EIO; /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 365f66fe7c68..f5b864b1a55d 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -229,541 +229,6 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, return 0; } -/* - * Initialization functions. - */ -static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - if (rt2x00_intf_is_usb(rt2x00dev)) { - /* - * Wait untill BBP and RF are ready. - */ - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - if (reg && reg != ~0) - break; - msleep(1); - } - - if (i == REGISTER_BUSY_COUNT) { - ERROR(rt2x00dev, "Unstable hardware.\n"); - return -EBUSY; - } - - rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); - rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, - reg & ~0x00002000); - } - - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); - rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); - rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - - if (rt2x00_intf_is_usb(rt2x00dev)) { - rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); - - rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, - USB_MODE_RESET, REGISTER_TIMEOUT); - } - - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); - - rt2800_register_read(rt2x00dev, BCN_OFFSET0, ®); - rt2x00_set_field32(®, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */ - rt2x00_set_field32(®, BCN_OFFSET0_BCN1, 0xe8); /* 0x3a00 */ - rt2x00_set_field32(®, BCN_OFFSET0_BCN2, 0xf0); /* 0x3c00 */ - rt2x00_set_field32(®, BCN_OFFSET0_BCN3, 0xf8); /* 0x3e00 */ - rt2800_register_write(rt2x00dev, BCN_OFFSET0, reg); - - rt2800_register_read(rt2x00dev, BCN_OFFSET1, ®); - rt2x00_set_field32(®, BCN_OFFSET1_BCN4, 0xc8); /* 0x3200 */ - rt2x00_set_field32(®, BCN_OFFSET1_BCN5, 0xd0); /* 0x3400 */ - rt2x00_set_field32(®, BCN_OFFSET1_BCN6, 0x77); /* 0x1dc0 */ - rt2x00_set_field32(®, BCN_OFFSET1_BCN7, 0x6f); /* 0x1bc0 */ - rt2800_register_write(rt2x00dev, BCN_OFFSET1, reg); - - rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f); - rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); - - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000); - - rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); - rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); - rt2x00_set_field32(®, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0); - rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); - - if (rt2x00_intf_is_usb(rt2x00dev) && - rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { - rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); - rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); - rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); - } else { - rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); - rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); - } - - rt2800_register_read(rt2x00dev, TX_LINK_CFG, ®); - rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB_LIFETIME, 32); - rt2x00_set_field32(®, TX_LINK_CFG_MFB_ENABLE, 0); - rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_UMFS_ENABLE, 0); - rt2x00_set_field32(®, TX_LINK_CFG_TX_MRQ_EN, 0); - rt2x00_set_field32(®, TX_LINK_CFG_TX_RDG_EN, 0); - rt2x00_set_field32(®, TX_LINK_CFG_TX_CF_ACK_EN, 1); - rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFB, 0); - rt2x00_set_field32(®, TX_LINK_CFG_REMOTE_MFS, 0); - rt2800_register_write(rt2x00dev, TX_LINK_CFG, reg); - - rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); - rt2x00_set_field32(®, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9); - rt2x00_set_field32(®, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10); - rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); - - rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); - rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); - if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION && - rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION) - rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 2); - else - rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); - rt2x00_set_field32(®, MAX_LEN_CFG_MIN_PSDU, 0); - rt2x00_set_field32(®, MAX_LEN_CFG_MIN_MPDU, 0); - rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg); - - rt2800_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f); - - rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); - rt2x00_set_field32(®, AUTO_RSP_CFG_AUTORESPONDER, 1); - rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MMODE, 0); - rt2x00_set_field32(®, AUTO_RSP_CFG_CTS_40_MREF, 0); - rt2x00_set_field32(®, AUTO_RSP_CFG_DUAL_CTS_EN, 0); - rt2x00_set_field32(®, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0); - rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); - - rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); - rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 8); - rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); - rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 8); - rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); - rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_RATE, 0x4004); - rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, MM20_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); - rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_RATE, 0x4084); - rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, MM40_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); - rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_RATE, 0x4004); - rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, GF20_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0); - rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); - rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_RATE, 0x4084); - rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_CTRL, 0); - rt2x00_set_field32(®, GF40_PROT_CFG_PROTECT_NAV, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_CCK, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_OFDM, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM20, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1); - rt2x00_set_field32(®, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1); - rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); - - if (rt2x00_intf_is_usb(rt2x00dev)) { - rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); - - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 3); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_BIG_ENDIAN, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_HDR_SCATTER, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_HDR_SEG_LEN, 0); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - } - - rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); - rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); - - rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); - rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32); - rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, - IEEE80211_MAX_RTS_THRESHOLD); - rt2x00_set_field32(®, TX_RTS_CFG_RTS_FBK_EN, 0); - rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); - - rt2800_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca); - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); - - /* - * ASIC will keep garbage value after boot, clear encryption keys. - */ - for (i = 0; i < 4; i++) - rt2800_register_write(rt2x00dev, - SHARED_KEY_MODE_ENTRY(i), 0); - - for (i = 0; i < 256; i++) { - u32 wcid[2] = { 0xffffffff, 0x00ffffff }; - rt2800_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), - wcid, sizeof(wcid)); - - rt2800_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); - rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); - } - - /* - * Clear all beacons - * For the Beacon base registers we only need to clear - * the first byte since that byte contains the VALID and OWNER - * bits which (when set to 0) will invalidate the entire beacon. - */ - rt2800_register_write(rt2x00dev, HW_BEACON_BASE0, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE1, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE2, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE3, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE4, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE5, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0); - rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0); - - if (rt2x00_intf_is_usb(rt2x00dev)) { - rt2800_register_read(rt2x00dev, USB_CYC_CFG, ®); - rt2x00_set_field32(®, USB_CYC_CFG_CLOCK_CYCLE, 30); - rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg); - } - - rt2800_register_read(rt2x00dev, HT_FBK_CFG0, ®); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS0FBK, 0); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS1FBK, 0); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS2FBK, 1); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS3FBK, 2); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS4FBK, 3); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS5FBK, 4); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS6FBK, 5); - rt2x00_set_field32(®, HT_FBK_CFG0_HTMCS7FBK, 6); - rt2800_register_write(rt2x00dev, HT_FBK_CFG0, reg); - - rt2800_register_read(rt2x00dev, HT_FBK_CFG1, ®); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS8FBK, 8); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS9FBK, 8); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS10FBK, 9); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS11FBK, 10); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS12FBK, 11); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS13FBK, 12); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS14FBK, 13); - rt2x00_set_field32(®, HT_FBK_CFG1_HTMCS15FBK, 14); - rt2800_register_write(rt2x00dev, HT_FBK_CFG1, reg); - - rt2800_register_read(rt2x00dev, LG_FBK_CFG0, ®); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 9); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 10); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 11); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 13); - rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); - rt2800_register_write(rt2x00dev, LG_FBK_CFG0, reg); - - rt2800_register_read(rt2x00dev, LG_FBK_CFG1, ®); - rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS0FBK, 0); - rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS1FBK, 0); - rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS2FBK, 1); - rt2x00_set_field32(®, LG_FBK_CFG0_CCKMCS3FBK, 2); - rt2800_register_write(rt2x00dev, LG_FBK_CFG1, reg); - - /* - * We must clear the error counters. - * These registers are cleared on read, - * so we may pass a useless variable to store the value. - */ - rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); - rt2800_register_read(rt2x00dev, RX_STA_CNT1, ®); - rt2800_register_read(rt2x00dev, RX_STA_CNT2, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT0, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT1, ®); - rt2800_register_read(rt2x00dev, TX_STA_CNT2, ®); - - return 0; -} - -static int rt2800usb_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) -{ - unsigned int i; - u32 reg; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_STATUS_CFG, ®); - if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY)) - return 0; - - udelay(REGISTER_BUSY_DELAY); - } - - ERROR(rt2x00dev, "BBP/RF register access failed, aborting.\n"); - return -EACCES; -} - -static int rt2800usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) -{ - unsigned int i; - u8 value; - - /* - * BBP was enabled after firmware was loaded, - * but we need to reactivate it now. - */ - rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); - rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); - msleep(1); - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_bbp_read(rt2x00dev, 0, &value); - if ((value != 0xff) && (value != 0x00)) - return 0; - udelay(REGISTER_BUSY_DELAY); - } - - ERROR(rt2x00dev, "BBP register access failed, aborting.\n"); - return -EACCES; -} - -static int rt2800usb_init_bbp(struct rt2x00_dev *rt2x00dev) -{ - unsigned int i; - u16 eeprom; - u8 reg_id; - u8 value; - - if (unlikely(rt2800usb_wait_bbp_rf_ready(rt2x00dev) || - rt2800usb_wait_bbp_ready(rt2x00dev))) - return -EACCES; - - rt2800_bbp_write(rt2x00dev, 65, 0x2c); - rt2800_bbp_write(rt2x00dev, 66, 0x38); - rt2800_bbp_write(rt2x00dev, 69, 0x12); - rt2800_bbp_write(rt2x00dev, 70, 0x0a); - rt2800_bbp_write(rt2x00dev, 73, 0x10); - rt2800_bbp_write(rt2x00dev, 81, 0x37); - rt2800_bbp_write(rt2x00dev, 82, 0x62); - rt2800_bbp_write(rt2x00dev, 83, 0x6a); - rt2800_bbp_write(rt2x00dev, 84, 0x99); - rt2800_bbp_write(rt2x00dev, 86, 0x00); - rt2800_bbp_write(rt2x00dev, 91, 0x04); - rt2800_bbp_write(rt2x00dev, 92, 0x00); - rt2800_bbp_write(rt2x00dev, 103, 0x00); - rt2800_bbp_write(rt2x00dev, 105, 0x05); - - if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { - rt2800_bbp_write(rt2x00dev, 69, 0x16); - rt2800_bbp_write(rt2x00dev, 73, 0x12); - } - - if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) - rt2800_bbp_write(rt2x00dev, 84, 0x19); - - if (rt2x00_intf_is_usb(rt2x00dev) && - rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { - rt2800_bbp_write(rt2x00dev, 70, 0x0a); - rt2800_bbp_write(rt2x00dev, 84, 0x99); - rt2800_bbp_write(rt2x00dev, 105, 0x05); - } - - for (i = 0; i < EEPROM_BBP_SIZE; i++) { - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom); - - if (eeprom != 0xffff && eeprom != 0x0000) { - reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID); - value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE); - rt2800_bbp_write(rt2x00dev, reg_id, value); - } - } - - return 0; -} - -static u8 rt2800usb_init_rx_filter(struct rt2x00_dev *rt2x00dev, - bool bw40, u8 rfcsr24, u8 filter_target) -{ - unsigned int i; - u8 bbp; - u8 rfcsr; - u8 passband; - u8 stopband; - u8 overtuned = 0; - - rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); - - rt2800_bbp_read(rt2x00dev, 4, &bbp); - rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); - rt2800_bbp_write(rt2x00dev, 4, bbp); - - rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); - rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); - - /* - * Set power & frequency of passband test tone - */ - rt2800_bbp_write(rt2x00dev, 24, 0); - - for (i = 0; i < 100; i++) { - rt2800_bbp_write(rt2x00dev, 25, 0x90); - msleep(1); - - rt2800_bbp_read(rt2x00dev, 55, &passband); - if (passband) - break; - } - - /* - * Set power & frequency of stopband test tone - */ - rt2800_bbp_write(rt2x00dev, 24, 0x06); - - for (i = 0; i < 100; i++) { - rt2800_bbp_write(rt2x00dev, 25, 0x90); - msleep(1); - - rt2800_bbp_read(rt2x00dev, 55, &stopband); - - if ((passband - stopband) <= filter_target) { - rfcsr24++; - overtuned += ((passband - stopband) == filter_target); - } else - break; - - rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); - } - - rfcsr24 -= !!overtuned; - - rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24); - return rfcsr24; -} - -static int rt2800usb_init_rfcsr(struct rt2x00_dev *rt2x00dev) -{ - u8 rfcsr; - u8 bbp; - - if (rt2x00_intf_is_usb(rt2x00dev) && - rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) - return 0; - - /* - * Init RF calibration. - */ - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); - rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); - msleep(1); - rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0); - rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); - - if (rt2x00_intf_is_usb(rt2x00dev)) { - rt2800_rfcsr_write(rt2x00dev, 4, 0x40); - rt2800_rfcsr_write(rt2x00dev, 5, 0x03); - rt2800_rfcsr_write(rt2x00dev, 6, 0x02); - rt2800_rfcsr_write(rt2x00dev, 7, 0x70); - rt2800_rfcsr_write(rt2x00dev, 9, 0x0f); - rt2800_rfcsr_write(rt2x00dev, 10, 0x71); - rt2800_rfcsr_write(rt2x00dev, 11, 0x21); - rt2800_rfcsr_write(rt2x00dev, 12, 0x7b); - rt2800_rfcsr_write(rt2x00dev, 14, 0x90); - rt2800_rfcsr_write(rt2x00dev, 15, 0x58); - rt2800_rfcsr_write(rt2x00dev, 16, 0xb3); - rt2800_rfcsr_write(rt2x00dev, 17, 0x92); - rt2800_rfcsr_write(rt2x00dev, 18, 0x2c); - rt2800_rfcsr_write(rt2x00dev, 19, 0x02); - rt2800_rfcsr_write(rt2x00dev, 20, 0xba); - rt2800_rfcsr_write(rt2x00dev, 21, 0xdb); - rt2800_rfcsr_write(rt2x00dev, 24, 0x16); - rt2800_rfcsr_write(rt2x00dev, 25, 0x01); - rt2800_rfcsr_write(rt2x00dev, 27, 0x03); - rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); - } - - /* - * Set RX Filter calibration for 20MHz and 40MHz - */ - rt2x00dev->calibration[0] = - rt2800usb_init_rx_filter(rt2x00dev, false, 0x07, 0x16); - rt2x00dev->calibration[1] = - rt2800usb_init_rx_filter(rt2x00dev, true, 0x27, 0x19); - - /* - * Set back to initial state - */ - rt2800_bbp_write(rt2x00dev, 24, 0); - - rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0); - rt2800_rfcsr_write(rt2x00dev, 22, rfcsr); - - /* - * set BBP back to BW20 - */ - rt2800_bbp_read(rt2x00dev, 4, &bbp); - rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0); - rt2800_bbp_write(rt2x00dev, 4, bbp); - - return 0; -} - /* * Device state switch handlers. */ @@ -806,9 +271,9 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) * Initialize all registers. */ if (unlikely(rt2800usb_wait_wpdma_ready(rt2x00dev) || - rt2800usb_init_registers(rt2x00dev) || - rt2800usb_init_bbp(rt2x00dev) || - rt2800usb_init_rfcsr(rt2x00dev))) + rt2800_init_registers(rt2x00dev) || + rt2800_init_bbp(rt2x00dev) || + rt2800_init_rfcsr(rt2x00dev))) return -EIO; rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); -- cgit v1.2.3 From 2ce33995216a088fc11e1f85768375580324174c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 4 Nov 2009 18:37:05 +0100 Subject: rt2800: add rt2800lib (part four) Code unification. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 157 +++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800lib.h | 2 + drivers/net/wireless/rt2x00/rt2800pci.c | 157 +------------------------------ drivers/net/wireless/rt2x00/rt2800usb.c | 158 +------------------------------- 4 files changed, 161 insertions(+), 313 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index ddd53c02be7a..5c7d74a6f16e 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1658,3 +1658,160 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) return 0; } EXPORT_SYMBOL_GPL(rt2800_init_rfcsr); + +/* + * IEEE80211 stack callback functions. + */ +static void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, + u32 *iv32, u16 *iv16) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct mac_iveiv_entry iveiv_entry; + u32 offset; + + offset = MAC_IVEIV_ENTRY(hw_key_idx); + rt2800_register_multiread(rt2x00dev, offset, + &iveiv_entry, sizeof(iveiv_entry)); + + memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16)); + memcpy(&iveiv_entry.iv[4], iv32, sizeof(iv32)); +} + +static int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u32 reg; + bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD); + + rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, value); + rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); + + rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); + rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, enabled); + rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); + rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, enabled); + rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); + rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, enabled); + rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); + rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, enabled); + rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); + rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, enabled); + rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); + + rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); + rt2x00_set_field32(®, GF40_PROT_CFG_RTS_TH_EN, enabled); + rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); + + return 0; +} + +static int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + struct rt2x00_field32 field; + int retval; + u32 reg; + u32 offset; + + /* + * First pass the configuration through rt2x00lib, that will + * update the queue settings and validate the input. After that + * we are free to update the registers based on the value + * in the queue parameter. + */ + retval = rt2x00mac_conf_tx(hw, queue_idx, params); + if (retval) + return retval; + + /* + * We only need to perform additional register initialization + * for WMM queues/ + */ + if (queue_idx >= 4) + return 0; + + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + + /* Update WMM TXOP register */ + offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2))); + field.bit_offset = (queue_idx & 1) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt2800_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, field, queue->txop); + rt2800_register_write(rt2x00dev, offset, reg); + + /* Update WMM registers */ + field.bit_offset = queue_idx * 4; + field.bit_mask = 0xf << field.bit_offset; + + rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); + rt2x00_set_field32(®, field, queue->aifs); + rt2800_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); + + rt2800_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); + rt2x00_set_field32(®, field, queue->cw_min); + rt2800_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); + + rt2800_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); + rt2x00_set_field32(®, field, queue->cw_max); + rt2800_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); + + /* Update EDCA registers */ + offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx); + + rt2800_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop); + rt2x00_set_field32(®, EDCA_AC0_CFG_AIFSN, queue->aifs); + rt2x00_set_field32(®, EDCA_AC0_CFG_CWMIN, queue->cw_min); + rt2x00_set_field32(®, EDCA_AC0_CFG_CWMAX, queue->cw_max); + rt2800_register_write(rt2x00dev, offset, reg); + + return 0; +} + +static u64 rt2800_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + u64 tsf; + u32 reg; + + rt2800_register_read(rt2x00dev, TSF_TIMER_DW1, ®); + tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32; + rt2800_register_read(rt2x00dev, TSF_TIMER_DW0, ®); + tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD); + + return tsf; +} + +const struct ieee80211_ops rt2800_mac80211_ops = { + .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, + .add_interface = rt2x00mac_add_interface, + .remove_interface = rt2x00mac_remove_interface, + .config = rt2x00mac_config, + .configure_filter = rt2x00mac_configure_filter, + .set_tim = rt2x00mac_set_tim, + .set_key = rt2x00mac_set_key, + .get_stats = rt2x00mac_get_stats, + .get_tkip_seq = rt2800_get_tkip_seq, + .set_rts_threshold = rt2800_set_rts_threshold, + .bss_info_changed = rt2x00mac_bss_info_changed, + .conf_tx = rt2800_conf_tx, + .get_tx_stats = rt2x00mac_get_tx_stats, + .get_tsf = rt2800_get_tsf, + .rfkill_poll = rt2x00mac_rfkill_poll, +}; +EXPORT_SYMBOL_GPL(rt2800_mac80211_ops); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 2da8f79215fd..5eea8fcba6cc 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -129,4 +129,6 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev); int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); +extern const struct ieee80211_ops rt2800_mac80211_ops; + #endif /* RT2800LIB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 78086cce55ee..3c5b875cdee8 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1513,161 +1513,6 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) return 0; } -/* - * IEEE80211 stack callback functions. - */ -static void rt2800pci_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, - u32 *iv32, u16 *iv16) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct mac_iveiv_entry iveiv_entry; - u32 offset; - - offset = MAC_IVEIV_ENTRY(hw_key_idx); - rt2800_register_multiread(rt2x00dev, offset, - &iveiv_entry, sizeof(iveiv_entry)); - - memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16)); - memcpy(&iveiv_entry.iv[4], iv32, sizeof(iv32)); -} - -static int rt2800pci_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD); - - rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); - rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, value); - rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); - - rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); - rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); - rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); - rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); - rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); - rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); - rt2x00_set_field32(®, GF40_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); - - return 0; -} - -static int rt2800pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, - const struct ieee80211_tx_queue_params *params) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct data_queue *queue; - struct rt2x00_field32 field; - int retval; - u32 reg; - u32 offset; - - /* - * First pass the configuration through rt2x00lib, that will - * update the queue settings and validate the input. After that - * we are free to update the registers based on the value - * in the queue parameter. - */ - retval = rt2x00mac_conf_tx(hw, queue_idx, params); - if (retval) - return retval; - - /* - * We only need to perform additional register initialization - * for WMM queues/ - */ - if (queue_idx >= 4) - return 0; - - queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); - - /* Update WMM TXOP register */ - offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2))); - field.bit_offset = (queue_idx & 1) * 16; - field.bit_mask = 0xffff << field.bit_offset; - - rt2800_register_read(rt2x00dev, offset, ®); - rt2x00_set_field32(®, field, queue->txop); - rt2800_register_write(rt2x00dev, offset, reg); - - /* Update WMM registers */ - field.bit_offset = queue_idx * 4; - field.bit_mask = 0xf << field.bit_offset; - - rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); - rt2x00_set_field32(®, field, queue->aifs); - rt2800_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); - - rt2800_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); - rt2x00_set_field32(®, field, queue->cw_min); - rt2800_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); - - rt2800_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); - rt2x00_set_field32(®, field, queue->cw_max); - rt2800_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); - - /* Update EDCA registers */ - offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx); - - rt2800_register_read(rt2x00dev, offset, ®); - rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop); - rt2x00_set_field32(®, EDCA_AC0_CFG_AIFSN, queue->aifs); - rt2x00_set_field32(®, EDCA_AC0_CFG_CWMIN, queue->cw_min); - rt2x00_set_field32(®, EDCA_AC0_CFG_CWMAX, queue->cw_max); - rt2800_register_write(rt2x00dev, offset, reg); - - return 0; -} - -static u64 rt2800pci_get_tsf(struct ieee80211_hw *hw) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u64 tsf; - u32 reg; - - rt2800_register_read(rt2x00dev, TSF_TIMER_DW1, ®); - tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32; - rt2800_register_read(rt2x00dev, TSF_TIMER_DW0, ®); - tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD); - - return tsf; -} - -static const struct ieee80211_ops rt2800pci_mac80211_ops = { - .tx = rt2x00mac_tx, - .start = rt2x00mac_start, - .stop = rt2x00mac_stop, - .add_interface = rt2x00mac_add_interface, - .remove_interface = rt2x00mac_remove_interface, - .config = rt2x00mac_config, - .configure_filter = rt2x00mac_configure_filter, - .set_key = rt2x00mac_set_key, - .get_stats = rt2x00mac_get_stats, - .get_tkip_seq = rt2800pci_get_tkip_seq, - .set_rts_threshold = rt2800pci_set_rts_threshold, - .bss_info_changed = rt2x00mac_bss_info_changed, - .conf_tx = rt2800pci_conf_tx, - .get_tx_stats = rt2x00mac_get_tx_stats, - .get_tsf = rt2800pci_get_tsf, - .rfkill_poll = rt2x00mac_rfkill_poll, -}; - static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .irq_handler = rt2800pci_interrupt, .probe_hw = rt2800pci_probe_hw, @@ -1730,7 +1575,7 @@ static const struct rt2x00_ops rt2800pci_ops = { .tx = &rt2800pci_queue_tx, .bcn = &rt2800pci_queue_bcn, .lib = &rt2800pci_rt2x00_ops, - .hw = &rt2800pci_mac80211_ops, + .hw = &rt2800_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS .debugfs = &rt2800_rt2x00debug, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f5b864b1a55d..ce2e893856c1 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1119,162 +1119,6 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) return 0; } -/* - * IEEE80211 stack callback functions. - */ -static void rt2800usb_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, - u32 *iv32, u16 *iv16) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct mac_iveiv_entry iveiv_entry; - u32 offset; - - offset = MAC_IVEIV_ENTRY(hw_key_idx); - rt2800_register_multiread(rt2x00dev, offset, - &iveiv_entry, sizeof(iveiv_entry)); - - memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16)); - memcpy(&iveiv_entry.iv[4], iv32, sizeof(iv32)); -} - -static int rt2800usb_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - bool enabled = (value < IEEE80211_MAX_RTS_THRESHOLD); - - rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); - rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, value); - rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg); - - rt2800_register_read(rt2x00dev, CCK_PROT_CFG, ®); - rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); - rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, MM20_PROT_CFG, ®); - rt2x00_set_field32(®, MM20_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, MM40_PROT_CFG, ®); - rt2x00_set_field32(®, MM40_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, GF20_PROT_CFG, ®); - rt2x00_set_field32(®, GF20_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg); - - rt2800_register_read(rt2x00dev, GF40_PROT_CFG, ®); - rt2x00_set_field32(®, GF40_PROT_CFG_RTS_TH_EN, enabled); - rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg); - - return 0; -} - -static int rt2800usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, - const struct ieee80211_tx_queue_params *params) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - struct data_queue *queue; - struct rt2x00_field32 field; - int retval; - u32 reg; - u32 offset; - - /* - * First pass the configuration through rt2x00lib, that will - * update the queue settings and validate the input. After that - * we are free to update the registers based on the value - * in the queue parameter. - */ - retval = rt2x00mac_conf_tx(hw, queue_idx, params); - if (retval) - return retval; - - /* - * We only need to perform additional register initialization - * for WMM queues/ - */ - if (queue_idx >= 4) - return 0; - - queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); - - /* Update WMM TXOP register */ - offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2))); - field.bit_offset = (queue_idx & 1) * 16; - field.bit_mask = 0xffff << field.bit_offset; - - rt2800_register_read(rt2x00dev, offset, ®); - rt2x00_set_field32(®, field, queue->txop); - rt2800_register_write(rt2x00dev, offset, reg); - - /* Update WMM registers */ - field.bit_offset = queue_idx * 4; - field.bit_mask = 0xf << field.bit_offset; - - rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG, ®); - rt2x00_set_field32(®, field, queue->aifs); - rt2800_register_write(rt2x00dev, WMM_AIFSN_CFG, reg); - - rt2800_register_read(rt2x00dev, WMM_CWMIN_CFG, ®); - rt2x00_set_field32(®, field, queue->cw_min); - rt2800_register_write(rt2x00dev, WMM_CWMIN_CFG, reg); - - rt2800_register_read(rt2x00dev, WMM_CWMAX_CFG, ®); - rt2x00_set_field32(®, field, queue->cw_max); - rt2800_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); - - /* Update EDCA registers */ - offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx); - - rt2800_register_read(rt2x00dev, offset, ®); - rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop); - rt2x00_set_field32(®, EDCA_AC0_CFG_AIFSN, queue->aifs); - rt2x00_set_field32(®, EDCA_AC0_CFG_CWMIN, queue->cw_min); - rt2x00_set_field32(®, EDCA_AC0_CFG_CWMAX, queue->cw_max); - rt2800_register_write(rt2x00dev, offset, reg); - - return 0; -} - -static u64 rt2800usb_get_tsf(struct ieee80211_hw *hw) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u64 tsf; - u32 reg; - - rt2800_register_read(rt2x00dev, TSF_TIMER_DW1, ®); - tsf = (u64) rt2x00_get_field32(reg, TSF_TIMER_DW1_HIGH_WORD) << 32; - rt2800_register_read(rt2x00dev, TSF_TIMER_DW0, ®); - tsf |= rt2x00_get_field32(reg, TSF_TIMER_DW0_LOW_WORD); - - return tsf; -} - -static const struct ieee80211_ops rt2800usb_mac80211_ops = { - .tx = rt2x00mac_tx, - .start = rt2x00mac_start, - .stop = rt2x00mac_stop, - .add_interface = rt2x00mac_add_interface, - .remove_interface = rt2x00mac_remove_interface, - .config = rt2x00mac_config, - .configure_filter = rt2x00mac_configure_filter, - .set_tim = rt2x00mac_set_tim, - .set_key = rt2x00mac_set_key, - .get_stats = rt2x00mac_get_stats, - .get_tkip_seq = rt2800usb_get_tkip_seq, - .set_rts_threshold = rt2800usb_set_rts_threshold, - .bss_info_changed = rt2x00mac_bss_info_changed, - .conf_tx = rt2800usb_conf_tx, - .get_tx_stats = rt2x00mac_get_tx_stats, - .get_tsf = rt2800usb_get_tsf, - .rfkill_poll = rt2x00mac_rfkill_poll, -}; - static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .probe_hw = rt2800usb_probe_hw, .get_firmware_name = rt2800usb_get_firmware_name, @@ -1336,7 +1180,7 @@ static const struct rt2x00_ops rt2800usb_ops = { .tx = &rt2800usb_queue_tx, .bcn = &rt2800usb_queue_bcn, .lib = &rt2800usb_rt2x00_ops, - .hw = &rt2800usb_mac80211_ops, + .hw = &rt2800_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS .debugfs = &rt2800_rt2x00debug, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ -- cgit v1.2.3 From 77c8258ff7e6788d3889e7062607e891618d811f Mon Sep 17 00:00:00 2001 From: Keng-Yu Lin Date: Thu, 5 Nov 2009 11:21:37 +0800 Subject: ath5k: add LED support for Acer Aspire One AO751h/AO531h Add LED support for a Foxconn AR242X module, found on the Acer Aspire One models AO751h/AO531h Signed-off-by: Keng-Yu Lin Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/led.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index b767c3b67b24..7ce98bd7c749 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -59,6 +59,8 @@ static const struct pci_device_id ath5k_led_devices[] = { { ATH_SDEVICE(PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID), ATH_LED(1, 1) }, /* Acer Aspire One A150 (maximlevitsky@gmail.com) */ { ATH_SDEVICE(PCI_VENDOR_ID_FOXCONN, 0xe008), ATH_LED(3, 0) }, + /* Acer Aspire One AO531h AO751h (keng-yu.lin@canonical.com) */ + { ATH_SDEVICE(PCI_VENDOR_ID_FOXCONN, 0xe00d), ATH_LED(3, 0) }, /* Acer Ferrari 5000 (russ.dill@gmail.com) */ { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0422), ATH_LED(1, 1) }, /* E-machines E510 (tuliom@gmail.com) */ -- cgit v1.2.3 From c1b84ab059541517f51df534e87071723264833d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 5 Nov 2009 00:08:59 -0600 Subject: b43: Remove deprecated 'qual' from returned RX status With the deprecation of the qual member of ieee80211_rx_status, that calculation and an associated constant can be removed. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 2 -- drivers/net/wireless/b43/xmit.c | 1 - 2 files changed, 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 65b23f725a04..fe3bf9491997 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -26,8 +26,6 @@ # define B43_DEBUG 0 #endif -#define B43_RX_MAX_SSI 60 - /* MMIO offsets */ #define B43_MMIO_DMA0_REASON 0x20 #define B43_MMIO_DMA0_IRQ_MASK 0x24 diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 7a5e294be2bc..eda06529ef5f 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -621,7 +621,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) (phystat0 & B43_RX_PHYST0_OFDM), (phystat0 & B43_RX_PHYST0_GAINCTL), (phystat3 & B43_RX_PHYST3_TRSTATE)); - status.qual = (rxhdr->jssi * 100) / B43_RX_MAX_SSI; } if (phystat0 & B43_RX_PHYST0_OFDM) -- cgit v1.2.3 From 715caaeb896a51fe1583f306fb10b22cfab4f7fd Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 5 Nov 2009 00:09:15 -0600 Subject: b43legacy: Remove deprecated 'qual' from returned RX status With the deprecation of the qual member of ieee80211_rx_status, that calculation and an associated constant can be removed. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/b43legacy.h | 2 -- drivers/net/wireless/b43legacy/xmit.c | 1 - 2 files changed, 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 038baa8869e2..89fe2f972c72 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -29,8 +29,6 @@ #define B43legacy_IRQWAIT_MAX_RETRIES 20 -#define B43legacy_RX_MAX_SSI 60 /* best guess at max ssi */ - /* MMIO offsets */ #define B43legacy_MMIO_DMA0_REASON 0x20 #define B43legacy_MMIO_DMA0_IRQ_MASK 0x24 diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 103f3c9e7f58..9c8882d9275e 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -549,7 +549,6 @@ void b43legacy_rx(struct b43legacy_wldev *dev, (phystat0 & B43legacy_RX_PHYST0_GAINCTL), (phystat3 & B43legacy_RX_PHYST3_TRSTATE)); status.noise = dev->stats.link_noise; - status.qual = (jssi * 100) / B43legacy_RX_MAX_SSI; /* change to support A PHY */ if (phystat0 & B43legacy_RX_PHYST0_OFDM) status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false); -- cgit v1.2.3 From 70d9f405d09e334b609702d88ee03b6119c4b45e Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 5 Nov 2009 00:09:51 -0600 Subject: rtl8187: Remove deprecated 'qual' from returned RX status The qual member of ieee80211_rx_status is deprecated. As a result, this driver no longer needs to calculate a quality value. Signed-off-by: Larry Finger Acked-by: Hin-Tak Leung Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187.h | 1 - drivers/net/wireless/rtl818x/rtl8187_dev.c | 13 +++---------- 2 files changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h index bf9175a8c1f4..abb4907cf296 100644 --- a/drivers/net/wireless/rtl818x/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -119,7 +119,6 @@ struct rtl8187_priv { } hw_rev; struct sk_buff_head rx_queue; u8 signal; - u8 quality; u8 noise; u8 slot_time; u8 aifsn[4]; diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 2017ccc00145..76973b8c7099 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -320,7 +320,6 @@ static void rtl8187_rx_cb(struct urb *urb) struct ieee80211_rx_status rx_status = { 0 }; int rate, signal; u32 flags; - u32 quality; unsigned long f; spin_lock_irqsave(&priv->rx_queue.lock, f); @@ -338,10 +337,9 @@ static void rtl8187_rx_cb(struct urb *urb) (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); flags = le32_to_cpu(hdr->flags); /* As with the RTL8187B below, the AGC is used to calculate - * signal strength and quality. In this case, the scaling + * signal strength. In this case, the scaling * constants are derived from the output of p54usb. */ - quality = 130 - ((41 * hdr->agc) >> 6); signal = -4 - ((27 * hdr->agc) >> 6); rx_status.antenna = (hdr->signal >> 7) & 1; rx_status.mactime = le64_to_cpu(hdr->mac_time); @@ -354,23 +352,18 @@ static void rtl8187_rx_cb(struct urb *urb) * In testing, none of these quantities show qualitative * agreement with AP signal strength, except for the AGC, * which is inversely proportional to the strength of the - * signal. In the following, the quality and signal strength - * are derived from the AGC. The arbitrary scaling constants + * signal. In the following, the signal strength + * is derived from the AGC. The arbitrary scaling constants * are chosen to make the results close to the values obtained * for a BCM4312 using b43 as the driver. The noise is ignored * for now. */ flags = le32_to_cpu(hdr->flags); - quality = 170 - hdr->agc; signal = 14 - hdr->agc / 2; rx_status.antenna = (hdr->rssi >> 7) & 1; rx_status.mactime = le64_to_cpu(hdr->mac_time); } - if (quality > 100) - quality = 100; - rx_status.qual = quality; - priv->quality = quality; rx_status.signal = signal; priv->signal = signal; rate = (flags >> 20) & 0xF; -- cgit v1.2.3 From 45a390ddd70d8bec0b17dd37bc8f77372c9c3d33 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:47 +0200 Subject: mwl8k: change pci id table driver data to a structure pointer To prepare for adding support for more device types, introduce a new structure, mwl8k_device_info, where per-device information can be stored, and change the pci id table driver data from an integer indicating only the part number to a pointer to a mwl8k_device_info structure. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 47 ++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index c0317e298c11..a582794495e5 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -28,13 +28,6 @@ #define MWL8K_NAME KBUILD_MODNAME #define MWL8K_VERSION "0.10" -static DEFINE_PCI_DEVICE_TABLE(mwl8k_table) = { - { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = 8687, }, - { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = 8687, }, - { } -}; -MODULE_DEVICE_TABLE(pci, mwl8k_table); - /* Register definitions */ #define MWL8K_HIU_GEN_PTR 0x00000c10 #define MWL8K_MODE_STA 0x0000005a @@ -87,6 +80,10 @@ MODULE_DEVICE_TABLE(pci, mwl8k_table); #define MWL8K_RX_QUEUES 1 #define MWL8K_TX_QUEUES 4 +struct mwl8k_device_info { + int part_num; +}; + struct mwl8k_rx_queue { int rxd_count; @@ -130,9 +127,10 @@ struct mwl8k_priv { struct pci_dev *pdev; + struct mwl8k_device_info *device_info; + /* firmware files and meta data */ struct mwl8k_firmware fw; - u32 part_num; /* firmware access */ struct mutex fw_mutex; @@ -356,15 +354,13 @@ static int mwl8k_request_fw(struct mwl8k_priv *priv, fname, &priv->pdev->dev); } -static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num) +static int mwl8k_request_firmware(struct mwl8k_priv *priv) { u8 filename[64]; int rc; - priv->part_num = part_num; - snprintf(filename, sizeof(filename), - "mwl8k/helper_%u.fw", priv->part_num); + "mwl8k/helper_%u.fw", priv->device_info->part_num); rc = mwl8k_request_fw(priv, filename, &priv->fw.helper); if (rc) { @@ -374,7 +370,7 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num) } snprintf(filename, sizeof(filename), - "mwl8k/fmimage_%u.fw", priv->part_num); + "mwl8k/fmimage_%u.fw", priv->device_info->part_num); rc = mwl8k_request_fw(priv, filename, &priv->fw.ucode); if (rc) { @@ -2941,6 +2937,22 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) priv->beacon_skb = NULL; } +static struct mwl8k_device_info di_8687 = { + .part_num = 8687, +}; + +static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { + { + PCI_VDEVICE(MARVELL, 0x2a2b), + .driver_data = (unsigned long)&di_8687, + }, { + PCI_VDEVICE(MARVELL, 0x2a30), + .driver_data = (unsigned long)&di_8687, + }, { + }, +}; +MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); + static int __devinit mwl8k_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -2981,6 +2993,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv = hw->priv; priv->hw = hw; priv->pdev = pdev; + priv->device_info = (void *)id->driver_data; priv->sniffer_enabled = false; priv->wmm_enabled = false; priv->pending_tx_pkts = 0; @@ -3092,7 +3105,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, mwl8k_hw_reset(priv); /* Ask userland hotplug daemon for the device firmware */ - rc = mwl8k_request_firmware(priv, (u32)id->driver_data); + rc = mwl8k_request_firmware(priv); if (rc) { printk(KERN_ERR "%s: Firmware files not found\n", wiphy_name(hw->wiphy)); @@ -3152,8 +3165,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, } printk(KERN_INFO "%s: 88w%u v%d, %pM, firmware version %u.%u.%u.%u\n", - wiphy_name(hw->wiphy), priv->part_num, priv->hw_rev, - hw->wiphy->perm_addr, + wiphy_name(hw->wiphy), priv->device_info->part_num, + priv->hw_rev, hw->wiphy->perm_addr, (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff, (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff); @@ -3239,7 +3252,7 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) static struct pci_driver mwl8k_driver = { .name = MWL8K_NAME, - .id_table = mwl8k_table, + .id_table = mwl8k_pci_id_table, .probe = mwl8k_probe, .remove = __devexit_p(mwl8k_remove), .shutdown = __devexit_p(mwl8k_shutdown), -- cgit v1.2.3 From a74b295edb3e2b39d6c03255b24dca862a843c59 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:50 +0200 Subject: mwl8k: spell out the names of firmware images in the pci driver data To allow use of a more flexible firmware file naming scheme. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index a582794495e5..b0080ae98a83 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -81,7 +81,9 @@ #define MWL8K_TX_QUEUES 4 struct mwl8k_device_info { - int part_num; + char *part_name; + char *helper_image; + char *fw_image; }; struct mwl8k_rx_queue { @@ -113,11 +115,11 @@ struct mwl8k_tx_queue { /* Pointers to the firmware data and meta information about it. */ struct mwl8k_firmware { - /* Microcode */ - struct firmware *ucode; - /* Boot helper code */ struct firmware *helper; + + /* Microcode */ + struct firmware *ucode; }; struct mwl8k_priv { @@ -356,26 +358,23 @@ static int mwl8k_request_fw(struct mwl8k_priv *priv, static int mwl8k_request_firmware(struct mwl8k_priv *priv) { - u8 filename[64]; + struct mwl8k_device_info *di = priv->device_info; int rc; - snprintf(filename, sizeof(filename), - "mwl8k/helper_%u.fw", priv->device_info->part_num); - - rc = mwl8k_request_fw(priv, filename, &priv->fw.helper); - if (rc) { - printk(KERN_ERR "%s: Error requesting helper firmware " - "file %s\n", pci_name(priv->pdev), filename); - return rc; + if (di->helper_image != NULL) { + rc = mwl8k_request_fw(priv, di->helper_image, &priv->fw.helper); + if (rc) { + printk(KERN_ERR "%s: Error requesting helper " + "firmware file %s\n", pci_name(priv->pdev), + di->helper_image); + return rc; + } } - snprintf(filename, sizeof(filename), - "mwl8k/fmimage_%u.fw", priv->device_info->part_num); - - rc = mwl8k_request_fw(priv, filename, &priv->fw.ucode); + rc = mwl8k_request_fw(priv, di->fw_image, &priv->fw.ucode); if (rc) { printk(KERN_ERR "%s: Error requesting firmware file %s\n", - pci_name(priv->pdev), filename); + pci_name(priv->pdev), di->fw_image); mwl8k_release_fw(&priv->fw.helper); return rc; } @@ -2938,7 +2937,9 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) } static struct mwl8k_device_info di_8687 = { - .part_num = 8687, + .part_name = "88w8687", + .helper_image = "mwl8k/helper_8687.fw", + .fw_image = "mwl8k/fmimage_8687.fw", }; static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { @@ -3164,8 +3165,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_stop_firmware; } - printk(KERN_INFO "%s: 88w%u v%d, %pM, firmware version %u.%u.%u.%u\n", - wiphy_name(hw->wiphy), priv->device_info->part_num, + printk(KERN_INFO "%s: %s v%d, %pM, firmware version %u.%u.%u.%u\n", + wiphy_name(hw->wiphy), priv->device_info->part_name, priv->hw_rev, hw->wiphy->perm_addr, (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff, (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff); -- cgit v1.2.3 From eae74e6545d995ab0baa8fb07309f714d9616293 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:53 +0200 Subject: mwl8k: handle loading AP firmware images AP and STA firmware images provide a different signature in the HIU_INT_CODE register after loading. Record which of the signatures we saw, as it determines which command sequences to use later on. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b0080ae98a83..8bec4652fda1 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -130,6 +130,7 @@ struct mwl8k_priv { struct pci_dev *pdev; struct mwl8k_device_info *device_info; + bool ap_fw; /* firmware files and meta data */ struct mwl8k_firmware fw; @@ -534,6 +535,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; struct firmware *fw = priv->fw.ucode; + struct mwl8k_device_info *di = priv->device_info; int rc; int loops; @@ -565,14 +567,26 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) return rc; } - iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); + if (di->modes & BIT(NL80211_IFTYPE_AP)) + iowrite32(MWL8K_MODE_AP, priv->regs + MWL8K_HIU_GEN_PTR); + else + iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR); msleep(1); loops = 200000; do { - if (ioread32(priv->regs + MWL8K_HIU_INT_CODE) - == MWL8K_FWSTA_READY) + u32 ready_code; + + ready_code = ioread32(priv->regs + MWL8K_HIU_INT_CODE); + if (ready_code == MWL8K_FWAP_READY) { + priv->ap_fw = 1; + break; + } else if (ready_code == MWL8K_FWSTA_READY) { + priv->ap_fw = 0; break; + } + + cond_resched(); udelay(1); } while (--loops); @@ -3165,9 +3179,10 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, goto err_stop_firmware; } - printk(KERN_INFO "%s: %s v%d, %pM, firmware version %u.%u.%u.%u\n", + printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n", wiphy_name(hw->wiphy), priv->device_info->part_name, priv->hw_rev, hw->wiphy->perm_addr, + priv->ap_fw ? "AP" : "STA", (priv->fw_rev >> 24) & 0xff, (priv->fw_rev >> 16) & 0xff, (priv->fw_rev >> 8) & 0xff, priv->fw_rev & 0xff); -- cgit v1.2.3 From 788838ebe8a4caca93a91982c7bbf393edf24c08 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:56 +0200 Subject: mwl8k: use pci_unmap_addr{,set}() to keep track of unmap addresses on rx Instead of reading back the unmap address from the receive descriptor when doing receive processing, use DECLARE_PCI_UNMAP_ADDR and pci_unmap_addr{,set}() to keep track of these addresses. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 55 ++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 8bec4652fda1..49ae31b8b621 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -97,7 +97,10 @@ struct mwl8k_rx_queue { struct mwl8k_rx_desc *rxd; dma_addr_t rxd_dma; - struct sk_buff **skb; + struct { + struct sk_buff *skb; + DECLARE_PCI_UNMAP_ADDR(dma) + } *buf; }; struct mwl8k_tx_queue { @@ -791,14 +794,14 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) } memset(rxq->rxd, 0, size); - rxq->skb = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->skb), GFP_KERNEL); - if (rxq->skb == NULL) { + rxq->buf = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->buf), GFP_KERNEL); + if (rxq->buf == NULL) { printk(KERN_ERR "%s: failed to alloc RX skbuff list\n", wiphy_name(hw->wiphy)); pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma); return -ENOMEM; } - memset(rxq->skb, 0, MWL8K_RX_DESCS * sizeof(*rxq->skb)); + memset(rxq->buf, 0, MWL8K_RX_DESCS * sizeof(*rxq->buf)); for (i = 0; i < MWL8K_RX_DESCS; i++) { struct mwl8k_rx_desc *rx_desc; @@ -824,6 +827,7 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit) refilled = 0; while (rxq->rxd_count < MWL8K_RX_DESCS && limit--) { struct sk_buff *skb; + dma_addr_t addr; int rx; skb = dev_alloc_skb(MWL8K_RX_MAXSZ); @@ -835,12 +839,13 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit) rx = rxq->tail; rxq->tail = (rx + 1) % MWL8K_RX_DESCS; - rxq->rxd[rx].pkt_phys_addr = - cpu_to_le32(pci_map_single(priv->pdev, skb->data, - MWL8K_RX_MAXSZ, DMA_FROM_DEVICE)); + addr = pci_map_single(priv->pdev, skb->data, + MWL8K_RX_MAXSZ, DMA_FROM_DEVICE); rxq->rxd[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ); - rxq->skb[rx] = skb; + rxq->rxd[rx].pkt_phys_addr = cpu_to_le32(addr); + rxq->buf[rx].skb = skb; + pci_unmap_addr_set(&rxq->buf[rx], dma, addr); wmb(); rxq->rxd[rx].rx_ctrl = 0; @@ -858,19 +863,19 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) int i; for (i = 0; i < MWL8K_RX_DESCS; i++) { - if (rxq->skb[i] != NULL) { - unsigned long addr; - - addr = le32_to_cpu(rxq->rxd[i].pkt_phys_addr); - pci_unmap_single(priv->pdev, addr, MWL8K_RX_MAXSZ, - PCI_DMA_FROMDEVICE); - kfree_skb(rxq->skb[i]); - rxq->skb[i] = NULL; + if (rxq->buf[i].skb != NULL) { + pci_unmap_single(priv->pdev, + pci_unmap_addr(&rxq->buf[i], dma), + MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); + pci_unmap_addr_set(&rxq->buf[i], dma, 0); + + kfree_skb(rxq->buf[i].skb); + rxq->buf[i].skb = NULL; } } - kfree(rxq->skb); - rxq->skb = NULL; + kfree(rxq->buf); + rxq->buf = NULL; pci_free_consistent(priv->pdev, MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc), @@ -920,7 +925,6 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) struct mwl8k_rx_desc *rx_desc; struct sk_buff *skb; struct ieee80211_rx_status status; - unsigned long addr; struct ieee80211_hdr *wh; u16 rate_info; @@ -929,18 +933,19 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) break; rmb(); - skb = rxq->skb[rxq->head]; + skb = rxq->buf[rxq->head].skb; if (skb == NULL) break; - rxq->skb[rxq->head] = NULL; + rxq->buf[rxq->head].skb = NULL; + + pci_unmap_single(priv->pdev, + pci_unmap_addr(&rxq->buf[rxq->head], dma), + MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); + pci_unmap_addr_set(&rxq->buf[rxq->head], dma, 0); rxq->head = (rxq->head + 1) % MWL8K_RX_DESCS; rxq->rxd_count--; - addr = le32_to_cpu(rx_desc->pkt_phys_addr); - pci_unmap_single(priv->pdev, addr, - MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); - skb_put(skb, le16_to_cpu(rx_desc->pkt_len)); mwl8k_remove_dma_header(skb); -- cgit v1.2.3 From 54bc3a0d7a0c9a13da31183609c42cf7786138e1 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:20:59 +0200 Subject: mwl8k: allow for different receive descriptor formats As the receive descriptor format is determined by the firmware running on the hardware and not by the hardware itself, and as these descriptor formats vary a bit between different firmware releases, abstract out the receive descriptor init/refill/process methods, and allow choosing between different formats at run time depending on the chip and firmware we're running on. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 180 ++++++++++++++++++++++++++++--------------- 1 file changed, 119 insertions(+), 61 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 49ae31b8b621..c9a4c1e1987f 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -80,10 +80,18 @@ #define MWL8K_RX_QUEUES 1 #define MWL8K_TX_QUEUES 4 +struct rxd_ops { + int rxd_size; + void (*rxd_init)(void *rxd, dma_addr_t next_dma_addr); + void (*rxd_refill)(void *rxd, dma_addr_t addr, int len); + int (*rxd_process)(void *rxd, struct ieee80211_rx_status *status); +}; + struct mwl8k_device_info { char *part_name; char *helper_image; char *fw_image; + struct rxd_ops *rxd_ops; }; struct mwl8k_rx_queue { @@ -95,7 +103,7 @@ struct mwl8k_rx_queue { /* refill descs here */ int tail; - struct mwl8k_rx_desc *rxd; + void *rxd; dma_addr_t rxd_dma; struct { struct sk_buff *skb; @@ -134,6 +142,7 @@ struct mwl8k_priv { struct mwl8k_device_info *device_info; bool ap_fw; + struct rxd_ops *rxd_ops; /* firmware files and meta data */ struct mwl8k_firmware fw; @@ -744,9 +753,7 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb) /* * Packet reception. */ -#define MWL8K_RX_CTRL_OWNED_BY_HOST 0x02 - -struct mwl8k_rx_desc { +struct mwl8k_rxd_8687 { __le16 pkt_len; __u8 link_quality; __u8 noise_level; @@ -763,16 +770,79 @@ struct mwl8k_rx_desc { __u8 pad2[2]; } __attribute__((packed)); +#define MWL8K_8687_RATE_INFO_SHORTPRE 0x8000 +#define MWL8K_8687_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3) +#define MWL8K_8687_RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f) +#define MWL8K_8687_RATE_INFO_40MHZ 0x0004 +#define MWL8K_8687_RATE_INFO_SHORTGI 0x0002 +#define MWL8K_8687_RATE_INFO_MCS_FORMAT 0x0001 + +#define MWL8K_8687_RX_CTRL_OWNED_BY_HOST 0x02 + +static void mwl8k_rxd_8687_init(void *_rxd, dma_addr_t next_dma_addr) +{ + struct mwl8k_rxd_8687 *rxd = _rxd; + + rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); + rxd->rx_ctrl = MWL8K_8687_RX_CTRL_OWNED_BY_HOST; +} + +static void mwl8k_rxd_8687_refill(void *_rxd, dma_addr_t addr, int len) +{ + struct mwl8k_rxd_8687 *rxd = _rxd; + + rxd->pkt_len = cpu_to_le16(len); + rxd->pkt_phys_addr = cpu_to_le32(addr); + wmb(); + rxd->rx_ctrl = 0; +} + +static int +mwl8k_rxd_8687_process(void *_rxd, struct ieee80211_rx_status *status) +{ + struct mwl8k_rxd_8687 *rxd = _rxd; + u16 rate_info; + + if (!(rxd->rx_ctrl & MWL8K_8687_RX_CTRL_OWNED_BY_HOST)) + return -1; + rmb(); + + rate_info = le16_to_cpu(rxd->rate_info); + + memset(status, 0, sizeof(*status)); + + status->signal = -rxd->rssi; + status->noise = -rxd->noise_level; + status->qual = rxd->link_quality; + status->antenna = MWL8K_8687_RATE_INFO_ANTSELECT(rate_info); + status->rate_idx = MWL8K_8687_RATE_INFO_RATEID(rate_info); + + if (rate_info & MWL8K_8687_RATE_INFO_SHORTPRE) + status->flag |= RX_FLAG_SHORTPRE; + if (rate_info & MWL8K_8687_RATE_INFO_40MHZ) + status->flag |= RX_FLAG_40MHZ; + if (rate_info & MWL8K_8687_RATE_INFO_SHORTGI) + status->flag |= RX_FLAG_SHORT_GI; + if (rate_info & MWL8K_8687_RATE_INFO_MCS_FORMAT) + status->flag |= RX_FLAG_HT; + + status->band = IEEE80211_BAND_2GHZ; + status->freq = ieee80211_channel_to_frequency(rxd->channel); + + return le16_to_cpu(rxd->pkt_len); +} + +static struct rxd_ops rxd_8687_ops = { + .rxd_size = sizeof(struct mwl8k_rxd_8687), + .rxd_init = mwl8k_rxd_8687_init, + .rxd_refill = mwl8k_rxd_8687_refill, + .rxd_process = mwl8k_rxd_8687_process, +}; + + #define MWL8K_RX_DESCS 256 #define MWL8K_RX_MAXSZ 3800 -#define RATE_INFO_SHORTPRE 0x8000 -#define RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3) -#define RATE_INFO_RATEID(x) (((x) >> 3) & 0x3f) -#define RATE_INFO_40MHZ 0x0004 -#define RATE_INFO_SHORTGI 0x0002 -#define RATE_INFO_MCS_FORMAT 0x0001 - static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) { struct mwl8k_priv *priv = hw->priv; @@ -784,7 +854,7 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) rxq->head = 0; rxq->tail = 0; - size = MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc); + size = MWL8K_RX_DESCS * priv->rxd_ops->rxd_size; rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma); if (rxq->rxd == NULL) { @@ -804,15 +874,20 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) memset(rxq->buf, 0, MWL8K_RX_DESCS * sizeof(*rxq->buf)); for (i = 0; i < MWL8K_RX_DESCS; i++) { - struct mwl8k_rx_desc *rx_desc; + int desc_size; + void *rxd; int nexti; + dma_addr_t next_dma_addr; + + desc_size = priv->rxd_ops->rxd_size; + rxd = rxq->rxd + (i * priv->rxd_ops->rxd_size); - rx_desc = rxq->rxd + i; - nexti = (i + 1) % MWL8K_RX_DESCS; + nexti = i + 1; + if (nexti == MWL8K_RX_DESCS) + nexti = 0; + next_dma_addr = rxq->rxd_dma + (nexti * desc_size); - rx_desc->next_rxd_phys_addr = - cpu_to_le32(rxq->rxd_dma + nexti * sizeof(*rx_desc)); - rx_desc->rx_ctrl = MWL8K_RX_CTRL_OWNED_BY_HOST; + priv->rxd_ops->rxd_init(rxd, next_dma_addr); } return 0; @@ -829,25 +904,24 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit) struct sk_buff *skb; dma_addr_t addr; int rx; + void *rxd; skb = dev_alloc_skb(MWL8K_RX_MAXSZ); if (skb == NULL) break; - rxq->rxd_count++; - - rx = rxq->tail; - rxq->tail = (rx + 1) % MWL8K_RX_DESCS; - addr = pci_map_single(priv->pdev, skb->data, MWL8K_RX_MAXSZ, DMA_FROM_DEVICE); - rxq->rxd[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ); - rxq->rxd[rx].pkt_phys_addr = cpu_to_le32(addr); + rxq->rxd_count++; + rx = rxq->tail++; + if (rxq->tail == MWL8K_RX_DESCS) + rxq->tail = 0; rxq->buf[rx].skb = skb; pci_unmap_addr_set(&rxq->buf[rx], dma, addr); - wmb(); - rxq->rxd[rx].rx_ctrl = 0; + + rxd = rxq->rxd + (rx * priv->rxd_ops->rxd_size); + priv->rxd_ops->rxd_refill(rxd, addr, MWL8K_RX_MAXSZ); refilled++; } @@ -878,7 +952,7 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index) rxq->buf = NULL; pci_free_consistent(priv->pdev, - MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc), + MWL8K_RX_DESCS * priv->rxd_ops->rxd_size, rxq->rxd, rxq->rxd_dma); rxq->rxd = NULL; } @@ -922,20 +996,21 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) processed = 0; while (rxq->rxd_count && limit--) { - struct mwl8k_rx_desc *rx_desc; struct sk_buff *skb; + void *rxd; + int pkt_len; struct ieee80211_rx_status status; - struct ieee80211_hdr *wh; - u16 rate_info; - - rx_desc = rxq->rxd + rxq->head; - if (!(rx_desc->rx_ctrl & MWL8K_RX_CTRL_OWNED_BY_HOST)) - break; - rmb(); skb = rxq->buf[rxq->head].skb; if (skb == NULL) break; + + rxd = rxq->rxd + (rxq->head * priv->rxd_ops->rxd_size); + + pkt_len = priv->rxd_ops->rxd_process(rxd, &status); + if (pkt_len < 0) + break; + rxq->buf[rxq->head].skb = NULL; pci_unmap_single(priv->pdev, @@ -943,42 +1018,23 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit) MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE); pci_unmap_addr_set(&rxq->buf[rxq->head], dma, 0); - rxq->head = (rxq->head + 1) % MWL8K_RX_DESCS; + rxq->head++; + if (rxq->head == MWL8K_RX_DESCS) + rxq->head = 0; + rxq->rxd_count--; - skb_put(skb, le16_to_cpu(rx_desc->pkt_len)); + skb_put(skb, pkt_len); mwl8k_remove_dma_header(skb); - wh = (struct ieee80211_hdr *)skb->data; - /* * Check for a pending join operation. Save a * copy of the beacon and schedule a tasklet to * send a FINALIZE_JOIN command to the firmware. */ - if (mwl8k_capture_bssid(priv, wh)) + if (mwl8k_capture_bssid(priv, (void *)skb->data)) mwl8k_save_beacon(hw, skb); - rate_info = le16_to_cpu(rx_desc->rate_info); - - memset(&status, 0, sizeof(status)); - status.mactime = 0; - status.signal = -rx_desc->rssi; - status.noise = -rx_desc->noise_level; - status.qual = rx_desc->link_quality; - status.antenna = RATE_INFO_ANTSELECT(rate_info); - status.rate_idx = RATE_INFO_RATEID(rate_info); - status.flag = 0; - if (rate_info & RATE_INFO_SHORTPRE) - status.flag |= RX_FLAG_SHORTPRE; - if (rate_info & RATE_INFO_40MHZ) - status.flag |= RX_FLAG_40MHZ; - if (rate_info & RATE_INFO_SHORTGI) - status.flag |= RX_FLAG_SHORT_GI; - if (rate_info & RATE_INFO_MCS_FORMAT) - status.flag |= RX_FLAG_HT; - status.band = IEEE80211_BAND_2GHZ; - status.freq = ieee80211_channel_to_frequency(rx_desc->channel); memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status)); ieee80211_rx_irqsafe(hw, skb); @@ -2959,6 +3015,7 @@ static struct mwl8k_device_info di_8687 = { .part_name = "88w8687", .helper_image = "mwl8k/helper_8687.fw", .fw_image = "mwl8k/fmimage_8687.fw", + .rxd_ops = &rxd_8687_ops, }; static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { @@ -3014,6 +3071,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->hw = hw; priv->pdev = pdev; priv->device_info = (void *)id->driver_data; + priv->rxd_ops = priv->device_info->rxd_ops; priv->sniffer_enabled = false; priv->wmm_enabled = false; priv->pending_tx_pkts = 0; -- cgit v1.2.3 From 547810e3af15cf9efc3b3ebaa7b006ef606fc892 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:21:02 +0200 Subject: mwl8k: set ->interface_modes from the driver data As different chip/firmware combinations support different interface types. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index c9a4c1e1987f..11669ed8829d 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -92,6 +92,7 @@ struct mwl8k_device_info { char *helper_image; char *fw_image; struct rxd_ops *rxd_ops; + u16 modes; }; struct mwl8k_rx_queue { @@ -3016,6 +3017,7 @@ static struct mwl8k_device_info di_8687 = { .helper_image = "mwl8k/helper_8687.fw", .fw_image = "mwl8k/fmimage_8687.fw", .rxd_ops = &rxd_8687_ops, + .modes = BIT(NL80211_IFTYPE_STATION), }; static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { @@ -3122,7 +3124,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, hw->queues = MWL8K_TX_QUEUES; - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + hw->wiphy->interface_modes = priv->device_info->modes; /* Set rssi and noise values to dBm */ hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; -- cgit v1.2.3 From 04b147b19303724aac5ee8e56f113f1935a5c255 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:21:05 +0200 Subject: mwl8k: rename mwl8k_cmd_get_hw_spec() to mwl8k_cmd_get_hw_spec_sta() As the AP version of the command uses a different format. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 11669ed8829d..90bf19cb6bf4 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1538,9 +1538,9 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) } /* - * GET_HW_SPEC. + * CMD_GET_HW_SPEC (STA version). */ -struct mwl8k_cmd_get_hw_spec { +struct mwl8k_cmd_get_hw_spec_sta { struct mwl8k_cmd_pkt header; __u8 hw_rev; __u8 host_interface; @@ -1559,10 +1559,10 @@ struct mwl8k_cmd_get_hw_spec { __le32 total_rxd; } __attribute__((packed)); -static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw) +static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) { struct mwl8k_priv *priv = hw->priv; - struct mwl8k_cmd_get_hw_spec *cmd; + struct mwl8k_cmd_get_hw_spec_sta *cmd; int rc; int i; @@ -3211,7 +3211,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); /* Get config data, mac addrs etc */ - rc = mwl8k_cmd_get_hw_spec(hw); + rc = mwl8k_cmd_get_hw_spec_sta(hw); if (rc) { printk(KERN_ERR "%s: Cannot initialise firmware\n", wiphy_name(hw->wiphy)); -- cgit v1.2.3 From 42fba21d56df644887488a29b158cc8916b9ba99 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:21:30 +0200 Subject: mwl8k: add the commands used for AP firmware initialisation Add the AP version of the GET_HW_SPEC command, as well as the SET_HW_SPEC command, for initialising AP firmware. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 133 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 90bf19cb6bf4..9b9ce7005da0 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -275,6 +275,7 @@ static const struct ieee80211_rate mwl8k_rates[] = { /* Firmware command codes */ #define MWL8K_CMD_CODE_DNLD 0x0001 #define MWL8K_CMD_GET_HW_SPEC 0x0003 +#define MWL8K_CMD_SET_HW_SPEC 0x0004 #define MWL8K_CMD_MAC_MULTICAST_ADR 0x0010 #define MWL8K_CMD_GET_STAT 0x0014 #define MWL8K_CMD_RADIO_CONTROL 0x001c @@ -305,6 +306,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) switch (cmd & ~0x8000) { MWL8K_CMDNAME(CODE_DNLD); MWL8K_CMDNAME(GET_HW_SPEC); + MWL8K_CMDNAME(SET_HW_SPEC); MWL8K_CMDNAME(MAC_MULTICAST_ADR); MWL8K_CMDNAME(GET_STAT); MWL8K_CMDNAME(RADIO_CONTROL); @@ -1595,6 +1597,129 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) return rc; } +/* + * CMD_GET_HW_SPEC (AP version). + */ +struct mwl8k_cmd_get_hw_spec_ap { + struct mwl8k_cmd_pkt header; + __u8 hw_rev; + __u8 host_interface; + __le16 num_wcb; + __le16 num_mcaddrs; + __u8 perm_addr[ETH_ALEN]; + __le16 region_code; + __le16 num_antenna; + __le32 fw_rev; + __le32 wcbbase0; + __le32 rxwrptr; + __le32 rxrdptr; + __le32 ps_cookie; + __le32 wcbbase1; + __le32 wcbbase2; + __le32 wcbbase3; +} __attribute__((packed)); + +static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_cmd_get_hw_spec_ap *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_HW_SPEC); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr)); + cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); + + rc = mwl8k_post_cmd(hw, &cmd->header); + + if (!rc) { + int off; + + SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr); + priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); + priv->fw_rev = le32_to_cpu(cmd->fw_rev); + priv->hw_rev = cmd->hw_rev; + + off = le32_to_cpu(cmd->wcbbase0) & 0xffff; + iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off); + + off = le32_to_cpu(cmd->rxwrptr) & 0xffff; + iowrite32(cpu_to_le32(priv->rxq[0].rxd_dma), priv->sram + off); + + off = le32_to_cpu(cmd->rxrdptr) & 0xffff; + iowrite32(cpu_to_le32(priv->rxq[0].rxd_dma), priv->sram + off); + + off = le32_to_cpu(cmd->wcbbase1) & 0xffff; + iowrite32(cpu_to_le32(priv->txq[1].txd_dma), priv->sram + off); + + off = le32_to_cpu(cmd->wcbbase2) & 0xffff; + iowrite32(cpu_to_le32(priv->txq[2].txd_dma), priv->sram + off); + + off = le32_to_cpu(cmd->wcbbase3) & 0xffff; + iowrite32(cpu_to_le32(priv->txq[3].txd_dma), priv->sram + off); + } + + kfree(cmd); + return rc; +} + +/* + * CMD_SET_HW_SPEC. + */ +struct mwl8k_cmd_set_hw_spec { + struct mwl8k_cmd_pkt header; + __u8 hw_rev; + __u8 host_interface; + __le16 num_mcaddrs; + __u8 perm_addr[ETH_ALEN]; + __le16 region_code; + __le32 fw_rev; + __le32 ps_cookie; + __le32 caps; + __le32 rx_queue_ptr; + __le32 num_tx_queues; + __le32 tx_queue_ptrs[MWL8K_TX_QUEUES]; + __le32 flags; + __le32 num_tx_desc_per_queue; + __le32 total_rxd; +} __attribute__((packed)); + +#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 + +static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) +{ + struct mwl8k_priv *priv = hw->priv; + struct mwl8k_cmd_set_hw_spec *cmd; + int rc; + int i; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_HW_SPEC); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + + cmd->ps_cookie = cpu_to_le32(priv->cookie_dma); + cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma); + cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); + for (i = 0; i < MWL8K_TX_QUEUES; i++) + cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); + cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT); + cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); + cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + /* * CMD_MAC_MULTICAST_ADR. */ @@ -3211,7 +3336,13 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); /* Get config data, mac addrs etc */ - rc = mwl8k_cmd_get_hw_spec_sta(hw); + if (priv->ap_fw) { + rc = mwl8k_cmd_get_hw_spec_ap(hw); + if (!rc) + rc = mwl8k_cmd_set_hw_spec(hw); + } else { + rc = mwl8k_cmd_get_hw_spec_sta(hw); + } if (rc) { printk(KERN_ERR "%s: Cannot initialise firmware\n", wiphy_name(hw->wiphy)); -- cgit v1.2.3 From 08b063477e45cb366df7204cbcdc79ff86513ef9 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:21:33 +0200 Subject: mwl8k: implement AP firmware antenna configuration Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 9b9ce7005da0..59219fdb342d 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -280,6 +280,7 @@ static const struct ieee80211_rate mwl8k_rates[] = { #define MWL8K_CMD_GET_STAT 0x0014 #define MWL8K_CMD_RADIO_CONTROL 0x001c #define MWL8K_CMD_RF_TX_POWER 0x001e +#define MWL8K_CMD_RF_ANTENNA 0x0020 #define MWL8K_CMD_SET_PRE_SCAN 0x0107 #define MWL8K_CMD_SET_POST_SCAN 0x0108 #define MWL8K_CMD_SET_RF_CHANNEL 0x010a @@ -311,6 +312,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) MWL8K_CMDNAME(GET_STAT); MWL8K_CMDNAME(RADIO_CONTROL); MWL8K_CMDNAME(RF_TX_POWER); + MWL8K_CMDNAME(RF_ANTENNA); MWL8K_CMDNAME(SET_PRE_SCAN); MWL8K_CMDNAME(SET_POST_SCAN); MWL8K_CMDNAME(SET_RF_CHANNEL); @@ -1918,6 +1920,39 @@ static int mwl8k_cmd_802_11_rf_tx_power(struct ieee80211_hw *hw, int dBm) return rc; } +/* + * CMD_RF_ANTENNA. + */ +struct mwl8k_cmd_rf_antenna { + struct mwl8k_cmd_pkt header; + __le16 antenna; + __le16 mode; +} __attribute__((packed)); + +#define MWL8K_RF_ANTENNA_RX 1 +#define MWL8K_RF_ANTENNA_TX 2 + +static int +mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask) +{ + struct mwl8k_cmd_rf_antenna *cmd; + int rc; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_ANTENNA); + cmd->header.length = cpu_to_le16(sizeof(*cmd)); + cmd->antenna = cpu_to_le16(antenna); + cmd->mode = cpu_to_le16(mask); + + rc = mwl8k_post_cmd(hw, &cmd->header); + kfree(cmd); + + return rc; +} + /* * CMD_SET_PRE_SCAN. */ @@ -2832,8 +2867,13 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) if (rc) goto out; - if (mwl8k_cmd_mimo_config(hw, 0x7, 0x7)) - rc = -EINVAL; + if (priv->ap_fw) { + rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x7); + if (!rc) + rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_TX, 0x7); + } else { + rc = mwl8k_cmd_mimo_config(hw, 0x7, 0x7); + } out: mwl8k_fw_unlock(hw); -- cgit v1.2.3 From c0adae2caa1a152c6ec691c5d1e815e47dac2a0c Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:21:36 +0200 Subject: mwl8k: add AP firmware handling to ->configure_filter() Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 59219fdb342d..19c6bea1bc48 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3013,6 +3013,16 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_pkt *cmd = (void *)(unsigned long)multicast; + /* + * AP firmware doesn't allow fine-grained control over + * the receive filter. + */ + if (priv->ap_fw) { + *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; + kfree(cmd); + return; + } + /* * Enable hardware sniffer mode if FIF_CONTROL or * FIF_OTHER_BSS is requested. -- cgit v1.2.3 From 5e4cf166f4a9801ea9ca1bab210d763d27538de6 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:21:38 +0200 Subject: mwl8k: add AP firmware handling to ->start() Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 19c6bea1bc48..1c4114f8d317 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2713,12 +2713,17 @@ static int mwl8k_start(struct ieee80211_hw *hw) if (!rc) { rc = mwl8k_cmd_802_11_radio_enable(hw); - if (!rc) - rc = mwl8k_cmd_set_pre_scan(hw); + if (!priv->ap_fw) { + if (!rc) + rc = mwl8k_enable_sniffer(hw, 0); - if (!rc) - rc = mwl8k_cmd_set_post_scan(hw, - "\x00\x00\x00\x00\x00\x00"); + if (!rc) + rc = mwl8k_cmd_set_pre_scan(hw); + + if (!rc) + rc = mwl8k_cmd_set_post_scan(hw, + "\x00\x00\x00\x00\x00\x00"); + } if (!rc) rc = mwl8k_cmd_setrateadaptmode(hw, 0); @@ -2726,9 +2731,6 @@ static int mwl8k_start(struct ieee80211_hw *hw) if (!rc) rc = mwl8k_set_wmm(hw, 0); - if (!rc) - rc = mwl8k_enable_sniffer(hw, 0); - mwl8k_fw_unlock(hw); } -- cgit v1.2.3 From 259a8e7ddd55485b4a75ec39bc6716745c08fce0 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:21:40 +0200 Subject: mwl8k: add AP firmware (mbss) handling to mwl8k_set_mac_addr() Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 1c4114f8d317..4ee68f7d20f4 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2135,11 +2135,18 @@ static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable) */ struct mwl8k_cmd_set_mac_addr { struct mwl8k_cmd_pkt header; - __u8 mac_addr[ETH_ALEN]; + union { + struct { + __le16 mac_type; + __u8 mac_addr[ETH_ALEN]; + } mbss; + __u8 mac_addr[ETH_ALEN]; + }; } __attribute__((packed)); static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) { + struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_set_mac_addr *cmd; int rc; @@ -2149,7 +2156,12 @@ static int mwl8k_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - memcpy(cmd->mac_addr, mac, ETH_ALEN); + if (priv->ap_fw) { + cmd->mbss.mac_type = 0; + memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); + } else { + memcpy(cmd->mac_addr, mac, ETH_ALEN); + } rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); -- cgit v1.2.3 From 2e484c8964f7845d320eb1161c514dbfcafdda78 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:21:43 +0200 Subject: mwl8k: implement AP firmware EDCA parameter configuration Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 49 +++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 4ee68f7d20f4..de38ec481f60 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2272,17 +2272,34 @@ struct mwl8k_cmd_set_edca_params { /* TX opportunity in units of 32 us */ __le16 txop; - /* Log exponent of max contention period: 0...15*/ - __u8 log_cw_max; + union { + struct { + /* Log exponent of max contention period: 0...15 */ + __le32 log_cw_max; + + /* Log exponent of min contention period: 0...15 */ + __le32 log_cw_min; + + /* Adaptive interframe spacing in units of 32us */ + __u8 aifs; + + /* TX queue to configure */ + __u8 txq; + } ap; + struct { + /* Log exponent of max contention period: 0...15 */ + __u8 log_cw_max; - /* Log exponent of min contention period: 0...15 */ - __u8 log_cw_min; + /* Log exponent of min contention period: 0...15 */ + __u8 log_cw_min; - /* Adaptive interframe spacing in units of 32us */ - __u8 aifs; + /* Adaptive interframe spacing in units of 32us */ + __u8 aifs; - /* TX queue to configure */ - __u8 txq; + /* TX queue to configure */ + __u8 txq; + } sta; + }; } __attribute__((packed)); #define MWL8K_SET_EDCA_CW 0x01 @@ -2298,6 +2315,7 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, __u16 cw_min, __u16 cw_max, __u8 aifs, __u16 txop) { + struct mwl8k_priv *priv = hw->priv; struct mwl8k_cmd_set_edca_params *cmd; int rc; @@ -2315,10 +2333,17 @@ mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, cmd->header.length = cpu_to_le16(sizeof(*cmd)); cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); cmd->txop = cpu_to_le16(txop); - cmd->log_cw_max = (u8)ilog2(cw_max + 1); - cmd->log_cw_min = (u8)ilog2(cw_min + 1); - cmd->aifs = aifs; - cmd->txq = qnum; + if (priv->ap_fw) { + cmd->ap.log_cw_max = cpu_to_le32(ilog2(cw_max + 1)); + cmd->ap.log_cw_min = cpu_to_le32(ilog2(cw_min + 1)); + cmd->ap.aifs = aifs; + cmd->ap.txq = qnum; + } else { + cmd->sta.log_cw_max = (u8)ilog2(cw_max + 1); + cmd->sta.log_cw_min = (u8)ilog2(cw_min + 1); + cmd->sta.aifs = aifs; + cmd->sta.txq = qnum; + } rc = mwl8k_post_cmd(hw, &cmd->header); kfree(cmd); -- cgit v1.2.3 From 6f6d1e9a8a7fea5e4400cad64bed717e322208e1 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 22 Oct 2009 20:21:48 +0200 Subject: mwl8k: add support for the 88w8366 Add support for the 88w8366 firmware receive descriptor format, and add the 88w8366 PCI ID. Signed-off-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 95 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index de38ec481f60..9fde17bb9911 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -756,7 +756,89 @@ static inline void mwl8k_add_dma_header(struct sk_buff *skb) /* - * Packet reception. + * Packet reception for 88w8366. + */ +struct mwl8k_rxd_8366 { + __le16 pkt_len; + __u8 sq2; + __u8 rate; + __le32 pkt_phys_addr; + __le32 next_rxd_phys_addr; + __le16 qos_control; + __le16 htsig2; + __le32 hw_rssi_info; + __le32 hw_noise_floor_info; + __u8 noise_floor; + __u8 pad0[3]; + __u8 rssi; + __u8 rx_status; + __u8 channel; + __u8 rx_ctrl; +} __attribute__((packed)); + +#define MWL8K_8366_RX_CTRL_OWNED_BY_HOST 0x80 + +static void mwl8k_rxd_8366_init(void *_rxd, dma_addr_t next_dma_addr) +{ + struct mwl8k_rxd_8366 *rxd = _rxd; + + rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr); + rxd->rx_ctrl = MWL8K_8366_RX_CTRL_OWNED_BY_HOST; +} + +static void mwl8k_rxd_8366_refill(void *_rxd, dma_addr_t addr, int len) +{ + struct mwl8k_rxd_8366 *rxd = _rxd; + + rxd->pkt_len = cpu_to_le16(len); + rxd->pkt_phys_addr = cpu_to_le32(addr); + wmb(); + rxd->rx_ctrl = 0; +} + +static int +mwl8k_rxd_8366_process(void *_rxd, struct ieee80211_rx_status *status) +{ + struct mwl8k_rxd_8366 *rxd = _rxd; + + if (!(rxd->rx_ctrl & MWL8K_8366_RX_CTRL_OWNED_BY_HOST)) + return -1; + rmb(); + + memset(status, 0, sizeof(*status)); + + status->signal = -rxd->rssi; + status->noise = -rxd->noise_floor; + + if (rxd->rate & 0x80) { + status->flag |= RX_FLAG_HT; + status->rate_idx = rxd->rate & 0x7f; + } else { + int i; + + for (i = 0; i < ARRAY_SIZE(mwl8k_rates); i++) { + if (mwl8k_rates[i].hw_value == rxd->rate) { + status->rate_idx = i; + break; + } + } + } + + status->band = IEEE80211_BAND_2GHZ; + status->freq = ieee80211_channel_to_frequency(rxd->channel); + + return le16_to_cpu(rxd->pkt_len); +} + +static struct rxd_ops rxd_8366_ops = { + .rxd_size = sizeof(struct mwl8k_rxd_8366), + .rxd_init = mwl8k_rxd_8366_init, + .rxd_refill = mwl8k_rxd_8366_refill, + .rxd_process = mwl8k_rxd_8366_process, +}; + +/* + * Packet reception for 88w8687. */ struct mwl8k_rxd_8687 { __le16 pkt_len; @@ -3226,6 +3308,14 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) priv->beacon_skb = NULL; } +static struct mwl8k_device_info di_8366 = { + .part_name = "88w8366", + .helper_image = "mwl8k/helper_8366.fw", + .fw_image = "mwl8k/fmimage_8366.fw", + .rxd_ops = &rxd_8366_ops, + .modes = 0, +}; + static struct mwl8k_device_info di_8687 = { .part_name = "88w8687", .helper_image = "mwl8k/helper_8687.fw", @@ -3241,6 +3331,9 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { }, { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = (unsigned long)&di_8687, + }, { + PCI_VDEVICE(MARVELL, 0x2a40), + .driver_data = (unsigned long)&di_8366, }, { }, }; -- cgit v1.2.3 From bcb628d579a61d0ab0cac4c6cc8a403de5254920 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 6 Nov 2009 16:40:16 -0500 Subject: mwl8k: use integral index instead of pointer for driver_data Use of an integral index makes adding new device IDs through sysfs more practical. Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 47 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 9fde17bb9911..2ebfee4da3fa 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -3308,34 +3308,33 @@ static void mwl8k_finalize_join_worker(struct work_struct *work) priv->beacon_skb = NULL; } -static struct mwl8k_device_info di_8366 = { - .part_name = "88w8366", - .helper_image = "mwl8k/helper_8366.fw", - .fw_image = "mwl8k/fmimage_8366.fw", - .rxd_ops = &rxd_8366_ops, - .modes = 0, +enum { + MWL8687 = 0, + MWL8366, }; -static struct mwl8k_device_info di_8687 = { - .part_name = "88w8687", - .helper_image = "mwl8k/helper_8687.fw", - .fw_image = "mwl8k/fmimage_8687.fw", - .rxd_ops = &rxd_8687_ops, - .modes = BIT(NL80211_IFTYPE_STATION), +static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { + { + .part_name = "88w8687", + .helper_image = "mwl8k/helper_8687.fw", + .fw_image = "mwl8k/fmimage_8687.fw", + .rxd_ops = &rxd_8687_ops, + .modes = BIT(NL80211_IFTYPE_STATION), + }, + { + .part_name = "88w8366", + .helper_image = "mwl8k/helper_8366.fw", + .fw_image = "mwl8k/fmimage_8366.fw", + .rxd_ops = &rxd_8366_ops, + .modes = 0, + }, }; static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { - { - PCI_VDEVICE(MARVELL, 0x2a2b), - .driver_data = (unsigned long)&di_8687, - }, { - PCI_VDEVICE(MARVELL, 0x2a30), - .driver_data = (unsigned long)&di_8687, - }, { - PCI_VDEVICE(MARVELL, 0x2a40), - .driver_data = (unsigned long)&di_8366, - }, { - }, + { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, + { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, + { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, + { }, }; MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); @@ -3379,7 +3378,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv = hw->priv; priv->hw = hw; priv->pdev = pdev; - priv->device_info = (void *)id->driver_data; + priv->device_info = &mwl8k_info_tbl[id->driver_data]; priv->rxd_ops = priv->device_info->rxd_ops; priv->sniffer_enabled = false; priv->wmm_enabled = false; -- cgit v1.2.3 From 9646e7ce3d1955478aa0573b36c151ab4b649486 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 6 Nov 2009 22:51:16 -0800 Subject: net, compat_ioctl: handle socket ioctl abuses in tty drivers Slip and a few other drivers use the same ioctl numbers on tty devices that are normally meant for sockets. This causes problems with our compat_ioctl handling that tries to convert the data structures in a different format. Fortunately, these five drivers all use 32 bit compatible data structures in the ioctl numbers, so we can just add a trivial compat_ioctl conversion function to each of them. SIOCSIFENCAP and SIOCGIFENCAP do not need to live in fs/compat_ioctl.c after this any more, and they are not used on any sockets. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/hamradio/6pack.c | 21 +++++++++++++++++++++ drivers/net/hamradio/mkiss.c | 21 +++++++++++++++++++++ drivers/net/slip.c | 25 +++++++++++++++++++++++++ drivers/net/wan/x25_asy.c | 19 +++++++++++++++++++ drivers/net/wireless/strip.c | 17 +++++++++++++++++ fs/compat_ioctl.c | 2 -- 6 files changed, 103 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index fb588301a05d..689b9bd377a5 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #define SIXPACK_VERSION "Revision: 0.3.0" @@ -777,6 +778,23 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file, return err; } +#ifdef CONFIG_COMPAT +static long sixpack_compat_ioctl(struct tty_struct * tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case SIOCGIFNAME: + case SIOCGIFENCAP: + case SIOCSIFENCAP: + case SIOCSIFHWADDR: + return sixpack_ioctl(tty, file, cmd, + (unsigned long)compat_ptr(arg)); + } + + return -ENOIOCTLCMD; +} +#endif + static struct tty_ldisc_ops sp_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, @@ -784,6 +802,9 @@ static struct tty_ldisc_ops sp_ldisc = { .open = sixpack_open, .close = sixpack_close, .ioctl = sixpack_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = sixpack_compat_ioctl, +#endif .receive_buf = sixpack_receive_buf, .write_wakeup = sixpack_write_wakeup, }; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index db4b7f1603f6..fc9c57893f8a 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -898,6 +899,23 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file, return err; } +#ifdef CONFIG_COMPAT +static long mkiss_compat_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (arg) { + case SIOCGIFNAME: + case SIOCGIFENCAP: + case SIOCSIFENCAP: + case SIOCSIFHWADDR: + return mkiss_ioctl(tty, file, cmd, + (unsigned long)compat_ptr(arg)); + } + + return -ENOIOCTLCMD; +} +#endif + /* * Handle the 'receiver data ready' interrupt. * This function is called by the 'tty_io' module in the kernel when @@ -972,6 +990,9 @@ static struct tty_ldisc_ops ax_ldisc = { .open = mkiss_open, .close = mkiss_close, .ioctl = mkiss_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = mkiss_compat_ioctl, +#endif .receive_buf = mkiss_receive_buf, .write_wakeup = mkiss_write_wakeup }; diff --git a/drivers/net/slip.c b/drivers/net/slip.c index e17c535a577e..ccfe45924fd9 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include "slip.h" @@ -1168,6 +1169,27 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, } } +#ifdef CONFIG_COMPAT +static long slip_compat_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case SIOCGIFNAME: + case SIOCGIFENCAP: + case SIOCSIFENCAP: + case SIOCSIFHWADDR: + case SIOCSKEEPALIVE: + case SIOCGKEEPALIVE: + case SIOCSOUTFILL: + case SIOCGOUTFILL: + return slip_ioctl(tty, file, cmd, + (unsigned long)compat_ptr(arg)); + } + + return -ENOIOCTLCMD; +} +#endif + /* VSV changes start here */ #ifdef CONFIG_SLIP_SMART /* function do_ioctl called from net/core/dev.c @@ -1260,6 +1282,9 @@ static struct tty_ldisc_ops sl_ldisc = { .close = slip_close, .hangup = slip_hangup, .ioctl = slip_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = slip_compat_ioctl, +#endif .receive_buf = slip_receive_buf, .write_wakeup = slip_write_wakeup, }; diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 27945049c9e1..3c325d77939b 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "x25_asy.h" #include @@ -705,6 +706,21 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file, } } +#ifdef CONFIG_COMPAT +static long x25_asy_compat_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case SIOCGIFNAME: + case SIOCSIFHWADDR: + return x25_asy_ioctl(tty, file, cmd, + (unsigned long)compat_ptr(arg)); + } + + return -ENOIOCTLCMD; +} +#endif + static int x25_asy_open_dev(struct net_device *dev) { struct x25_asy *sl = netdev_priv(dev); @@ -754,6 +770,9 @@ static struct tty_ldisc_ops x25_ldisc = { .open = x25_asy_open_tty, .close = x25_asy_close_tty, .ioctl = x25_asy_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = x25_asy_compat_ioctl, +#endif .receive_buf = x25_asy_receive_buf, .write_wakeup = x25_asy_write_wakeup, }; diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index ea6a87c19319..698aade79d40 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -106,6 +106,7 @@ static const char StripVersion[] = "1.3A-STUART.CHESHIRE"; #include #include #include +#include #include #include @@ -2725,6 +2726,19 @@ static int strip_ioctl(struct tty_struct *tty, struct file *file, return 0; } +#ifdef CONFIG_COMPAT +static long strip_compat_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case SIOCGIFNAME: + case SIOCSIFHWADDR: + return strip_ioctl(tty, file, cmd, + (unsigned long)compat_ptr(arg)); + } + return -ENOIOCTLCMD; +} +#endif /************************************************************************/ /* Initialization */ @@ -2736,6 +2750,9 @@ static struct tty_ldisc_ops strip_ldisc = { .open = strip_open, .close = strip_close, .ioctl = strip_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = strip_compat_ioctl, +#endif .receive_buf = strip_receive_buf, .write_wakeup = strip_write_some_more, }; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index c562e9a4da70..f4a5a01fc661 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -2020,8 +2020,6 @@ COMPATIBLE_IOCTL(FIOGETOWN) COMPATIBLE_IOCTL(SIOCGPGRP) COMPATIBLE_IOCTL(SIOCATMARK) COMPATIBLE_IOCTL(SIOCSIFLINK) -COMPATIBLE_IOCTL(SIOCSIFENCAP) -COMPATIBLE_IOCTL(SIOCGIFENCAP) COMPATIBLE_IOCTL(SIOCSIFNAME) COMPATIBLE_IOCTL(SIOCSARP) COMPATIBLE_IOCTL(SIOCGARP) -- cgit v1.2.3 From f54a52021d7ad039c16fe5a1e094d8f0394d90ec Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 6 Nov 2009 18:32:44 +0100 Subject: b43: Rewrite TX bounce buffer handling Do not mess with the original skb, but allocate an independent bouncebuffer. This protects against bad interference with mac80211's assumptions about the skb (which already caused bugs). Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 48 +++++++++++++++++------------------------ drivers/net/wireless/b43/xmit.h | 19 ++++++++++++++++ 2 files changed, 39 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index de4e804bedf0..b5cd7f57055b 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1157,18 +1157,17 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) } static int dma_tx_fragment(struct b43_dmaring *ring, - struct sk_buff **in_skb) + struct sk_buff *skb) { - struct sk_buff *skb = *in_skb; const struct b43_dma_ops *ops = ring->ops; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct b43_private_tx_info *priv_info = b43_get_priv_tx_info(info); u8 *header; int slot, old_top_slot, old_used_slots; int err; struct b43_dmadesc_generic *desc; struct b43_dmadesc_meta *meta; struct b43_dmadesc_meta *meta_hdr; - struct sk_buff *bounce_skb; u16 cookie; size_t hdrsize = b43_txhdr_size(ring->dev); @@ -1212,34 +1211,28 @@ static int dma_tx_fragment(struct b43_dmaring *ring, meta->skb = skb; meta->is_last_fragment = 1; + priv_info->bouncebuffer = NULL; meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); /* create a bounce buffer in zone_dma on mapping failure. */ if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { - bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); - if (!bounce_skb) { + priv_info->bouncebuffer = kmalloc(skb->len, GFP_ATOMIC | GFP_DMA); + if (!priv_info->bouncebuffer) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; err = -ENOMEM; goto out_unmap_hdr; } + memcpy(priv_info->bouncebuffer, skb->data, skb->len); - memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); - memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb)); - bounce_skb->dev = skb->dev; - skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb)); - info = IEEE80211_SKB_CB(bounce_skb); - - dev_kfree_skb_any(skb); - skb = bounce_skb; - *in_skb = bounce_skb; - meta->skb = skb; - meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + meta->dmaaddr = map_descbuffer(ring, priv_info->bouncebuffer, skb->len, 1); if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { + kfree(priv_info->bouncebuffer); + priv_info->bouncebuffer = NULL; ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; err = -EIO; - goto out_free_bounce; + goto out_unmap_hdr; } } @@ -1256,8 +1249,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ops->poke_tx(ring, next_slot(ring, slot)); return 0; -out_free_bounce: - dev_kfree_skb_any(skb); out_unmap_hdr: unmap_descbuffer(ring, meta_hdr->dmaaddr, hdrsize, 1); @@ -1362,11 +1353,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) * static, so we don't need to store it per frame. */ ring->queue_prio = skb_get_queue_mapping(skb); - /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing - * into the skb data or cb now. */ - hdr = NULL; - info = NULL; - err = dma_tx_fragment(ring, &skb); + err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -1413,12 +1400,17 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); desc = ops->idx2desc(ring, slot, &meta); - if (meta->skb) - unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, - 1); - else + if (meta->skb) { + struct b43_private_tx_info *priv_info = + b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); + + unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); + kfree(priv_info->bouncebuffer); + priv_info->bouncebuffer = NULL; + } else { unmap_descbuffer(ring, meta->dmaaddr, b43_txhdr_size(dev), 1); + } if (meta->is_last_fragment) { struct ieee80211_tx_info *info; diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 3530de871873..d23ff9fe0c9e 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -2,6 +2,8 @@ #define B43_XMIT_H_ #include "main.h" +#include + #define _b43_declare_plcp_hdr(size) \ struct b43_plcp_hdr##size { \ @@ -332,4 +334,21 @@ static inline u8 b43_kidx_to_raw(struct b43_wldev *dev, u8 firmware_kidx) return raw_kidx; } +/* struct b43_private_tx_info - TX info private to b43. + * The structure is placed in (struct ieee80211_tx_info *)->rate_driver_data + * + * @bouncebuffer: DMA Bouncebuffer (if used) + */ +struct b43_private_tx_info { + void *bouncebuffer; +}; + +static inline struct b43_private_tx_info * +b43_get_priv_tx_info(struct ieee80211_tx_info *info) +{ + BUILD_BUG_ON(sizeof(struct b43_private_tx_info) > + sizeof(info->rate_driver_data)); + return (struct b43_private_tx_info *)info->rate_driver_data; +} + #endif /* B43_XMIT_H_ */ -- cgit v1.2.3 From cf7ff8dfe64c8ca8a71b4fcbac357a3476ed1888 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 6 Nov 2009 14:52:44 -0800 Subject: iwlwifi: change debug message to error in failure case Since these messages indicate failure we would be interested in seeing them always. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 905645d15a9b..e8002c1d3eba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -199,13 +199,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) } if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { - IWL_DEBUG_INFO(priv, "Command %s aborted: RF KILL Switch\n", + IWL_ERR(priv, "Command %s aborted: RF KILL Switch\n", get_cmd_string(cmd->id)); ret = -ECANCELED; goto fail; } if (test_bit(STATUS_FW_ERROR, &priv->status)) { - IWL_DEBUG_INFO(priv, "Command %s failed: FW Error\n", + IWL_ERR(priv, "Command %s failed: FW Error\n", get_cmd_string(cmd->id)); ret = -EIO; goto fail; -- cgit v1.2.3 From a3b6bd5bf23c5cd95389e24121da02d2330eaf21 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 6 Nov 2009 14:52:45 -0800 Subject: iwlwifi: allocate 128 bytes linear buffer for rx skb Allocate 128 bytes linear buffer for rx skb. The first 64 bytes is reserved for mac80211 usage (for radiotap header expansion, etc). The frame header starts from the second 64 bytes. Cc: Johannes Berg Signed-off-by: Zhu Yi Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-rx.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 09a7bd2c0be4..26a1134f84a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -564,7 +564,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, return; } - skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC); + skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); if (!skb) { IWL_ERR(priv, "alloc_skb failed\n"); return; @@ -575,6 +575,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, (struct ieee80211_hdr *)rxb_addr(rxb), le32_to_cpu(rx_end->status), stats); + skb_reserve(skb, IWL_LINK_HDR_MAX); skb_add_rx_frag(skb, 0, rxb->page, (void *)rx_hdr->payload - (void *)pkt, len); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index e5339c9ad13e..d2dc7cceb5f2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -937,12 +937,13 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; - skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC); + skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); if (!skb) { IWL_ERR(priv, "alloc_skb failed\n"); return; } + skb_reserve(skb, IWL_LINK_HDR_MAX); skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); /* mac80211 currently doesn't support paged SKB. Convert it to -- cgit v1.2.3 From a643565efcdafdc37638aa5131ced91b2d3ddcb2 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:46 -0800 Subject: iwlwifi: print rx_on config to help debug To help debug rx related issues, if IWL_DEBUG_RADIO flag is set, print the rxon configuration when rxon host command send to uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-core.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.h | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b5fe8f87aa7e..1710815691d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -133,6 +133,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) } memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); + iwl_print_rx_config_cmd(priv); return 0; } @@ -228,6 +229,7 @@ int iwl_commit_rxon(struct iwl_priv *priv) } memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); } + iwl_print_rx_config_cmd(priv); iwl_init_sensitivity(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e0b5b4aef41d..f88a1cb7a12b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1328,7 +1328,7 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) EXPORT_SYMBOL(iwl_rx_csa); #ifdef CONFIG_IWLWIFI_DEBUG -static void iwl_print_rx_config_cmd(struct iwl_priv *priv) +void iwl_print_rx_config_cmd(struct iwl_priv *priv) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -1346,6 +1346,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv) IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } +EXPORT_SYMBOL(iwl_print_rx_config_cmd); #endif /** * iwl_irq_handle_error - called for HW or SW error interrupt from card diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 9574d8f33537..3f97036ac29b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -579,6 +579,7 @@ int iwl_pci_resume(struct pci_dev *pdev); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_dump_nic_event_log(struct iwl_priv *priv); void iwl_dump_nic_error_log(struct iwl_priv *priv); +void iwl_print_rx_config_cmd(struct iwl_priv *priv); #else static inline void iwl_dump_nic_event_log(struct iwl_priv *priv) { @@ -587,6 +588,10 @@ static inline void iwl_dump_nic_event_log(struct iwl_priv *priv) static inline void iwl_dump_nic_error_log(struct iwl_priv *priv) { } + +static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv) +{ +} #endif void iwl_clear_isr_stats(struct iwl_priv *priv); -- cgit v1.2.3 From f1e3d7d428616c04ef71bee3c2b6f274b8947755 Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Fri, 6 Nov 2009 14:52:47 -0800 Subject: iwlwifi: use only one chain for scan in PS When doing scan in power saving mode, choose only 1 valid RX chain instead of turning all chains on. Signed-off-by: Shanyu Zhao Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-scan.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 1eb0d0bf1fe4..48bc2636a8ef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -581,6 +581,7 @@ static void iwl_bg_request_scan(struct work_struct *data) u8 rate; bool is_active = false; int chan_mod; + u8 active_chains; conf = ieee80211_get_hw_conf(priv->hw); @@ -734,9 +735,22 @@ static void iwl_bg_request_scan(struct work_struct *data) rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); + /* In power save mode use one chain, otherwise use all chains */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + /* rx_ant has been set to all valid chains previously */ + active_chains = rx_ant & + ((u8)(priv->chain_noise_data.active_chains)); + if (!active_chains) + active_chains = rx_ant; + + IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n", + priv->chain_noise_data.active_chains); + + rx_ant = first_antenna(active_chains); + } /* MIMO is not used here, but value is required */ rx_chain |= ANT_ABC << RXON_RX_CHAIN_VALID_POS; - rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; + rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; scan->rx_chain = cpu_to_le16(rx_chain); -- cgit v1.2.3 From b23aa883678aec0f5d9e96c9b3e416ec4fdf735e Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Fri, 6 Nov 2009 14:52:48 -0800 Subject: iwlwifi: use configured valid rx chain for scan Use configured valid rx chains in scan command instead of ANT_ABC, correcting valid rx chain configuration of 4965, should be ANT_ABC instead of ANT_AB. Signed-off-by: Shanyu Zhao Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1ff465ad40d8..faa4c4e2d43c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2228,7 +2228,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, .mod_params = &iwl4965_mod_params, .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, + .valid_rx_ant = ANT_ABC, .pll_cfg_val = 0, .set_l0s = true, .use_bsm = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 48bc2636a8ef..a2b2b8315ff9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -749,7 +749,7 @@ static void iwl_bg_request_scan(struct work_struct *data) rx_ant = first_antenna(active_chains); } /* MIMO is not used here, but value is required */ - rx_chain |= ANT_ABC << RXON_RX_CHAIN_VALID_POS; + rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; -- cgit v1.2.3 From 0748dc1fcd8589c0e215e26112320b76e7c9a262 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:49 -0800 Subject: iwlwifi: no periodic Tx/IQ calibration for 6x00/6x50 series For both 6x00 and 6x50 series devices, periodic Tx IQ calibration is disabled in uCode, driver do not need to set the periodic Tx/IQ calibration bit in calibration command. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 70e117f8d0c4..9ab79546b8a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -166,9 +166,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) BIT(IWL_CALIB_XTAL) | BIT(IWL_CALIB_LO) | BIT(IWL_CALIB_TX_IQ) | - BIT(IWL_CALIB_TX_IQ_PERD) | BIT(IWL_CALIB_BASE_BAND); - return 0; } -- cgit v1.2.3 From a221e6f7b48ee2d9352827af8aec8b49272b5b43 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 6 Nov 2009 14:52:50 -0800 Subject: iwlwifi: don't double-activate queue 4 The fourth queue (command queue) is already activated in the loop above that also maps it to the command FIFO and therefore doesn't need to be marked as activated again. Also change the TODO comment to be accurate -- we need to initialise the _queues_, not FIFOs, and map them to device FIFOs. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 910217f0ad8a..6ea5e2dc273c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -661,9 +661,13 @@ int iwl5000_alive_notify(struct iwl_priv *priv) iwl_txq_ctx_activate(priv, i); iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0); } - /* TODO - need to initialize those FIFOs inside the loop above, - * not only mark them as active */ - iwl_txq_ctx_activate(priv, 4); + + /* + * TODO - need to initialize these queues and map them to FIFOs + * in the loop above, not only mark them as active. We do this + * because we want the first aggregation queue to be queue #10, + * but do not use 8 or 9 otherwise yet. + */ iwl_txq_ctx_activate(priv, 7); iwl_txq_ctx_activate(priv, 8); iwl_txq_ctx_activate(priv, 9); -- cgit v1.2.3 From 1a716557a5ed3b814cb32b8be79848d53e470871 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 6 Nov 2009 14:52:51 -0800 Subject: iwlwifi: fix FIFO vs. queue confusion When I added that code setting the swq_id, I evidently did not understand the distinction between FIFO and TX queue yet and added code to compare a queue ID and a FIFO number, which is bogus. However, the code there need not be this specific, it can just set all queues to the identity mapping which will be overwritten by the aggregation queue code. As a bit of defensive coding, don't assign an swq_id to the command queue so that if we ever use it for frames we notice quickly. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 5 +++-- drivers/net/wireless/iwlwifi/iwl-tx.c | 9 +++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cb2642c18da4..b4e814543039 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -324,8 +324,9 @@ struct iwl_channel_info { #define IWL_MIN_NUM_QUEUES 10 /* - * uCode queue management definitions ... - * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00. + * Queue #4 is the command queue for 3945/4965/5x00/1000/6x00, + * the driver maps it into the appropriate device FIFO for the + * uCode. */ #define IWL_CMD_QUEUE_NUM 4 diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 05e75109d842..905ceca88b95 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -364,8 +364,13 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, txq->need_update = 0; - /* aggregation TX queues will get their ID when aggregation begins */ - if (txq_id <= IWL_TX_FIFO_AC3) + /* + * Aggregation TX queues will get their ID when aggregation begins; + * they overwrite the setting done here. The command FIFO doesn't + * need an swq_id so don't set one to catch errors, all others can + * be set up to the identity mapping. + */ + if (txq_id != IWL_CMD_QUEUE_NUM) txq->swq_id = txq_id; /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise -- cgit v1.2.3 From bed0a68f98d93c0abdc96b4c290a92c80234c182 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:52 -0800 Subject: iwlwifi: remove un-used parameter Remove un-used parameter "recovery_rxon" from "priv" data structure Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index b4e814543039..997564584c71 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1087,8 +1087,6 @@ struct iwl_priv { const struct iwl_rxon_cmd active_rxon; struct iwl_rxon_cmd staging_rxon; - struct iwl_rxon_cmd recovery_rxon; - /* 1st responses from initialize and runtime uCode images. * 4965's initialize alive response contains some calibration data. */ struct iwl_init_alive_resp card_alive_init; -- cgit v1.2.3 From 681988653ed46a14032ac5fe2ee84eaae314b72e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 6 Nov 2009 14:52:53 -0800 Subject: iwlwifi: add FIFO usage for 5000 This is part of the code, but the comment doesn't have it, add pointers to the code and the FIFO usage for 5000 and up. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-prph.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index d393e8f02102..6d95832db06d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -254,7 +254,8 @@ * device. A queue maps to only one (selectable by driver) Tx DMA channel, * but one DMA channel may take input from several queues. * - * Tx DMA channels have dedicated purposes. For 4965, they are used as follows: + * Tx DMA channels have dedicated purposes. For 4965, they are used as follows + * (cf. default_queue_to_tx_fifo in iwl-4965.c): * * 0 -- EDCA BK (background) frames, lowest priority * 1 -- EDCA BE (best effort) frames, normal priority @@ -265,9 +266,21 @@ * 6 -- HCCA long frames * 7 -- not used by driver (device-internal only) * + * For 5000 series and up, they are used slightly differently + * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c): + * + * 0 -- EDCA BK (background) frames, lowest priority + * 1 -- EDCA BE (best effort) frames, normal priority + * 2 -- EDCA VI (video) frames, higher priority + * 3 -- EDCA VO (voice) and management frames, highest priority + * 4 -- (TBD) + * 5 -- HCCA short frames + * 6 -- HCCA long frames + * 7 -- Commands + * * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6. - * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to - * support 11n aggregation via EDCA DMA channels. + * In addition, driver can map the remaining queues to Tx DMA/FIFO + * channels 0-3 to support 11n aggregation via EDCA DMA channels. * * The driver sets up each queue to work in one of two modes: * -- cgit v1.2.3 From 0924e519a3a18ffbfaa043f4a2c369140c5a235c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:54 -0800 Subject: iwlwifi: fix for channel switch Different channel has different configuration, need to pass correct configuration to uCode when send "channel switch" command to uCode. Invalid configuration will cause sysassert in uCode and produce un-expected result. Even it is a very small windows, but we also need to consider and handle the case if commit_rxon occurred before the "channel switch announcement" notification received from uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 12 +++++---- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 +++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 6 +++-- drivers/net/wireless/iwlwifi/iwl-agn.c | 11 ++++++++ drivers/net/wireless/iwlwifi/iwl-core.c | 45 +++++++++++++++++++++------------ drivers/net/wireless/iwlwifi/iwl-dev.h | 13 ++++++++++ 6 files changed, 68 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index faa4c4e2d43c..1d22ea390c00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1449,14 +1449,14 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) is_ht40 = is_ht40_channel(priv->staging_rxon.flags); if (is_ht40 && - (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) + (priv->staging_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) ctrl_chan_high = 1; cmd.band = band; cmd.expect_beacon = 0; cmd.channel = cpu_to_le16(channel); - cmd.rxon_flags = priv->active_rxon.flags; - cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.rxon_flags = priv->staging_rxon.flags; + cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); if (ch_info) cmd.expect_beacon = is_channel_radar(ch_info); @@ -1473,8 +1473,10 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) return rc; } - rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); - return rc; + priv->switch_rxon.channel = cpu_to_le16(channel); + priv->switch_rxon.switch_in_progress = true; + + return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); } /** diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 6ea5e2dc273c..6eaf26b07636 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1391,8 +1391,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) priv->active_rxon.channel, channel); cmd.band = priv->band == IEEE80211_BAND_2GHZ; cmd.channel = cpu_to_le16(channel); - cmd.rxon_flags = priv->active_rxon.flags; - cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.rxon_flags = priv->staging_rxon.flags; + cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); ch_info = iwl_get_channel_info(priv, priv->band, channel); if (ch_info) @@ -1402,6 +1402,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) priv->active_rxon.channel, channel); return -EFAULT; } + priv->switch_rxon.channel = cpu_to_le16(channel); + priv->switch_rxon.switch_in_progress = true; return iwl_send_cmd_sync(priv, &hcmd); } diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 9ab79546b8a4..1f769ea23636 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -186,8 +186,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) cmd.band = priv->band == IEEE80211_BAND_2GHZ; cmd.channel = cpu_to_le16(channel); - cmd.rxon_flags = priv->active_rxon.flags; - cmd.rxon_filter_flags = priv->active_rxon.filter_flags; + cmd.rxon_flags = priv->staging_rxon.flags; + cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); ch_info = iwl_get_channel_info(priv, priv->band, channel); if (ch_info) @@ -197,6 +197,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) priv->active_rxon.channel, channel); return -EFAULT; } + priv->switch_rxon.channel = cpu_to_le16(channel); + priv->switch_rxon.switch_in_progress = true; return iwl_send_cmd_sync(priv, &hcmd); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1710815691d5..7bdedf61dd36 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -122,6 +122,17 @@ int iwl_commit_rxon(struct iwl_priv *priv) return -EINVAL; } + /* + * receive commit_rxon request + * abort any previous channel switch if still in process + */ + if (priv->switch_rxon.switch_in_progress && + (priv->switch_rxon.channel != priv->staging_rxon.channel)) { + IWL_DEBUG_11H(priv, "abort channel switch on %d\n", + le16_to_cpu(priv->switch_rxon.channel)); + priv->switch_rxon.switch_in_progress = false; + } + /* If we don't need to send a full RXON, we can use * iwl_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index f88a1cb7a12b..e0edc607e33f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1316,14 +1316,19 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; struct iwl_csa_notification *csa = &(pkt->u.csa_notif); - if (!le32_to_cpu(csa->status)) { - rxon->channel = csa->channel; - priv->staging_rxon.channel = csa->channel; - IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", - le16_to_cpu(csa->channel)); - } else - IWL_ERR(priv, "CSA notif (fail) : channel %d\n", - le16_to_cpu(csa->channel)); + if (priv->switch_rxon.switch_in_progress) { + if (!le32_to_cpu(csa->status) && + (csa->channel == priv->switch_rxon.channel)) { + rxon->channel = csa->channel; + priv->staging_rxon.channel = csa->channel; + IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", + le16_to_cpu(csa->channel)); + } else + IWL_ERR(priv, "CSA notif (fail) : channel %d\n", + le16_to_cpu(csa->channel)); + + priv->switch_rxon.switch_in_progress = false; + } } EXPORT_SYMBOL(iwl_rx_csa); @@ -2690,14 +2695,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) goto set_ch_out; } - if (iwl_is_associated(priv) && - (le16_to_cpu(priv->active_rxon.channel) != ch) && - priv->cfg->ops->lib->set_channel_switch) { - ret = priv->cfg->ops->lib->set_channel_switch(priv, - ch); - goto out; - } - spin_lock_irqsave(&priv->lock, flags); /* Configure HT40 channels */ @@ -2732,6 +2729,22 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) iwl_set_flags_for_band(priv, conf->channel->band); spin_unlock_irqrestore(&priv->lock, flags); + if (iwl_is_associated(priv) && + (le16_to_cpu(priv->active_rxon.channel) != ch) && + priv->cfg->ops->lib->set_channel_switch) { + iwl_set_rate(priv); + /* + * at this point, staging_rxon has the + * configuration for channel switch + */ + ret = priv->cfg->ops->lib->set_channel_switch(priv, + ch); + if (!ret) { + iwl_print_rx_config_cmd(priv); + goto out; + } + priv->switch_rxon.switch_in_progress = false; + } set_ch_out: /* The list of supported rates and rate mask can be different * for each band; since the band may have changed, reset diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 997564584c71..9a19a3d1f704 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -994,6 +994,17 @@ struct traffic_stats { }; #endif +/* + * iwl_switch_rxon: "channel switch" structure + * + * @ switch_in_progress: channel switch in progress + * @ channel: new channel + */ +struct iwl_switch_rxon { + bool switch_in_progress; + __le16 channel; +}; + struct iwl_priv { /* ieee device used by generic ieee processing code */ @@ -1087,6 +1098,8 @@ struct iwl_priv { const struct iwl_rxon_cmd active_rxon; struct iwl_rxon_cmd staging_rxon; + struct iwl_switch_rxon switch_rxon; + /* 1st responses from initialize and runtime uCode images. * 4965's initialize alive response contains some calibration data. */ struct iwl_init_alive_resp card_alive_init; -- cgit v1.2.3 From 740e7f51c226076d8f8ccb203d9ba6258a5bcec7 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:55 -0800 Subject: iwlwifi: drop non-production PCI-IDs Remove the support for all the PCI_IDs never make into production Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 98 +-------------------------------- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 --- drivers/net/wireless/iwlwifi/iwl-dev.h | 4 +- 3 files changed, 2 insertions(+), 108 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 1f769ea23636..f732f6d194a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -90,11 +90,7 @@ static void iwl6000_nic_config(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); /* no locking required for register write */ - if (priv->cfg->pa_type == IWL_PA_HYBRID) { - /* 2x2 hybrid phy type */ - iwl_write32(priv, CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB); - } else if (priv->cfg->pa_type == IWL_PA_INTERNAL) { + if (priv->cfg->pa_type == IWL_PA_INTERNAL) { /* 2x2 IPA phy type */ iwl_write32(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); @@ -279,98 +275,6 @@ static struct iwl_ops iwl6050_ops = { .led = &iwlagn_led_ops, }; - -/* - * "h": Hybrid configuration, use both internal and external Power Amplifier - */ -struct iwl_cfg iwl6000h_2agn_cfg = { - .name = "6000 Series 2x2 AGN", - .fw_name_pre = IWL6000_FW_PRE, - .ucode_api_max = IWL6000_UCODE_API_MAX, - .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .num_of_queues = IWL50_NUM_QUEUES, - .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, - .mod_params = &iwl50_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_HYBRID, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_ht = true, /* use rts/cts protection */ - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, -}; - -struct iwl_cfg iwl6000h_2abg_cfg = { - .name = "6000 Series 2x2 ABG", - .fw_name_pre = IWL6000_FW_PRE, - .ucode_api_max = IWL6000_UCODE_API_MAX, - .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G, - .ops = &iwl6000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .num_of_queues = IWL50_NUM_QUEUES, - .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, - .mod_params = &iwl50_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_HYBRID, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, -}; - -struct iwl_cfg iwl6000h_2bg_cfg = { - .name = "6000 Series 2x2 BG", - .fw_name_pre = IWL6000_FW_PRE, - .ucode_api_max = IWL6000_UCODE_API_MAX, - .ucode_api_min = IWL6000_UCODE_API_MIN, - .sku = IWL_SKU_G, - .ops = &iwl6000_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6000_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .num_of_queues = IWL50_NUM_QUEUES, - .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, - .mod_params = &iwl50_mod_params, - .valid_tx_ant = ANT_AB, - .valid_rx_ant = ANT_AB, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_HYBRID, - .max_ll_items = OTP_MAX_LL_ITEMS_6x00, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, -}; - /* * "i": Internal configuration, use internal Power Amplifier */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7bdedf61dd36..ad8a348b1c81 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3452,14 +3452,6 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, /* 6x00 Series */ - {IWL_PCI_DEVICE(0x008D, 0x1301, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x008D, 0x1321, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x008D, 0x1326, iwl6000h_2abg_cfg)}, - {IWL_PCI_DEVICE(0x008D, 0x1306, iwl6000h_2abg_cfg)}, - {IWL_PCI_DEVICE(0x008D, 0x1307, iwl6000h_2bg_cfg)}, - {IWL_PCI_DEVICE(0x008E, 0x1311, iwl6000h_2agn_cfg)}, - {IWL_PCI_DEVICE(0x008E, 0x1316, iwl6000h_2abg_cfg)}, - {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)}, {IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9a19a3d1f704..9dea8fa08c0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -927,13 +927,11 @@ enum iwl_access_mode { /** * enum iwl_pa_type - Power Amplifier type * @IWL_PA_SYSTEM: based on uCode configuration - * @IWL_PA_HYBRID: use both Internal and external PA * @IWL_PA_INTERNAL: use Internal only */ enum iwl_pa_type { IWL_PA_SYSTEM = 0, - IWL_PA_HYBRID = 1, - IWL_PA_INTERNAL = 2, + IWL_PA_INTERNAL = 1, }; /* interrupt statistics */ -- cgit v1.2.3 From 6762f07fd55ff5e588aa5f0a1b70efe8e268a2e8 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:52:56 -0800 Subject: iwlwifi: do not base station's sm_ps setting on AP Do not use AP's SM_PS setting for our own SM_PS setting. Reported-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index e0edc607e33f..d09e74815323 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2316,12 +2316,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; maxstreams += 1; - ht_conf->sm_ps = - (u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS) - >> 2); - IWL_DEBUG_MAC80211(priv, "sm_ps: 0x%x\n", - ht_conf->sm_ps); - if ((ht_cap->mcs.rx_mask[1] == 0) && (ht_cap->mcs.rx_mask[2] == 0)) ht_conf->single_chain_sufficient = true; -- cgit v1.2.3 From 84c4069232a671b3739387949d5cb588dacbd24a Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:52:57 -0800 Subject: iwlwifi: Limit size of Event Log dump If device provides bad values for Event Log parameters (due to being asleep or SRAM corruption, etc.), the size can be very, very large (e.g. 0xa5a5a5a5), which can flood system log. Sanity-check capacity and next_entry values and limit to reasonable size dump. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 15 +++++++++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 15 +++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ad8a348b1c81..9c40742727a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1702,6 +1702,9 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, } } +/* For sanity check only. Actual size is determined by uCode, typ. 512 */ +#define MAX_EVENT_LOG_SIZE (512) + void iwl_dump_nic_event_log(struct iwl_priv *priv) { u32 base; /* SRAM byte address of event log header */ @@ -1727,6 +1730,18 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); + if (capacity > MAX_EVENT_LOG_SIZE) { + IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n", + capacity, MAX_EVENT_LOG_SIZE); + capacity = MAX_EVENT_LOG_SIZE; + } + + if (next_entry > MAX_EVENT_LOG_SIZE) { + IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", + next_entry, MAX_EVENT_LOG_SIZE); + next_entry = MAX_EVENT_LOG_SIZE; + } + size = num_wraps ? capacity : next_entry; /* bail out if nothing in log */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 23b31e6dcacd..a17afe01c0c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1603,6 +1603,9 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, } } +/* For sanity check only. Actual size is determined by uCode, typ. 512 */ +#define IWL3945_MAX_EVENT_LOG_SIZE (512) + void iwl3945_dump_nic_event_log(struct iwl_priv *priv) { u32 base; /* SRAM byte address of event log header */ @@ -1624,6 +1627,18 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv) num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); + if (capacity > IWL3945_MAX_EVENT_LOG_SIZE) { + IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n", + capacity, IWL3945_MAX_EVENT_LOG_SIZE); + capacity = IWL3945_MAX_EVENT_LOG_SIZE; + } + + if (next_entry > IWL3945_MAX_EVENT_LOG_SIZE) { + IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", + next_entry, IWL3945_MAX_EVENT_LOG_SIZE); + next_entry = IWL3945_MAX_EVENT_LOG_SIZE; + } + size = num_wraps ? capacity : next_entry; /* bail out if nothing in log */ -- cgit v1.2.3 From e585447189123de627ecbfaccab9d7a3328a5dd8 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:52:58 -0800 Subject: iwlwifi: speed up event log dumps Take advantage of device's auto-increment for SRAM reads to eliminate extra write address accesses. Grab/release NIC access before/after entire read sequence, rather than for each read individually. After a quick check of dmesg logs, this seems to double Event Log dump speed, reducing from about 20 milliseconds to about 10 milliseconds for 512 entries using 3945. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 22 ++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl3945-base.c | 22 ++++++++++++++++------ 2 files changed, 32 insertions(+), 12 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 9c40742727a2..2abd1f5b5eea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1666,6 +1666,7 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ u32 ptr; /* SRAM byte address of log data */ u32 ev, time, data; /* event log data */ + unsigned long reg_flags; if (num_events == 0) return; @@ -1681,25 +1682,34 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + /* Make sure device is powered up for SRAM reads */ + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + + /* Set starting address; reads will auto-increment */ + _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + rmb(); + /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - time = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); + ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); } else { - data = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); + data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", time, data, ev); trace_iwlwifi_dev_ucode_event(priv, time, data, ev); } } + + /* Allow device to power down */ + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } /* For sanity check only. Actual size is determined by uCode, typ. 512 */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a17afe01c0c0..92ecdd9abd9f 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1570,6 +1570,7 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ u32 ptr; /* SRAM byte address of log data */ u32 ev, time, data; /* event log data */ + unsigned long reg_flags; if (num_events == 0) return; @@ -1583,24 +1584,33 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + /* Make sure device is powered up for SRAM reads */ + spin_lock_irqsave(&priv->reg_lock, reg_flags); + iwl_grab_nic_access(priv); + + /* Set starting address; reads will auto-increment */ + _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr); + rmb(); + /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); - time = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); + ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); + time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ IWL_ERR(priv, "0x%08x\t%04u\n", time, ev); trace_iwlwifi_dev_ucode_event(priv, 0, time, ev); } else { - data = iwl_read_targ_mem(priv, ptr); - ptr += sizeof(u32); + data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev); trace_iwlwifi_dev_ucode_event(priv, time, data, ev); } } + + /* Allow device to power down */ + iwl_release_nic_access(priv); + spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } /* For sanity check only. Actual size is determined by uCode, typ. 512 */ -- cgit v1.2.3 From 2a3b793d6a0ff30ad4a541230a6dba2ecb6fff1b Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:52:59 -0800 Subject: iwlwifi: Update comments for struct iwl_ssid_ie Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-commands.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index b62c90ec9e1e..2857287be4fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -2566,9 +2566,10 @@ struct iwl_scan_channel { /** * struct iwl_ssid_ie - directed scan network information element * - * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field - * in struct iwl_scan_channel; each channel may select different ssids from - * among the 4 entries. SSID IEs get transmitted in reverse order of entry. + * Up to 20 of these may appear in REPLY_SCAN_CMD (Note: Only 4 are in + * 3945 SCAN api), selected by "type" bit field in struct iwl_scan_channel; + * each channel may select different ssids from among the 20 (4) entries. + * SSID IEs get transmitted in reverse order of entry. */ struct iwl_ssid_ie { u8 id; -- cgit v1.2.3 From a7e6611034530fce62f5499f77dd4fb6cde4d130 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:53:00 -0800 Subject: iwlwifi: Add comments about MAC_ACCESS_REQ Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-io.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 0a078b082833..d0a358c9d96b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -200,6 +200,26 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv) /* this bit wakes up the NIC */ _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* + * These bits say the device is running, and should keep running for + * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), + * but they do not indicate that embedded SRAM is restored yet; + * 3945 and 4965 have volatile SRAM, and must save/restore contents + * to/from host DRAM when sleeping/waking for power-saving. + * Each direction takes approximately 1/4 millisecond; with this + * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a + * series of register accesses are expected (e.g. reading Event Log), + * to keep device from sleeping. + * + * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that + * SRAM is okay/restored. We don't check that here because this call + * is just for hardware register access; but GP1 MAC_SLEEP check is a + * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). + * + * 5000 series and later (including 1000 series) have non-volatile SRAM, + * and do not save/restore SRAM when power cycling. + */ ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | -- cgit v1.2.3 From 8756990f99ecdfe64ed32cce878e36bddc16bdcc Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:53:01 -0800 Subject: iwlagn: update write pointers in iwl_irq_tasklet() Follow-up to "update write pointers for all tx queues after wakeup"; that patch changed iwl_irq_tasklet_legacy(), but not iwl_irq_tasklet(), so newer devices were not covered. Comments from original patch: Wakeup interrupt has been updating write pointers (indexes, actually) only for tx queues 0-5. This is adequate just for 3945, but inadequate for other devices, all of which have more tx queues. Now updating all tx/command queues, so device can be aware of all new tx and host commands enqueued while device was asleep. This can potentially improve data traffic bandwidth and/or latency. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 2abd1f5b5eea..8198e14b8fad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1084,6 +1084,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) u32 inta = 0; u32 handled = 0; unsigned long flags; + u32 i; #ifdef CONFIG_IWLWIFI_DEBUG u32 inta_mask; #endif @@ -1194,12 +1195,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_WAKEUP) { IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - iwl_txq_update_write_ptr(priv, &priv->txq[0]); - iwl_txq_update_write_ptr(priv, &priv->txq[1]); - iwl_txq_update_write_ptr(priv, &priv->txq[2]); - iwl_txq_update_write_ptr(priv, &priv->txq[3]); - iwl_txq_update_write_ptr(priv, &priv->txq[4]); - iwl_txq_update_write_ptr(priv, &priv->txq[5]); + for (i = 0; i < priv->hw_params.max_txq_num; i++) + iwl_txq_update_write_ptr(priv, &priv->txq[i]); priv->isr_stats.wakeup++; -- cgit v1.2.3 From f060face819401fb1f6456d362c5bc6672bba655 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 6 Nov 2009 14:53:02 -0800 Subject: iwlwifi: Fix issue on file transfer stalled in HT mode Turn on RTS/CTS for HT to prevent uCode TX fifo underrun This is fix for http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2103 Signed-off-by: Wey-Yi Guy Tested-by: Jiajia Zheng Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 1e387b9dce1e..8f82537045bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -170,6 +170,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .shadow_ram_support = false, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, }; -- cgit v1.2.3 From 309e731a619bee28ace609b0c4c3a0029b7e5394 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 6 Nov 2009 14:53:03 -0800 Subject: iwlwifi: MAC_ACCESS_REQ cleanup Add txq_id info to "Tx queue requesting wakeup" debug message Add "Rx queue requesting wakeup" debug message Move clear of CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ to be after nearby iwl_write_prph(), since iwl_write_prph() sets it and clears it. Almost removed it entirely, but just making sure in case someone removes the iwl_write_prph()! Also remove unneeded priv->lock usage; this is now handled by priv->reg_lock within iwl_clear_bit(). Join a couple of lines that had unneeded line returns. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 12 +++++------- drivers/net/wireless/iwlwifi/iwl-rx.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-tx.c | 3 ++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 ++--- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8198e14b8fad..da0b38e866ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1934,19 +1934,17 @@ static void __iwl_down(struct iwl_priv *priv) /* device going down, Stop using ICT table */ iwl_disable_ict(priv); - spin_lock_irqsave(&priv->lock, flags); - iwl_clear_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - spin_unlock_irqrestore(&priv->lock, flags); iwl_txq_ctx_stop(priv); iwl_rxq_stop(priv); - iwl_write_prph(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - + /* Power-down device's busmaster DMA clocks */ + iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); udelay(5); + /* Make sure (redundant) we've released our request to stay awake */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + /* Stop the device, and put it in low power state */ priv->cfg->ops->lib->apm_ops.stop(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index d2dc7cceb5f2..61b3b0e6ed73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -140,6 +140,8 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO(priv, "Rx queue requesting wakeup, GP1 = 0x%x\n", + reg); iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); goto exit_unlock; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 905ceca88b95..9370e062000d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -96,7 +96,8 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO(priv, "Requesting wakeup, GP1 = 0x%x\n", reg); + IWL_DEBUG_INFO(priv, "Tx queue %d requesting wakeup, GP1 = 0x%x\n", + txq_id, reg); iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 92ecdd9abd9f..05f118529fea 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2600,9 +2600,8 @@ static void __iwl3945_down(struct iwl_priv *priv) iwl3945_hw_txq_ctx_stop(priv); iwl3945_hw_rxq_stop(priv); - iwl_write_prph(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - + /* Power-down device's busmaster DMA clocks */ + iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); udelay(5); /* Stop the device, and put it in low power state */ -- cgit v1.2.3 From c286181d5bfd8703219b954284143cfadff60b9b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 7 Nov 2009 18:54:22 +0100 Subject: b43-pio: Fix RX error path for rev>=8 devices This fixes the RX error path for rev>=8 devices. The wrong register size and definitions were used. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/pio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 3105f235303a..7d2550269ede 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -761,7 +761,11 @@ data_ready: rx_error: if (err_msg) b43dbg(q->dev->wl, "PIO RX error: %s\n", err_msg); - b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY); + if (q->rev >= 8) + b43_piorx_write32(q, B43_PIO8_RXCTL, B43_PIO8_RXCTL_DATARDY); + else + b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY); + return 1; } -- cgit v1.2.3 From 202982dbf51ece7c2b49dc8b6066ff60cb02bcce Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 21:56:08 +0000 Subject: at76c50x-usb: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: John W. Linville --- drivers/net/wireless/at76c50x-usb.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index e559dc960552..0a917e44b22c 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -121,6 +121,14 @@ static struct fwentry firmwares[] = { [BOARD_505A] = { "atmel_at76c505a-rfmd2958.bin" }, [BOARD_505AMX] = { "atmel_at76c505amx-rfmd.bin" }, }; +MODULE_FIRMWARE("atmel_at76c503-i3861.bin"); +MODULE_FIRMWARE("atmel_at76c503-i3863.bin"); +MODULE_FIRMWARE("atmel_at76c503-rfmd.bin"); +MODULE_FIRMWARE("atmel_at76c503-rfmd-acc.bin"); +MODULE_FIRMWARE("atmel_at76c505-rfmd.bin"); +MODULE_FIRMWARE("atmel_at76c505-rfmd2958.bin"); +MODULE_FIRMWARE("atmel_at76c505a-rfmd2958.bin"); +MODULE_FIRMWARE("atmel_at76c505amx-rfmd.bin"); #define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) -- cgit v1.2.3 From b98a032f6d9d4a5bc17490f67b13e5ca77c8410f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 21:58:05 +0000 Subject: atmel: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: John W. Linville --- drivers/net/wireless/atmel.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index cce188837d10..3edbbcf0f548 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -99,6 +99,22 @@ static struct { { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" }, { ATMEL_FW_TYPE_NONE, NULL, NULL } }; +MODULE_FIRMWARE("atmel_at76c502-wpa.bin"); +MODULE_FIRMWARE("atmel_at76c502.bin"); +MODULE_FIRMWARE("atmel_at76c502d-wpa.bin"); +MODULE_FIRMWARE("atmel_at76c502d.bin"); +MODULE_FIRMWARE("atmel_at76c502e-wpa.bin"); +MODULE_FIRMWARE("atmel_at76c502e.bin"); +MODULE_FIRMWARE("atmel_at76c502_3com-wpa.bin"); +MODULE_FIRMWARE("atmel_at76c502_3com.bin"); +MODULE_FIRMWARE("atmel_at76c504-wpa.bin"); +MODULE_FIRMWARE("atmel_at76c504.bin"); +MODULE_FIRMWARE("atmel_at76c504_2958-wpa.bin"); +MODULE_FIRMWARE("atmel_at76c504_2958.bin"); +MODULE_FIRMWARE("atmel_at76c504a_2958-wpa.bin"); +MODULE_FIRMWARE("atmel_at76c504a_2958.bin"); +MODULE_FIRMWARE("atmel_at76c506-wpa.bin"); +MODULE_FIRMWARE("atmel_at76c506.bin"); #define MAX_SSID_LENGTH 32 #define MGMT_JIFFIES (256 * HZ / 100) -- cgit v1.2.3 From a278ea3e423f7231934ba06a29592cddad8a6663 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 21:58:47 +0000 Subject: ipw2100: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Acked-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 240cff1e6979..a9bc8a97c4e1 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -8462,6 +8462,12 @@ static int ipw2100_get_firmware(struct ipw2100_priv *priv, return 0; } +MODULE_FIRMWARE(IPW2100_FW_NAME("-i")); +#ifdef CONFIG_IPW2100_MONITOR +MODULE_FIRMWARE(IPW2100_FW_NAME("-p")); +#endif +MODULE_FIRMWARE(IPW2100_FW_NAME("")); + static void ipw2100_release_firmware(struct ipw2100_priv *priv, struct ipw2100_fw *fw) { -- cgit v1.2.3 From 873395a9fe15e5c42004e341b7d3632e6a273f73 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 21:59:10 +0000 Subject: ipw2200: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Acked-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 61ef8904af97..39808e9378ba 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -80,6 +80,11 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("ipw2200-ibss.fw"); +#ifdef CONFIG_IPW2200_MONITOR +MODULE_FIRMWARE("ipw2200-sniffer.fw"); +#endif +MODULE_FIRMWARE("ipw2200-bss.fw"); static int cmdlog = 0; static int debug = 0; -- cgit v1.2.3 From 328aca32783cc98088151ce905977c8e899e5fc9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 21:59:38 +0000 Subject: iwmc3200wifi: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/sdio.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index cf86294f719b..a7ec7eac9137 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -399,6 +399,9 @@ static struct iwm_if_ops if_sdio_ops = { .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin", .lmac_name = "iwmc3200wifi-lmac-sdio.bin", }; +MODULE_FIRMWARE("iwmc3200wifi-umac-sdio.bin"); +MODULE_FIRMWARE("iwmc3200wifi-calib-sdio.bin"); +MODULE_FIRMWARE("iwmc3200wifi-lmac-sdio.bin"); static int iwm_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) -- cgit v1.2.3 From a974a4bbcb1ceddc9c89defd7dab4da4b2b53d77 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 22:00:03 +0000 Subject: libertas: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_cs.c | 1 + drivers/net/wireless/libertas/if_sdio.c | 6 ++++++ drivers/net/wireless/libertas/if_spi.c | 4 ++++ drivers/net/wireless/libertas/if_usb.c | 2 ++ 4 files changed, 13 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 465742f19ecb..875516db319c 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -48,6 +48,7 @@ MODULE_AUTHOR("Holger Schurig "); MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("libertas_cs_helper.fw"); diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 9716728a33cb..09fcfad742e7 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -99,6 +99,12 @@ static struct if_sdio_model if_sdio_models[] = { .firmware = "sd8688.bin", }, }; +MODULE_FIRMWARE("sd8385_helper.bin"); +MODULE_FIRMWARE("sd8385.bin"); +MODULE_FIRMWARE("sd8686_helper.bin"); +MODULE_FIRMWARE("sd8686.bin"); +MODULE_FIRMWARE("sd8688_helper.bin"); +MODULE_FIRMWARE("sd8688.bin"); struct if_sdio_packet { struct if_sdio_packet *next; diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index d6a48dd3652c..bf4bfbae6227 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -902,6 +902,10 @@ static int if_spi_calculate_fw_names(u16 card_id, chip_id_to_device_name[i].name); return 0; } +MODULE_FIRMWARE("libertas/gspi8385_hlp.bin"); +MODULE_FIRMWARE("libertas/gspi8385.bin"); +MODULE_FIRMWARE("libertas/gspi8686_hlp.bin"); +MODULE_FIRMWARE("libertas/gspi8686.bin"); static int __devinit if_spi_probe(struct spi_device *spi) { diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index f12d667ba100..65e174595d12 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -28,6 +28,8 @@ static char *lbs_fw_name = "usb8388.bin"; module_param_named(fw_name, lbs_fw_name, charp, 0644); +MODULE_FIRMWARE("usb8388.bin"); + static struct usb_device_id if_usb_table[] = { /* Enter the device signature inside */ { USB_DEVICE(0x1286, 0x2001) }, -- cgit v1.2.3 From 790e7560c09a0184afcc00ac0f8df95de7468acc Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 22:00:38 +0000 Subject: libertas_tf_usb: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: John W. Linville --- drivers/net/wireless/libertas_tf/if_usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c index 392337b37b1d..3691c307e674 100644 --- a/drivers/net/wireless/libertas_tf/if_usb.c +++ b/drivers/net/wireless/libertas_tf/if_usb.c @@ -23,6 +23,8 @@ static char *lbtf_fw_name = "lbtf_usb.bin"; module_param_named(fw_name, lbtf_fw_name, charp, 0644); +MODULE_FIRMWARE("lbtf_usb.bin"); + static struct usb_device_id if_usb_table[] = { /* Enter the device signature inside */ { USB_DEVICE(0x1286, 0x2001) }, -- cgit v1.2.3 From 7e75b942f67a13a9980c5e2b4fa1993b20426284 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 22:00:57 +0000 Subject: mwl8k: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 2ebfee4da3fa..9e64dd43a3be 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -400,6 +400,9 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv) return 0; } +MODULE_FIRMWARE("mwl8k/helper_8687.fw"); +MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); + struct mwl8k_cmd_pkt { __le16 code; __le16 length; -- cgit v1.2.3 From 6f48d0e981c026572eac643ed43ebfb883048c14 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 22:01:29 +0000 Subject: orinoco: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/fw.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c index 1257250a1e22..cfa72962052b 100644 --- a/drivers/net/wireless/orinoco/fw.c +++ b/drivers/net/wireless/orinoco/fw.c @@ -28,6 +28,12 @@ static const struct fw_info orinoco_fw[] = { { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } }; +MODULE_FIRMWARE("agere_sta_fw.bin"); +MODULE_FIRMWARE("agere_ap_fw.bin"); +MODULE_FIRMWARE("prism_sta_fw.bin"); +MODULE_FIRMWARE("prism_ap_fw.bin"); +MODULE_FIRMWARE("symbol_sp24t_prim_fw"); +MODULE_FIRMWARE("symbol_sp24t_sec_fw"); /* Structure used to access fields in FW * Make sure LE decoding macros are used -- cgit v1.2.3 From a830e6599263aa535e298f5f834f3a119050757f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 22:01:55 +0000 Subject: prism54: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: John W. Linville --- drivers/net/wireless/prism54/islpci_dev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index e26d7b3ceab5..3e6a71ce5b54 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -40,6 +40,9 @@ #define ISL3877_IMAGE_FILE "isl3877" #define ISL3886_IMAGE_FILE "isl3886" #define ISL3890_IMAGE_FILE "isl3890" +MODULE_FIRMWARE(ISL3877_IMAGE_FILE); +MODULE_FIRMWARE(ISL3886_IMAGE_FILE); +MODULE_FIRMWARE(ISL3890_IMAGE_FILE); static int prism54_bring_down(islpci_private *); static int islpci_alloc_memory(islpci_private *); -- cgit v1.2.3 From 49f146de405cfb37c51976b8a682330b8cb2972e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 22:02:15 +0000 Subject: wl12xx: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 1 + drivers/net/wireless/wl12xx/wl1271_main.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index da3bf1cebc08..d03a07e1be7c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1431,3 +1431,4 @@ MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kalle Valo "); MODULE_ALIAS("spi:wl1251"); +MODULE_FIRMWARE(WL1251_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d2149fcd3cf1..00ddcc2d37c1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1979,3 +1979,4 @@ module_exit(wl1271_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); +MODULE_FIRMWARE(WL1271_FW_NAME); -- cgit v1.2.3 From e01b0e0f90681072d29fe1ba6a29298683f42c15 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 22:02:39 +0000 Subject: zd1201: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: John W. Linville --- drivers/net/wireless/zd1201.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index bc81974a2bc7..33c8be7ec8e6 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -112,6 +112,9 @@ exit: return err; } +MODULE_FIRMWARE("zd1201-ap.fw"); +MODULE_FIRMWARE("zd1201.fw"); + static void zd1201_usbfree(struct urb *urb) { struct zd1201 *zd = urb->context; -- cgit v1.2.3 From 3e8b4d006ed04b1ddb7450faee7fa429e2a00e48 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 22:03:22 +0000 Subject: zd1211rw: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index d46f20a57b7d..ac19ecd19cfe 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -318,6 +318,13 @@ error: return r; } +MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ur"); +MODULE_FIRMWARE(FW_ZD1211_PREFIX "ur"); +MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ub"); +MODULE_FIRMWARE(FW_ZD1211_PREFIX "ub"); +MODULE_FIRMWARE(FW_ZD1211B_PREFIX "uphr"); +MODULE_FIRMWARE(FW_ZD1211_PREFIX "uphr"); + /* Read data from device address space using "firmware interface" which does * not require firmware to be loaded. */ int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) -- cgit v1.2.3 From f9ef6028b2c1272a2f12299053efef90e8721f21 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 8 Nov 2009 09:23:07 +0100 Subject: drivers/net/wireless: correct check on CCS_START_NETWORK CCS_START_NETWORK is declared in drivers/net/wireless/rayctl.h with the comment Values for cmd. status is previously compared to CCS_COMMAND_COMPLETE, which is declared in the same file with the comment Values for buffer_status. Finally, it is possible at this point that cmd is CCS_START_NETWORK, because it is compared to that value in an enclosing switch that has CCS_START_NETWORK as one of two case labels around this code. Signed-off-by: Julia Lawall Signed-off-by: John W. Linville --- drivers/net/wireless/ray_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 88cd58eb3b9f..595e4414d770 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -2074,7 +2074,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) del_timer(&local->timer); local->timer.expires = jiffies + HZ * 5; local->timer.data = (long)local; - if (status == CCS_START_NETWORK) { + if (cmd == CCS_START_NETWORK) { DEBUG(0, "ray_cs interrupt network \"%s\" start failed\n", local->sparm.b4.a_current_ess_id); -- cgit v1.2.3 From 2015d1920c6ec637b16db1e8734d9070983db21f Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 8 Nov 2009 12:30:14 +0100 Subject: rt2x00: Move interface type assignments to generic code. Make sure all drivers can benefit of the assignment of the interface type of an adapter, instead of keeping it for rt2800 only. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 2 -- drivers/net/wireless/rt2x00/rt2800usb.c | 2 -- drivers/net/wireless/rt2x00/rt2x00pci.c | 2 ++ drivers/net/wireless/rt2x00/rt2x00soc.c | 5 +++++ drivers/net/wireless/rt2x00/rt2x00usb.c | 2 ++ 5 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 3c5b875cdee8..bff870799f64 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1465,8 +1465,6 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; - rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); - rt2x00dev->priv = (void *)&rt2800pci_rt2800_ops; /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index ce2e893856c1..3168ad4437a4 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1074,8 +1074,6 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; - rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB); - rt2x00dev->priv = (void *)&rt2800usb_rt2800_ops; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index cdd5154bd4c0..ece70d72880f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -310,6 +310,8 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) rt2x00dev->irq = pci_dev->irq; rt2x00dev->name = pci_name(pci_dev); + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); + /* * Determine RT chipset by reading PCI header. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c index 539568c48953..4abcfa6bf1b2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/rt2x00/rt2x00soc.c @@ -93,6 +93,11 @@ int rt2x00soc_probe(struct platform_device *pdev, rt2x00dev->irq = platform_get_irq(pdev, 0); rt2x00dev->name = pdev->dev.driver->name; + /* + * SoC devices mimic PCI behavior. + */ + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); + rt2x00_set_chip_rt(rt2x00dev, chipset); retval = rt2x00soc_alloc_reg(rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index c9cbdaa1073f..aa6c31d612a7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -653,6 +653,8 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, rt2x00dev->ops = ops; rt2x00dev->hw = hw; + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB); + retval = rt2x00usb_alloc_reg(rt2x00dev); if (retval) goto exit_free_device; -- cgit v1.2.3 From ac9d1a7bef71afa4837769ef38edb0f7e2ef8028 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 9 Nov 2009 23:38:35 +0100 Subject: rt2x00: Fix building of rt2800lib when rt2x00 driver is built-in. When enabling rt2800usb as a built-in driver (as opposed to a as a module) the build fails. See http://marc.info/?l=linux-wireless&m=125768687711034&w=2 for details. Fix it by properly including from rt2x00usb.h Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00usb.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 9943e428bc21..1c9d6cafb057 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -26,6 +26,8 @@ #ifndef RT2X00USB_H #define RT2X00USB_H +#include + #define to_usb_device_intf(d) \ ({ \ struct usb_interface *intf = to_usb_interface(d); \ -- cgit v1.2.3 From ddd21046e7b5e112b5a4722b7e071ae9d4c96a2b Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 11 Nov 2009 13:04:42 -0800 Subject: iwlwifi: fix iwl1000 "RTS/CTS for HT" merge damage I may have botched my merge conflict resolution instructions for Dave... Signed-off-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 1e387b9dce1e..8f82537045bf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -170,6 +170,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .shadow_ram_support = false, .ht_greenfield_support = true, .led_compensation = 51, + .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, }; -- cgit v1.2.3 From 194b7c13b4c516db94db8ee004342f8935922739 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 29 Oct 2009 10:41:15 -0700 Subject: ath9k: fix listening to idle requests The way idle configuration detection was implemented as busted due to the fact that it assumed the ath9k virtual wiphy, the aphy, would be marked as inactive if it was not used but it turns out an aphy is always active if its the only wiphy present. We need to distinguish between aphy activity and idleness so we now add an idle bool for the aphy and mark it as such based on the passed IEEE80211_CONF_CHANGE_IDLE from mac80211. Previous to all_wiphys_idle would never be true when using only one device so we never really were using IEEE80211_CONF_CHANGE_IDLE -- we never turned the radio off or on upon IEEE80211_CONF_CHANGE_IDLE changes as radio changes depended on all_wiphys_idle being true either to turn the radio on or off. Since it was always false for one device this code was doing nothing. Cc: Jouni.Malinen Reported-by: Vasanthakumar Thiagarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 ++ drivers/net/wireless/ath/ath9k/main.c | 33 +++++++++++++++++++++++++------- drivers/net/wireless/ath/ath9k/virtual.c | 17 +++++++++++++--- 3 files changed, 42 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 13dd0202d6b5..da5357838dda 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -620,6 +620,7 @@ struct ath_wiphy { ATH_WIPHY_PAUSED, ATH_WIPHY_SCAN, } state; + bool idle; int chan_idx; int chan_is_ht; }; @@ -691,6 +692,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc, bool ath9k_wiphy_scanning(struct ath_softc *sc); void ath9k_wiphy_work(struct work_struct *work); bool ath9k_all_wiphys_idle(struct ath_softc *sc); +void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle); int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9fefc51aec17..bdce0ab99ded 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2688,22 +2688,37 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_conf *conf = &hw->conf; struct ath_hw *ah = sc->sc_ah; - bool all_wiphys_idle = false, disable_radio = false; + bool disable_radio; mutex_lock(&sc->mutex); - /* Leave this as the first check */ + /* + * Leave this as the first check because we need to turn on the + * radio if it was disabled before prior to processing the rest + * of the changes. Likewise we must only disable the radio towards + * the end. + */ if (changed & IEEE80211_CONF_CHANGE_IDLE) { + bool enable_radio; + bool all_wiphys_idle; + bool idle = !!(conf->flags & IEEE80211_CONF_IDLE); spin_lock_bh(&sc->wiphy_lock); all_wiphys_idle = ath9k_all_wiphys_idle(sc); + ath9k_set_wiphy_idle(aphy, idle); + + if (!idle && all_wiphys_idle) + enable_radio = true; + + /* + * After we unlock here its possible another wiphy + * can be re-renabled so to account for that we will + * only disable the radio toward the end of this routine + * if by then all wiphys are still idle. + */ spin_unlock_bh(&sc->wiphy_lock); - if (conf->flags & IEEE80211_CONF_IDLE){ - if (all_wiphys_idle) - disable_radio = true; - } - else if (all_wiphys_idle) { + if (enable_radio) { ath_radio_enable(sc); ath_print(common, ATH_DBG_CONFIG, "not-idle: enabling radio\n"); @@ -2779,6 +2794,10 @@ skip_chan_change: if (changed & IEEE80211_CONF_CHANGE_POWER) sc->config.txpowlimit = 2 * conf->power_level; + spin_lock_bh(&sc->wiphy_lock); + disable_radio = ath9k_all_wiphys_idle(sc); + spin_unlock_bh(&sc->wiphy_lock); + if (disable_radio) { ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); ath_radio_disable(sc); diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index bc7d173b6fae..e6a50f3aa472 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -668,15 +668,26 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int) bool ath9k_all_wiphys_idle(struct ath_softc *sc) { unsigned int i; - if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) { + if (!sc->pri_wiphy->idle) return false; - } for (i = 0; i < sc->num_sec_wiphy; i++) { struct ath_wiphy *aphy = sc->sec_wiphy[i]; if (!aphy) continue; - if (aphy->state != ATH_WIPHY_INACTIVE) + if (!aphy->idle) return false; } return true; } + +/* caller must hold wiphy_lock */ +void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle) +{ + struct ath_softc *sc = aphy->sc; + + aphy->idle = idle; + ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, + "Marking %s as %s\n", + wiphy_name(aphy->hw->wiphy), + idle ? "idle" : "not-idle"); +} -- cgit v1.2.3 From 1bdf6c3bece59c96aec3b8b457a9a554f6b2c433 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 28 Oct 2009 13:39:40 -0700 Subject: ath9k: update hw configuration for virtual wiphys ath9k supports its own virtual wiphys. The hardware code relies on the ieee80211_hw for the present interface but with recent changes introduced the common->hw was never updated and is required for virtual wiphys. Cc: Jouni.Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/virtual.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index e6a50f3aa472..7678c4a2ca6f 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -298,6 +298,7 @@ static void ath9k_wiphy_unpause_channel(struct ath_softc *sc) void ath9k_wiphy_chan_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, chan_work); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_wiphy *aphy = sc->next_wiphy; if (aphy == NULL) @@ -313,6 +314,10 @@ void ath9k_wiphy_chan_work(struct work_struct *work) /* XXX: remove me eventually */ ath9k_update_ichannel(sc, aphy->hw, &sc->sc_ah->channels[sc->chan_idx]); + + /* sync hw configuration for hw code */ + common->hw = aphy->hw; + ath_update_chainmask(sc, sc->chan_is_ht); if (ath_set_channel(sc, aphy->hw, &sc->sc_ah->channels[sc->chan_idx]) < 0) { -- cgit v1.2.3 From b4afffc0cfa3f35ee011d5ed4153e49f5cc3bc96 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 2 Nov 2009 11:36:08 -0800 Subject: ath9k: simpify RX by calling ath_get_virt_hw() once ath_get_virt_hw() is required on RX to determine for which virtual wiphy an skb came in for. Instead of searching for the hw twice do it only once. Cc: Jouni.Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 355dd1834e1d..c910c1047ecc 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -105,23 +105,21 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) * up the frame up to let mac80211 handle the actual error case, be it no * decryption key or real decryption error. This let us keep statistics there. */ -static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, +static int ath_rx_prepare(struct ieee80211_hw *hw, + struct sk_buff *skb, struct ath_desc *ds, struct ieee80211_rx_status *rx_status, bool *decrypt_error, struct ath_softc *sc) { struct ieee80211_hdr *hdr; u8 ratecode; __le16 fc; - struct ieee80211_hw *hw; struct ieee80211_sta *sta; struct ath_node *an; int last_rssi = ATH_RSSI_DUMMY_MARKER; - hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - hw = ath_get_virt_hw(sc, hdr); if (ds->ds_rxstat.rs_more) { /* @@ -616,7 +614,8 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) } } -static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, +static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw, + struct ath_softc *sc, struct sk_buff *skb, struct ieee80211_rx_status *rx_status) { struct ieee80211_hdr *hdr; @@ -648,7 +647,7 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, } else { /* Deliver unicast frames based on receiver address */ memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); - ieee80211_rx(ath_get_virt_hw(sc, hdr), skb); + ieee80211_rx(hw, skb); } } @@ -664,6 +663,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ieee80211_rx_status rx_status; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + /* + * The hw can techncically differ from common->hw when using ath9k + * virtual wiphy so to account for that we iterate over the active + * wiphys and find the appropriate wiphy and therefore hw. + */ + struct ieee80211_hw *hw = NULL; struct ieee80211_hdr *hdr; int hdrlen, padsize, retval; bool decrypt_error = false; @@ -743,6 +748,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) sc->rx.bufsize, DMA_FROM_DEVICE); + hdr = (struct ieee80211_hdr *) skb->data; + hw = ath_get_virt_hw(sc, hdr); + /* * If we're asked to flush receive queue, directly * chain it back at the queue without processing it. @@ -757,7 +765,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen) goto requeue; - if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc)) + if (!ath_rx_prepare(hw, skb, ds, + &rx_status, &decrypt_error, sc)) goto requeue; /* Ensure we always have an skb to requeue once we are done @@ -779,7 +788,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) skb_put(skb, ds->ds_rxstat.rs_datalen); /* see if any padding is done by the hw and remove it */ - hdr = (struct ieee80211_hdr *)skb->data; hdrlen = ieee80211_get_hdrlen_from_skb(skb); fc = hdr->frame_control; @@ -826,7 +834,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) bf->bf_mpdu = NULL; ath_print(common, ATH_DBG_FATAL, "dma_mapping_error() on RX\n"); - ath_rx_send_to_mac80211(sc, skb, &rx_status); + ath_rx_send_to_mac80211(hw, sc, skb, &rx_status); break; } bf->bf_dmacontext = bf->bf_buf_addr; @@ -847,7 +855,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) SC_OP_WAIT_FOR_PSPOLL_DATA))) ath_rx_ps(sc, skb); - ath_rx_send_to_mac80211(sc, skb, &rx_status); + ath_rx_send_to_mac80211(hw, sc, skb, &rx_status); requeue: list_move_tail(&bf->list, &sc->rx.rxbuf); -- cgit v1.2.3 From cee71d6c1471953239ea4c13306888cf2b36426e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 2 Nov 2009 14:17:51 -0800 Subject: ath9k: use the passed ieee80211_hw on ath_rx_prepare() this now uses the proper hw which should mean finding the right sta when using ath9k virtual wiphy stuff. Only advantage I see here is getting the rssi properly updated so the 'fix' itself isn't that great, but at least this is correct. Cc: Jouni.Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c910c1047ecc..c6904f0d572f 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -201,7 +201,7 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, rcu_read_lock(); /* XXX: use ieee80211_find_sta! */ - sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr2); + sta = ieee80211_find_sta_by_hw(hw, hdr->addr2); if (sta) { an = (struct ath_node *) sta->drv_priv; if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD && -- cgit v1.2.3 From 68a89116157d9d479a854db6d79a9116be79cd99 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 2 Nov 2009 14:35:42 -0800 Subject: ath9k: pass the ieee80211_hw on radio enable/disable We use the ieee80211_hw for radio enable/disable but the wrong structure hw was being used in consideration for virtual wiphys as each virtual wiphy has its own ieee80211_hw struct. Just pass the hw struct to ensure we use the right one. This should fix the hw used and passed for radio enable/disable. This includes the stoping / starting of the software TX queues so mac80211 doesn't send us data for a specific virtual wiphy. ath9k already takes care of pausing virtual wiphys and stopping the respective queues on its own, but this should handle the idle mac80211 conf calls as well. Cc: Jouni.Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 5 +++-- drivers/net/wireless/ath/ath9k/main.c | 18 +++++++++--------- drivers/net/wireless/ath/ath9k/virtual.c | 5 +++-- 3 files changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index da5357838dda..59ce7ec5b224 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -655,8 +655,9 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, void ath_update_chainmask(struct ath_softc *sc, int is_ht); int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, struct ath9k_channel *hchan); -void ath_radio_enable(struct ath_softc *sc); -void ath_radio_disable(struct ath_softc *sc); + +void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw); +void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); #ifdef CONFIG_PCI int ath_pci_init(void); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index bdce0ab99ded..11aaa7d69a1f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1200,11 +1200,11 @@ fail: ath_deinit_leds(sc); } -void ath_radio_enable(struct ath_softc *sc) +void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_channel *channel = sc->hw->conf.channel; + struct ieee80211_channel *channel = hw->conf.channel; int r; ath9k_ps_wakeup(sc); @@ -1241,18 +1241,18 @@ void ath_radio_enable(struct ath_softc *sc) AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(ah, ah->led_pin, 0); - ieee80211_wake_queues(sc->hw); + ieee80211_wake_queues(hw); ath9k_ps_restore(sc); } -void ath_radio_disable(struct ath_softc *sc) +void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; - struct ieee80211_channel *channel = sc->hw->conf.channel; + struct ieee80211_channel *channel = hw->conf.channel; int r; ath9k_ps_wakeup(sc); - ieee80211_stop_queues(sc->hw); + ieee80211_stop_queues(hw); /* Disable LED */ ath9k_hw_set_gpio(ah, ah->led_pin, 1); @@ -1266,7 +1266,7 @@ void ath_radio_disable(struct ath_softc *sc) ath_flushrecv(sc); /* flush recv queue */ if (!ah->curchan) - ah->curchan = ath_get_curchannel(sc, sc->hw); + ah->curchan = ath_get_curchannel(sc, hw); spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, ah->curchan, false); @@ -2719,7 +2719,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) spin_unlock_bh(&sc->wiphy_lock); if (enable_radio) { - ath_radio_enable(sc); + ath_radio_enable(sc, hw); ath_print(common, ATH_DBG_CONFIG, "not-idle: enabling radio\n"); } @@ -2800,7 +2800,7 @@ skip_chan_change: if (disable_radio) { ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n"); - ath_radio_disable(sc); + ath_radio_disable(sc, hw); } mutex_unlock(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 7678c4a2ca6f..69a871ba051f 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -526,8 +526,9 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy) * frame being completed) */ spin_unlock_bh(&sc->wiphy_lock); - ath_radio_disable(sc); - ath_radio_enable(sc); + ath_radio_disable(sc, aphy->hw); + ath_radio_enable(sc, aphy->hw); + /* Only the primary wiphy hw is used for queuing work */ ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work); return -EBUSY; /* previous select still in progress */ -- cgit v1.2.3 From 76d5a9e83b6e72ebe651c08e6dc247a58469ddda Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 2 Nov 2009 16:08:34 -0800 Subject: ath9k: use correct hw for tx aggregation TX completion When ath9k virtual wiphys are used the sc->hw will not always represent the active hw, instead we need to get it from the skb->cb private driver area. This ensures the right hw is used to find a sta for the TX'd skb. Cc: Jouni.Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 8e052f406c35..6d7f0bcc6dd7 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -267,7 +267,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_node *an = NULL; struct sk_buff *skb; struct ieee80211_sta *sta; + struct ieee80211_hw *hw; struct ieee80211_hdr *hdr; + struct ieee80211_tx_info *tx_info; + struct ath_tx_info_priv *tx_info_priv; struct ath_atx_tid *tid = NULL; struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; struct ath_desc *ds = bf_last->bf_desc; @@ -280,10 +283,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; + tx_info = IEEE80211_SKB_CB(skb); + tx_info_priv = (struct ath_tx_info_priv *) tx_info->rate_driver_data[0]; + hw = tx_info_priv->aphy->hw; + rcu_read_lock(); /* XXX: use ieee80211_find_sta! */ - sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr1); + sta = ieee80211_find_sta_by_hw(hw, hdr->addr1); if (!sta) { rcu_read_unlock(); return; -- cgit v1.2.3 From 5008f3727b05b5eb970ce703721aa5897a088e30 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 2 Nov 2009 16:27:33 -0800 Subject: ath9k: use the right hw on ath_tx_setup_buffer() for HT When using virtual wiphys the base sc->hw was being used, the correct hw is passed along the caller already so just use that. Cc: Jouni.Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 6d7f0bcc6dd7..fc06768e8231 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1576,7 +1576,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); - if (conf_is_ht(&sc->hw->conf) && !is_pae(skb)) + if (conf_is_ht(&hw->conf) && !is_pae(skb)) bf->bf_state.bf_type |= BUF_HT; bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); -- cgit v1.2.3 From f52de03bf9843673cadff8016a609e1628c139e2 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 2 Nov 2009 17:09:12 -0800 Subject: ath9k: handle low buffer space for virtual wiphys ath9k virtual wiphys all share the same internal buffer space for TX but they do not share the mac80211 skb queues. When ath9k detects it is running low on buffer space to TX it tells mac80211 to stop sending it skbs its way but it always does this only for the primary wiphy. This means mac80211 won't know its best to avoid sending ath9k more skbs on a separate virtual wiphy. The same issue is present for reliving the skb queue. Since ath9k does not keep track of which virtual wiphy is hammering on TX silence all wiphy's TX when we're low on buffer space. When we're free on buffer space only bother informing the virtual wiphy which is active that we have free buffers. Cc: Jouni.Malinen Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 ++ drivers/net/wireless/ath/ath9k/virtual.c | 52 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/xmit.c | 10 +++--- 3 files changed, 60 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 59ce7ec5b224..4169d2b3f71e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -695,5 +695,8 @@ void ath9k_wiphy_work(struct work_struct *work); bool ath9k_all_wiphys_idle(struct ath_softc *sc); void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle); +void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue); +void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue); + int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 69a871ba051f..0a36b572294c 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -697,3 +697,55 @@ void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle) wiphy_name(aphy->hw->wiphy), idle ? "idle" : "not-idle"); } +/* Only bother starting a queue on an active virtual wiphy */ +void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue) +{ + struct ieee80211_hw *hw = sc->pri_wiphy->hw; + unsigned int i; + + spin_lock_bh(&sc->wiphy_lock); + + /* Start the primary wiphy */ + if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) { + ieee80211_wake_queue(hw, skb_queue); + goto unlock; + } + + /* Now start the secondary wiphy queues */ + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (!aphy) + continue; + if (aphy->state != ATH_WIPHY_ACTIVE) + continue; + + hw = aphy->hw; + ieee80211_wake_queue(hw, skb_queue); + break; + } + +unlock: + spin_unlock_bh(&sc->wiphy_lock); +} + +/* Go ahead and propagate information to all virtual wiphys, it won't hurt */ +void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue) +{ + struct ieee80211_hw *hw = sc->pri_wiphy->hw; + unsigned int i; + + spin_lock_bh(&sc->wiphy_lock); + + /* Stop the primary wiphy */ + ieee80211_stop_queue(hw, skb_queue); + + /* Now stop the secondary wiphy queues */ + for (i = 0; i < sc->num_sec_wiphy; i++) { + struct ath_wiphy *aphy = sc->sec_wiphy[i]; + if (!aphy) + continue; + hw = aphy->hw; + ieee80211_stop_queue(hw, skb_queue); + } + spin_unlock_bh(&sc->wiphy_lock); +} diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index fc06768e8231..86b54ddd01cb 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -915,9 +915,10 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) { struct ath_txq *txq = NULL; + u16 skb_queue = skb_get_queue_mapping(skb); int qnum; - qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); + qnum = ath_get_hal_qnum(skb_queue, sc); txq = &sc->tx.txq[qnum]; spin_lock_bh(&txq->axq_lock); @@ -926,7 +927,7 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT, "TX queue: %d is full, depth: %d\n", qnum, txq->axq_depth); - ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); + ath_mac80211_stop_queue(sc, skb_queue); txq->stopped = 1; spin_unlock_bh(&txq->axq_lock); return NULL; @@ -1705,8 +1706,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, * on the queue */ spin_lock_bh(&txq->axq_lock); if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) { - ieee80211_stop_queue(sc->hw, - skb_get_queue_mapping(skb)); + ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb)); txq->stopped = 1; } spin_unlock_bh(&txq->axq_lock); @@ -1946,7 +1946,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) { qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc); if (qnum != -1) { - ieee80211_wake_queue(sc->hw, qnum); + ath_mac80211_start_queue(sc, qnum); txq->stopped = 0; } } -- cgit v1.2.3 From 26ab2645b478fd98aa1d10a07eb07f2235bc1f1c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 2 Nov 2009 18:49:56 -0800 Subject: ath9k: do not pass the entire descriptor to ath_rx_prepare() Its not needed, so just pass the hardware RX status. We'll be simplfying ath_rx_prepare() with code we can share between ath9k and ath9k_htc. This will help make that code easier to read and manage. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 70 ++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c6904f0d572f..fd45f775e1f6 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -106,7 +106,7 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) * decryption key or real decryption error. This let us keep statistics there. */ static int ath_rx_prepare(struct ieee80211_hw *hw, - struct sk_buff *skb, struct ath_desc *ds, + struct sk_buff *skb, struct ath_rx_status *rx_stats, struct ieee80211_rx_status *rx_status, bool *decrypt_error, struct ath_softc *sc) { @@ -121,7 +121,7 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, fc = hdr->frame_control; memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - if (ds->ds_rxstat.rs_more) { + if (rx_stats->rs_more) { /* * Frame spans multiple descriptors; this cannot happen yet * as we don't support jumbograms. If not in monitor mode, @@ -130,22 +130,22 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, */ if (sc->sc_ah->opmode != NL80211_IFTYPE_MONITOR) goto rx_next; - } else if (ds->ds_rxstat.rs_status != 0) { - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) + } else if (rx_stats->rs_status != 0) { + if (rx_stats->rs_status & ATH9K_RXERR_CRC) rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) + if (rx_stats->rs_status & ATH9K_RXERR_PHY) goto rx_next; - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) { + if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) { *decrypt_error = true; - } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) { + } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) { if (ieee80211_is_ctl(fc)) /* * Sometimes, we get invalid * MIC failures on valid control frames. * Remove these mic errors. */ - ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC; + rx_stats->rs_status &= ~ATH9K_RXERR_MIC; else rx_status->flag |= RX_FLAG_MMIC_ERROR; } @@ -155,26 +155,26 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, * we also ignore the CRC error. */ if (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR) { - if (ds->ds_rxstat.rs_status & + if (rx_stats->rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_CRC)) goto rx_next; } else { - if (ds->ds_rxstat.rs_status & + if (rx_stats->rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { goto rx_next; } } } - ratecode = ds->ds_rxstat.rs_rate; + ratecode = rx_stats->rs_rate; if (ratecode & 0x80) { /* HT rate */ rx_status->flag |= RX_FLAG_HT; - if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) + if (rx_stats->rs_flags & ATH9K_RX_2040) rx_status->flag |= RX_FLAG_40MHZ; - if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) + if (rx_stats->rs_flags & ATH9K_RX_GI) rx_status->flag |= RX_FLAG_SHORT_GI; rx_status->rate_idx = ratecode & 0x7f; } else { @@ -204,31 +204,31 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, sta = ieee80211_find_sta_by_hw(hw, hdr->addr2); if (sta) { an = (struct ath_node *) sta->drv_priv; - if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD && - !ds->ds_rxstat.rs_moreaggr) - ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi); + if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && + !rx_stats->rs_moreaggr) + ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi); last_rssi = an->last_rssi; } rcu_read_unlock(); if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi, - ATH_RSSI_EP_MULTIPLIER); - if (ds->ds_rxstat.rs_rssi < 0) - ds->ds_rxstat.rs_rssi = 0; - else if (ds->ds_rxstat.rs_rssi > 127) - ds->ds_rxstat.rs_rssi = 127; + rx_stats->rs_rssi = ATH_EP_RND(last_rssi, + ATH_RSSI_EP_MULTIPLIER); + if (rx_stats->rs_rssi < 0) + rx_stats->rs_rssi = 0; + else if (rx_stats->rs_rssi > 127) + rx_stats->rs_rssi = 127; /* Update Beacon RSSI, this is used by ANI. */ if (ieee80211_is_beacon(fc)) - sc->sc_ah->stats.avgbrssi = ds->ds_rxstat.rs_rssi; + sc->sc_ah->stats.avgbrssi = rx_stats->rs_rssi; - rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); + rx_status->mactime = ath_extend_tsf(sc, rx_stats->rs_tstamp); rx_status->band = hw->conf.channel->band; rx_status->freq = hw->conf.channel->center_freq; rx_status->noise = sc->ani.noise_floor; - rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi; - rx_status->antenna = ds->ds_rxstat.rs_antenna; + rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; + rx_status->antenna = rx_stats->rs_antenna; /* * Theory for reporting quality: @@ -252,9 +252,9 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, * */ if (conf_is_ht(&hw->conf)) - rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; + rx_status->qual = rx_stats->rs_rssi * 100 / 45; else - rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 35; + rx_status->qual = rx_stats->rs_rssi * 100 / 35; /* rssi can be more than 45 though, anything above that * should be considered at 100% */ @@ -659,6 +659,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ath_buf *bf; struct ath_desc *ds; + struct ath_rx_status *rx_stats; struct sk_buff *skb = NULL, *requeue_skb; struct ieee80211_rx_status rx_status; struct ath_hw *ah = sc->sc_ah; @@ -750,6 +751,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) hdr = (struct ieee80211_hdr *) skb->data; hw = ath_get_virt_hw(sc, hdr); + rx_stats = &ds->ds_rxstat; /* * If we're asked to flush receive queue, directly @@ -758,14 +760,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (flush) goto requeue; - if (!ds->ds_rxstat.rs_datalen) + if (!rx_stats->rs_datalen) goto requeue; /* The status portion of the descriptor could get corrupted. */ - if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen) + if (sc->rx.bufsize < rx_stats->rs_datalen) goto requeue; - if (!ath_rx_prepare(hw, skb, ds, + if (!ath_rx_prepare(hw, skb, rx_stats, &rx_status, &decrypt_error, sc)) goto requeue; @@ -785,7 +787,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) sc->rx.bufsize, DMA_FROM_DEVICE); - skb_put(skb, ds->ds_rxstat.rs_datalen); + skb_put(skb, rx_stats->rs_datalen); /* see if any padding is done by the hw and remove it */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -805,7 +807,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) skb_pull(skb, padsize); } - keyix = ds->ds_rxstat.rs_keyix; + keyix = rx_stats->rs_keyix; if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { rx_status.flag |= RX_FLAG_DECRYPTED; @@ -845,7 +847,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) */ if (sc->rx.defant != ds->ds_rxstat.rs_antenna) { if (++sc->rx.rxotherant >= 3) - ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna); + ath_setdefantenna(sc, rx_stats->rs_antenna); } else { sc->rx.rxotherant = 0; } -- cgit v1.2.3 From 30cbd42265546a3efa146d4eb3456165325c83a7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 3 Nov 2009 16:10:46 -0800 Subject: ath9k_hw: move ath_extend_tsf() to hw code to share as ath9k_hw_extend_tsf() This will be shared between ath9k and ath9k_htc. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 15 +++++++++++++++ drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/recv.c | 16 +--------------- 3 files changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 111ff049f75d..b25eedf67e0b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3710,6 +3710,21 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) } EXPORT_SYMBOL(ath9k_hw_set_tsfadjust); +/* + * Extend 15-bit time stamp from rx descriptor to + * a full 64-bit TSF using the current h/w TSF. +*/ +u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp) +{ + u64 tsf; + + tsf = ath9k_hw_gettsf64(ah); + if ((tsf & 0x7fff) < rstamp) + tsf -= 0x8000; + return (tsf & ~0x7fff) | rstamp; +} +EXPORT_SYMBOL(ath9k_hw_extend_tsf); + bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) { if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c7b0c4d5f75a..6d3e314c4bea 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -689,6 +689,7 @@ u64 ath9k_hw_gettsf64(struct ath_hw *ah); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); +u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp); bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); void ath9k_hw_set11nmac2040(struct ath_hw *ah); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index fd45f775e1f6..b27ea89bbc97 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -86,20 +86,6 @@ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) sc->rx.rxotherant = 0; } -/* - * Extend 15-bit time stamp from rx descriptor to - * a full 64-bit TSF using the current h/w TSF. -*/ -static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) -{ - u64 tsf; - - tsf = ath9k_hw_gettsf64(sc->sc_ah); - if ((tsf & 0x7fff) < rstamp) - tsf -= 0x8000; - return (tsf & ~0x7fff) | rstamp; -} - /* * 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 @@ -223,7 +209,7 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, if (ieee80211_is_beacon(fc)) sc->sc_ah->stats.avgbrssi = rx_stats->rs_rssi; - rx_status->mactime = ath_extend_tsf(sc, rx_stats->rs_tstamp); + rx_status->mactime = ath9k_hw_extend_tsf(sc->sc_ah, rx_stats->rs_tstamp); rx_status->band = hw->conf.channel->band; rx_status->freq = hw->conf.channel->center_freq; rx_status->noise = sc->ani.noise_floor; -- cgit v1.2.3 From 3d536acf45ba65acb15fc65bf46f8d6c7ad6c463 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 3 Nov 2009 17:07:04 -0800 Subject: ath9k: move struct ath_ani to common area This can be shared between ath9k and ath9k_htc. It will also help with sharing routine helpers on the RX path. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 12 ++++++++ drivers/net/wireless/ath/ath9k/ath9k.h | 11 ------- drivers/net/wireless/ath/ath9k/main.c | 56 +++++++++++++++++----------------- drivers/net/wireless/ath/ath9k/recv.c | 3 +- 4 files changed, 42 insertions(+), 40 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 5e19a7330d39..b3c8ee08bb7c 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -23,6 +23,16 @@ static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +struct ath_ani { + bool caldone; + int16_t noise_floor; + unsigned int longcal_timer; + unsigned int shortcal_timer; + unsigned int resetcal_timer; + unsigned int checkani_timer; + struct timer_list timer; +}; + enum ath_device_state { ATH_HW_UNAVAILABLE, ATH_HW_INITIALIZED, @@ -66,6 +76,8 @@ struct ath_common { int debug_mask; enum ath_device_state state; + struct ath_ani ani; + u16 cachelsz; u16 curaid; u8 macaddr[ETH_ALEN]; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 4169d2b3f71e..24f61fdb1c20 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -434,16 +434,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ -struct ath_ani { - bool caldone; - int16_t noise_floor; - unsigned int longcal_timer; - unsigned int shortcal_timer; - unsigned int resetcal_timer; - unsigned int checkani_timer; - struct timer_list timer; -}; - /* Defines the BT AR_BT_COEX_WGHT used */ enum ath_stomp_type { ATH_BTCOEX_NO_STOMP, @@ -601,7 +591,6 @@ struct ath_softc { int beacon_interval; - struct ath_ani ani; #ifdef CONFIG_ATH9K_DEBUG struct ath9k_debug debug; #endif diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 11aaa7d69a1f..01ac8974eb07 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -405,34 +405,34 @@ static void ath_ani_calibrate(unsigned long data) ath9k_ps_wakeup(sc); /* Long calibration runs independently of short calibration. */ - if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { + if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { longcal = true; ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); - sc->ani.longcal_timer = timestamp; + common->ani.longcal_timer = timestamp; } /* Short calibration applies only while caldone is false */ - if (!sc->ani.caldone) { - if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) { + if (!common->ani.caldone) { + if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { shortcal = true; ath_print(common, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); - sc->ani.shortcal_timer = timestamp; - sc->ani.resetcal_timer = timestamp; + common->ani.shortcal_timer = timestamp; + common->ani.resetcal_timer = timestamp; } } else { - if ((timestamp - sc->ani.resetcal_timer) >= + if ((timestamp - common->ani.resetcal_timer) >= ATH_RESTART_CALINTERVAL) { - sc->ani.caldone = ath9k_hw_reset_calvalid(ah); - if (sc->ani.caldone) - sc->ani.resetcal_timer = timestamp; + common->ani.caldone = ath9k_hw_reset_calvalid(ah); + if (common->ani.caldone) + common->ani.resetcal_timer = timestamp; } } /* Verify whether we must check ANI */ - if ((timestamp - sc->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { + if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { aniflag = true; - sc->ani.checkani_timer = timestamp; + common->ani.checkani_timer = timestamp; } /* Skip all processing if there's nothing to do. */ @@ -443,21 +443,21 @@ static void ath_ani_calibrate(unsigned long data) /* Perform calibration if necessary */ if (longcal || shortcal) { - sc->ani.caldone = + common->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan, common->rx_chainmask, longcal); if (longcal) - sc->ani.noise_floor = ath9k_hw_getchan_noise(ah, + common->ani.noise_floor = ath9k_hw_getchan_noise(ah, ah->curchan); ath_print(common, ATH_DBG_ANI, " calibrate chan %u/%x nf: %d\n", ah->curchan->channel, ah->curchan->channelFlags, - sc->ani.noise_floor); + common->ani.noise_floor); } } @@ -473,21 +473,21 @@ set_timer: cal_interval = ATH_LONG_CALINTERVAL; if (sc->sc_ah->config.enable_ani) cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); - if (!sc->ani.caldone) + if (!common->ani.caldone) cal_interval = min(cal_interval, (u32)short_cal_interval); - mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); + mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); } -static void ath_start_ani(struct ath_softc *sc) +static void ath_start_ani(struct ath_common *common) { unsigned long timestamp = jiffies_to_msecs(jiffies); - sc->ani.longcal_timer = timestamp; - sc->ani.shortcal_timer = timestamp; - sc->ani.checkani_timer = timestamp; + common->ani.longcal_timer = timestamp; + common->ani.shortcal_timer = timestamp; + common->ani.checkani_timer = timestamp; - mod_timer(&sc->ani.timer, + mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); } @@ -1023,12 +1023,12 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, /* Reset rssi stats */ sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - ath_start_ani(sc); + ath_start_ani(common); } else { ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n"); common->curaid = 0; /* Stop ANI */ - del_timer_sync(&sc->ani.timer); + del_timer_sync(&common->ani.timer); } } @@ -1761,8 +1761,8 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, /* Initializes the noise floor to a reasonable default value. * Later on this will be updated during ANI processing. */ - sc->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; - setup_timer(&sc->ani.timer, ath_ani_calibrate, (unsigned long)sc); + common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; + setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, ATH9K_CIPHER_TKIP, NULL)) { @@ -2634,7 +2634,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, if (conf->type == NL80211_IFTYPE_AP || conf->type == NL80211_IFTYPE_ADHOC || conf->type == NL80211_IFTYPE_MONITOR) - ath_start_ani(sc); + ath_start_ani(common); out: mutex_unlock(&sc->mutex); @@ -2655,7 +2655,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); /* Stop ANI */ - del_timer_sync(&sc->ani.timer); + del_timer_sync(&common->ani.timer); /* Reclaim beacon resources */ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index b27ea89bbc97..403debb4ec11 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -102,6 +102,7 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, struct ieee80211_sta *sta; struct ath_node *an; int last_rssi = ATH_RSSI_DUMMY_MARKER; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; @@ -212,7 +213,7 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, rx_status->mactime = ath9k_hw_extend_tsf(sc->sc_ah, rx_stats->rs_tstamp); rx_status->band = hw->conf.channel->band; rx_status->freq = hw->conf.channel->center_freq; - rx_status->noise = sc->ani.noise_floor; + rx_status->noise = common->ani.noise_floor; rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; rx_status->antenna = rx_stats->rs_antenna; -- cgit v1.2.3 From 712c13a86affe69dd8462631808edd5825b5e1cb Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 3 Nov 2009 15:57:16 -0800 Subject: ath9k: use the ieee80211_hw to get to an sband on ath_rx_prepare() No need to use the private driver structure to get to an sband. This will make it easier to share this code with ath9k_htc. With the sc gone we can now just pass the common structure to ath_rx_prepare(). Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 39 ++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 403debb4ec11..fa78914cbfb1 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -91,18 +91,19 @@ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) * up the frame up to let mac80211 handle the actual error case, be it no * decryption key or real decryption error. This let us keep statistics there. */ -static int ath_rx_prepare(struct ieee80211_hw *hw, +static int ath_rx_prepare(struct ath_common *common, + struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rx_status, bool *decrypt_error, - struct ath_softc *sc) + struct ieee80211_rx_status *rx_status, + bool *decrypt_error) { + struct ath_hw *ah = common->ah; struct ieee80211_hdr *hdr; u8 ratecode; __le16 fc; struct ieee80211_sta *sta; struct ath_node *an; int last_rssi = ATH_RSSI_DUMMY_MARKER; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; @@ -115,7 +116,7 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, * discard the frame. Enable this if you want to see * error frames in Monitor mode. */ - if (sc->sc_ah->opmode != NL80211_IFTYPE_MONITOR) + if (ah->opmode != NL80211_IFTYPE_MONITOR) goto rx_next; } else if (rx_stats->rs_status != 0) { if (rx_stats->rs_status & ATH9K_RXERR_CRC) @@ -141,7 +142,7 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, * decryption and MIC failures. For monitor mode, * we also ignore the CRC error. */ - if (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR) { + if (ah->opmode == NL80211_IFTYPE_MONITOR) { if (rx_stats->rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_CRC)) @@ -165,20 +166,20 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, rx_status->flag |= RX_FLAG_SHORT_GI; rx_status->rate_idx = ratecode & 0x7f; } else { - int i = 0, cur_band, n_rates; + struct ieee80211_supported_band *sband; + unsigned int i = 0; + enum ieee80211_band band; - cur_band = hw->conf.channel->band; - n_rates = sc->sbands[cur_band].n_bitrates; + band = hw->conf.channel->band; + sband = hw->wiphy->bands[band]; - for (i = 0; i < n_rates; i++) { - if (sc->sbands[cur_band].bitrates[i].hw_value == - ratecode) { + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { rx_status->rate_idx = i; break; } - - if (sc->sbands[cur_band].bitrates[i].hw_value_short == - ratecode) { + if (sband->bitrates[i].hw_value_short == + rx_stats->rs_rate) { rx_status->rate_idx = i; rx_status->flag |= RX_FLAG_SHORTPRE; break; @@ -208,9 +209,9 @@ static int ath_rx_prepare(struct ieee80211_hw *hw, /* Update Beacon RSSI, this is used by ANI. */ if (ieee80211_is_beacon(fc)) - sc->sc_ah->stats.avgbrssi = rx_stats->rs_rssi; + ah->stats.avgbrssi = rx_stats->rs_rssi; - rx_status->mactime = ath9k_hw_extend_tsf(sc->sc_ah, rx_stats->rs_tstamp); + rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp); rx_status->band = hw->conf.channel->band; rx_status->freq = hw->conf.channel->center_freq; rx_status->noise = common->ani.noise_floor; @@ -754,8 +755,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (sc->rx.bufsize < rx_stats->rs_datalen) goto requeue; - if (!ath_rx_prepare(hw, skb, rx_stats, - &rx_status, &decrypt_error, sc)) + if (!ath_rx_prepare(common, hw, skb, rx_stats, + &rx_status, &decrypt_error)) goto requeue; /* Ensure we always have an skb to requeue once we are done -- cgit v1.2.3 From 207e96854e39380fce8b589bbbdaf6e9a83b9151 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 3 Nov 2009 17:39:00 -0800 Subject: ath9k: move RX check code into helper ath9k_rx_accept() This does sanity checking on the skb and RX status descriptor prior to processing. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 63 +++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index fa78914cbfb1..6e00eafc9b24 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -86,28 +86,19 @@ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) sc->rx.rxotherant = 0; } -/* - * 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 - * decryption key or real decryption error. This let us keep statistics there. - */ -static int ath_rx_prepare(struct ath_common *common, - struct ieee80211_hw *hw, - struct sk_buff *skb, struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rx_status, - bool *decrypt_error) +/* Assumes you've already done the endian to CPU conversion */ +static bool ath9k_rx_accept(struct ath_common *common, + struct sk_buff *skb, + struct ieee80211_rx_status *rxs, + struct ath_rx_status *rx_stats, + bool *decrypt_error) { struct ath_hw *ah = common->ah; struct ieee80211_hdr *hdr; - u8 ratecode; __le16 fc; - struct ieee80211_sta *sta; - struct ath_node *an; - int last_rssi = ATH_RSSI_DUMMY_MARKER; - hdr = (struct ieee80211_hdr *)skb->data; + hdr = (struct ieee80211_hdr *) skb->data; fc = hdr->frame_control; - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); if (rx_stats->rs_more) { /* @@ -117,12 +108,12 @@ static int ath_rx_prepare(struct ath_common *common, * error frames in Monitor mode. */ if (ah->opmode != NL80211_IFTYPE_MONITOR) - goto rx_next; + return false; } else if (rx_stats->rs_status != 0) { if (rx_stats->rs_status & ATH9K_RXERR_CRC) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + rxs->flag |= RX_FLAG_FAILED_FCS_CRC; if (rx_stats->rs_status & ATH9K_RXERR_PHY) - goto rx_next; + return false; if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) { *decrypt_error = true; @@ -135,7 +126,7 @@ static int ath_rx_prepare(struct ath_common *common, */ rx_stats->rs_status &= ~ATH9K_RXERR_MIC; else - rx_status->flag |= RX_FLAG_MMIC_ERROR; + rxs->flag |= RX_FLAG_MMIC_ERROR; } /* * Reject error frames with the exception of @@ -146,14 +137,42 @@ static int ath_rx_prepare(struct ath_common *common, if (rx_stats->rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_CRC)) - goto rx_next; + return false; } else { if (rx_stats->rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { - goto rx_next; + return false; } } } + return true; +} + +/* + * 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 + * decryption key or real decryption error. This let us keep statistics there. + */ +static int ath_rx_prepare(struct ath_common *common, + struct ieee80211_hw *hw, + struct sk_buff *skb, struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rx_status, + bool *decrypt_error) +{ + struct ath_hw *ah = common->ah; + struct ieee80211_hdr *hdr; + u8 ratecode; + __le16 fc; + struct ieee80211_sta *sta; + struct ath_node *an; + int last_rssi = ATH_RSSI_DUMMY_MARKER; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + + if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) + goto rx_next; ratecode = rx_stats->rs_rate; -- cgit v1.2.3 From 14077f5b7a28bdcd166faed2c0b36fad9f3eadda Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 3 Nov 2009 17:52:33 -0800 Subject: ath9k: remove temp variable ratecode from ath_rx_prepare() Its just a distraction when reading the code, instead use the rx_stats->rs_rate directly. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6e00eafc9b24..9e6dded399fd 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -161,7 +161,6 @@ static int ath_rx_prepare(struct ath_common *common, { struct ath_hw *ah = common->ah; struct ieee80211_hdr *hdr; - u8 ratecode; __le16 fc; struct ieee80211_sta *sta; struct ath_node *an; @@ -174,16 +173,14 @@ static int ath_rx_prepare(struct ath_common *common, if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) goto rx_next; - ratecode = rx_stats->rs_rate; - - if (ratecode & 0x80) { + if (rx_stats->rs_rate & 0x80) { /* HT rate */ rx_status->flag |= RX_FLAG_HT; if (rx_stats->rs_flags & ATH9K_RX_2040) rx_status->flag |= RX_FLAG_40MHZ; if (rx_stats->rs_flags & ATH9K_RX_GI) rx_status->flag |= RX_FLAG_SHORT_GI; - rx_status->rate_idx = ratecode & 0x7f; + rx_status->rate_idx = rx_stats->rs_rate & 0x7f; } else { struct ieee80211_supported_band *sband; unsigned int i = 0; -- cgit v1.2.3 From 9878841e1360266fa4522fbdc2448fcdce95e0dd Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 3 Nov 2009 18:10:30 -0800 Subject: ath9k: move rate descriptor reading into a helper ath9k_process_rate() now does all the rx status processing to read the rate the hardware passed and translate it to whatever mac80211 wants. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 72 +++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 9e6dded399fd..9eae9467c275 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -148,6 +148,47 @@ static bool ath9k_rx_accept(struct ath_common *common, return true; } +static u8 ath9k_process_rate(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs, + struct sk_buff *skb) +{ + struct ieee80211_supported_band *sband; + enum ieee80211_band band; + unsigned int i = 0; + + band = hw->conf.channel->band; + sband = hw->wiphy->bands[band]; + + if (rx_stats->rs_rate & 0x80) { + /* HT rate */ + rxs->flag |= RX_FLAG_HT; + if (rx_stats->rs_flags & ATH9K_RX_2040) + rxs->flag |= RX_FLAG_40MHZ; + if (rx_stats->rs_flags & ATH9K_RX_GI) + rxs->flag |= RX_FLAG_SHORT_GI; + return rx_stats->rs_rate & 0x7f; + } + + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].hw_value == rx_stats->rs_rate) + return i; + if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { + rxs->flag |= RX_FLAG_SHORTPRE; + return i; + } + } + + /* No valid hardware bitrate found -- we should not get here */ + ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected " + "0x%02x using 1 Mbit\n", rx_stats->rs_rate); + if ((common->debug_mask & ATH_DBG_XMIT)) + print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len); + + return 0; +} + /* * 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 @@ -173,35 +214,6 @@ static int ath_rx_prepare(struct ath_common *common, if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) goto rx_next; - if (rx_stats->rs_rate & 0x80) { - /* HT rate */ - rx_status->flag |= RX_FLAG_HT; - if (rx_stats->rs_flags & ATH9K_RX_2040) - rx_status->flag |= RX_FLAG_40MHZ; - if (rx_stats->rs_flags & ATH9K_RX_GI) - rx_status->flag |= RX_FLAG_SHORT_GI; - rx_status->rate_idx = rx_stats->rs_rate & 0x7f; - } else { - struct ieee80211_supported_band *sband; - unsigned int i = 0; - enum ieee80211_band band; - - band = hw->conf.channel->band; - sband = hw->wiphy->bands[band]; - - for (i = 0; i < sband->n_bitrates; i++) { - if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { - rx_status->rate_idx = i; - break; - } - if (sband->bitrates[i].hw_value_short == - rx_stats->rs_rate) { - rx_status->rate_idx = i; - rx_status->flag |= RX_FLAG_SHORTPRE; - break; - } - } - } rcu_read_lock(); /* XXX: use ieee80211_find_sta! */ @@ -227,6 +239,8 @@ static int ath_rx_prepare(struct ath_common *common, if (ieee80211_is_beacon(fc)) ah->stats.avgbrssi = rx_stats->rs_rssi; + rx_status->rate_idx = ath9k_process_rate(common, hw, + rx_stats, rx_status, skb); rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp); rx_status->band = hw->conf.channel->band; rx_status->freq = hw->conf.channel->center_freq; -- cgit v1.2.3 From 21b22738068366d7740b4b7cf55ce270f479543a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 3 Nov 2009 18:20:26 -0800 Subject: ath9k: move qual processing into a helper This moves the qual computing into a small helper, ath9k_compute_qual() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 74 ++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 32 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 9eae9467c275..d357b9adcf49 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -189,6 +189,47 @@ static u8 ath9k_process_rate(struct ath_common *common, return 0; } +/* + * Theory for reporting quality: + * + * At a hardware RSSI of 45 you will be able to use MCS 7 reliably. + * At a hardware RSSI of 45 you will be able to use MCS 15 reliably. + * At a hardware RSSI of 35 you should be able use 54 Mbps reliably. + * + * MCS 7 is the highets MCS index usable by a 1-stream device. + * MCS 15 is the highest MCS index usable by a 2-stream device. + * + * All ath9k devices are either 1-stream or 2-stream. + * + * How many bars you see is derived from the qual reporting. + * + * A more elaborate scheme can be used here but it requires tables + * of SNR/throughput for each possible mode used. For the MCS table + * you can refer to the wireless wiki: + * + * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n + * + */ +static int ath9k_compute_qual(struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats) +{ + int qual; + + if (conf_is_ht(&hw->conf)) + qual = rx_stats->rs_rssi * 100 / 45; + else + qual = rx_stats->rs_rssi * 100 / 35; + + /* + * rssi can be more than 45 though, anything above that + * should be considered at 100% + */ + if (qual > 100) + qual = 100; + + return qual; +} + /* * 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 @@ -247,38 +288,7 @@ static int ath_rx_prepare(struct ath_common *common, rx_status->noise = common->ani.noise_floor; rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; rx_status->antenna = rx_stats->rs_antenna; - - /* - * Theory for reporting quality: - * - * At a hardware RSSI of 45 you will be able to use MCS 7 reliably. - * At a hardware RSSI of 45 you will be able to use MCS 15 reliably. - * At a hardware RSSI of 35 you should be able use 54 Mbps reliably. - * - * MCS 7 is the highets MCS index usable by a 1-stream device. - * MCS 15 is the highest MCS index usable by a 2-stream device. - * - * All ath9k devices are either 1-stream or 2-stream. - * - * How many bars you see is derived from the qual reporting. - * - * A more elaborate scheme can be used here but it requires tables - * of SNR/throughput for each possible mode used. For the MCS table - * you can refer to the wireless wiki: - * - * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n - * - */ - if (conf_is_ht(&hw->conf)) - rx_status->qual = rx_stats->rs_rssi * 100 / 45; - else - rx_status->qual = rx_stats->rs_rssi * 100 / 35; - - /* rssi can be more than 45 though, anything above that - * should be considered at 100% */ - if (rx_status->qual > 100) - rx_status->qual = 100; - + rx_status->qual = ath9k_compute_qual(hw, rx_stats); rx_status->flag |= RX_FLAG_TSFT; return 1; -- cgit v1.2.3 From dbfc22df1afbeb91d528e2f84d6603ac9ce98bc2 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 3 Nov 2009 18:35:05 -0800 Subject: ath9k: move rssi processing into a helper This moves all the RX processing of RSSI into a helper, ath_rx_prepare(). ath_rx_prepare() should now be really easy to read and follow. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 44 +++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index d357b9adcf49..4c4c22f54e99 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -230,31 +230,20 @@ static int ath9k_compute_qual(struct ieee80211_hw *hw, return qual; } -/* - * 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 - * decryption key or real decryption error. This let us keep statistics there. - */ -static int ath_rx_prepare(struct ath_common *common, - struct ieee80211_hw *hw, - struct sk_buff *skb, struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rx_status, - bool *decrypt_error) +static void ath9k_process_rssi(struct ath_common *common, + struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ath_rx_status *rx_stats) { struct ath_hw *ah = common->ah; - struct ieee80211_hdr *hdr; - __le16 fc; struct ieee80211_sta *sta; + struct ieee80211_hdr *hdr; struct ath_node *an; int last_rssi = ATH_RSSI_DUMMY_MARKER; + __le16 fc; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - - if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) - goto rx_next; - rcu_read_lock(); /* XXX: use ieee80211_find_sta! */ @@ -279,6 +268,27 @@ static int ath_rx_prepare(struct ath_common *common, /* Update Beacon RSSI, this is used by ANI. */ if (ieee80211_is_beacon(fc)) ah->stats.avgbrssi = rx_stats->rs_rssi; +} + +/* + * 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 + * decryption key or real decryption error. This let us keep statistics there. + */ +static int ath_rx_prepare(struct ath_common *common, + struct ieee80211_hw *hw, + struct sk_buff *skb, struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rx_status, + bool *decrypt_error) +{ + struct ath_hw *ah = common->ah; + + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + + if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) + goto rx_next; + + ath9k_process_rssi(common, hw, skb, rx_stats); rx_status->rate_idx = ath9k_process_rate(common, hw, rx_stats, rx_status, skb); -- cgit v1.2.3 From 5ca42627f3ddc0e4fc3e62d879cc35ab5beaaa8b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 4 Nov 2009 08:20:42 -0800 Subject: ath9k: avoid the copy skb->cb on every RX'd skb The skb->cb (control buffer, 48 bytes) is available to the skb upon skb allocation. You can fill it up imediately after skb allocation. ath9k was copying onto the skb->cb the data from the processed skb for mac80211 from a stack struct ieee80211_rx_status structure. This is unnecessary, instead use the skb->cb for the rx status immediately after the skb becomes available and DMA synched. Additionally, avoid the copy of the skb->cb also for virtual wiphys as skb_copy() will copy over the skb->cb for us as well. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 38 +++++++++++++++-------------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 4c4c22f54e99..079361423efc 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -283,8 +283,6 @@ static int ath_rx_prepare(struct ath_common *common, { struct ath_hw *ah = common->ah; - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) goto rx_next; @@ -654,7 +652,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw, struct ath_softc *sc, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) + struct ieee80211_rx_status *rxs) { struct ieee80211_hdr *hdr; @@ -674,19 +672,14 @@ static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw, if (aphy == NULL) continue; nskb = skb_copy(skb, GFP_ATOMIC); - if (nskb) { - memcpy(IEEE80211_SKB_RXCB(nskb), rx_status, - sizeof(*rx_status)); - ieee80211_rx(aphy->hw, nskb); - } + if (!nskb) + continue; + ieee80211_rx(aphy->hw, nskb); } - memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); ieee80211_rx(sc->hw, skb); - } else { + } else /* Deliver unicast frames based on receiver address */ - memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status)); ieee80211_rx(hw, skb); - } } int ath_rx_tasklet(struct ath_softc *sc, int flush) @@ -699,7 +692,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ath_desc *ds; struct ath_rx_status *rx_stats; struct sk_buff *skb = NULL, *requeue_skb; - struct ieee80211_rx_status rx_status; + struct ieee80211_rx_status *rxs; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); /* @@ -788,6 +781,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) DMA_FROM_DEVICE); hdr = (struct ieee80211_hdr *) skb->data; + rxs = IEEE80211_SKB_RXCB(skb); + hw = ath_get_virt_hw(sc, hdr); rx_stats = &ds->ds_rxstat; @@ -806,7 +801,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) goto requeue; if (!ath_rx_prepare(common, hw, skb, rx_stats, - &rx_status, &decrypt_error)) + rxs, &decrypt_error)) goto requeue; /* Ensure we always have an skb to requeue once we are done @@ -848,20 +843,19 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) keyix = rx_stats->rs_keyix; if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { - rx_status.flag |= RX_FLAG_DECRYPTED; + rxs->flag |= RX_FLAG_DECRYPTED; } else if (ieee80211_has_protected(fc) && !decrypt_error && skb->len >= hdrlen + 4) { keyix = skb->data[hdrlen + 3] >> 6; if (test_bit(keyix, sc->keymap)) - rx_status.flag |= RX_FLAG_DECRYPTED; + rxs->flag |= RX_FLAG_DECRYPTED; } if (ah->sw_mgmt_crypto && - (rx_status.flag & RX_FLAG_DECRYPTED) && - ieee80211_is_mgmt(fc)) { + (rxs->flag & RX_FLAG_DECRYPTED) && + ieee80211_is_mgmt(fc)) /* Use software decrypt for management frames. */ - rx_status.flag &= ~RX_FLAG_DECRYPTED; - } + rxs->flag &= ~RX_FLAG_DECRYPTED; /* We will now give hardware our shiny new allocated skb */ bf->bf_mpdu = requeue_skb; @@ -874,7 +868,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) bf->bf_mpdu = NULL; ath_print(common, ATH_DBG_FATAL, "dma_mapping_error() on RX\n"); - ath_rx_send_to_mac80211(hw, sc, skb, &rx_status); + ath_rx_send_to_mac80211(hw, sc, skb, rxs); break; } bf->bf_dmacontext = bf->bf_buf_addr; @@ -895,7 +889,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) SC_OP_WAIT_FOR_PSPOLL_DATA))) ath_rx_ps(sc, skb); - ath_rx_send_to_mac80211(hw, sc, skb, &rx_status); + ath_rx_send_to_mac80211(hw, sc, skb, rxs); requeue: list_move_tail(&bf->list, &sc->rx.rxbuf); -- cgit v1.2.3 From 0a45da765e4bf5e8a7705266fa36e0f44787b0a1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 4 Nov 2009 08:58:45 -0800 Subject: ath9k: move the rx_stats->rs_datalen check to ath9k_rx_accept() Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 079361423efc..4420a5800bd6 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -100,6 +100,9 @@ static bool ath9k_rx_accept(struct ath_common *common, hdr = (struct ieee80211_hdr *) skb->data; fc = hdr->frame_control; + if (!rx_stats->rs_datalen) + return false; + if (rx_stats->rs_more) { /* * Frame spans multiple descriptors; this cannot happen yet @@ -793,9 +796,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (flush) goto requeue; - if (!rx_stats->rs_datalen) - goto requeue; - /* The status portion of the descriptor could get corrupted. */ if (sc->rx.bufsize < rx_stats->rs_datalen) goto requeue; -- cgit v1.2.3 From cc861f7468724e66567baf087b4e413e91b18150 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 4 Nov 2009 09:11:34 -0800 Subject: ath: move the rx bufsize to common to share with ath5k/ath9k This will also be used by ath9k_htc. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 2 ++ drivers/net/wireless/ath/ath5k/base.c | 22 +++++++++++++-------- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/recv.c | 35 +++++++++++++++++++--------------- 4 files changed, 36 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index b3c8ee08bb7c..4af13628bafe 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -87,6 +87,8 @@ struct ath_common { u8 tx_chainmask; u8 rx_chainmask; + u32 rx_bufsize; + struct ath_regulatory regulatory; const struct ath_ops *ops; const struct ath_bus_ops *bus_ops; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index cb3dc892d697..f1a7c77c0f8d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -323,10 +323,13 @@ static inline void ath5k_txbuf_free(struct ath5k_softc *sc, static inline void ath5k_rxbuf_free(struct ath5k_softc *sc, struct ath5k_buf *bf) { + struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); + BUG_ON(!bf); if (!bf->skb) return; - pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, + pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(bf->skb); bf->skb = NULL; @@ -1181,17 +1184,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(common, - sc->rxbufsize + common->cachelsz - 1, + common->rx_bufsize + common->cachelsz - 1, GFP_ATOMIC); if (!skb) { ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", - sc->rxbufsize + common->cachelsz - 1); + common->rx_bufsize + common->cachelsz - 1); return NULL; } *skb_addr = pci_map_single(sc->pdev, - skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); + skb->data, common->rx_bufsize, + 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); @@ -1631,10 +1635,10 @@ ath5k_rx_start(struct ath5k_softc *sc) struct ath5k_buf *bf; int ret; - sc->rxbufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz); + common->rx_bufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz); - ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", - common->cachelsz, sc->rxbufsize); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n", + common->cachelsz, common->rx_bufsize); spin_lock_bh(&sc->rxbuflock); sc->rxlink = NULL; @@ -1769,6 +1773,8 @@ ath5k_tasklet_rx(unsigned long data) struct sk_buff *skb, *next_skb; dma_addr_t next_skb_addr; struct ath5k_softc *sc = (void *)data; + struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); struct ath5k_buf *bf; struct ath5k_desc *ds; int ret; @@ -1846,7 +1852,7 @@ accept: if (!next_skb) goto next; - pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, + pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize, PCI_DMA_FROMDEVICE); skb_put(skb, rs.rs_datalen); diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 24f61fdb1c20..377b0eac5e4c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -323,7 +323,6 @@ struct ath_rx { u8 defant; u8 rxotherant; u32 *rxlink; - int bufsize; unsigned int rxfilter; spinlock_t rxflushlock; spinlock_t rxbuflock; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 4420a5800bd6..48ff77255d2f 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -48,6 +48,7 @@ static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc, static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_desc *ds; struct sk_buff *skb; @@ -62,11 +63,13 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) BUG_ON(skb == NULL); ds->ds_vdata = skb->data; - /* setup rx descriptors. The rx.bufsize here tells the harware + /* + * setup rx descriptors. The rx_bufsize here tells the hardware * how much data it can DMA to us and that we are prepared - * to process */ + * to process + */ ath9k_hw_setuprxdesc(ah, ds, - sc->rx.bufsize, + common->rx_bufsize, 0); if (sc->rx.rxlink == NULL) @@ -344,11 +347,11 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) sc->sc_flags &= ~SC_OP_RXFLUSH; spin_lock_init(&sc->rx.rxbuflock); - sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, - min(common->cachelsz, (u16)64)); + common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN, + min(common->cachelsz, (u16)64)); ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", - common->cachelsz, sc->rx.bufsize); + common->cachelsz, common->rx_bufsize); /* Initialize rx descriptors */ @@ -361,7 +364,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) } list_for_each_entry(bf, &sc->rx.rxbuf, list) { - skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_KERNEL); + skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL); if (skb == NULL) { error = -ENOMEM; goto err; @@ -369,7 +372,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) bf->bf_mpdu = skb; bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, - sc->rx.bufsize, + common->rx_bufsize, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { @@ -393,6 +396,8 @@ err: void ath_rx_cleanup(struct ath_softc *sc) { + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct sk_buff *skb; struct ath_buf *bf; @@ -400,7 +405,7 @@ void ath_rx_cleanup(struct ath_softc *sc) skb = bf->bf_mpdu; if (skb) { dma_unmap_single(sc->dev, bf->bf_buf_addr, - sc->rx.bufsize, DMA_FROM_DEVICE); + common->rx_bufsize, DMA_FROM_DEVICE); dev_kfree_skb(skb); } } @@ -780,7 +785,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * 2. requeueing the same buffer to h/w */ dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr, - sc->rx.bufsize, + common->rx_bufsize, DMA_FROM_DEVICE); hdr = (struct ieee80211_hdr *) skb->data; @@ -797,7 +802,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) goto requeue; /* The status portion of the descriptor could get corrupted. */ - if (sc->rx.bufsize < rx_stats->rs_datalen) + if (common->rx_bufsize < rx_stats->rs_datalen) goto requeue; if (!ath_rx_prepare(common, hw, skb, rx_stats, @@ -806,7 +811,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(common, sc->rx.bufsize, GFP_ATOMIC); + requeue_skb = ath_rxbuf_alloc(common, common->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 @@ -817,7 +822,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) /* Unmap the frame */ dma_unmap_single(sc->dev, bf->bf_buf_addr, - sc->rx.bufsize, + common->rx_bufsize, DMA_FROM_DEVICE); skb_put(skb, rx_stats->rs_datalen); @@ -860,8 +865,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) /* We will now give hardware our shiny new allocated skb */ bf->bf_mpdu = requeue_skb; bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, - sc->rx.bufsize, - DMA_FROM_DEVICE); + common->rx_bufsize, + DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(requeue_skb); -- cgit v1.2.3 From dd849782a7388e091e356373a744f8b7ae97188a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 4 Nov 2009 09:44:50 -0800 Subject: ath5k: remove double cache alignment, ath_rxbuf_alloc() already does it ath5k is using the (csz - 1) twice as ath_rxbuf_alloc() already allocates and moves skb->data accordingly. Remove the extra (csz -1). Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index f1a7c77c0f8d..4cefd9e85dd4 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1184,12 +1184,12 @@ 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(common, - common->rx_bufsize + common->cachelsz - 1, + common->rx_bufsize, GFP_ATOMIC); if (!skb) { ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", - common->rx_bufsize + common->cachelsz - 1); + common->rx_bufsize); return NULL; } -- cgit v1.2.3 From 2c74aa4d73dbed2e879e7eb5ee9de95d40e5298d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 4 Nov 2009 15:11:05 -0800 Subject: ath9k: move the max rx buffer size check to ath9k_rx_accept() While at it flip the order, seems easier to read and also add some better description as to why we do this check. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 48ff77255d2f..16ed9292c805 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -105,6 +105,13 @@ static bool ath9k_rx_accept(struct ath_common *common, if (!rx_stats->rs_datalen) return false; + /* + * rs_status follows rs_datalen so if rs_datalen is too large + * we can take a hint that hardware corrupted it, so ignore + * those frames. + */ + if (rx_stats->rs_datalen > common->rx_bufsize) + return false; if (rx_stats->rs_more) { /* @@ -801,10 +808,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (flush) goto requeue; - /* The status portion of the descriptor could get corrupted. */ - if (common->rx_bufsize < rx_stats->rs_datalen) - goto requeue; - if (!ath_rx_prepare(common, hw, skb, rx_stats, rxs, &decrypt_error)) goto requeue; -- cgit v1.2.3 From 1e875e9f16e3138d0e23cbf806a6d9520b622db2 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 4 Nov 2009 16:34:33 -0800 Subject: ath9k: rename ath_rx_prepare() to ath9k_rx_skb_preprocess() And change the return value to something more obvious. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 16ed9292c805..c4a8663af3ff 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -288,16 +288,17 @@ static void ath9k_process_rssi(struct ath_common *common, * up the frame up to let mac80211 handle the actual error case, be it no * decryption key or real decryption error. This let us keep statistics there. */ -static int ath_rx_prepare(struct ath_common *common, - struct ieee80211_hw *hw, - struct sk_buff *skb, struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rx_status, - bool *decrypt_error) +static int ath9k_rx_skb_preprocess(struct ath_common *common, + struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rx_status, + bool *decrypt_error) { struct ath_hw *ah = common->ah; if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) - goto rx_next; + return -EINVAL; ath9k_process_rssi(common, hw, skb, rx_stats); @@ -312,8 +313,6 @@ static int ath_rx_prepare(struct ath_common *common, rx_status->qual = ath9k_compute_qual(hw, rx_stats); rx_status->flag |= RX_FLAG_TSFT; - return 1; -rx_next: return 0; } @@ -808,8 +807,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (flush) goto requeue; - if (!ath_rx_prepare(common, hw, skb, rx_stats, - rxs, &decrypt_error)) + retval = ath9k_rx_skb_preprocess(common, hw, skb, rx_stats, + rxs, &decrypt_error); + if (retval) goto requeue; /* Ensure we always have an skb to requeue once we are done -- cgit v1.2.3 From 7e86c1048a9f5f1e157daf28411f3526f0b9f7b6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 4 Nov 2009 17:21:01 -0800 Subject: ath9k: move driver keymap, keymax and splitmic to common This will make sharing code easier between ath9k and ath9k_htc. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath.h | 14 ++++ drivers/net/wireless/ath/ath9k/ath9k.h | 13 ---- drivers/net/wireless/ath/ath9k/main.c | 136 +++++++++++++++++---------------- drivers/net/wireless/ath/ath9k/recv.c | 2 +- 4 files changed, 85 insertions(+), 80 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 4af13628bafe..9e05648356fe 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -21,6 +21,16 @@ #include #include +/* + * The key cache is used for h/w cipher state and also for + * tracking station state such as the current tx antenna. + * We also setup a mapping table between key cache slot indices + * and station state to short-circuit node lookups on rx. + * Different parts have different size key caches. We handle + * up to ATH_KEYMAX entries (could dynamically allocate state). + */ +#define ATH_KEYMAX 128 /* max key cache size we handle */ + static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; struct ath_ani { @@ -89,6 +99,10 @@ struct ath_common { u32 rx_bufsize; + u32 keymax; + DECLARE_BITMAP(keymap, ATH_KEYMAX); + u8 splitmic; + struct ath_regulatory regulatory; const struct ath_ops *ops; const struct ath_bus_ops *bus_ops; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 377b0eac5e4c..88969cbae132 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -492,16 +492,6 @@ struct ath_led { #define ATH_CHAN_MAX 255 #define IEEE80211_WEP_NKID 4 /* number of key ids */ -/* - * The key cache is used for h/w cipher state and also for - * tracking station state such as the current tx antenna. - * We also setup a mapping table between key cache slot indices - * and station state to short-circuit node lookups on rx. - * Different parts have different size key caches. We handle - * up to ATH_KEYMAX entries (could dynamically allocate state). - */ -#define ATH_KEYMAX 128 /* max key cache size we handle */ - #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define ATH_RSSI_DUMMY_MARKER 0x127 #define ATH_RATE_DUMMY_MARKER 0 @@ -562,9 +552,6 @@ struct ath_softc { u16 curtxpow; u8 nbcnvifs; u16 nvifs; - u32 keymax; - DECLARE_BITMAP(keymap, ATH_KEYMAX); - u8 splitmic; bool ps_enabled; unsigned long ps_usecount; enum ath9k_int imask; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 01ac8974eb07..3c02b977a613 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -733,10 +733,11 @@ static u32 ath_get_extchanmode(struct ath_softc *sc, return chanmode; } -static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, +static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key, struct ath9k_keyval *hk, const u8 *addr, bool authenticator) { + struct ath_hw *ah = common->ah; const u8 *key_rxmic; const u8 *key_txmic; @@ -756,42 +757,42 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); } - return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr); + return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); } - if (!sc->splitmic) { + if (!common->splitmic) { /* TX and RX keys share the same key cache entry. */ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); - return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr); + return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); } /* Separate key cache entries for TX and RX */ /* TX key goes at first index, RX key at +32. */ memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); - if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) { + if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) { /* TX MIC entry failed. No need to proceed further */ - ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, + ath_print(common, ATH_DBG_FATAL, "Setting TX MIC Key Failed\n"); return 0; } memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); /* XXX delete tx key on failure? */ - return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix + 32, hk, addr); + return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr); } -static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc) +static int ath_reserve_key_cache_slot_tkip(struct ath_common *common) { int i; - for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) { - if (test_bit(i, sc->keymap) || - test_bit(i + 64, sc->keymap)) + for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { + if (test_bit(i, common->keymap) || + test_bit(i + 64, common->keymap)) continue; /* At least one part of TKIP key allocated */ - if (sc->splitmic && - (test_bit(i + 32, sc->keymap) || - test_bit(i + 64 + 32, sc->keymap))) + if (common->splitmic && + (test_bit(i + 32, common->keymap) || + test_bit(i + 64 + 32, common->keymap))) continue; /* At least one part of TKIP key allocated */ /* Found a free slot for a TKIP key */ @@ -800,60 +801,60 @@ static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc) return -1; } -static int ath_reserve_key_cache_slot(struct ath_softc *sc) +static int ath_reserve_key_cache_slot(struct ath_common *common) { int i; /* First, try to find slots that would not be available for TKIP. */ - if (sc->splitmic) { - for (i = IEEE80211_WEP_NKID; i < sc->keymax / 4; i++) { - if (!test_bit(i, sc->keymap) && - (test_bit(i + 32, sc->keymap) || - test_bit(i + 64, sc->keymap) || - test_bit(i + 64 + 32, sc->keymap))) + if (common->splitmic) { + for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) { + if (!test_bit(i, common->keymap) && + (test_bit(i + 32, common->keymap) || + test_bit(i + 64, common->keymap) || + test_bit(i + 64 + 32, common->keymap))) return i; - if (!test_bit(i + 32, sc->keymap) && - (test_bit(i, sc->keymap) || - test_bit(i + 64, sc->keymap) || - test_bit(i + 64 + 32, sc->keymap))) + if (!test_bit(i + 32, common->keymap) && + (test_bit(i, common->keymap) || + test_bit(i + 64, common->keymap) || + test_bit(i + 64 + 32, common->keymap))) return i + 32; - if (!test_bit(i + 64, sc->keymap) && - (test_bit(i , sc->keymap) || - test_bit(i + 32, sc->keymap) || - test_bit(i + 64 + 32, sc->keymap))) + if (!test_bit(i + 64, common->keymap) && + (test_bit(i , common->keymap) || + test_bit(i + 32, common->keymap) || + test_bit(i + 64 + 32, common->keymap))) return i + 64; - if (!test_bit(i + 64 + 32, sc->keymap) && - (test_bit(i, sc->keymap) || - test_bit(i + 32, sc->keymap) || - test_bit(i + 64, sc->keymap))) + if (!test_bit(i + 64 + 32, common->keymap) && + (test_bit(i, common->keymap) || + test_bit(i + 32, common->keymap) || + test_bit(i + 64, common->keymap))) return i + 64 + 32; } } else { - for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) { - if (!test_bit(i, sc->keymap) && - test_bit(i + 64, sc->keymap)) + for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { + if (!test_bit(i, common->keymap) && + test_bit(i + 64, common->keymap)) return i; - if (test_bit(i, sc->keymap) && - !test_bit(i + 64, sc->keymap)) + if (test_bit(i, common->keymap) && + !test_bit(i + 64, common->keymap)) return i + 64; } } /* No partially used TKIP slots, pick any available slot */ - for (i = IEEE80211_WEP_NKID; i < sc->keymax; i++) { + for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) { /* Do not allow slots that could be needed for TKIP group keys * to be used. This limitation could be removed if we know that * TKIP will not be used. */ if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) continue; - if (sc->splitmic) { + if (common->splitmic) { if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) continue; if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) continue; } - if (!test_bit(i, sc->keymap)) + if (!test_bit(i, common->keymap)) return i; /* Found a free slot for a key */ } @@ -861,11 +862,12 @@ static int ath_reserve_key_cache_slot(struct ath_softc *sc) return -1; } -static int ath_key_config(struct ath_softc *sc, +static int ath_key_config(struct ath_common *common, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { + struct ath_hw *ah = common->ah; struct ath9k_keyval hk; const u8 *mac = NULL; int ret = 0; @@ -911,48 +913,50 @@ static int ath_key_config(struct ath_softc *sc, mac = sta->addr; if (key->alg == ALG_TKIP) - idx = ath_reserve_key_cache_slot_tkip(sc); + idx = ath_reserve_key_cache_slot_tkip(common); else - idx = ath_reserve_key_cache_slot(sc); + idx = ath_reserve_key_cache_slot(common); if (idx < 0) return -ENOSPC; /* no free key cache entries */ } if (key->alg == ALG_TKIP) - ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac, + ret = ath_setkey_tkip(common, idx, key->key, &hk, mac, vif->type == NL80211_IFTYPE_AP); else - ret = ath9k_hw_set_keycache_entry(sc->sc_ah, idx, &hk, mac); + ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac); if (!ret) return -EIO; - set_bit(idx, sc->keymap); + set_bit(idx, common->keymap); if (key->alg == ALG_TKIP) { - set_bit(idx + 64, sc->keymap); - if (sc->splitmic) { - set_bit(idx + 32, sc->keymap); - set_bit(idx + 64 + 32, sc->keymap); + set_bit(idx + 64, common->keymap); + if (common->splitmic) { + set_bit(idx + 32, common->keymap); + set_bit(idx + 64 + 32, common->keymap); } } return idx; } -static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) +static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key) { - ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx); + struct ath_hw *ah = common->ah; + + ath9k_hw_keyreset(ah, key->hw_key_idx); if (key->hw_key_idx < IEEE80211_WEP_NKID) return; - clear_bit(key->hw_key_idx, sc->keymap); + clear_bit(key->hw_key_idx, common->keymap); if (key->alg != ALG_TKIP) return; - clear_bit(key->hw_key_idx + 64, sc->keymap); - if (sc->splitmic) { - clear_bit(key->hw_key_idx + 32, sc->keymap); - clear_bit(key->hw_key_idx + 64 + 32, sc->keymap); + clear_bit(key->hw_key_idx + 64, common->keymap); + if (common->splitmic) { + clear_bit(key->hw_key_idx + 32, common->keymap); + clear_bit(key->hw_key_idx + 64 + 32, common->keymap); } } @@ -1679,19 +1683,19 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, } /* Get the hardware key cache size. */ - sc->keymax = ah->caps.keycache_size; - if (sc->keymax > ATH_KEYMAX) { + common->keymax = ah->caps.keycache_size; + if (common->keymax > ATH_KEYMAX) { ath_print(common, ATH_DBG_ANY, "Warning, using only %u entries in %u key cache\n", - ATH_KEYMAX, sc->keymax); - sc->keymax = ATH_KEYMAX; + ATH_KEYMAX, common->keymax); + common->keymax = ATH_KEYMAX; } /* * Reset the key cache since some parts do not * reset the contents on initial power up. */ - for (i = 0; i < sc->keymax; i++) + for (i = 0; i < common->keymax; i++) ath9k_hw_keyreset(ah, (u16) i); /* default to MONITOR mode */ @@ -1788,7 +1792,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, ATH9K_CIPHER_MIC, NULL) && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, 0, NULL)) - sc->splitmic = 1; + common->splitmic = 1; /* turn on mcast key search if possible */ if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) @@ -2917,7 +2921,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, switch (cmd) { case SET_KEY: - ret = ath_key_config(sc, vif, sta, key); + ret = ath_key_config(common, vif, sta, key); if (ret >= 0) { key->hw_key_idx = ret; /* push IV and Michael MIC generation to stack */ @@ -2930,7 +2934,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, } break; case DISABLE_KEY: - ath_key_delete(sc, key); + ath_key_delete(common, key); break; default: ret = -EINVAL; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c4a8663af3ff..3abefb580a47 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -856,7 +856,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) && !decrypt_error && skb->len >= hdrlen + 4) { keyix = skb->data[hdrlen + 3] >> 6; - if (test_bit(keyix, sc->keymap)) + if (test_bit(keyix, common->keymap)) rxs->flag |= RX_FLAG_DECRYPTED; } if (ah->sw_mgmt_crypto && -- cgit v1.2.3 From dc1e001bf498a19dcb46676d933cd0e92dc53ef3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 4 Nov 2009 17:47:31 -0800 Subject: ath5k: use the common->keymap Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 10 +++++++--- drivers/net/wireless/ath/ath5k/base.h | 2 -- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 4cefd9e85dd4..a4c086f069b1 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1683,6 +1683,8 @@ static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, struct sk_buff *skb, struct ath5k_rx_status *rs) { + struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); struct ieee80211_hdr *hdr = (void *)skb->data; unsigned int keyix, hlen; @@ -1699,7 +1701,7 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, skb->len >= hlen + 4) { keyix = skb->data[hlen + 3] >> 6; - if (test_bit(keyix, sc->keymap)) + if (test_bit(keyix, common->keymap)) return RX_FLAG_DECRYPTED; } @@ -3038,6 +3040,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); int ret = 0; if (modparam_nohwcrypt) @@ -3070,14 +3074,14 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ATH5K_ERR(sc, "can't set the key\n"); goto unlock; } - __set_bit(key->keyidx, sc->keymap); + __set_bit(key->keyidx, common->keymap); key->hw_key_idx = key->keyidx; key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV | IEEE80211_KEY_FLAG_GENERATE_MMIC); break; case DISABLE_KEY: ath5k_hw_reset_key(sc->ah, key->keyidx); - __clear_bit(key->keyidx, sc->keymap); + __clear_bit(key->keyidx, common->keymap); break; default: ret = -EINVAL; diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index b14ba07e9157..b72338c9bde7 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -153,8 +153,6 @@ struct ath5k_softc { enum ath5k_int imask; /* interrupt mask copy */ - DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */ - u8 bssidmask[ETH_ALEN]; unsigned int led_pin, /* GPIO pin for driving LED */ -- cgit v1.2.3 From c9b1417055cd2518e8a3b4b27e1f8e4b72821dff Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 4 Nov 2009 16:47:22 -0800 Subject: ath9k: move RX skb post processing to a helper Use a helper for the RX skb post processing, ath9k_rx_skb_postprocess(). Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 89 ++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 3abefb580a47..8b7489d61d38 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -316,6 +316,55 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, return 0; } +static void ath9k_rx_skb_postprocess(struct ath_common *common, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs, + bool decrypt_error) +{ + struct ath_hw *ah = common->ah; + struct ieee80211_hdr *hdr; + int hdrlen, padsize; + u8 keyix; + __le16 fc; + + /* see if any padding is done by the hw and remove it */ + hdr = (struct ieee80211_hdr *) skb->data; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + fc = hdr->frame_control; + + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - hdrlen % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); + } + + keyix = rx_stats->rs_keyix; + + if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { + rxs->flag |= RX_FLAG_DECRYPTED; + } else if (ieee80211_has_protected(fc) + && !decrypt_error && skb->len >= hdrlen + 4) { + keyix = skb->data[hdrlen + 3] >> 6; + + if (test_bit(keyix, common->keymap)) + rxs->flag |= RX_FLAG_DECRYPTED; + } + if (ah->sw_mgmt_crypto && + (rxs->flag & RX_FLAG_DECRYPTED) && + ieee80211_is_mgmt(fc)) + /* Use software decrypt for management frames. */ + rxs->flag &= ~RX_FLAG_DECRYPTED; +} + static void ath_opmode_init(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; @@ -716,10 +765,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) */ struct ieee80211_hw *hw = NULL; struct ieee80211_hdr *hdr; - int hdrlen, padsize, retval; + int retval; bool decrypt_error = false; - u8 keyix; - __le16 fc; spin_lock_bh(&sc->rx.rxbuflock); @@ -830,40 +877,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) skb_put(skb, rx_stats->rs_datalen); - /* see if any padding is done by the hw and remove it */ - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - - /* The MAC header is padded to have 32-bit boundary if the - * packet payload is non-zero. The general calculation for - * padsize would take into account odd header lengths: - * padsize = (4 - hdrlen % 4) % 4; However, since only - * even-length headers are used, padding can only be 0 or 2 - * bytes and we can optimize this a bit. In addition, we must - * not try to remove padding from short control frames that do - * not have payload. */ - padsize = hdrlen & 3; - if (padsize && hdrlen >= 24) { - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } - - keyix = rx_stats->rs_keyix; - - if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { - rxs->flag |= RX_FLAG_DECRYPTED; - } else if (ieee80211_has_protected(fc) - && !decrypt_error && skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; - - if (test_bit(keyix, common->keymap)) - rxs->flag |= RX_FLAG_DECRYPTED; - } - if (ah->sw_mgmt_crypto && - (rxs->flag & RX_FLAG_DECRYPTED) && - ieee80211_is_mgmt(fc)) - /* Use software decrypt for management frames. */ - rxs->flag &= ~RX_FLAG_DECRYPTED; + ath9k_rx_skb_postprocess(common, skb, rx_stats, + rxs, decrypt_error); /* We will now give hardware our shiny new allocated skb */ bf->bf_mpdu = requeue_skb; -- cgit v1.2.3 From db86f07ec6cdea9670a0928bd1289109d2a989dc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 5 Nov 2009 08:44:39 -0800 Subject: ath9k_common: add new module to share 802.11n driver helpers ath9k and ath9k_htc share a lot of common hardware characteristics. They only differ in that ath9k_htc works with a target CPU and ath9k works directly with the hardware. ath9k_htc will do *some* things in the firmware, but a lot of others on the host. The common 802.11n hardware code is already shared through the ath9k_hw module. Common helpers amongst all Atheros drivers can use the ath module, this includes ath5k and ar9170 as users. But there is some common driver specific helpers which are not exactly hardware code which ath9k and ath9k_htc can share. We'll be using ath9k_common for this to avoid bloating the ath module and the common 802.11n hardware module ath9k_hw. We start by sharing skb pre and post processing in preparation for a hand off to mac80211. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Kconfig | 3 + drivers/net/wireless/ath/ath9k/Makefile | 3 + drivers/net/wireless/ath/ath9k/ath9k.h | 95 +--------- drivers/net/wireless/ath/ath9k/common.c | 326 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/common.h | 123 ++++++++++++ drivers/net/wireless/ath/ath9k/rc.h | 2 + drivers/net/wireless/ath/ath9k/recv.c | 284 +--------------------------- 7 files changed, 467 insertions(+), 369 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/common.c create mode 100644 drivers/net/wireless/ath/ath9k/common.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index b735fb399fb1..006364f76bb4 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -1,5 +1,7 @@ config ATH9K_HW tristate +config ATH9K_COMMON + tristate config ATH9K tristate "Atheros 802.11n wireless cards support" @@ -8,6 +10,7 @@ config ATH9K select MAC80211_LEDS select LEDS_CLASS select NEW_LEDS + select ATH9K_COMMON ---help--- This module adds support for wireless adapters based on Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 8caf2a8f8953..e53f9680a385 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -23,3 +23,6 @@ ath9k_hw-y:= hw.o \ mac.o \ obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o + +obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o +ath9k_common-y:= common.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 88969cbae132..d9bcc3abb425 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -19,14 +19,16 @@ #include #include -#include #include -#include "hw.h" #include "rc.h" #include "debug.h" -#include "../ath.h" -#include "../debug.h" +#include "common.h" + +/* + * Header for the ath9k.ko driver core *only* -- hw code nor any other driver + * should rely on this file or its contents. + */ struct ath_node; @@ -99,18 +101,6 @@ enum buffer_type { BUF_XRETRY = BIT(5), }; -struct ath_buf_state { - int bfs_nframes; - u16 bfs_al; - u16 bfs_frmlen; - int bfs_seqno; - int bfs_tidno; - int bfs_retries; - u8 bf_type; - u32 bfs_keyix; - enum ath9k_key_type bfs_keytype; -}; - #define bf_nframes bf_state.bfs_nframes #define bf_al bf_state.bfs_al #define bf_frmlen bf_state.bfs_frmlen @@ -125,21 +115,6 @@ struct ath_buf_state { #define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) #define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) -struct ath_buf { - struct list_head list; - struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or - an aggregate) */ - struct ath_buf *bf_next; /* next subframe in the aggregate */ - struct sk_buff *bf_mpdu; /* enclosing frame structure */ - struct ath_desc *bf_desc; /* virtual addr of desc */ - dma_addr_t bf_daddr; /* physical addr of desc */ - dma_addr_t bf_buf_addr; /* physical addr of data buffer */ - bool bf_stale; - u16 bf_flags; - struct ath_buf_state bf_state; - dma_addr_t bf_dmacontext; -}; - struct ath_descdma { struct ath_desc *dd_desc; dma_addr_t dd_desc_paddr; @@ -159,13 +134,9 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_MAX_ANTENNA 3 #define ATH_RXBUF 512 -#define WME_NUM_TID 16 #define ATH_TXBUF 512 #define ATH_TXMAXTRY 13 #define ATH_MGT_TXMAXTRY 4 -#define WME_BA_BMP_SIZE 64 -#define WME_MAX_BA WME_BA_BMP_SIZE -#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) #define TID_TO_WME_AC(_tid) \ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ @@ -173,12 +144,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ WME_AC_VO) -#define WME_AC_BE 0 -#define WME_AC_BK 1 -#define WME_AC_VI 2 -#define WME_AC_VO 3 -#define WME_NUM_AC 4 - #define ADDBA_EXCHANGE_ATTEMPTS 10 #define ATH_AGGR_DELIM_SZ 4 #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ @@ -252,30 +217,6 @@ struct ath_txq { #define AGGR_ADDBA_COMPLETE BIT(2) #define AGGR_ADDBA_PROGRESS BIT(3) -struct ath_atx_tid { - struct list_head list; - struct list_head buf_q; - struct ath_node *an; - struct ath_atx_ac *ac; - struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; - u16 seq_start; - u16 seq_next; - u16 baw_size; - int tidno; - int baw_head; /* first un-acked tx buffer */ - int baw_tail; /* next unused tx buffer slot */ - int sched; - int paused; - u8 state; -}; - -struct ath_atx_ac { - int sched; - int qnum; - struct list_head list; - struct list_head tid_q; -}; - struct ath_tx_control { struct ath_txq *txq; int if_id; @@ -286,29 +227,6 @@ struct ath_tx_control { #define ATH_TX_XRETRY 0x02 #define ATH_TX_BAR 0x04 -#define ATH_RSSI_LPF_LEN 10 -#define RSSI_LPF_THRESHOLD -20 -#define ATH_RSSI_EP_MULTIPLIER (1<<7) -#define ATH_EP_MUL(x, mul) ((x) * (mul)) -#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER)) -#define ATH_LPF_RSSI(x, y, len) \ - ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y)) -#define ATH_RSSI_LPF(x, y) do { \ - if ((y) >= RSSI_LPF_THRESHOLD) \ - x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \ -} while (0) -#define ATH_EP_RND(x, mul) \ - ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) - -struct ath_node { - struct ath_softc *an_sc; - struct ath_atx_tid tid[WME_NUM_TID]; - struct ath_atx_ac ac[WME_NUM_AC]; - u16 maxampdu; - u8 mpdudensity; - int last_rssi; -}; - struct ath_tx { u16 seq_no; u32 txqsetup; @@ -493,7 +411,6 @@ struct ath_led { #define IEEE80211_WEP_NKID 4 /* number of key ids */ #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ -#define ATH_RSSI_DUMMY_MARKER 0x127 #define ATH_RATE_DUMMY_MARKER 0 #define SC_OP_INVALID BIT(0) diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c new file mode 100644 index 000000000000..5fb164e294de --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 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. + */ + +/* + * Module for common driver code between ath9k and ath9k_htc + */ + +#include +#include + +#include "common.h" + +MODULE_AUTHOR("Atheros Communications"); +MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards."); +MODULE_LICENSE("Dual BSD/GPL"); + +/* Common RX processing */ + +/* Assumes you've already done the endian to CPU conversion */ +static bool ath9k_rx_accept(struct ath_common *common, + struct sk_buff *skb, + struct ieee80211_rx_status *rxs, + struct ath_rx_status *rx_stats, + bool *decrypt_error) +{ + struct ath_hw *ah = common->ah; + struct ieee80211_hdr *hdr; + __le16 fc; + + hdr = (struct ieee80211_hdr *) skb->data; + fc = hdr->frame_control; + + if (!rx_stats->rs_datalen) + return false; + /* + * rs_status follows rs_datalen so if rs_datalen is too large + * we can take a hint that hardware corrupted it, so ignore + * those frames. + */ + if (rx_stats->rs_datalen > common->rx_bufsize) + return false; + + if (rx_stats->rs_more) { + /* + * Frame spans multiple descriptors; this cannot happen yet + * as we don't support jumbograms. If not in monitor mode, + * discard the frame. Enable this if you want to see + * error frames in Monitor mode. + */ + if (ah->opmode != NL80211_IFTYPE_MONITOR) + return false; + } else if (rx_stats->rs_status != 0) { + if (rx_stats->rs_status & ATH9K_RXERR_CRC) + rxs->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rx_stats->rs_status & ATH9K_RXERR_PHY) + return false; + + if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) { + *decrypt_error = true; + } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) { + if (ieee80211_is_ctl(fc)) + /* + * Sometimes, we get invalid + * MIC failures on valid control frames. + * Remove these mic errors. + */ + rx_stats->rs_status &= ~ATH9K_RXERR_MIC; + else + rxs->flag |= RX_FLAG_MMIC_ERROR; + } + /* + * Reject error frames with the exception of + * decryption and MIC failures. For monitor mode, + * we also ignore the CRC error. + */ + if (ah->opmode == NL80211_IFTYPE_MONITOR) { + if (rx_stats->rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | + ATH9K_RXERR_CRC)) + return false; + } else { + if (rx_stats->rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { + return false; + } + } + } + return true; +} + +static u8 ath9k_process_rate(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs, + struct sk_buff *skb) +{ + struct ieee80211_supported_band *sband; + enum ieee80211_band band; + unsigned int i = 0; + + band = hw->conf.channel->band; + sband = hw->wiphy->bands[band]; + + if (rx_stats->rs_rate & 0x80) { + /* HT rate */ + rxs->flag |= RX_FLAG_HT; + if (rx_stats->rs_flags & ATH9K_RX_2040) + rxs->flag |= RX_FLAG_40MHZ; + if (rx_stats->rs_flags & ATH9K_RX_GI) + rxs->flag |= RX_FLAG_SHORT_GI; + return rx_stats->rs_rate & 0x7f; + } + + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].hw_value == rx_stats->rs_rate) + return i; + if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { + rxs->flag |= RX_FLAG_SHORTPRE; + return i; + } + } + + /* No valid hardware bitrate found -- we should not get here */ + ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected " + "0x%02x using 1 Mbit\n", rx_stats->rs_rate); + if ((common->debug_mask & ATH_DBG_XMIT)) + print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len); + + return 0; +} + +/* + * Theory for reporting quality: + * + * At a hardware RSSI of 45 you will be able to use MCS 7 reliably. + * At a hardware RSSI of 45 you will be able to use MCS 15 reliably. + * At a hardware RSSI of 35 you should be able use 54 Mbps reliably. + * + * MCS 7 is the highets MCS index usable by a 1-stream device. + * MCS 15 is the highest MCS index usable by a 2-stream device. + * + * All ath9k devices are either 1-stream or 2-stream. + * + * How many bars you see is derived from the qual reporting. + * + * A more elaborate scheme can be used here but it requires tables + * of SNR/throughput for each possible mode used. For the MCS table + * you can refer to the wireless wiki: + * + * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n + * + */ +static int ath9k_compute_qual(struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats) +{ + int qual; + + if (conf_is_ht(&hw->conf)) + qual = rx_stats->rs_rssi * 100 / 45; + else + qual = rx_stats->rs_rssi * 100 / 35; + + /* + * rssi can be more than 45 though, anything above that + * should be considered at 100% + */ + if (qual > 100) + qual = 100; + + return qual; +} + +static void ath9k_process_rssi(struct ath_common *common, + struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ath_rx_status *rx_stats) +{ + struct ath_hw *ah = common->ah; + struct ieee80211_sta *sta; + struct ieee80211_hdr *hdr; + struct ath_node *an; + int last_rssi = ATH_RSSI_DUMMY_MARKER; + __le16 fc; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + + rcu_read_lock(); + /* + * XXX: use ieee80211_find_sta! This requires quite a bit of work + * under the current ath9k virtual wiphy implementation as we have + * no way of tying a vif to wiphy. Typically vifs are attached to + * at least one sdata of a wiphy on mac80211 but with ath9k virtual + * wiphy you'd have to iterate over every wiphy and each sdata. + */ + sta = ieee80211_find_sta_by_hw(hw, hdr->addr2); + if (sta) { + an = (struct ath_node *) sta->drv_priv; + if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && + !rx_stats->rs_moreaggr) + ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi); + last_rssi = an->last_rssi; + } + rcu_read_unlock(); + + if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) + rx_stats->rs_rssi = ATH_EP_RND(last_rssi, + ATH_RSSI_EP_MULTIPLIER); + if (rx_stats->rs_rssi < 0) + rx_stats->rs_rssi = 0; + else if (rx_stats->rs_rssi > 127) + rx_stats->rs_rssi = 127; + + /* Update Beacon RSSI, this is used by ANI. */ + if (ieee80211_is_beacon(fc)) + ah->stats.avgbrssi = rx_stats->rs_rssi; +} + +/* + * 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 + * decryption key or real decryption error. This let us keep statistics there. + */ +int ath9k_cmn_rx_skb_preprocess(struct ath_common *common, + struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rx_status, + bool *decrypt_error) +{ + struct ath_hw *ah = common->ah; + + if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) + return -EINVAL; + + ath9k_process_rssi(common, hw, skb, rx_stats); + + rx_status->rate_idx = ath9k_process_rate(common, hw, + rx_stats, rx_status, skb); + rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp); + rx_status->band = hw->conf.channel->band; + rx_status->freq = hw->conf.channel->center_freq; + rx_status->noise = common->ani.noise_floor; + rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; + rx_status->antenna = rx_stats->rs_antenna; + rx_status->qual = ath9k_compute_qual(hw, rx_stats); + rx_status->flag |= RX_FLAG_TSFT; + + return 0; +} +EXPORT_SYMBOL(ath9k_cmn_rx_skb_preprocess); + +void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs, + bool decrypt_error) +{ + struct ath_hw *ah = common->ah; + struct ieee80211_hdr *hdr; + int hdrlen, padsize; + u8 keyix; + __le16 fc; + + /* see if any padding is done by the hw and remove it */ + hdr = (struct ieee80211_hdr *) skb->data; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + fc = hdr->frame_control; + + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - hdrlen % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); + } + + keyix = rx_stats->rs_keyix; + + if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { + rxs->flag |= RX_FLAG_DECRYPTED; + } else if (ieee80211_has_protected(fc) + && !decrypt_error && skb->len >= hdrlen + 4) { + keyix = skb->data[hdrlen + 3] >> 6; + + if (test_bit(keyix, common->keymap)) + rxs->flag |= RX_FLAG_DECRYPTED; + } + if (ah->sw_mgmt_crypto && + (rxs->flag & RX_FLAG_DECRYPTED) && + ieee80211_is_mgmt(fc)) + /* Use software decrypt for management frames. */ + rxs->flag &= ~RX_FLAG_DECRYPTED; +} +EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess); + +static int __init ath9k_cmn_init(void) +{ + return 0; +} +module_init(ath9k_cmn_init); + +static void __exit ath9k_cmn_exit(void) +{ + return; +} +module_exit(ath9k_cmn_exit); diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h new file mode 100644 index 000000000000..292e3d860c0e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 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. + */ + +#include + +#include "../ath.h" +#include "../debug.h" + +#include "hw.h" + +/* Common header for Atheros 802.11n base driver cores */ + +#define WME_NUM_TID 16 +#define WME_BA_BMP_SIZE 64 +#define WME_MAX_BA WME_BA_BMP_SIZE +#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) + +#define WME_AC_BE 0 +#define WME_AC_BK 1 +#define WME_AC_VI 2 +#define WME_AC_VO 3 +#define WME_NUM_AC 4 + +#define ATH_RSSI_DUMMY_MARKER 0x127 +#define ATH_RSSI_LPF_LEN 10 +#define RSSI_LPF_THRESHOLD -20 +#define ATH_RSSI_EP_MULTIPLIER (1<<7) +#define ATH_EP_MUL(x, mul) ((x) * (mul)) +#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER)) +#define ATH_LPF_RSSI(x, y, len) \ + ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y)) +#define ATH_RSSI_LPF(x, y) do { \ + if ((y) >= RSSI_LPF_THRESHOLD) \ + x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \ +} while (0) +#define ATH_EP_RND(x, mul) \ + ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) + +struct ath_atx_ac { + int sched; + int qnum; + struct list_head list; + struct list_head tid_q; +}; + +struct ath_buf_state { + int bfs_nframes; + u16 bfs_al; + u16 bfs_frmlen; + int bfs_seqno; + int bfs_tidno; + int bfs_retries; + u8 bf_type; + u32 bfs_keyix; + enum ath9k_key_type bfs_keytype; +}; + +struct ath_buf { + struct list_head list; + struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or + an aggregate) */ + struct ath_buf *bf_next; /* next subframe in the aggregate */ + struct sk_buff *bf_mpdu; /* enclosing frame structure */ + struct ath_desc *bf_desc; /* virtual addr of desc */ + dma_addr_t bf_daddr; /* physical addr of desc */ + dma_addr_t bf_buf_addr; /* physical addr of data buffer */ + bool bf_stale; + u16 bf_flags; + struct ath_buf_state bf_state; + dma_addr_t bf_dmacontext; +}; + +struct ath_atx_tid { + struct list_head list; + struct list_head buf_q; + struct ath_node *an; + struct ath_atx_ac *ac; + struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; + u16 seq_start; + u16 seq_next; + u16 baw_size; + int tidno; + int baw_head; /* first un-acked tx buffer */ + int baw_tail; /* next unused tx buffer slot */ + int sched; + int paused; + u8 state; +}; + +struct ath_node { + struct ath_common *common; + struct ath_atx_tid tid[WME_NUM_TID]; + struct ath_atx_ac ac[WME_NUM_AC]; + u16 maxampdu; + u8 mpdudensity; + int last_rssi; +}; + +int ath9k_cmn_rx_skb_preprocess(struct ath_common *common, + struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rx_status, + bool *decrypt_error); + +void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs, + bool decrypt_error); diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index fa21a628ddd0..94cb9f8d2446 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -19,6 +19,8 @@ #ifndef RC_H #define RC_H +#include "hw.h" + struct ath_softc; #define ATH_RATE_MAX 30 diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 8b7489d61d38..477365e5ae69 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -89,282 +89,6 @@ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) sc->rx.rxotherant = 0; } -/* Assumes you've already done the endian to CPU conversion */ -static bool ath9k_rx_accept(struct ath_common *common, - struct sk_buff *skb, - struct ieee80211_rx_status *rxs, - struct ath_rx_status *rx_stats, - bool *decrypt_error) -{ - struct ath_hw *ah = common->ah; - struct ieee80211_hdr *hdr; - __le16 fc; - - hdr = (struct ieee80211_hdr *) skb->data; - fc = hdr->frame_control; - - if (!rx_stats->rs_datalen) - return false; - /* - * rs_status follows rs_datalen so if rs_datalen is too large - * we can take a hint that hardware corrupted it, so ignore - * those frames. - */ - if (rx_stats->rs_datalen > common->rx_bufsize) - return false; - - if (rx_stats->rs_more) { - /* - * Frame spans multiple descriptors; this cannot happen yet - * as we don't support jumbograms. If not in monitor mode, - * discard the frame. Enable this if you want to see - * error frames in Monitor mode. - */ - if (ah->opmode != NL80211_IFTYPE_MONITOR) - return false; - } else if (rx_stats->rs_status != 0) { - if (rx_stats->rs_status & ATH9K_RXERR_CRC) - rxs->flag |= RX_FLAG_FAILED_FCS_CRC; - if (rx_stats->rs_status & ATH9K_RXERR_PHY) - return false; - - if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) { - *decrypt_error = true; - } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) { - if (ieee80211_is_ctl(fc)) - /* - * Sometimes, we get invalid - * MIC failures on valid control frames. - * Remove these mic errors. - */ - rx_stats->rs_status &= ~ATH9K_RXERR_MIC; - else - rxs->flag |= RX_FLAG_MMIC_ERROR; - } - /* - * Reject error frames with the exception of - * decryption and MIC failures. For monitor mode, - * we also ignore the CRC error. - */ - if (ah->opmode == NL80211_IFTYPE_MONITOR) { - if (rx_stats->rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_CRC)) - return false; - } else { - if (rx_stats->rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { - return false; - } - } - } - return true; -} - -static u8 ath9k_process_rate(struct ath_common *common, - struct ieee80211_hw *hw, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rxs, - struct sk_buff *skb) -{ - struct ieee80211_supported_band *sband; - enum ieee80211_band band; - unsigned int i = 0; - - band = hw->conf.channel->band; - sband = hw->wiphy->bands[band]; - - if (rx_stats->rs_rate & 0x80) { - /* HT rate */ - rxs->flag |= RX_FLAG_HT; - if (rx_stats->rs_flags & ATH9K_RX_2040) - rxs->flag |= RX_FLAG_40MHZ; - if (rx_stats->rs_flags & ATH9K_RX_GI) - rxs->flag |= RX_FLAG_SHORT_GI; - return rx_stats->rs_rate & 0x7f; - } - - for (i = 0; i < sband->n_bitrates; i++) { - if (sband->bitrates[i].hw_value == rx_stats->rs_rate) - return i; - if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { - rxs->flag |= RX_FLAG_SHORTPRE; - return i; - } - } - - /* No valid hardware bitrate found -- we should not get here */ - ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected " - "0x%02x using 1 Mbit\n", rx_stats->rs_rate); - if ((common->debug_mask & ATH_DBG_XMIT)) - print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len); - - return 0; -} - -/* - * Theory for reporting quality: - * - * At a hardware RSSI of 45 you will be able to use MCS 7 reliably. - * At a hardware RSSI of 45 you will be able to use MCS 15 reliably. - * At a hardware RSSI of 35 you should be able use 54 Mbps reliably. - * - * MCS 7 is the highets MCS index usable by a 1-stream device. - * MCS 15 is the highest MCS index usable by a 2-stream device. - * - * All ath9k devices are either 1-stream or 2-stream. - * - * How many bars you see is derived from the qual reporting. - * - * A more elaborate scheme can be used here but it requires tables - * of SNR/throughput for each possible mode used. For the MCS table - * you can refer to the wireless wiki: - * - * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n - * - */ -static int ath9k_compute_qual(struct ieee80211_hw *hw, - struct ath_rx_status *rx_stats) -{ - int qual; - - if (conf_is_ht(&hw->conf)) - qual = rx_stats->rs_rssi * 100 / 45; - else - qual = rx_stats->rs_rssi * 100 / 35; - - /* - * rssi can be more than 45 though, anything above that - * should be considered at 100% - */ - if (qual > 100) - qual = 100; - - return qual; -} - -static void ath9k_process_rssi(struct ath_common *common, - struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ath_rx_status *rx_stats) -{ - struct ath_hw *ah = common->ah; - struct ieee80211_sta *sta; - struct ieee80211_hdr *hdr; - struct ath_node *an; - int last_rssi = ATH_RSSI_DUMMY_MARKER; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - rcu_read_lock(); - /* XXX: use ieee80211_find_sta! */ - sta = ieee80211_find_sta_by_hw(hw, hdr->addr2); - if (sta) { - an = (struct ath_node *) sta->drv_priv; - if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && - !rx_stats->rs_moreaggr) - ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi); - last_rssi = an->last_rssi; - } - rcu_read_unlock(); - - if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - rx_stats->rs_rssi = ATH_EP_RND(last_rssi, - ATH_RSSI_EP_MULTIPLIER); - if (rx_stats->rs_rssi < 0) - rx_stats->rs_rssi = 0; - else if (rx_stats->rs_rssi > 127) - rx_stats->rs_rssi = 127; - - /* Update Beacon RSSI, this is used by ANI. */ - if (ieee80211_is_beacon(fc)) - ah->stats.avgbrssi = rx_stats->rs_rssi; -} - -/* - * 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 - * decryption key or real decryption error. This let us keep statistics there. - */ -static int ath9k_rx_skb_preprocess(struct ath_common *common, - struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rx_status, - bool *decrypt_error) -{ - struct ath_hw *ah = common->ah; - - if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) - return -EINVAL; - - ath9k_process_rssi(common, hw, skb, rx_stats); - - rx_status->rate_idx = ath9k_process_rate(common, hw, - rx_stats, rx_status, skb); - rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp); - rx_status->band = hw->conf.channel->band; - rx_status->freq = hw->conf.channel->center_freq; - rx_status->noise = common->ani.noise_floor; - rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; - rx_status->antenna = rx_stats->rs_antenna; - rx_status->qual = ath9k_compute_qual(hw, rx_stats); - rx_status->flag |= RX_FLAG_TSFT; - - return 0; -} - -static void ath9k_rx_skb_postprocess(struct ath_common *common, - struct sk_buff *skb, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rxs, - bool decrypt_error) -{ - struct ath_hw *ah = common->ah; - struct ieee80211_hdr *hdr; - int hdrlen, padsize; - u8 keyix; - __le16 fc; - - /* see if any padding is done by the hw and remove it */ - hdr = (struct ieee80211_hdr *) skb->data; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - - /* The MAC header is padded to have 32-bit boundary if the - * packet payload is non-zero. The general calculation for - * padsize would take into account odd header lengths: - * padsize = (4 - hdrlen % 4) % 4; However, since only - * even-length headers are used, padding can only be 0 or 2 - * bytes and we can optimize this a bit. In addition, we must - * not try to remove padding from short control frames that do - * not have payload. */ - padsize = hdrlen & 3; - if (padsize && hdrlen >= 24) { - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } - - keyix = rx_stats->rs_keyix; - - if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { - rxs->flag |= RX_FLAG_DECRYPTED; - } else if (ieee80211_has_protected(fc) - && !decrypt_error && skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; - - if (test_bit(keyix, common->keymap)) - rxs->flag |= RX_FLAG_DECRYPTED; - } - if (ah->sw_mgmt_crypto && - (rxs->flag & RX_FLAG_DECRYPTED) && - ieee80211_is_mgmt(fc)) - /* Use software decrypt for management frames. */ - rxs->flag &= ~RX_FLAG_DECRYPTED; -} - static void ath_opmode_init(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; @@ -854,8 +578,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (flush) goto requeue; - retval = ath9k_rx_skb_preprocess(common, hw, skb, rx_stats, - rxs, &decrypt_error); + retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, rx_stats, + rxs, &decrypt_error); if (retval) goto requeue; @@ -877,8 +601,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) skb_put(skb, rx_stats->rs_datalen); - ath9k_rx_skb_postprocess(common, skb, rx_stats, - rxs, decrypt_error); + ath9k_cmn_rx_skb_postprocess(common, skb, rx_stats, + rxs, decrypt_error); /* We will now give hardware our shiny new allocated skb */ bf->bf_mpdu = requeue_skb; -- cgit v1.2.3 From 165864d08774823e3b88d5fcf4dad302700612e3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 5 Nov 2009 08:53:10 -0800 Subject: ath9k_common: remove ath9k_compute_qual() This is now deprecated and unused within mac80211, so time to remove it as otherwise we'd be doing some unecessary computations for nothing. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common.c | 42 --------------------------------- 1 file changed, 42 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 5fb164e294de..80edf7a302ca 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -142,47 +142,6 @@ static u8 ath9k_process_rate(struct ath_common *common, return 0; } -/* - * Theory for reporting quality: - * - * At a hardware RSSI of 45 you will be able to use MCS 7 reliably. - * At a hardware RSSI of 45 you will be able to use MCS 15 reliably. - * At a hardware RSSI of 35 you should be able use 54 Mbps reliably. - * - * MCS 7 is the highets MCS index usable by a 1-stream device. - * MCS 15 is the highest MCS index usable by a 2-stream device. - * - * All ath9k devices are either 1-stream or 2-stream. - * - * How many bars you see is derived from the qual reporting. - * - * A more elaborate scheme can be used here but it requires tables - * of SNR/throughput for each possible mode used. For the MCS table - * you can refer to the wireless wiki: - * - * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n - * - */ -static int ath9k_compute_qual(struct ieee80211_hw *hw, - struct ath_rx_status *rx_stats) -{ - int qual; - - if (conf_is_ht(&hw->conf)) - qual = rx_stats->rs_rssi * 100 / 45; - else - qual = rx_stats->rs_rssi * 100 / 35; - - /* - * rssi can be more than 45 though, anything above that - * should be considered at 100% - */ - if (qual > 100) - qual = 100; - - return qual; -} - static void ath9k_process_rssi(struct ath_common *common, struct ieee80211_hw *hw, struct sk_buff *skb, @@ -256,7 +215,6 @@ int ath9k_cmn_rx_skb_preprocess(struct ath_common *common, rx_status->noise = common->ani.noise_floor; rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; rx_status->antenna = rx_stats->rs_antenna; - rx_status->qual = ath9k_compute_qual(hw, rx_stats); rx_status->flag |= RX_FLAG_TSFT; return 0; -- cgit v1.2.3 From 748d451028ef037576b57517bc81e62f1fd92250 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 5 Nov 2009 14:10:07 -0800 Subject: ath9k_common: clarify and correct jumbogram processing Jumbograms are frames put together linked together through more than one descriptor. For example ath9k_htc will use this to send from the target a large frame split up into 2 or more segments. The driver then would be in charge of putting the frame back together. When jumbograms are constructed the rx_stats->rs_more will bet set and rx_stats->rs_status will not have any valid content as the actual status will only be avialable at the end of the chained descriptors. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 80edf7a302ca..acd4bb503dfc 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -53,16 +53,17 @@ static bool ath9k_rx_accept(struct ath_common *common, if (rx_stats->rs_datalen > common->rx_bufsize) return false; - if (rx_stats->rs_more) { - /* - * Frame spans multiple descriptors; this cannot happen yet - * as we don't support jumbograms. If not in monitor mode, - * discard the frame. Enable this if you want to see - * error frames in Monitor mode. - */ - if (ah->opmode != NL80211_IFTYPE_MONITOR) - return false; - } else if (rx_stats->rs_status != 0) { + /* + * rs_more indicates chained descriptors which can be used + * to link buffers together for a sort of scatter-gather + * operation. + * + * The rx_stats->rs_status will not be set until the end of the + * chained descriptors so it can be ignored if rs_more is set. The + * rs_more will be false at the last element of the chained + * descriptors. + */ + if (!rx_stats->rs_more && rx_stats->rs_status != 0) { if (rx_stats->rs_status & ATH9K_RXERR_CRC) rxs->flag |= RX_FLAG_FAILED_FCS_CRC; if (rx_stats->rs_status & ATH9K_RXERR_PHY) -- cgit v1.2.3 From a65986824d2552dd76786d5a0012989a64c45ab7 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 8 Nov 2009 12:30:35 +0100 Subject: rt2x00: Add dynamic detection of eFuse EEPROM in rt2800pci. Instead of assuming that all rt3090 devices will have an eFuse EEPROM, do as the legacy Ralink driver, and detect at run-time whether an eFuse EEPROM is present. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 22 ++++++++++++++++++---- drivers/net/wireless/rt2x00/rt2800pci.h | 1 + 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index bff870799f64..2f284a6f384e 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -145,6 +145,15 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) EEPROM_SIZE / sizeof(u16)); } +static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2800_register_read(rt2x00dev, EFUSE_CTRL, ®); + + return rt2x00_get_field32(reg, EFUSE_CTRL_PRESENT); +} + static void rt2800pci_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) { @@ -182,6 +191,11 @@ static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) { } +static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) +{ + return 0; +} + static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) { } @@ -1091,11 +1105,11 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) case RT3052: rt2800pci_read_eeprom_soc(rt2x00dev); break; - case RT3090: - rt2800pci_read_eeprom_efuse(rt2x00dev); - break; default: - rt2800pci_read_eeprom_pci(rt2x00dev); + if (rt2800pci_efuse_detect(rt2x00dev)) + rt2800pci_read_eeprom_efuse(rt2x00dev); + else + rt2800pci_read_eeprom_pci(rt2x00dev); break; } diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index 1dbf13270cda..8f944ee8a970 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -62,6 +62,7 @@ #define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000) #define EFUSE_CTRL_MODE FIELD32(0x000000c0) #define EFUSE_CTRL_KICK FIELD32(0x40000000) +#define EFUSE_CTRL_PRESENT FIELD32(0x80000000) /* * EFUSE_DATA0 -- cgit v1.2.3 From 863cc978a73bc07f1de0e9a9bd9889bed6e618da Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 8 Nov 2009 14:37:48 +0100 Subject: rt2x00: Remove deprecated ieee80211_rx_status->qual usage ieee80211_rx_status->qual has been marked deprecated. This allows us to remove several functions and fields which were used to calculate a reasonable value for it. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 7 --- drivers/net/wireless/rt2x00/rt2x00dev.c | 1 - drivers/net/wireless/rt2x00/rt2x00lib.h | 13 ----- drivers/net/wireless/rt2x00/rt2x00link.c | 88 -------------------------------- 4 files changed, 109 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index c83dbaefd57a..1a84574a26d3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -312,13 +312,6 @@ struct link { */ struct avg_val avg_rssi; - /* - * Currently precalculated percentages of successful - * TX and RX frames. - */ - int rx_percentage; - int tx_percentage; - /* * Work structure for scheduling periodic link tuning. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 73bbec58341e..00bfb2255ceb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -430,7 +430,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, rx_status->mactime = rxdesc.timestamp; rx_status->rate_idx = rate_idx; - rx_status->qual = rt2x00link_calculate_signal(rt2x00dev, rxdesc.rssi); rx_status->signal = rxdesc.rssi; rx_status->noise = rxdesc.noise; rx_status->flag = rxdesc.flags; diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 567f029a8cda..e17016572c3f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -222,19 +222,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, struct rxdone_entry_desc *rxdesc); -/** - * rt2x00link_calculate_signal - Calculate signal quality - * @rt2x00dev: Pointer to &struct rt2x00_dev. - * @rssi: RX Frame RSSI - * - * Calculate the signal quality of a frame based on the rssi - * measured during the receiving of the frame and the global - * link quality statistics measured since the start of the - * link tuning. The result is a value between 0 and 100 which - * is an indication of the signal quality. - */ -int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi); - /** * rt2x00link_start_tuner - Start periodic link tuner work * @rt2x00dev: Pointer to &struct rt2x00_dev. diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index c708d0be9155..f918f29e2d73 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -35,24 +35,6 @@ */ #define DEFAULT_RSSI -128 -/* - * When no TX/RX percentage could be calculated due to lack of - * frames on the air, we fallback to a percentage of 50%. - * This will assure we will get at least get some decent value - * when the link tuner starts. - * The value will be dropped and overwritten with the correct (measured) - * value anyway during the first run of the link tuner. - */ -#define DEFAULT_PERCENTAGE 50 - -/* - * Small helper macro for percentage calculation - * This is a very simple macro with the only catch that it will - * produce a default value in case no total value was provided. - */ -#define PERCENTAGE(__value, __total) \ - ( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) ) - /* * Helper struct and macro to work with moving/walking averages. * When adding a value to the average value the following calculation @@ -91,27 +73,6 @@ __new; \ }) -/* - * For calculating the Signal quality we have determined - * the total number of success and failed RX and TX frames. - * With the addition of the average RSSI value we can determine - * the link quality using the following algorithm: - * - * rssi_percentage = (avg_rssi * 100) / rssi_offset - * rx_percentage = (rx_success * 100) / rx_total - * tx_percentage = (tx_success * 100) / tx_total - * avg_signal = ((WEIGHT_RSSI * avg_rssi) + - * (WEIGHT_TX * tx_percentage) + - * (WEIGHT_RX * rx_percentage)) / 100 - * - * This value should then be checked to not be greater then 100. - * This means the values of WEIGHT_RSSI, WEIGHT_RX, WEIGHT_TX must - * sum up to 100 as well. - */ -#define WEIGHT_RSSI 20 -#define WEIGHT_RX 40 -#define WEIGHT_TX 40 - static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev) { struct link_ant *ant = &rt2x00dev->link.ant; @@ -304,46 +265,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi); } -static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev) -{ - struct link *link = &rt2x00dev->link; - struct link_qual *qual = &rt2x00dev->link.qual; - - link->rx_percentage = - PERCENTAGE(qual->rx_success, qual->rx_failed + qual->rx_success); - link->tx_percentage = - PERCENTAGE(qual->tx_success, qual->tx_failed + qual->tx_success); -} - -int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi) -{ - struct link *link = &rt2x00dev->link; - int rssi_percentage = 0; - int signal; - - /* - * We need a positive value for the RSSI. - */ - if (rssi < 0) - rssi += rt2x00dev->rssi_offset; - - /* - * Calculate the different percentages, - * which will be used for the signal. - */ - rssi_percentage = PERCENTAGE(rssi, rt2x00dev->rssi_offset); - - /* - * Add the individual percentages and use the WEIGHT - * defines to calculate the current link signal. - */ - signal = ((WEIGHT_RSSI * rssi_percentage) + - (WEIGHT_TX * link->tx_percentage) + - (WEIGHT_RX * link->rx_percentage)) / 100; - - return max_t(int, signal, 100); -} - void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) { struct link *link = &rt2x00dev->link; @@ -357,9 +278,6 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count) return; - link->rx_percentage = DEFAULT_PERCENTAGE; - link->tx_percentage = DEFAULT_PERCENTAGE; - rt2x00link_reset_tuner(rt2x00dev, false); if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) @@ -447,12 +365,6 @@ static void rt2x00link_tuner(struct work_struct *work) if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags)) rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count); - /* - * Precalculate a portion of the link signal which is - * in based on the tx/rx success/failure counters. - */ - rt2x00link_precalculate_signal(rt2x00dev); - /* * Send a signal to the led to update the led signal strength. */ -- cgit v1.2.3 From 7ab71325cf0940099c376799aca6de7bc86ad2d0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 8 Nov 2009 14:38:54 +0100 Subject: rt2800: prepare for unification of EEPROM support code * Factor out common code from rt2800[pci,usb]_validate_eeprom() to rt2800_validate_eeprom(). * Fix interface specific comment in rt2800[pci,usb]_validate_eeprom(). * Enclose interface specific code in rt2800[pci,usb]_init_eeprom() with rt2x00_intf_is_[pci,usb]() checks. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 51 +++++++++++++++++++-------------- drivers/net/wireless/rt2x00/rt2800usb.c | 40 ++++++++++++++++---------- 2 files changed, 55 insertions(+), 36 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 2f284a6f384e..67081a4f04bd 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1091,28 +1091,12 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) /* * Device probe functions. */ -static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) +static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) { u16 word; u8 *mac; u8 default_lna_gain; - /* - * Read EEPROM into buffer - */ - switch(rt2x00dev->chip.rt) { - case RT2880: - case RT3052: - rt2800pci_read_eeprom_soc(rt2x00dev); - break; - default: - if (rt2800pci_efuse_detect(rt2x00dev)) - rt2800pci_read_eeprom_efuse(rt2x00dev); - else - rt2800pci_read_eeprom_pci(rt2x00dev); - break; - } - /* * Start validation of the data that has been read. */ @@ -1131,7 +1115,7 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { /* - * There is a max of 2 RX streams for RT2860 series + * There is a max of 2 RX streams for RT28x0 series */ if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); @@ -1210,6 +1194,27 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) return 0; } +static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + /* + * Read EEPROM into buffer + */ + switch (rt2x00dev->chip.rt) { + case RT2880: + case RT3052: + rt2800pci_read_eeprom_soc(rt2x00dev); + break; + default: + if (rt2800pci_efuse_detect(rt2x00dev)) + rt2800pci_read_eeprom_efuse(rt2x00dev); + else + rt2800pci_read_eeprom_pci(rt2x00dev); + break; + } + + return rt2800_validate_eeprom(rt2x00dev); +} + static int rt2800pci_init_eeprom(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -1226,7 +1231,9 @@ static int rt2800pci_init_eeprom(struct rt2x00_dev *rt2x00dev) */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - rt2x00_set_chip_rf(rt2x00dev, value, reg); + + if (rt2x00_intf_is_pci(rt2x00dev)) + rt2x00_set_chip_rf(rt2x00dev, value, reg); if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && !rt2x00_rf(&rt2x00dev->chip, RF2850) && @@ -1234,8 +1241,10 @@ static int rt2800pci_init_eeprom(struct rt2x00_dev *rt2x00dev) !rt2x00_rf(&rt2x00dev->chip, RF2750) && !rt2x00_rf(&rt2x00dev->chip, RF3020) && !rt2x00_rf(&rt2x00dev->chip, RF2020) && - !rt2x00_rf(&rt2x00dev->chip, RF3021) && - !rt2x00_rf(&rt2x00dev->chip, RF3022)) { + (rt2x00_intf_is_usb(rt2x00dev) || + (rt2x00_intf_is_pci(rt2x00dev) && + !rt2x00_rf(&rt2x00dev->chip, RF3021) && + !rt2x00_rf(&rt2x00dev->chip, RF3022)))) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3168ad4437a4..080947cc5d6b 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -665,14 +665,12 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, /* * Device probe functions. */ -static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) +static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) { u16 word; u8 *mac; u8 default_lna_gain; - rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); - /* * Start validation of the data that has been read. */ @@ -691,7 +689,7 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { /* - * There is a max of 2 RX streams for RT2870 series + * There is a max of 2 RX streams for RT28x0 series */ if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); @@ -770,6 +768,13 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) return 0; } +static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); + + return rt2800_validate_eeprom(rt2x00dev); +} + static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -786,18 +791,23 @@ static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev) */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - rt2x00_set_chip(rt2x00dev, RT2870, value, reg); - /* - * The check for rt2860 is not a typo, some rt2870 hardware - * identifies itself as rt2860 in the CSR register. - */ - if (!rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28600000) && - !rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28700000) && - !rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28800000) && - !rt2x00_check_rev(&rt2x00dev->chip, 0xffff0000, 0x30700000)) { - ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); - return -ENODEV; + if (rt2x00_intf_is_usb(rt2x00dev)) { + struct rt2x00_chip *chip = &rt2x00dev->chip; + + rt2x00_set_chip(rt2x00dev, RT2870, value, reg); + + /* + * The check for rt2860 is not a typo, some rt2870 hardware + * identifies itself as rt2860 in the CSR register. + */ + if (!rt2x00_check_rev(chip, 0xfff00000, 0x28600000) && + !rt2x00_check_rev(chip, 0xfff00000, 0x28700000) && + !rt2x00_check_rev(chip, 0xfff00000, 0x28800000) && + !rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) { + ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); + return -ENODEV; + } } if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && -- cgit v1.2.3 From 38bd7b8a0f485ba5ad514fcd621a1842ebadf9e6 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 8 Nov 2009 14:39:01 +0100 Subject: rt2800: unify EEPROM support code Add rt2800_validate_eeprom() and rt2800_init_eeprom() to rt2800lib. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 199 ++++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800lib.h | 3 + drivers/net/wireless/rt2x00/rt2800pci.c | 183 +---------------------------- drivers/net/wireless/rt2x00/rt2800usb.c | 195 +------------------------------ 4 files changed, 204 insertions(+), 376 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 5c7d74a6f16e..2c211199e569 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1659,6 +1659,205 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) } EXPORT_SYMBOL_GPL(rt2800_init_rfcsr); +int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u16 word; + u8 *mac; + u8 default_lna_gain; + + /* + * Start validation of the data that has been read. + */ + mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); + if (!is_valid_ether_addr(mac)) { + random_ether_addr(mac); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); + } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { + /* + * There is a max of 2 RX streams for RT28x0 series + */ + if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) + rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); + if (word == 0xffff) { + rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0); + rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); + rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0); + rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0); + rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); + EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); + if ((word & 0x00ff) == 0x00ff) { + rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); + rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, + LED_MODE_TXRX_ACTIVITY); + rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221); + rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8); + EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); + } + + /* + * During the LNA validation we are going to use + * lna0 as correct value. Note that EEPROM_LNA + * is never validated. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word); + default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); + if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, + default_lna_gain); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); + if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) + rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); + if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || + rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) + rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, + default_lna_gain); + rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_validate_eeprom); + +int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 value; + u16 eeprom; + + /* + * Read EEPROM word for configuration. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Identify RF chipset. + */ + value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); + rt2800_register_read(rt2x00dev, MAC_CSR0, ®); + + if (rt2x00_intf_is_usb(rt2x00dev)) { + struct rt2x00_chip *chip = &rt2x00dev->chip; + + rt2x00_set_chip(rt2x00dev, RT2870, value, reg); + + /* + * The check for rt2860 is not a typo, some rt2870 hardware + * identifies itself as rt2860 in the CSR register. + */ + if (!rt2x00_check_rev(chip, 0xfff00000, 0x28600000) && + !rt2x00_check_rev(chip, 0xfff00000, 0x28700000) && + !rt2x00_check_rev(chip, 0xfff00000, 0x28800000) && + !rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) { + ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); + return -ENODEV; + } + } else if (rt2x00_intf_is_pci(rt2x00dev)) + rt2x00_set_chip_rf(rt2x00dev, value, reg); + + if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && + !rt2x00_rf(&rt2x00dev->chip, RF2850) && + !rt2x00_rf(&rt2x00dev->chip, RF2720) && + !rt2x00_rf(&rt2x00dev->chip, RF2750) && + !rt2x00_rf(&rt2x00dev->chip, RF3020) && + !rt2x00_rf(&rt2x00dev->chip, RF2020) && + (rt2x00_intf_is_usb(rt2x00dev) || + (rt2x00_intf_is_pci(rt2x00dev) && + !rt2x00_rf(&rt2x00dev->chip, RF3021) && + !rt2x00_rf(&rt2x00dev->chip, RF3022)))) { + ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + return -ENODEV; + } + + /* + * Identify default antenna configuration. + */ + rt2x00dev->default_ant.tx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH); + rt2x00dev->default_ant.rx = + rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH); + + /* + * Read frequency offset and RF programming sequence. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + + /* + * Read external LNA informations. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) + __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); + if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) + __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); + + /* + * Detect if this device has an hardware controlled radio. + */ + if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO)) + __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); + + /* + * Store led settings, for correct led behaviour. + */ +#ifdef CONFIG_RT2X00_LIB_LEDS + rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); + rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); + rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); +#endif /* CONFIG_RT2X00_LIB_LEDS */ + + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_init_eeprom); + /* * IEEE80211 stack callback functions. */ diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 5eea8fcba6cc..da447114c83b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -129,6 +129,9 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev); int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); +int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev); +int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev); + extern const struct ieee80211_ops rt2800_mac80211_ops; #endif /* RT2800LIB_H */ diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 67081a4f04bd..06d9835bbc56 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1091,109 +1091,6 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) /* * Device probe functions. */ -static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) -{ - u16 word; - u8 *mac; - u8 default_lna_gain; - - /* - * Start validation of the data that has been read. - */ - mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); - if (!is_valid_ether_addr(mac)) { - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %pM\n", mac); - } - - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); - if (word == 0xffff) { - rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); - rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1); - rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); - rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); - EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); - } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { - /* - * There is a max of 2 RX streams for RT28x0 series - */ - if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) - rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); - rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); - } - - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); - if (word == 0xffff) { - rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0); - rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0); - rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); - rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); - rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); - rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0); - rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0); - rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0); - rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0); - rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); - EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); - } - - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); - if ((word & 0x00ff) == 0x00ff) { - rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); - rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, - LED_MODE_TXRX_ACTIVITY); - rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); - rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555); - rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221); - rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8); - EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); - } - - /* - * During the LNA validation we are going to use - * lna0 as correct value. Note that EEPROM_LNA - * is never validated. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word); - default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); - if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || - rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) - rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, - default_lna_gain); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); - if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || - rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) - rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, - default_lna_gain); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); - - return 0; -} - static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) { /* @@ -1215,84 +1112,6 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) return rt2800_validate_eeprom(rt2x00dev); } -static int rt2800pci_init_eeprom(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - u16 value; - u16 eeprom; - - /* - * Read EEPROM word for configuration. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); - - /* - * Identify RF chipset. - */ - value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - - if (rt2x00_intf_is_pci(rt2x00dev)) - rt2x00_set_chip_rf(rt2x00dev, value, reg); - - if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && - !rt2x00_rf(&rt2x00dev->chip, RF2850) && - !rt2x00_rf(&rt2x00dev->chip, RF2720) && - !rt2x00_rf(&rt2x00dev->chip, RF2750) && - !rt2x00_rf(&rt2x00dev->chip, RF3020) && - !rt2x00_rf(&rt2x00dev->chip, RF2020) && - (rt2x00_intf_is_usb(rt2x00dev) || - (rt2x00_intf_is_pci(rt2x00dev) && - !rt2x00_rf(&rt2x00dev->chip, RF3021) && - !rt2x00_rf(&rt2x00dev->chip, RF3022)))) { - ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); - return -ENODEV; - } - - /* - * Identify default antenna configuration. - */ - rt2x00dev->default_ant.tx = - rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH); - rt2x00dev->default_ant.rx = - rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH); - - /* - * Read frequency offset and RF programming sequence. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); - rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); - - /* - * Read external LNA informations. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); - - if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) - __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); - if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) - __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); - - /* - * Detect if this device has an hardware controlled radio. - */ - if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); - - /* - * Store led settings, for correct led behaviour. - */ -#ifdef CONFIG_RT2X00_LIB_LEDS - rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); - rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); - rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); -#endif /* CONFIG_RT2X00_LIB_LEDS */ - - return 0; -} - /* * RF value list for rt2860 * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750) @@ -1497,7 +1316,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; - retval = rt2800pci_init_eeprom(rt2x00dev); + retval = rt2800_init_eeprom(rt2x00dev); if (retval) return retval; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 080947cc5d6b..347c14df63c8 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -665,109 +665,6 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, /* * Device probe functions. */ -static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) -{ - u16 word; - u8 *mac; - u8 default_lna_gain; - - /* - * Start validation of the data that has been read. - */ - mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); - if (!is_valid_ether_addr(mac)) { - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %pM\n", mac); - } - - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); - if (word == 0xffff) { - rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); - rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1); - rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); - rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); - EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); - } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { - /* - * There is a max of 2 RX streams for RT28x0 series - */ - if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) - rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); - rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); - } - - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); - if (word == 0xffff) { - rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0); - rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0); - rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0); - rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0); - rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0); - rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0); - rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0); - rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0); - rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0); - rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word); - EEPROM(rt2x00dev, "NIC: 0x%04x\n", word); - } - - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word); - if ((word & 0x00ff) == 0x00ff) { - rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0); - rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE, - LED_MODE_TXRX_ACTIVITY); - rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word); - rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555); - rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221); - rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8); - EEPROM(rt2x00dev, "Freq: 0x%04x\n", word); - } - - /* - * During the LNA validation we are going to use - * lna0 as correct value. Note that EEPROM_LNA - * is never validated. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word); - default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0); - if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 || - rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff) - rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1, - default_lna_gain); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word); - if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10) - rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0); - if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 || - rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff) - rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2, - default_lna_gain); - rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); - - return 0; -} - static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) { rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); @@ -775,96 +672,6 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) return rt2800_validate_eeprom(rt2x00dev); } -static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - u16 value; - u16 eeprom; - - /* - * Read EEPROM word for configuration. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); - - /* - * Identify RF chipset. - */ - value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - - if (rt2x00_intf_is_usb(rt2x00dev)) { - struct rt2x00_chip *chip = &rt2x00dev->chip; - - rt2x00_set_chip(rt2x00dev, RT2870, value, reg); - - /* - * The check for rt2860 is not a typo, some rt2870 hardware - * identifies itself as rt2860 in the CSR register. - */ - if (!rt2x00_check_rev(chip, 0xfff00000, 0x28600000) && - !rt2x00_check_rev(chip, 0xfff00000, 0x28700000) && - !rt2x00_check_rev(chip, 0xfff00000, 0x28800000) && - !rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) { - ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); - return -ENODEV; - } - } - - if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && - !rt2x00_rf(&rt2x00dev->chip, RF2850) && - !rt2x00_rf(&rt2x00dev->chip, RF2720) && - !rt2x00_rf(&rt2x00dev->chip, RF2750) && - !rt2x00_rf(&rt2x00dev->chip, RF3020) && - !rt2x00_rf(&rt2x00dev->chip, RF2020)) { - ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); - return -ENODEV; - } - - /* - * Identify default antenna configuration. - */ - rt2x00dev->default_ant.tx = - rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH); - rt2x00dev->default_ant.rx = - rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH); - - /* - * Read frequency offset and RF programming sequence. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); - rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); - - /* - * Read external LNA informations. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); - - if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A)) - __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); - if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG)) - __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); - - /* - * Detect if this device has an hardware controlled radio. - */ - if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO)) - __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); - - /* - * Store led settings, for correct led behaviour. - */ -#ifdef CONFIG_RT2X00_LIB_LEDS - rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO); - rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); - rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, - &rt2x00dev->led_mcu_reg); -#endif /* CONFIG_RT2X00_LIB_LEDS */ - - return 0; -} - /* * RF value list for rt2870 * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750) @@ -1093,7 +900,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (retval) return retval; - retval = rt2800usb_init_eeprom(rt2x00dev); + retval = rt2800_init_eeprom(rt2x00dev); if (retval) return retval; -- cgit v1.2.3 From 4d685e550b5ace42fdf6d72506bab6e7ae93e669 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 8 Nov 2009 14:39:09 +0100 Subject: rt2800pci: add missing RF values to rf_vals table rt2800pci's rf_vals[] copy was missing values for some channels. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 06d9835bbc56..f9ab3726d7f8 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1172,6 +1172,10 @@ static const struct rf_channel rf_vals[] = { { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 }, { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 }, { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 }, + { 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f }, + { 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 }, + { 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 }, + { 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f }, /* 802.11 Japan */ { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b }, -- cgit v1.2.3 From 726984b61e744c1fef72d20e56eadd0864ecb240 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 8 Nov 2009 14:39:16 +0100 Subject: rt2800usb: reorganize code in rt2800usb_probe_hw_mode() Move hw_mode information initialization code block before HT information initialization one to match the ordering used by rt2800pci's rt2800pci_probe_hw_mode(). Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 347c14df63c8..36acb384f328 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -794,6 +794,27 @@ static int rt2800usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + /* + * Initialize hw_mode information. + */ + spec->supported_bands = SUPPORT_BAND_2GHZ; + spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; + + if (rt2x00_rf(&rt2x00dev->chip, RF2820) || + rt2x00_rf(&rt2x00dev->chip, RF2720)) { + spec->num_channels = 14; + spec->channels = rf_vals; + } else if (rt2x00_rf(&rt2x00dev->chip, RF2850) || + rt2x00_rf(&rt2x00dev->chip, RF2750)) { + spec->supported_bands |= SUPPORT_BAND_5GHZ; + spec->num_channels = ARRAY_SIZE(rf_vals); + spec->channels = rf_vals; + } else if (rt2x00_rf(&rt2x00dev->chip, RF3020) || + rt2x00_rf(&rt2x00dev->chip, RF2020)) { + spec->num_channels = ARRAY_SIZE(rf_vals_3070); + spec->channels = rf_vals_3070; + } + /* * Initialize HT information. */ @@ -825,27 +846,6 @@ static int rt2800usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) break; } - /* - * Initialize hw_mode information. - */ - spec->supported_bands = SUPPORT_BAND_2GHZ; - spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - - if (rt2x00_rf(&rt2x00dev->chip, RF2820) || - rt2x00_rf(&rt2x00dev->chip, RF2720)) { - spec->num_channels = 14; - spec->channels = rf_vals; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2850) || - rt2x00_rf(&rt2x00dev->chip, RF2750)) { - spec->supported_bands |= SUPPORT_BAND_5GHZ; - spec->num_channels = ARRAY_SIZE(rf_vals); - spec->channels = rf_vals; - } else if (rt2x00_rf(&rt2x00dev->chip, RF3020) || - rt2x00_rf(&rt2x00dev->chip, RF2020)) { - spec->num_channels = ARRAY_SIZE(rf_vals_3070); - spec->channels = rf_vals_3070; - } - /* * Create channel information array */ -- cgit v1.2.3 From f2b38cbfd98eb36799f45178c73b2ed81402abd8 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 8 Nov 2009 14:39:25 +0100 Subject: rt2800: prepare for rt2800*_probe_hw_mode() unification Enclose interface specific code in rt2800[pci,usb]_probe_hw_mode() with rt2x00_intf_is_[pci,usb]() checks. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 24 ++++++++++++++---------- drivers/net/wireless/rt2x00/rt2800usb.c | 19 ++++++++++++------- 2 files changed, 26 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index f9ab3726d7f8..c60779069508 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1189,6 +1189,7 @@ static const struct rf_channel rf_vals[] = { static int rt2800pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { + struct rt2x00_chip *chip = &rt2x00dev->chip; struct hw_mode_spec *spec = &rt2x00dev->spec; struct channel_info *info; char *tx_power1; @@ -1204,7 +1205,9 @@ static int rt2800pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK; - rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE; + + if (rt2x00_intf_is_pci(rt2x00dev)) + rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE; SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -1219,17 +1222,18 @@ static int rt2800pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (rt2x00_rf(&rt2x00dev->chip, RF2820) || - rt2x00_rf(&rt2x00dev->chip, RF2720) || - rt2x00_rf(&rt2x00dev->chip, RF3020) || - rt2x00_rf(&rt2x00dev->chip, RF3021) || - rt2x00_rf(&rt2x00dev->chip, RF3022) || - rt2x00_rf(&rt2x00dev->chip, RF2020) || - rt2x00_rf(&rt2x00dev->chip, RF3052)) { + if (rt2x00_rf(chip, RF2820) || + rt2x00_rf(chip, RF2720) || + (rt2x00_intf_is_pci(rt2x00dev) && + (rt2x00_rf(chip, RF3020) || + rt2x00_rf(chip, RF3021) || + rt2x00_rf(chip, RF3022) || + rt2x00_rf(chip, RF2020) || + rt2x00_rf(chip, RF3052)))) { spec->num_channels = 14; spec->channels = rf_vals; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2850) || - rt2x00_rf(&rt2x00dev->chip, RF2750)) { + } else if (rt2x00_rf(chip, RF2850) || + rt2x00_rf(chip, RF2750)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals); spec->channels = rf_vals; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 36acb384f328..e86858a0e196 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -770,6 +770,7 @@ static const struct rf_channel rf_vals_3070[] = { static int rt2800usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { + struct rt2x00_chip *chip = &rt2x00dev->chip; struct hw_mode_spec *spec = &rt2x00dev->spec; struct channel_info *info; char *tx_power1; @@ -785,7 +786,10 @@ static int rt2800usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK; - rt2x00dev->hw->extra_tx_headroom = TXINFO_DESC_SIZE + TXWI_DESC_SIZE; + + if (rt2x00_intf_is_usb(rt2x00dev)) + rt2x00dev->hw->extra_tx_headroom = + TXINFO_DESC_SIZE + TXWI_DESC_SIZE; SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -800,17 +804,18 @@ static int rt2800usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->supported_bands = SUPPORT_BAND_2GHZ; spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - if (rt2x00_rf(&rt2x00dev->chip, RF2820) || - rt2x00_rf(&rt2x00dev->chip, RF2720)) { + if (rt2x00_rf(chip, RF2820) || + rt2x00_rf(chip, RF2720)) { spec->num_channels = 14; spec->channels = rf_vals; - } else if (rt2x00_rf(&rt2x00dev->chip, RF2850) || - rt2x00_rf(&rt2x00dev->chip, RF2750)) { + } else if (rt2x00_rf(chip, RF2850) || + rt2x00_rf(chip, RF2750)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals); spec->channels = rf_vals; - } else if (rt2x00_rf(&rt2x00dev->chip, RF3020) || - rt2x00_rf(&rt2x00dev->chip, RF2020)) { + } else if (rt2x00_intf_is_usb(rt2x00dev) && + (rt2x00_rf(chip, RF3020) || + rt2x00_rf(chip, RF2020))) { spec->num_channels = ARRAY_SIZE(rf_vals_3070); spec->channels = rf_vals_3070; } -- cgit v1.2.3 From 4da2933fe1f2d3d9ed548660f5c02a9b0608a8c7 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 8 Nov 2009 14:39:32 +0100 Subject: rt2800: unify rt2800*_probe_hw_mode() Add rf_vals tables and rt2800_probe_hw_mode() to rt2800lib. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 218 ++++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800lib.h | 1 + drivers/net/wireless/rt2x00/rt2800pci.c | 190 +--------------------------- drivers/net/wireless/rt2x00/rt2800usb.c | 211 +------------------------------ 4 files changed, 221 insertions(+), 399 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 2c211199e569..d7771eaee049 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1858,6 +1858,224 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) } EXPORT_SYMBOL_GPL(rt2800_init_eeprom); +/* + * RF value list for rt28x0 + * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750) + */ +static const struct rf_channel rf_vals[] = { + { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b }, + { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f }, + { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b }, + { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f }, + { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b }, + { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f }, + { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b }, + { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f }, + { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b }, + { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f }, + { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b }, + { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f }, + { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b }, + { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 }, + + /* 802.11 UNI / HyperLan 2 */ + { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 }, + { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 }, + { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 }, + { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 }, + { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b }, + { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b }, + { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 }, + { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 }, + { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b }, + { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 }, + { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 }, + { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 }, + + /* 802.11 HyperLan 2 */ + { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 }, + { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 }, + { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 }, + { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 }, + { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 }, + { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b }, + { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 }, + { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 }, + { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 }, + { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 }, + { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b }, + { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 }, + { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b }, + { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 }, + { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b }, + { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 }, + + /* 802.11 UNII */ + { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 }, + { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 }, + { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f }, + { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f }, + { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 }, + { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 }, + { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 }, + { 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f }, + { 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 }, + { 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 }, + { 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f }, + + /* 802.11 Japan */ + { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b }, + { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 }, + { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b }, + { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 }, + { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 }, + { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b }, + { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 }, +}; + +/* + * RF value list for rt3070 + * Supports: 2.4 GHz + */ +static const struct rf_channel rf_vals_3070[] = { + {1, 241, 2, 2 }, + {2, 241, 2, 7 }, + {3, 242, 2, 2 }, + {4, 242, 2, 7 }, + {5, 243, 2, 2 }, + {6, 243, 2, 7 }, + {7, 244, 2, 2 }, + {8, 244, 2, 7 }, + {9, 245, 2, 2 }, + {10, 245, 2, 7 }, + {11, 246, 2, 2 }, + {12, 246, 2, 7 }, + {13, 247, 2, 2 }, + {14, 248, 2, 4 }, +}; + +int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) +{ + struct rt2x00_chip *chip = &rt2x00dev->chip; + struct hw_mode_spec *spec = &rt2x00dev->spec; + struct channel_info *info; + char *tx_power1; + char *tx_power2; + unsigned int i; + u16 eeprom; + + /* + * Initialize all hw fields. + */ + rt2x00dev->hw->flags = + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK; + + if (rt2x00_intf_is_usb(rt2x00dev)) + rt2x00dev->hw->extra_tx_headroom = + TXINFO_DESC_SIZE + TXWI_DESC_SIZE; + else if (rt2x00_intf_is_pci(rt2x00dev)) + rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE; + + SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); + SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + + /* + * Initialize hw_mode information. + */ + spec->supported_bands = SUPPORT_BAND_2GHZ; + spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; + + if (rt2x00_rf(chip, RF2820) || + rt2x00_rf(chip, RF2720) || + (rt2x00_intf_is_pci(rt2x00dev) && + (rt2x00_rf(chip, RF3020) || + rt2x00_rf(chip, RF3021) || + rt2x00_rf(chip, RF3022) || + rt2x00_rf(chip, RF2020) || + rt2x00_rf(chip, RF3052)))) { + spec->num_channels = 14; + spec->channels = rf_vals; + } else if (rt2x00_rf(chip, RF2850) || + rt2x00_rf(chip, RF2750)) { + spec->supported_bands |= SUPPORT_BAND_5GHZ; + spec->num_channels = ARRAY_SIZE(rf_vals); + spec->channels = rf_vals; + } else if (rt2x00_intf_is_usb(rt2x00dev) && + (rt2x00_rf(chip, RF3020) || + rt2x00_rf(chip, RF2020))) { + spec->num_channels = ARRAY_SIZE(rf_vals_3070); + spec->channels = rf_vals_3070; + } + + /* + * Initialize HT information. + */ + spec->ht.ht_supported = true; + spec->ht.cap = + IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_TX_STBC | + IEEE80211_HT_CAP_RX_STBC | + IEEE80211_HT_CAP_PSMP_SUPPORT; + spec->ht.ampdu_factor = 3; + spec->ht.ampdu_density = 4; + spec->ht.mcs.tx_params = + IEEE80211_HT_MCS_TX_DEFINED | + IEEE80211_HT_MCS_TX_RX_DIFF | + ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + + switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) { + case 3: + spec->ht.mcs.rx_mask[2] = 0xff; + case 2: + spec->ht.mcs.rx_mask[1] = 0xff; + case 1: + spec->ht.mcs.rx_mask[0] = 0xff; + spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */ + break; + } + + /* + * Create channel information array + */ + info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + spec->channels_info = info; + + tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); + tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); + + for (i = 0; i < 14; i++) { + info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); + info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); + } + + if (spec->num_channels > 14) { + tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); + tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); + + for (i = 14; i < spec->num_channels; i++) { + info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); + info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_probe_hw_mode); + /* * IEEE80211 stack callback functions. */ diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index da447114c83b..2aa15f2b2c5d 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -131,6 +131,7 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev); int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev); +int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev); extern const struct ieee80211_ops rt2800_mac80211_ops; diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index c60779069508..e8fe2eabebbd 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1112,194 +1112,6 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) return rt2800_validate_eeprom(rt2x00dev); } -/* - * RF value list for rt2860 - * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750) - */ -static const struct rf_channel rf_vals[] = { - { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b }, - { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f }, - { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b }, - { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f }, - { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b }, - { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f }, - { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b }, - { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f }, - { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b }, - { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f }, - { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b }, - { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f }, - { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b }, - { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 }, - - /* 802.11 UNI / HyperLan 2 */ - { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 }, - { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 }, - { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 }, - { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 }, - { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b }, - { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b }, - { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 }, - { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 }, - { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b }, - { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 }, - { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 }, - { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 }, - - /* 802.11 HyperLan 2 */ - { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 }, - { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 }, - { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 }, - { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 }, - { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 }, - { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b }, - { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 }, - { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 }, - { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 }, - { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 }, - { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b }, - { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 }, - { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b }, - { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 }, - { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b }, - { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 }, - - /* 802.11 UNII */ - { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 }, - { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 }, - { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f }, - { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f }, - { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 }, - { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 }, - { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 }, - { 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f }, - { 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 }, - { 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 }, - { 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f }, - - /* 802.11 Japan */ - { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b }, - { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 }, - { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b }, - { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 }, - { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 }, - { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b }, - { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 }, -}; - -static int rt2800pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) -{ - struct rt2x00_chip *chip = &rt2x00dev->chip; - struct hw_mode_spec *spec = &rt2x00dev->spec; - struct channel_info *info; - char *tx_power1; - char *tx_power2; - unsigned int i; - u16 eeprom; - - /* - * Initialize all hw fields. - */ - rt2x00dev->hw->flags = - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_PS_NULLFUNC_STACK; - - if (rt2x00_intf_is_pci(rt2x00dev)) - rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE; - - SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); - SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, - rt2x00_eeprom_addr(rt2x00dev, - EEPROM_MAC_ADDR_0)); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); - - /* - * Initialize hw_mode information. - */ - spec->supported_bands = SUPPORT_BAND_2GHZ; - spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - - if (rt2x00_rf(chip, RF2820) || - rt2x00_rf(chip, RF2720) || - (rt2x00_intf_is_pci(rt2x00dev) && - (rt2x00_rf(chip, RF3020) || - rt2x00_rf(chip, RF3021) || - rt2x00_rf(chip, RF3022) || - rt2x00_rf(chip, RF2020) || - rt2x00_rf(chip, RF3052)))) { - spec->num_channels = 14; - spec->channels = rf_vals; - } else if (rt2x00_rf(chip, RF2850) || - rt2x00_rf(chip, RF2750)) { - spec->supported_bands |= SUPPORT_BAND_5GHZ; - spec->num_channels = ARRAY_SIZE(rf_vals); - spec->channels = rf_vals; - } - - /* - * Initialize HT information. - */ - spec->ht.ht_supported = true; - spec->ht.cap = - IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_GRN_FLD | - IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_TX_STBC | - IEEE80211_HT_CAP_RX_STBC | - IEEE80211_HT_CAP_PSMP_SUPPORT; - spec->ht.ampdu_factor = 3; - spec->ht.ampdu_density = 4; - spec->ht.mcs.tx_params = - IEEE80211_HT_MCS_TX_DEFINED | - IEEE80211_HT_MCS_TX_RX_DIFF | - ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - - switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) { - case 3: - spec->ht.mcs.rx_mask[2] = 0xff; - case 2: - spec->ht.mcs.rx_mask[1] = 0xff; - case 1: - spec->ht.mcs.rx_mask[0] = 0xff; - spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */ - break; - } - - /* - * Create channel information array - */ - info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - spec->channels_info = info; - - tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); - tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); - - for (i = 0; i < 14; i++) { - info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); - info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); - } - - if (spec->num_channels > 14) { - tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); - tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); - - for (i = 14; i < spec->num_channels; i++) { - info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); - info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); - } - } - - return 0; -} - static const struct rt2800_ops rt2800pci_rt2800_ops = { .register_read = rt2x00pci_register_read, .register_write = rt2x00pci_register_write, @@ -1331,7 +1143,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - retval = rt2800pci_probe_hw_mode(rt2x00dev); + retval = rt2800_probe_hw_mode(rt2x00dev); if (retval) return retval; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index e86858a0e196..67bae36ecddf 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -672,215 +672,6 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) return rt2800_validate_eeprom(rt2x00dev); } -/* - * RF value list for rt2870 - * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750) - */ -static const struct rf_channel rf_vals[] = { - { 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b }, - { 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f }, - { 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b }, - { 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f }, - { 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b }, - { 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f }, - { 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b }, - { 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f }, - { 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b }, - { 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f }, - { 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b }, - { 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f }, - { 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b }, - { 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 }, - - /* 802.11 UNI / HyperLan 2 */ - { 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 }, - { 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 }, - { 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 }, - { 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 }, - { 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b }, - { 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b }, - { 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 }, - { 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 }, - { 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b }, - { 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 }, - { 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 }, - { 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 }, - - /* 802.11 HyperLan 2 */ - { 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 }, - { 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 }, - { 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 }, - { 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 }, - { 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 }, - { 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b }, - { 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 }, - { 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 }, - { 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 }, - { 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 }, - { 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b }, - { 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 }, - { 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b }, - { 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 }, - { 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b }, - { 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 }, - - /* 802.11 UNII */ - { 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 }, - { 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 }, - { 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f }, - { 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f }, - { 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 }, - { 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 }, - { 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 }, - { 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f }, - { 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 }, - { 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 }, - { 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f }, - - /* 802.11 Japan */ - { 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b }, - { 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 }, - { 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b }, - { 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 }, - { 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 }, - { 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b }, - { 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 }, -}; - -/* - * RF value list for rt3070 - * Supports: 2.4 GHz - */ -static const struct rf_channel rf_vals_3070[] = { - {1, 241, 2, 2 }, - {2, 241, 2, 7 }, - {3, 242, 2, 2 }, - {4, 242, 2, 7 }, - {5, 243, 2, 2 }, - {6, 243, 2, 7 }, - {7, 244, 2, 2 }, - {8, 244, 2, 7 }, - {9, 245, 2, 2 }, - {10, 245, 2, 7 }, - {11, 246, 2, 2 }, - {12, 246, 2, 7 }, - {13, 247, 2, 2 }, - {14, 248, 2, 4 }, -}; - -static int rt2800usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) -{ - struct rt2x00_chip *chip = &rt2x00dev->chip; - struct hw_mode_spec *spec = &rt2x00dev->spec; - struct channel_info *info; - char *tx_power1; - char *tx_power2; - unsigned int i; - u16 eeprom; - - /* - * Initialize all hw fields. - */ - rt2x00dev->hw->flags = - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_PS_NULLFUNC_STACK; - - if (rt2x00_intf_is_usb(rt2x00dev)) - rt2x00dev->hw->extra_tx_headroom = - TXINFO_DESC_SIZE + TXWI_DESC_SIZE; - - SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); - SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, - rt2x00_eeprom_addr(rt2x00dev, - EEPROM_MAC_ADDR_0)); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); - - /* - * Initialize hw_mode information. - */ - spec->supported_bands = SUPPORT_BAND_2GHZ; - spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; - - if (rt2x00_rf(chip, RF2820) || - rt2x00_rf(chip, RF2720)) { - spec->num_channels = 14; - spec->channels = rf_vals; - } else if (rt2x00_rf(chip, RF2850) || - rt2x00_rf(chip, RF2750)) { - spec->supported_bands |= SUPPORT_BAND_5GHZ; - spec->num_channels = ARRAY_SIZE(rf_vals); - spec->channels = rf_vals; - } else if (rt2x00_intf_is_usb(rt2x00dev) && - (rt2x00_rf(chip, RF3020) || - rt2x00_rf(chip, RF2020))) { - spec->num_channels = ARRAY_SIZE(rf_vals_3070); - spec->channels = rf_vals_3070; - } - - /* - * Initialize HT information. - */ - spec->ht.ht_supported = true; - spec->ht.cap = - IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_GRN_FLD | - IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_TX_STBC | - IEEE80211_HT_CAP_RX_STBC | - IEEE80211_HT_CAP_PSMP_SUPPORT; - spec->ht.ampdu_factor = 3; - spec->ht.ampdu_density = 4; - spec->ht.mcs.tx_params = - IEEE80211_HT_MCS_TX_DEFINED | - IEEE80211_HT_MCS_TX_RX_DIFF | - ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - - switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) { - case 3: - spec->ht.mcs.rx_mask[2] = 0xff; - case 2: - spec->ht.mcs.rx_mask[1] = 0xff; - case 1: - spec->ht.mcs.rx_mask[0] = 0xff; - spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */ - break; - } - - /* - * Create channel information array - */ - info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - spec->channels_info = info; - - tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); - tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); - - for (i = 0; i < 14; i++) { - info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); - info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); - } - - if (spec->num_channels > 14) { - tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); - tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); - - for (i = 14; i < spec->num_channels; i++) { - info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); - info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); - } - } - - return 0; -} - static const struct rt2800_ops rt2800usb_rt2800_ops = { .register_read = rt2x00usb_register_read, .register_write = rt2x00usb_register_write, @@ -912,7 +703,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * Initialize hw specifications. */ - retval = rt2800usb_probe_hw_mode(rt2x00dev); + retval = rt2800_probe_hw_mode(rt2x00dev); if (retval) return retval; -- cgit v1.2.3 From 4116cb483ec148e30f70408ad0600304a5de2a3c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 8 Nov 2009 14:39:40 +0100 Subject: rt2800usb: fix RX descriptor naming Rename RXD_W0_* defines to RXINFO_W0_* ones to match naming used for TX descriptor and by the vendor driver. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 10 ++++----- drivers/net/wireless/rt2x00/rt2800usb.h | 40 ++++++++++++++++----------------- 2 files changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 67bae36ecddf..a6b0484d5816 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -594,16 +594,16 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, rt2x00_desc_read(rxwi, 2, &rxwi2); rt2x00_desc_read(rxwi, 3, &rxwi3); - if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR)) + if (rt2x00_get_field32(rxd0, RXINFO_W0_CRC_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF); rxdesc->cipher_status = - rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR); + rt2x00_get_field32(rxd0, RXINFO_W0_CIPHER_ERROR); } - if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) { + if (rt2x00_get_field32(rxd0, RXINFO_W0_DECRYPTED)) { /* * Hardware has stripped IV/EIV data from 802.11 frame during * decryption. Unfortunately the descriptor doesn't contain @@ -618,10 +618,10 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, rxdesc->flags |= RX_FLAG_MMIC_ERROR; } - if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS)) + if (rt2x00_get_field32(rxd0, RXINFO_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; - if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) { + if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) { rxdesc->dev_flags |= RXDONE_L2PAD; skbdesc->flags |= SKBDESC_L2_PADDED; } diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index c9d7d40ee5fb..8f317446eca4 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -111,25 +111,25 @@ * AMSDU: rx with 802.3 header, not 802.11 header. */ -#define RXD_W0_BA FIELD32(0x00000001) -#define RXD_W0_DATA FIELD32(0x00000002) -#define RXD_W0_NULLDATA FIELD32(0x00000004) -#define RXD_W0_FRAG FIELD32(0x00000008) -#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000010) -#define RXD_W0_MULTICAST FIELD32(0x00000020) -#define RXD_W0_BROADCAST FIELD32(0x00000040) -#define RXD_W0_MY_BSS FIELD32(0x00000080) -#define RXD_W0_CRC_ERROR FIELD32(0x00000100) -#define RXD_W0_CIPHER_ERROR FIELD32(0x00000600) -#define RXD_W0_AMSDU FIELD32(0x00000800) -#define RXD_W0_HTC FIELD32(0x00001000) -#define RXD_W0_RSSI FIELD32(0x00002000) -#define RXD_W0_L2PAD FIELD32(0x00004000) -#define RXD_W0_AMPDU FIELD32(0x00008000) -#define RXD_W0_DECRYPTED FIELD32(0x00010000) -#define RXD_W0_PLCP_RSSI FIELD32(0x00020000) -#define RXD_W0_CIPHER_ALG FIELD32(0x00040000) -#define RXD_W0_LAST_AMSDU FIELD32(0x00080000) -#define RXD_W0_PLCP_SIGNAL FIELD32(0xfff00000) +#define RXINFO_W0_BA FIELD32(0x00000001) +#define RXINFO_W0_DATA FIELD32(0x00000002) +#define RXINFO_W0_NULLDATA FIELD32(0x00000004) +#define RXINFO_W0_FRAG FIELD32(0x00000008) +#define RXINFO_W0_UNICAST_TO_ME FIELD32(0x00000010) +#define RXINFO_W0_MULTICAST FIELD32(0x00000020) +#define RXINFO_W0_BROADCAST FIELD32(0x00000040) +#define RXINFO_W0_MY_BSS FIELD32(0x00000080) +#define RXINFO_W0_CRC_ERROR FIELD32(0x00000100) +#define RXINFO_W0_CIPHER_ERROR FIELD32(0x00000600) +#define RXINFO_W0_AMSDU FIELD32(0x00000800) +#define RXINFO_W0_HTC FIELD32(0x00001000) +#define RXINFO_W0_RSSI FIELD32(0x00002000) +#define RXINFO_W0_L2PAD FIELD32(0x00004000) +#define RXINFO_W0_AMPDU FIELD32(0x00008000) +#define RXINFO_W0_DECRYPTED FIELD32(0x00010000) +#define RXINFO_W0_PLCP_RSSI FIELD32(0x00020000) +#define RXINFO_W0_CIPHER_ALG FIELD32(0x00040000) +#define RXINFO_W0_LAST_AMSDU FIELD32(0x00080000) +#define RXINFO_W0_PLCP_SIGNAL FIELD32(0xfff00000) #endif /* RT2800USB_H */ -- cgit v1.2.3 From 30e840346c516ad4e36f710fa485933ccc7afa66 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 8 Nov 2009 14:39:48 +0100 Subject: rt2800: add eFuse EEPROM support code to rt2800lib eFuse EEPROM is used also by USB chips (i.e. RT3070) so move the needed code from rt2800pci to rt2800lib. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 29 ++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800lib.c | 43 +++++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800lib.h | 2 ++ drivers/net/wireless/rt2x00/rt2800pci.c | 38 +++-------------------------- drivers/net/wireless/rt2x00/rt2800pci.h | 29 ---------------------- 5 files changed, 77 insertions(+), 64 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index d9b6a72e6d27..74fb5253ee23 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -361,6 +361,35 @@ #define RF_CSR_CFG_WRITE FIELD32(0x00010000) #define RF_CSR_CFG_BUSY FIELD32(0x00020000) +/* + * EFUSE_CSR: RT30x0 EEPROM + */ +#define EFUSE_CTRL 0x0580 +#define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000) +#define EFUSE_CTRL_MODE FIELD32(0x000000c0) +#define EFUSE_CTRL_KICK FIELD32(0x40000000) +#define EFUSE_CTRL_PRESENT FIELD32(0x80000000) + +/* + * EFUSE_DATA0 + */ +#define EFUSE_DATA0 0x0590 + +/* + * EFUSE_DATA1 + */ +#define EFUSE_DATA1 0x0594 + +/* + * EFUSE_DATA2 + */ +#define EFUSE_DATA2 0x0598 + +/* + * EFUSE_DATA3 + */ +#define EFUSE_DATA3 0x059c + /* * MAC Control/Status Registers(CSR). * Some values are set in TU, whereas 1 TU == 1024 us. diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index d7771eaee049..f207e9fa5b98 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1659,6 +1659,49 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) } EXPORT_SYMBOL_GPL(rt2800_init_rfcsr); +int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2800_register_read(rt2x00dev, EFUSE_CTRL, ®); + + return rt2x00_get_field32(reg, EFUSE_CTRL_PRESENT); +} +EXPORT_SYMBOL_GPL(rt2800_efuse_detect); + +static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) +{ + u32 reg; + + rt2800_register_read(rt2x00dev, EFUSE_CTRL, ®); + rt2x00_set_field32(®, EFUSE_CTRL_ADDRESS_IN, i); + rt2x00_set_field32(®, EFUSE_CTRL_MODE, 0); + rt2x00_set_field32(®, EFUSE_CTRL_KICK, 1); + rt2800_register_write(rt2x00dev, EFUSE_CTRL, reg); + + /* Wait until the EEPROM has been loaded */ + rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®); + + /* Apparently the data is read from end to start */ + rt2800_register_read(rt2x00dev, EFUSE_DATA3, + (u32 *)&rt2x00dev->eeprom[i]); + rt2800_register_read(rt2x00dev, EFUSE_DATA2, + (u32 *)&rt2x00dev->eeprom[i + 2]); + rt2800_register_read(rt2x00dev, EFUSE_DATA1, + (u32 *)&rt2x00dev->eeprom[i + 4]); + rt2800_register_read(rt2x00dev, EFUSE_DATA0, + (u32 *)&rt2x00dev->eeprom[i + 6]); +} + +void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + + for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8) + rt2800_efuse_read(rt2x00dev, i); +} +EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse); + int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) { u16 word; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 2aa15f2b2c5d..7c790118999b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -129,6 +129,8 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev); int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); +int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev); +void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev); int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev); int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index e8fe2eabebbd..6f151d0c6b02 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -147,44 +147,12 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev) { - u32 reg; - - rt2800_register_read(rt2x00dev, EFUSE_CTRL, ®); - - return rt2x00_get_field32(reg, EFUSE_CTRL_PRESENT); + return rt2800_efuse_detect(rt2x00dev); } -static void rt2800pci_efuse_read(struct rt2x00_dev *rt2x00dev, - unsigned int i) -{ - u32 reg; - - rt2800_register_read(rt2x00dev, EFUSE_CTRL, ®); - rt2x00_set_field32(®, EFUSE_CTRL_ADDRESS_IN, i); - rt2x00_set_field32(®, EFUSE_CTRL_MODE, 0); - rt2x00_set_field32(®, EFUSE_CTRL_KICK, 1); - rt2800_register_write(rt2x00dev, EFUSE_CTRL, reg); - - /* Wait until the EEPROM has been loaded */ - rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®); - - /* Apparently the data is read from end to start */ - rt2800_register_read(rt2x00dev, EFUSE_DATA3, - (u32 *)&rt2x00dev->eeprom[i]); - rt2800_register_read(rt2x00dev, EFUSE_DATA2, - (u32 *)&rt2x00dev->eeprom[i + 2]); - rt2800_register_read(rt2x00dev, EFUSE_DATA1, - (u32 *)&rt2x00dev->eeprom[i + 4]); - rt2800_register_read(rt2x00dev, EFUSE_DATA0, - (u32 *)&rt2x00dev->eeprom[i + 6]); -} - -static void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) +static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) { - unsigned int i; - - for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8) - rt2800pci_efuse_read(rt2x00dev, i); + rt2800_read_eeprom_efuse(rt2x00dev); } #else static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index 8f944ee8a970..b866dd01f286 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -55,35 +55,6 @@ #define TX_CTX_IDX(__x) TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) #define TX_DTX_IDX(__x) TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) -/* - * EFUSE_CSR: RT3090 EEPROM - */ -#define EFUSE_CTRL 0x0580 -#define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000) -#define EFUSE_CTRL_MODE FIELD32(0x000000c0) -#define EFUSE_CTRL_KICK FIELD32(0x40000000) -#define EFUSE_CTRL_PRESENT FIELD32(0x80000000) - -/* - * EFUSE_DATA0 - */ -#define EFUSE_DATA0 0x0590 - -/* - * EFUSE_DATA1 - */ -#define EFUSE_DATA1 0x0594 - -/* - * EFUSE_DATA2 - */ -#define EFUSE_DATA2 0x0598 - -/* - * EFUSE_DATA3 - */ -#define EFUSE_DATA3 0x059c - /* * 8051 firmware image. */ -- cgit v1.2.3 From 40beee5c15a816bf77747e15940ac3b97229faf4 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 8 Nov 2009 14:39:55 +0100 Subject: rt2800usb: add eFuse EEPROM support It is needed for at least RT3070 chip. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index a6b0484d5816..54afbc8378df 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -667,7 +667,11 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, */ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) { - rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE); + if (rt2800_efuse_detect(rt2x00dev)) + rt2800_read_eeprom_efuse(rt2x00dev); + else + rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, + EEPROM_SIZE); return rt2800_validate_eeprom(rt2x00dev); } -- cgit v1.2.3 From 6aefbfa0204b1dab4b9f23ca30f8840ba0d9134a Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 8 Nov 2009 14:43:35 +0100 Subject: rt2500usb: remove dead link tuning code Link tuning code from the legacy rt2570 driver turned out to be harmful and got disabled by the commit d06193f ("rt2x00: Disable link tuning in rt2500usb") in August 2008. There is no reason to keep this dead code any longer so remove it (it can still be retrieved from the git history if necessary). Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 134 -------------------------------- 1 file changed, 134 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 22dd6d9e2981..6acd8e8ae6e2 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -715,139 +715,6 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev, qual->vgc_level = value; } -/* - * NOTE: This function is directly ported from legacy driver, but - * despite it being declared it was never called. Although link tuning - * sounds like a good idea, and usually works well for the other drivers, - * it does _not_ work with rt2500usb. Enabling this function will result - * in TX capabilities only until association kicks in. Immediately - * after the successful association all TX frames will be kept in the - * hardware queue and never transmitted. - */ -#if 0 -static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) -{ - int rssi = rt2x00_get_link_rssi(&rt2x00dev->link); - u16 bbp_thresh; - u16 vgc_bound; - u16 sens; - u16 r24; - u16 r25; - u16 r61; - u16 r17_sens; - u8 r17; - u8 up_bound; - u8 low_bound; - - /* - * Read current r17 value, as well as the sensitivity values - * for the r17 register. - */ - rt2500usb_bbp_read(rt2x00dev, 17, &r17); - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound); - up_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER); - low_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCLOWER); - - /* - * If we are not associated, we should go straight to the - * dynamic CCA tuning. - */ - if (!rt2x00dev->intf_associated) - goto dynamic_cca_tune; - - /* - * Determine the BBP tuning threshold and correctly - * set BBP 24, 25 and 61. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &bbp_thresh); - bbp_thresh = rt2x00_get_field16(bbp_thresh, EEPROM_BBPTUNE_THRESHOLD); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &r24); - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &r25); - rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &r61); - - if ((rssi + bbp_thresh) > 0) { - r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_HIGH); - r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_HIGH); - r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_HIGH); - } else { - r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_LOW); - r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_LOW); - r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_LOW); - } - - rt2500usb_bbp_write(rt2x00dev, 24, r24); - rt2500usb_bbp_write(rt2x00dev, 25, r25); - rt2500usb_bbp_write(rt2x00dev, 61, r61); - - /* - * A too low RSSI will cause too much false CCA which will - * then corrupt the R17 tuning. To remidy this the tuning should - * be stopped (While making sure the R17 value will not exceed limits) - */ - if (rssi >= -40) { - if (r17 != 0x60) - rt2500usb_bbp_write(rt2x00dev, 17, 0x60); - return; - } - - /* - * Special big-R17 for short distance - */ - if (rssi >= -58) { - sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_LOW); - if (r17 != sens) - rt2500usb_bbp_write(rt2x00dev, 17, sens); - return; - } - - /* - * Special mid-R17 for middle distance - */ - if (rssi >= -74) { - sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_HIGH); - if (r17 != sens) - rt2500usb_bbp_write(rt2x00dev, 17, sens); - return; - } - - /* - * Leave short or middle distance condition, restore r17 - * to the dynamic tuning range. - */ - low_bound = 0x32; - if (rssi < -77) - up_bound -= (-77 - rssi); - - if (up_bound < low_bound) - up_bound = low_bound; - - if (r17 > up_bound) { - rt2500usb_bbp_write(rt2x00dev, 17, up_bound); - rt2x00dev->link.vgc_level = up_bound; - return; - } - -dynamic_cca_tune: - - /* - * R17 is inside the dynamic tuning range, - * start tuning the link based on the false cca counter. - */ - if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) { - rt2500usb_bbp_write(rt2x00dev, 17, ++r17); - rt2x00dev->link.vgc_level = r17; - } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) { - rt2500usb_bbp_write(rt2x00dev, 17, --r17); - rt2x00dev->link.vgc_level = r17; - } -} -#else -#define rt2500usb_link_tuner NULL -#endif - /* * Initialization functions. */ @@ -1910,7 +1777,6 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .rfkill_poll = rt2500usb_rfkill_poll, .link_stats = rt2500usb_link_stats, .reset_tuner = rt2500usb_reset_tuner, - .link_tuner = rt2500usb_link_tuner, .write_tx_desc = rt2500usb_write_tx_desc, .write_tx_data = rt2x00usb_write_tx_data, .write_beacon = rt2500usb_write_beacon, -- cgit v1.2.3 From 9c9a0d145fee73b5e821bb460732ac2a66c680b3 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 8 Nov 2009 16:39:55 +0100 Subject: rt2x00: Update copyright statements. As mentioned on the linux-wireless mailing list, the current copyright statements in the rt2x00 are meaningless, as the rt2x00 project is not even a formal legal entity. Therefore it is better to replace the existing copyright statements with copyright statements for the people that actually wrote the code. Note: Updated to the best of my knowledge with respect to who contributed considerable amounts of code. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn CC: Bartlomiej Zolnierkiewicz Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/rt2x00/rt2400pci.h | 2 +- drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500pci.h | 2 +- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2500usb.h | 2 +- drivers/net/wireless/rt2x00/rt2800.h | 9 ++++++++- drivers/net/wireless/rt2x00/rt2800lib.c | 15 ++++++++++----- drivers/net/wireless/rt2x00/rt2800pci.c | 9 ++++++++- drivers/net/wireless/rt2x00/rt2800pci.h | 9 ++++++++- drivers/net/wireless/rt2x00/rt2800usb.c | 6 +++++- drivers/net/wireless/rt2x00/rt2800usb.h | 6 +++++- drivers/net/wireless/rt2x00/rt2x00.h | 3 ++- drivers/net/wireless/rt2x00/rt2x00config.c | 2 +- drivers/net/wireless/rt2x00/rt2x00crypto.c | 2 +- drivers/net/wireless/rt2x00/rt2x00debug.c | 2 +- drivers/net/wireless/rt2x00/rt2x00debug.h | 2 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 2 +- drivers/net/wireless/rt2x00/rt2x00dump.h | 2 +- drivers/net/wireless/rt2x00/rt2x00firmware.c | 3 ++- drivers/net/wireless/rt2x00/rt2x00ht.c | 2 +- drivers/net/wireless/rt2x00/rt2x00leds.c | 2 +- drivers/net/wireless/rt2x00/rt2x00leds.h | 2 +- drivers/net/wireless/rt2x00/rt2x00lib.h | 3 ++- drivers/net/wireless/rt2x00/rt2x00link.c | 2 +- drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +- drivers/net/wireless/rt2x00/rt2x00pci.c | 2 +- drivers/net/wireless/rt2x00/rt2x00pci.h | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 3 ++- drivers/net/wireless/rt2x00/rt2x00queue.h | 2 +- drivers/net/wireless/rt2x00/rt2x00reg.h | 2 +- drivers/net/wireless/rt2x00/rt2x00soc.c | 3 ++- drivers/net/wireless/rt2x00/rt2x00soc.h | 2 +- drivers/net/wireless/rt2x00/rt2x00usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00usb.h | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt61pci.h | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.h | 2 +- 39 files changed, 82 insertions(+), 43 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 798f625e38f7..0f912f51a15a 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index ccd644104ad1..6c21ef66dfe0 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 2e872ac69826..6618cbd808b3 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 54d37957883c..b0075674c09b 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 6acd8e8ae6e2..bb64473dae67 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index b01edca42583..341a70454635 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 74fb5253ee23..c5fe867665e6 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1,5 +1,12 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn + Copyright (C) 2009 Alban Browaeys + Copyright (C) 2009 Felix Fietkau + Copyright (C) 2009 Luis Correia + Copyright (C) 2009 Mattias Nissler + Copyright (C) 2009 Mark Asselstine + Copyright (C) 2009 Xose Vazquez Perez + Copyright (C) 2009 Bart Zolnierkiewicz This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index f207e9fa5b98..a0d5901bf50b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1,9 +1,14 @@ /* - Copyright (C) 2009 Bartlomiej Zolnierkiewicz - - Based on the original rt2800pci.c and rt2800usb.c: - - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2009 Bartlomiej Zolnierkiewicz + + Based on the original rt2800pci.c and rt2800usb.c. + Copyright (C) 2009 Ivo van Doorn + Copyright (C) 2009 Alban Browaeys + Copyright (C) 2009 Felix Fietkau + Copyright (C) 2009 Luis Correia + Copyright (C) 2009 Mattias Nissler + Copyright (C) 2009 Mark Asselstine + Copyright (C) 2009 Xose Vazquez Perez This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 6f151d0c6b02..c7a596f2da39 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1,5 +1,12 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2009 Ivo van Doorn + Copyright (C) 2009 Alban Browaeys + Copyright (C) 2009 Felix Fietkau + Copyright (C) 2009 Luis Correia + Copyright (C) 2009 Mattias Nissler + Copyright (C) 2009 Mark Asselstine + Copyright (C) 2009 Xose Vazquez Perez + Copyright (C) 2009 Bart Zolnierkiewicz This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index b866dd01f286..afc8e7da27cb 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -1,5 +1,12 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2009 Ivo van Doorn + Copyright (C) 2009 Alban Browaeys + Copyright (C) 2009 Felix Fietkau + Copyright (C) 2009 Luis Correia + Copyright (C) 2009 Mattias Nissler + Copyright (C) 2009 Mark Asselstine + Copyright (C) 2009 Xose Vazquez Perez + Copyright (C) 2009 Bart Zolnierkiewicz This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 54afbc8378df..b57999ba8d93 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1,5 +1,9 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2009 Ivo van Doorn + Copyright (C) 2009 Mattias Nissler + Copyright (C) 2009 Felix Fietkau + Copyright (C) 2009 Xose Vazquez Perez + Copyright (C) 2009 Axel Kollhofer This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 8f317446eca4..1e4340a182ef 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -1,5 +1,9 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2009 Ivo van Doorn + Copyright (C) 2009 Mattias Nissler + Copyright (C) 2009 Felix Fietkau + Copyright (C) 2009 Xose Vazquez Perez + Copyright (C) 2009 Axel Kollhofer This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 1a84574a26d3..5a1b1612dcaa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1,5 +1,6 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn + Copyright (C) 2004 - 2009 Gertjan van Wingerde This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 40a201e2e151..098315a271ca 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index de36837dcf86..d291c7862e10 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 7b3ee8c2eaef..e6b0fbbc3fc7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h index 035cbc98c593..fa11409cb5c6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.h +++ b/drivers/net/wireless/rt2x00/rt2x00debug.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 00bfb2255ceb..6c6d0ac35549 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h index fdedb5122928..727019a748e7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dump.h +++ b/drivers/net/wireless/rt2x00/rt2x00dump.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index d2deea2f2679..34beb00c4347 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -1,5 +1,6 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn + Copyright (C) 2004 - 2009 Gertjan van Wingerde This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c index e3cec839e540..1056c92143a8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c index 49671fed91d7..ca585e34d00e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00leds.c +++ b/drivers/net/wireless/rt2x00/rt2x00leds.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.h b/drivers/net/wireless/rt2x00/rt2x00leds.h index 8e03c045e037..3b46f0c3332a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00leds.h +++ b/drivers/net/wireless/rt2x00/rt2x00leds.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index e17016572c3f..c1f48acaee41 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -1,5 +1,6 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn + Copyright (C) 2004 - 2009 Gertjan van Wingerde This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index f918f29e2d73..0efbf5a6c254 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 929b85f34f38..eed093d34532 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index ece70d72880f..0feb4d0e4668 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index ae33eebe9a6f..d4f9449ab0a4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 577029efe320..02972a036bce 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -1,5 +1,6 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn + Copyright (C) 2004 - 2009 Gertjan van Wingerde This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index a5591fb2b191..97c7895c0ece 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 983e52e127a7..603bfc0adaa3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c index 4abcfa6bf1b2..19e684f8ffa1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/rt2x00/rt2x00soc.c @@ -1,5 +1,6 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn + Copyright (C) 2004 - 2009 Felix Fietkau This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.h b/drivers/net/wireless/rt2x00/rt2x00soc.h index 5cf114ac2b9c..8a3416624af5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00soc.h +++ b/drivers/net/wireless/rt2x00/rt2x00soc.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index aa6c31d612a7..0a751e73aa0f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 1c9d6cafb057..3da6841b5d42 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index b20e3eac9d67..ea8a86f4462d 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 93eb699165cc..6f33f7f5668c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 14e7bb210075..7236f017910d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 81fe0be51c42..e783a099a8f1 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + Copyright (C) 2004 - 2009 Ivo van Doorn This program is free software; you can redistribute it and/or modify -- cgit v1.2.3 From a6ef92ad3588d4e011295bf724f88e7d5b8c0e1b Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Sun, 8 Nov 2009 18:58:01 -0500 Subject: at76c50x-usb: Remove mac2str and replace with %pM format specifier. Signed-off-by: Jason Andryuk Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/at76c50x-usb.c | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 0a917e44b22c..be2e5962319b 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -532,20 +532,6 @@ static char *hex2str(void *buf, int len) return ret; } -#define MAC2STR_BUFFERS 4 - -static inline char *mac2str(u8 *mac) -{ - static atomic_t a = ATOMIC_INIT(0); - static char bufs[MAC2STR_BUFFERS][6 * 3]; - char *str; - - str = bufs[atomic_inc_return(&a) & (MAC2STR_BUFFERS - 1)]; - sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - return str; -} - /* LED trigger */ static int tx_activity; static void at76_ledtrig_tx_timerfunc(unsigned long data); @@ -981,13 +967,13 @@ static void at76_dump_mib_mac_addr(struct at76_priv *priv) goto exit; } - at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x", + at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %pM res 0x%x 0x%x", wiphy_name(priv->hw->wiphy), - mac2str(m->mac_addr), m->res[0], m->res[1]); + m->mac_addr, m->res[0], m->res[1]); for (i = 0; i < ARRAY_SIZE(m->group_addr); i++) - at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %s, " + at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %pM, " "status %d", wiphy_name(priv->hw->wiphy), i, - mac2str(m->group_addr[i]), m->group_addr_status[i]); + m->group_addr[i], m->group_addr_status[i]); exit: kfree(m); } @@ -1050,7 +1036,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv) at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration " "%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d " "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d " - "current_bssid %s current_essid %s current_bss_type %d " + "current_bssid %pM current_essid %s current_bss_type %d " "pm_mode %d ibss_change %d res %d " "multi_domain_capability_implemented %d " "international_roaming %d country_string %.3s", @@ -1059,7 +1045,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv) le16_to_cpu(m->medium_occupancy_limit), le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window), m->CFP_mode, m->privacy_option_implemented, m->DTIM_period, - m->CFP_period, mac2str(m->current_bssid), + m->CFP_period, m->current_bssid, hex2str(m->current_essid, IW_ESSID_MAX_SIZE), m->current_bss_type, m->power_mgmt_mode, m->ibss_change, m->res, m->multi_domain_capability_implemented, @@ -1088,7 +1074,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv) "cwmin %d cwmax %d short_retry_time %d long_retry_time %d " "scan_type %d scan_channel %d probe_delay %u " "min_channel_time %d max_channel_time %d listen_int %d " - "desired_ssid %s desired_bssid %s desired_bsstype %d", + "desired_ssid %s desired_bssid %pM desired_bsstype %d", wiphy_name(priv->hw->wiphy), le32_to_cpu(m->max_tx_msdu_lifetime), le32_to_cpu(m->max_rx_lifetime), @@ -1100,7 +1086,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv) le16_to_cpu(m->max_channel_time), le16_to_cpu(m->listen_interval), hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE), - mac2str(m->desired_bssid), m->desired_bsstype); + m->desired_bssid, m->desired_bsstype); exit: kfree(m); } @@ -2292,9 +2278,9 @@ static int at76_init_new_device(struct at76_priv *priv, priv->mac80211_registered = 1; - printk(KERN_INFO "%s: USB %s, MAC %s, firmware %d.%d.%d-%d\n", + printk(KERN_INFO "%s: USB %s, MAC %pM, firmware %d.%d.%d-%d\n", wiphy_name(priv->hw->wiphy), - dev_name(&interface->dev), mac2str(priv->mac_addr), + dev_name(&interface->dev), priv->mac_addr, priv->fw_version.major, priv->fw_version.minor, priv->fw_version.patch, priv->fw_version.build); printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n", -- cgit v1.2.3 From 13b409cc8c1614090f256729ee0038438a6946f7 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Sun, 8 Nov 2009 19:02:19 -0500 Subject: at76c50x-usb: Supply additional parameters to at76_start_monitor scan request For my Linksys WUSB11 at76c503-i3861 device, scanning fails without probe_delay, min_channel_time, and max_channel_time specified for the scan request. These values were found by checking scan requests from the at76_usb driver. Signed-off-by: Jason Andryuk Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/at76c50x-usb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index be2e5962319b..2517364d3ebe 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1188,6 +1188,9 @@ static int at76_start_monitor(struct at76_priv *priv) scan.channel = priv->channel; scan.scan_type = SCAN_TYPE_PASSIVE; scan.international_scan = 0; + scan.min_channel_time = cpu_to_le16(priv->scan_min_time); + scan.max_channel_time = cpu_to_le16(priv->scan_max_time); + scan.probe_delay = cpu_to_le16(0); ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan)); if (ret >= 0) -- cgit v1.2.3 From b34e620faa843d746400e324580e9a9efd457e4d Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Mon, 9 Nov 2009 09:45:50 +0100 Subject: rt2x00: fix some typos and punctuation in comments fix some typos and punctuation in comments Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Jiri Kosina Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index ea8a86f4462d..6e4613517461 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -51,7 +51,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * These indirect registers work with busy bits, * and we will try maximal REGISTER_BUSY_COUNT times to access * the register while taking a REGISTER_BUSY_DELAY us delay - * between each attampt. When the busy bit is still set at that time, + * between each attempt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. */ @@ -386,7 +386,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, * The driver does not support the IV/EIV generation * in hardware. However it doesn't support the IV/EIV * inside the ieee80211 frame either, but requires it - * to be provided seperately for the descriptor. + * to be provided separately for the descriptor. * rt2x00lib will cut the IV/EIV data out of all frames * given to us by mac80211, but we must tell mac80211 * to generate the IV/EIV data. @@ -397,7 +397,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev, /* * SEC_CSR0 contains only single-bit fields to indicate * a particular key is valid. Because using the FIELD32() - * defines directly will cause a lot of overhead we use + * defines directly will cause a lot of overhead, we use * a calculation to determine the correct bit directly. */ mask = 1 << key->hw_key_idx; @@ -425,11 +425,11 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, /* * rt2x00lib can't determine the correct free * key_idx for pairwise keys. We have 2 registers - * with key valid bits. The goal is simple, read - * the first register, if that is full move to + * with key valid bits. The goal is simple: read + * the first register. If that is full, move to * the next register. - * When both registers are full, we drop the key, - * otherwise we use the first invalid entry. + * When both registers are full, we drop the key. + * Otherwise, we use the first invalid entry. */ rt2x00pci_register_read(rt2x00dev, SEC_CSR2, ®); if (reg && reg == ~0) { @@ -464,8 +464,8 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, &addr_entry, sizeof(addr_entry)); /* - * Enable pairwise lookup table for given BSS idx, - * without this received frames will not be decrypted + * Enable pairwise lookup table for given BSS idx. + * Without this, received frames will not be decrypted * by the hardware. */ rt2x00pci_register_read(rt2x00dev, SEC_CSR4, ®); @@ -487,7 +487,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev, /* * SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate * a particular key is valid. Because using the FIELD32() - * defines directly will cause a lot of overhead we use + * defines directly will cause a lot of overhead, we use * a calculation to determine the correct bit directly. */ if (key->hw_key_idx < 32) { @@ -556,7 +556,7 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev, if (flags & CONFIG_UPDATE_TYPE) { /* * Clear current synchronisation setup. - * For the Beacon base registers we only need to clear + * For the Beacon base registers, we only need to clear * the first byte since that byte contains the VALID and OWNER * bits which (when set to 0) will invalidate the entire beacon. */ @@ -1168,8 +1168,8 @@ static int rt61pci_check_firmware(struct rt2x00_dev *rt2x00dev, return FW_BAD_LENGTH; /* - * The last 2 bytes in the firmware array are the crc checksum itself, - * this means that we should never pass those 2 bytes to the crc + * The last 2 bytes in the firmware array are the crc checksum itself. + * This means that we should never pass those 2 bytes to the crc * algorithm. */ fw_crc = (data[len - 2] << 8 | data[len - 1]); @@ -1986,7 +1986,7 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, /* * Hardware has stripped IV/EIV data from 802.11 frame during - * decryption. It has provided the data seperately but rt2x00lib + * decryption. It has provided the data separately but rt2x00lib * should decide if it should be reinserted. */ rxdesc->flags |= RX_FLAG_IV_STRIPPED; @@ -2042,7 +2042,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) * During each loop we will compare the freshly read * STA_CSR4 register value with the value read from * the previous loop. If the 2 values are equal then - * we should stop processing because the chance it + * we should stop processing because the chance is * quite big that the device has been unplugged and * we risk going into an endless loop. */ @@ -2330,7 +2330,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); /* - * Detect if this device has an hardware controlled radio. + * Detect if this device has a hardware controlled radio. */ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags); @@ -2355,7 +2355,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); /* - * When working with a RF2529 chip without double antenna + * When working with a RF2529 chip without double antenna, * the antenna settings should be gathered from the NIC * eeprom word. */ @@ -2668,7 +2668,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, /* * We only need to perform additional register initialization - * for WMM queues/ + * for WMM queues. */ if (queue_idx >= 4) return 0; -- cgit v1.2.3 From 41a2617064a8458178ccdf31ed2be2b4eade4a2a Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 9 Nov 2009 22:59:04 +0100 Subject: rt2x00: Fix typo in rf programming of rt2800lib. Fix a type in rt2800_config_channel_rt3x. The second write to RF register 2 should be to RF register 3. This is confirmed by the legacy Ralink code. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index a0d5901bf50b..eb6d12911b9a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -774,7 +774,7 @@ static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, u8 rfcsr; rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); - rt2800_rfcsr_write(rt2x00dev, 2, rf->rf3); + rt2800_rfcsr_write(rt2x00dev, 3, rf->rf3); rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); -- cgit v1.2.3 From f273fe55e3f3f0b66b7624c0102d3ef44bbdfe6a Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Tue, 10 Nov 2009 22:41:51 +0100 Subject: rt2x00: Properly detect Ralink RT3070 devices. Allow rt2800usb to properly detect RT307X based devices, and set the appropriate chipset values. Signed-off-by: Gertjan van Wingede Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 28 +++++++++++++++------------- drivers/net/wireless/rt2x00/rt2x00.h | 1 + 2 files changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index eb6d12911b9a..c41bb4a59d16 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1828,24 +1828,26 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2800_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00_set_chip_rf(rt2x00dev, value, reg); + if (rt2x00_intf_is_usb(rt2x00dev)) { struct rt2x00_chip *chip = &rt2x00dev->chip; - rt2x00_set_chip(rt2x00dev, RT2870, value, reg); - /* * The check for rt2860 is not a typo, some rt2870 hardware * identifies itself as rt2860 in the CSR register. */ - if (!rt2x00_check_rev(chip, 0xfff00000, 0x28600000) && - !rt2x00_check_rev(chip, 0xfff00000, 0x28700000) && - !rt2x00_check_rev(chip, 0xfff00000, 0x28800000) && - !rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) { + if (rt2x00_check_rev(chip, 0xfff00000, 0x28600000) || + rt2x00_check_rev(chip, 0xfff00000, 0x28700000) || + rt2x00_check_rev(chip, 0xfff00000, 0x28800000)) { + rt2x00_set_chip_rt(rt2x00dev, RT2870); + } else if (rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) { + rt2x00_set_chip_rt(rt2x00dev, RT3070); + } else { ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); return -ENODEV; } - } else if (rt2x00_intf_is_pci(rt2x00dev)) - rt2x00_set_chip_rf(rt2x00dev, value, reg); + } if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && !rt2x00_rf(&rt2x00dev->chip, RF2850) && @@ -1853,10 +1855,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) !rt2x00_rf(&rt2x00dev->chip, RF2750) && !rt2x00_rf(&rt2x00dev->chip, RF3020) && !rt2x00_rf(&rt2x00dev->chip, RF2020) && - (rt2x00_intf_is_usb(rt2x00dev) || - (rt2x00_intf_is_pci(rt2x00dev) && - !rt2x00_rf(&rt2x00dev->chip, RF3021) && - !rt2x00_rf(&rt2x00dev->chip, RF3022)))) { + !rt2x00_rf(&rt2x00dev->chip, RF3021) && + !rt2x00_rf(&rt2x00dev->chip, RF3022)) { ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); return -ENODEV; } @@ -2057,7 +2057,9 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels = rf_vals; } else if (rt2x00_intf_is_usb(rt2x00dev) && (rt2x00_rf(chip, RF3020) || - rt2x00_rf(chip, RF2020))) { + rt2x00_rf(chip, RF2020) || + rt2x00_rf(chip, RF3021) || + rt2x00_rf(chip, RF3022))) { spec->num_channels = ARRAY_SIZE(rf_vals_3070); spec->channels = rf_vals_3070; } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 5a1b1612dcaa..62da572795a8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -172,6 +172,7 @@ struct rt2x00_chip { #define RT3052 0x3052 /* WSOC */ #define RT3090 0x3090 /* 2.4GHz PCIe */ #define RT2870 0x1600 +#define RT3070 0x1800 u16 rf; u32 rev; -- cgit v1.2.3 From c90017dd43f0cdb42134b9229761e8be02bcd524 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 13 Nov 2009 14:32:39 +0530 Subject: ath9k_hw: Fix possible OOB array indexing in gen_timer_index[] on 64-bit Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6d3e314c4bea..abaa2f09a3bc 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -432,7 +432,7 @@ struct ath9k_hw_version { * Using de Bruijin sequence to to look up 1's index in a 32 bit number * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001 */ -#define debruijn32 0x077CB531UL +#define debruijn32 0x077CB531U struct ath_gen_timer_configuration { u32 next_addr; -- cgit v1.2.3 From c37919bfe0a5c1bee9a31701a31e05a2f8840936 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 13 Nov 2009 14:32:40 +0530 Subject: ath9k_hw: Fix AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB and its shift value in 0x4054 The bit value of AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB is wrong, it should be 0x400 and the number of bits to be right shifted is 10. Having this wrong value in 0x4054 sometimes affects bt quality on btcoex environment. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/reg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 061e12ce0b24..49ec25f020f0 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -971,10 +971,10 @@ enum { #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S 4 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00000400 +#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 10 #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000 #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12 -#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00001000 -#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 1 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000 #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15 #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 -- cgit v1.2.3 From 235faf9b41b7b090be15b483bf900c0b9a8da4ea Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Thu, 12 Nov 2009 20:04:52 +0100 Subject: rt2800lib: fix some typos and punctuation in comments fix some typos and punctuation in comments Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Jiri Kosina [bart: ported the change from the older patch for rt2800usb & rt61pci] Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index c41bb4a59d16..9656699c6ef6 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1089,7 +1089,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2x00_intf_is_usb(rt2x00dev)) { /* - * Wait untill BBP and RF are ready. + * Wait until BBP and RF are ready. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2800_register_read(rt2x00dev, MAC_CSR0, ®); -- cgit v1.2.3 From fa6f632fba300f92d21962ef6e58411345465241 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 9 Nov 2009 22:59:58 +0100 Subject: rt2x00: Fix rt2800lib RF chip programming selection. Mirror the legacy Ralink driver with respect to rt2800 RF register programming. Execute rt2800_config_channel_rt3x for all RF2020, RF3020, RF3021 & RF3022 chipsets when operating on RT3070 devices. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 9656699c6ef6..53baa09082d3 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -806,10 +806,14 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, unsigned int tx_pin; u8 bbp; - if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) - rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info); - else + if (rt2x00_rt(&rt2x00dev->chip, RT3070) && + (rt2x00_rf(&rt2x00dev->chip, RF2020) || + rt2x00_rf(&rt2x00dev->chip, RF3020) || + rt2x00_rf(&rt2x00dev->chip, RF3021) || + rt2x00_rf(&rt2x00dev->chip, RF3022))) rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info); + else + rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info); /* * Change BBP settings -- cgit v1.2.3 From cce5fc45f9e9570f320009431d033d5a8f6144cc Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Tue, 10 Nov 2009 22:42:40 +0100 Subject: rt2x00: Initialize rf302x RF values properly for rt2800pci. Ensure RF302x and RF2020 chipsets are handled properly in rt2800lib for the rt3090 chipset. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 53baa09082d3..d88857ccdf85 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1,5 +1,6 @@ /* Copyright (C) 2009 Bartlomiej Zolnierkiewicz + Copyright (C) 2009 Gertjan van Wingerde Based on the original rt2800pci.c and rt2800usb.c. Copyright (C) 2009 Ivo van Doorn @@ -806,7 +807,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, unsigned int tx_pin; u8 bbp; - if (rt2x00_rt(&rt2x00dev->chip, RT3070) && + if ((rt2x00_rt(&rt2x00dev->chip, RT3070) || + rt2x00_rt(&rt2x00dev->chip, RT3090)) && (rt2x00_rf(&rt2x00dev->chip, RF2020) || rt2x00_rf(&rt2x00dev->chip, RF3020) || rt2x00_rf(&rt2x00dev->chip, RF3021) || @@ -1989,7 +1991,7 @@ static const struct rf_channel rf_vals[] = { * RF value list for rt3070 * Supports: 2.4 GHz */ -static const struct rf_channel rf_vals_3070[] = { +static const struct rf_channel rf_vals_302x[] = { {1, 241, 2, 2 }, {2, 241, 2, 7 }, {3, 242, 2, 2 }, @@ -2046,26 +2048,19 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) if (rt2x00_rf(chip, RF2820) || rt2x00_rf(chip, RF2720) || - (rt2x00_intf_is_pci(rt2x00dev) && - (rt2x00_rf(chip, RF3020) || - rt2x00_rf(chip, RF3021) || - rt2x00_rf(chip, RF3022) || - rt2x00_rf(chip, RF2020) || - rt2x00_rf(chip, RF3052)))) { + (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(chip, RF3052))) { spec->num_channels = 14; spec->channels = rf_vals; - } else if (rt2x00_rf(chip, RF2850) || - rt2x00_rf(chip, RF2750)) { + } else if (rt2x00_rf(chip, RF2850) || rt2x00_rf(chip, RF2750)) { spec->supported_bands |= SUPPORT_BAND_5GHZ; spec->num_channels = ARRAY_SIZE(rf_vals); spec->channels = rf_vals; - } else if (rt2x00_intf_is_usb(rt2x00dev) && - (rt2x00_rf(chip, RF3020) || - rt2x00_rf(chip, RF2020) || - rt2x00_rf(chip, RF3021) || - rt2x00_rf(chip, RF3022))) { - spec->num_channels = ARRAY_SIZE(rf_vals_3070); - spec->channels = rf_vals_3070; + } else if (rt2x00_rf(chip, RF3020) || + rt2x00_rf(chip, RF2020) || + rt2x00_rf(chip, RF3021) || + rt2x00_rf(chip, RF3022)) { + spec->num_channels = ARRAY_SIZE(rf_vals_302x); + spec->channels = rf_vals_302x; } /* -- cgit v1.2.3 From 16475b095a9c952f16e626c142b30bc95cfeadb3 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 14 Nov 2009 20:20:35 +0100 Subject: rt2x00: Log RT/RF chipset information correctly. Some drivers (rt2800* most notably) cannot set the RF and RT chipset in the correct order to have the information logging in rt2x00_set_chip be correct. Fix this by decoupling the setting of the chipset information from the logging of the chipset information so that drivers can determine themselves when all information is set. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 1 + drivers/net/wireless/rt2x00/rt2500pci.c | 1 + drivers/net/wireless/rt2x00/rt2500usb.c | 1 + drivers/net/wireless/rt2x00/rt2800lib.c | 1 + drivers/net/wireless/rt2x00/rt2x00.h | 11 +++++++---- drivers/net/wireless/rt2x00/rt61pci.c | 1 + drivers/net/wireless/rt2x00/rt73usb.c | 1 + 7 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 0f912f51a15a..6e68bc7efd4e 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1341,6 +1341,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); rt2x00_set_chip_rf(rt2x00dev, value, reg); + rt2x00_print_chip(rt2x00dev); if (!rt2x00_rf(&rt2x00dev->chip, RF2420) && !rt2x00_rf(&rt2x00dev->chip, RF2421)) { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 6618cbd808b3..9a31e5e7b8df 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1505,6 +1505,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, CSR0, ®); rt2x00_set_chip_rf(rt2x00dev, value, reg); + rt2x00_print_chip(rt2x00dev); if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && !rt2x00_rf(&rt2x00dev->chip, RF2523) && diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index bb64473dae67..b2de43e4f656 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1409,6 +1409,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2570, value, reg); + rt2x00_print_chip(rt2x00dev); if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) || rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index d88857ccdf85..c7108050af3a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1854,6 +1854,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) return -ENODEV; } } + rt2x00_print_chip(rt2x00dev); if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && !rt2x00_rf(&rt2x00dev->chip, RF2850) && diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 62da572795a8..1cbb7ac2f32f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -906,10 +906,6 @@ static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev, static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev, const u16 rt, const u16 rf, const u32 rev) { - INFO(rt2x00dev, - "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n", - rt, rf, rev); - rt2x00dev->chip.rt = rt; rt2x00dev->chip.rf = rf; rt2x00dev->chip.rev = rev; @@ -927,6 +923,13 @@ static inline void rt2x00_set_chip_rf(struct rt2x00_dev *rt2x00dev, rt2x00_set_chip(rt2x00dev, rt2x00dev->chip.rt, rf, rev); } +static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev) +{ + INFO(rt2x00dev, + "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n", + rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev); +} + static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip) { return (chipset->rt == chip); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 6e4613517461..bf04605896c7 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2300,6 +2300,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00pci_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip_rf(rt2x00dev, value, reg); + rt2x00_print_chip(rt2x00dev); if (!rt2x00_rf(&rt2x00dev->chip, RF5225) && !rt2x00_rf(&rt2x00dev->chip, RF5325) && diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 7236f017910d..5bbcf6626f7d 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1825,6 +1825,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2571, value, reg); + rt2x00_print_chip(rt2x00dev); if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) || rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { -- cgit v1.2.3 From 31a4cf1f22677ba1ea90be055bc20aac25b8e7c4 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 14 Nov 2009 20:20:36 +0100 Subject: rt2x00: Fix BUG on rt2800usb when trying to read eFuse EEPROM. Current tree hits a BUG_ON in rt2x00_regbusy_read, because the eFuse EEPROM reading code of rt2800lib uses the function without the csr_mutex locked. Fix this by locking the csr_mutex for the of the EEPROM reading cycly and using the _lock variants of the register reading and writing functions. This also introcudes the register_read_lock function pointer in the rt2800_ops structure. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 24 ++++++++++++++---------- drivers/net/wireless/rt2x00/rt2800lib.h | 11 +++++++++++ drivers/net/wireless/rt2x00/rt2800pci.c | 1 + drivers/net/wireless/rt2x00/rt2800usb.c | 1 + 4 files changed, 27 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index c7108050af3a..621dac18ca6c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1684,24 +1684,28 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) { u32 reg; - rt2800_register_read(rt2x00dev, EFUSE_CTRL, ®); + mutex_lock(&rt2x00dev->csr_mutex); + + rt2800_register_read_lock(rt2x00dev, EFUSE_CTRL, ®); rt2x00_set_field32(®, EFUSE_CTRL_ADDRESS_IN, i); rt2x00_set_field32(®, EFUSE_CTRL_MODE, 0); rt2x00_set_field32(®, EFUSE_CTRL_KICK, 1); - rt2800_register_write(rt2x00dev, EFUSE_CTRL, reg); + rt2800_register_write_lock(rt2x00dev, EFUSE_CTRL, reg); /* Wait until the EEPROM has been loaded */ rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®); /* Apparently the data is read from end to start */ - rt2800_register_read(rt2x00dev, EFUSE_DATA3, - (u32 *)&rt2x00dev->eeprom[i]); - rt2800_register_read(rt2x00dev, EFUSE_DATA2, - (u32 *)&rt2x00dev->eeprom[i + 2]); - rt2800_register_read(rt2x00dev, EFUSE_DATA1, - (u32 *)&rt2x00dev->eeprom[i + 4]); - rt2800_register_read(rt2x00dev, EFUSE_DATA0, - (u32 *)&rt2x00dev->eeprom[i + 6]); + rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, + (u32 *)&rt2x00dev->eeprom[i]); + rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, + (u32 *)&rt2x00dev->eeprom[i + 2]); + rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, + (u32 *)&rt2x00dev->eeprom[i + 4]); + rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0, + (u32 *)&rt2x00dev->eeprom[i + 6]); + + mutex_unlock(&rt2x00dev->csr_mutex); } void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 7c790118999b..535ce22f2ac8 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -23,6 +23,8 @@ struct rt2800_ops { void (*register_read)(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 *value); + void (*register_read_lock)(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 *value); void (*register_write)(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 value); void (*register_write_lock)(struct rt2x00_dev *rt2x00dev, @@ -49,6 +51,15 @@ static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev, rt2800ops->register_read(rt2x00dev, offset, value); } +static inline void rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) +{ + const struct rt2800_ops *rt2800ops = rt2x00dev->priv; + + rt2800ops->register_read_lock(rt2x00dev, offset, value); +} + static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 value) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index c7a596f2da39..87a5094ae953 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1089,6 +1089,7 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) static const struct rt2800_ops rt2800pci_rt2800_ops = { .register_read = rt2x00pci_register_read, + .register_read_lock = rt2x00pci_register_read, /* same for PCI */ .register_write = rt2x00pci_register_write, .register_write_lock = rt2x00pci_register_write, /* same for PCI */ diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index b57999ba8d93..b1d63935f44d 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -682,6 +682,7 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) static const struct rt2800_ops rt2800usb_rt2800_ops = { .register_read = rt2x00usb_register_read, + .register_read_lock = rt2x00usb_register_read_lock, .register_write = rt2x00usb_register_write, .register_write_lock = rt2x00usb_register_write_lock, -- cgit v1.2.3 From dd6ae4f877ce8cde9f57046a8eea4efc46950502 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 15 Nov 2009 22:27:17 +0100 Subject: ath9k: fix massive rx packet loss issue This patch fixes a regression introduced in "ath9k: avoid the copy skb->cb on every RX'd skb" With that change, the rx status in skb->cb was left uninitialized Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index acd4bb503dfc..2f1e1612e2ad 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -203,6 +203,7 @@ int ath9k_cmn_rx_skb_preprocess(struct ath_common *common, { struct ath_hw *ah = common->ah; + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) return -EINVAL; -- cgit v1.2.3 From 6a62e5ef94f754892734f99e87ca3dedd3cef277 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Sun, 15 Nov 2009 21:33:18 -0500 Subject: rt2800: do not enable tbtt unless we are in a beacon mode Please be gentle, I'm a fs developer and this is my first foray into drivers, as I'm tired of building ralinks driver everytime I update my kernel. Whenever I load the rt2800pci driver my box bogs down, and a few printk's later I discovered its because I was getting 10's of thousands of TBTT interrupts a second. I discovered this was because we were setting the beacon timer to 0, which is apparently what TBTT keys off of. It seems to me that we should only be enabling TBTT when we are in a beacon transmitting mode, which from what I can tell is in AD-HOC and other such modes where the mac80211 layer would have given us a proper beacon_int to set the beacon timer to instead of 0. So this is my fix, only enable TBTT if our sync mode is for beacon. This makes it so my box doesn't die everytime I load the rt2800pci driver. Let me know if this is acceptable, I just learned all these terms about 15 minutes ago via wikipedia, so I really am not familiar with how this stuff is supposed to work. Thanks, Signed-off-by: Josef Bacik Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 621dac18ca6c..e94f1e13fea9 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -561,7 +561,8 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); - rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); + rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, + (conf->sync == TSF_SYNC_BEACON)); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); } -- cgit v1.2.3 From 634a555ce3ee5ea1fdcaee8b4ac9ce7b54f301ac Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Mon, 16 Nov 2009 12:49:43 +0200 Subject: rndis_wlan: handle NL80211_AUTHTYPE_AUTOMATIC rndis_wlan didn't know about NL80211_AUTHTYPE_AUTOMATIC and simple setup with 'iwconfig wlan essid no-encrypt' would fail (ENOSUPP). v2: use NDIS_80211_AUTH_AUTO_SWITCH instead of _OPEN. This will make device try shared key auth first, then open. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 54175b6fa86c..aa1880add186 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1072,6 +1072,8 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version, auth_mode = NDIS_80211_AUTH_SHARED; else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) auth_mode = NDIS_80211_AUTH_OPEN; + else if (auth_type == NL80211_AUTHTYPE_AUTOMATIC) + auth_mode = NDIS_80211_AUTH_AUTO_SWITCH; else return -ENOTSUPP; -- cgit v1.2.3 From 2eb2fa67e5462a36e98172fb92c78bc405b3035f Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 16 Nov 2009 08:30:29 -0500 Subject: ath5k: allow setting txpower to 0 As a holdover from earlier code when we used to set the power limit to '0' after a reset to configure the default transmit power, ath5k interprets txpower=0 as 12.5 dBm. Fix that by just passing 0 through. This fixes http://bugzilla.kernel.org/show_bug.cgi?id=14567 Cc: stable@kernel.org Reported-by: Daniel Folkers Tested-by: Daniel Folkers Signed-off-by: Bob Copeland Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/phy.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 895990751d36..721ec5ee381d 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -3025,8 +3025,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); return -EINVAL; } - if (txpower == 0) - txpower = AR5K_TUNE_DEFAULT_TXPOWER; /* Reset TX power values */ memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); -- cgit v1.2.3 From fe4eb54845fff09ec01b8421f53f92e08b67229c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 18 Nov 2009 08:24:50 +0000 Subject: drivers/net/adm8211.c: remove exceptional & on function name In this file, function names are otherwise used as pointers without &. A simplified version of the semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r@ identifier f; @@ f(...) { ... } @@ identifier r.f; @@ - &f + f // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/wireless/adm8211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index b80f514877d8..39410016b4ff 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1538,7 +1538,7 @@ static int adm8211_start(struct ieee80211_hw *dev) adm8211_hw_init(dev); adm8211_rf_set_channel(dev, priv->channel); - retval = request_irq(priv->pdev->irq, &adm8211_interrupt, + retval = request_irq(priv->pdev->irq, adm8211_interrupt, IRQF_SHARED, "adm8211", dev); if (retval) { printk(KERN_ERR "%s: failed to register IRQ handler\n", -- cgit v1.2.3 From d20a80f0e6eb9a4f31489a0518a9ba0754eeee12 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 18 Nov 2009 08:25:25 +0000 Subject: drivers/net/wireless/iwlwifi: remove exceptional & on function name In this file, function names are otherwise used as pointers without &. A simplified version of the semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r@ identifier f; @@ f(...) { ... } @@ identifier r.f; @@ - &f + f // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index dc81e19674f7..d4b49883b30e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -355,7 +355,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, init_timer(&rs_sta->rate_scale_flush); rs_sta->rate_scale_flush.data = (unsigned long)rs_sta; - rs_sta->rate_scale_flush.function = &iwl3945_bg_rate_scale_flush; + rs_sta->rate_scale_flush.function = iwl3945_bg_rate_scale_flush; for (i = 0; i < IWL_RATE_COUNT_3945; i++) iwl3945_clear_window(&rs_sta->win[i]); -- cgit v1.2.3 From 8fbd90b0612cca7cd9a29df59b69502a841bebf8 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 18 Nov 2009 08:25:43 +0000 Subject: drivers/net/wireless/p54: remove exceptional & on function name In this file, function names are otherwise used as pointers without &. A simplified version of the semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r@ identifier f; @@ f(...) { ... } @@ identifier r.f; @@ - &f + f // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/wireless/p54/p54pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index d348c265e867..a15962a19b2a 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -411,7 +411,7 @@ static int p54p_open(struct ieee80211_hw *dev) int err; init_completion(&priv->boot_comp); - err = request_irq(priv->pdev->irq, &p54p_interrupt, + err = request_irq(priv->pdev->irq, p54p_interrupt, IRQF_SHARED, "p54pci", dev); if (err) { dev_err(&priv->pdev->dev, "failed to register IRQ handler\n"); -- cgit v1.2.3 From ea31ba359c55e0734ff895692185d4c50cf0c537 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 18 Nov 2009 08:26:02 +0000 Subject: drivers/net/wireless/rtl818x: remove exceptional & on function name In this file, function names are otherwise used as pointers without &. A simplified version of the semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r@ identifier f; @@ f(...) { ... } @@ identifier r.f; @@ - &f + f // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/wireless/rtl818x/rtl8180_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index 16429c49139c..a1a3dd15c664 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -548,7 +548,7 @@ static int rtl8180_start(struct ieee80211_hw *dev) rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); - ret = request_irq(priv->pdev->irq, &rtl8180_interrupt, + ret = request_irq(priv->pdev->irq, rtl8180_interrupt, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) { printk(KERN_ERR "%s: failed to register IRQ handler\n", -- cgit v1.2.3 From 85f0d9e87794818356146996826b829100daa6bc Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:23 -0800 Subject: iwlwifi: validate enhanced tx power entry Validate enhanced tx power entry read from EEPROM before applying the tx power value. Different versions of EEPROM might contain different size of table; always a good idea to make sure the entry is valid before applying to the targeted channel. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-eeprom.h | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 8a0709e81a9f..143728c6382e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -913,6 +913,16 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) enhanced_txpower = (struct iwl_eeprom_enhanced_txpwr *) iwl_eeprom_query_addr(priv, offset); + /* + * check for valid entry - + * different version of EEPROM might contain different set + * of enhanced tx power table + * always check for valid entry before process + * the information + */ + if (!enhanced_txpower->common || enhanced_txpower->reserved) + continue; + for (element = 0; element < eeprom_section_count; element++) { if (enhinfo[section].is_common) max_txpower_avg = diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 5ba5a4e9e49a..5cd2b66bbe45 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -127,19 +127,21 @@ struct iwl_eeprom_channel { * Enhanced regulatory tx power portion of eeprom image can be broken down * into individual structures; each one is 8 bytes in size and contain the * following information + * @common: (desc + channel) not used by driver, should _NOT_ be "zero" * @chain_a_max_pwr: chain a max power in 1/2 dBm * @chain_b_max_pwr: chain b max power in 1/2 dBm * @chain_c_max_pwr: chain c max power in 1/2 dBm + * @reserved: not used, should be "zero" * @mimo2_max_pwr: mimo2 max power in 1/2 dBm * @mimo3_max_pwr: mimo3 max power in 1/2 dBm * */ struct iwl_eeprom_enhanced_txpwr { - u16 reserved; + u16 common; s8 chain_a_max; s8 chain_b_max; s8 chain_c_max; - s8 reserved1; + s8 reserved; s8 mimo2_max; s8 mimo3_max; } __attribute__ ((packed)); -- cgit v1.2.3 From 85bb174a386850c8a43e8d107af47de3c910be03 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:24 -0800 Subject: iwlwifi: disable coex until implementation ready for 6x50 Temporary disable the coex function for wifi/wimax for 6x50 series until the full implementation ready. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index f732f6d194a0..72ed944843b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -395,7 +395,6 @@ struct iwl_cfg iwl6050_2agn_cfg = { .adv_thermal_throttle = true, .support_ct_kill_exit = true, .support_sm_ps = true, - .support_wimax_coexist = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -425,7 +424,6 @@ struct iwl_cfg iwl6050_2abg_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .support_wimax_coexist = true, }; struct iwl_cfg iwl6000_3agn_cfg = { -- cgit v1.2.3 From d7d144012a2949cf7f8eed758013adadf5e5a82e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:25 -0800 Subject: iwlwifi: remove unused parameter from iwl_channel_info Number of HT40 power parameters are not used; remove those from iwl_channel_info data structure Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 --- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 7 ------- 2 files changed, 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9dea8fa08c0e..d0f091519793 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -295,9 +295,6 @@ struct iwl_channel_info { /* HT40 channel info */ s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ - s8 ht40_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ - s8 ht40_min_power; /* always 0 */ - s8 ht40_scan_power; /* (dBm) eeprom, direct scans, any rate */ u8 ht40_flags; /* flags copied from EEPROM */ u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 143728c6382e..e42eb6499f0e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -751,9 +751,6 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, ch_info->ht40_eeprom = *eeprom_ch; ch_info->ht40_max_power_avg = eeprom_ch->max_power_avg; - ch_info->ht40_curr_txpow = eeprom_ch->max_power_avg; - ch_info->ht40_min_power = 0; - ch_info->ht40_scan_power = eeprom_ch->max_power_avg; ch_info->ht40_flags = eeprom_ch->flags; ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; @@ -840,8 +837,6 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv, (ch_info->ht40_max_power_avg < max_txpower_avg)) { /* Update regulatory-based run-time data */ ch_info->ht40_max_power_avg = max_txpower_avg; - ch_info->ht40_curr_txpow = max_txpower_avg; - ch_info->ht40_scan_power = max_txpower_avg; } ch_info++; } @@ -881,8 +876,6 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, (ch_info->ht40_max_power_avg < max_txpower_avg)) { /* Update regulatory-based run-time data */ ch_info->ht40_max_power_avg = max_txpower_avg; - ch_info->ht40_curr_txpow = max_txpower_avg; - ch_info->ht40_scan_power = max_txpower_avg; } break; } -- cgit v1.2.3 From a8a9a159bf907ef02aca2e316025e427f315e82a Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:26 -0800 Subject: iwlwifi: drop non-production PCI-IDs for 6x50 series drop the non-production PCI-IDs for 6x50 series Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 32 -------------------------------- drivers/net/wireless/iwlwifi/iwl-agn.c | 3 --- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 3 files changed, 36 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 72ed944843b0..4ab9897f4fe1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -456,37 +456,5 @@ struct iwl_cfg iwl6000_3agn_cfg = { .support_ct_kill_exit = true, }; -struct iwl_cfg iwl6050_3agn_cfg = { - .name = "6050 Series 3x3 AGN", - .fw_name_pre = IWL6050_FW_PRE, - .ucode_api_max = IWL6050_UCODE_API_MAX, - .ucode_api_min = IWL6050_UCODE_API_MIN, - .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, - .ops = &iwl6050_ops, - .eeprom_size = OTP_LOW_IMAGE_SIZE, - .eeprom_ver = EEPROM_6050_EEPROM_VERSION, - .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, - .num_of_queues = IWL50_NUM_QUEUES, - .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, - .mod_params = &iwl50_mod_params, - .valid_tx_ant = ANT_ABC, - .valid_rx_ant = ANT_ABC, - .pll_cfg_val = 0, - .set_l0s = true, - .use_bsm = false, - .pa_type = IWL_PA_SYSTEM, - .max_ll_items = OTP_MAX_LL_ITEMS_6x50, - .shadow_ram_support = true, - .ht_greenfield_support = true, - .led_compensation = 51, - .use_rts_for_ht = true, /* use rts/cts protection */ - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, - .supports_idle = true, - .adv_thermal_throttle = true, - .support_ct_kill_exit = true, - .support_sm_ps = true, - .support_wimax_coexist = true, -}; - MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index da0b38e866ba..6532e9e68951 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3484,13 +3484,10 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)}, /* 6x50 WiFi/WiMax Series */ - {IWL_PCI_DEVICE(0x0086, 0x1101, iwl6050_3agn_cfg)}, - {IWL_PCI_DEVICE(0x0086, 0x1121, iwl6050_3agn_cfg)}, {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)}, {IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)}, {IWL_PCI_DEVICE(0x0087, 0x1321, iwl6050_2agn_cfg)}, {IWL_PCI_DEVICE(0x0087, 0x1326, iwl6050_2abg_cfg)}, - {IWL_PCI_DEVICE(0x0088, 0x1111, iwl6050_3agn_cfg)}, {IWL_PCI_DEVICE(0x0089, 0x1311, iwl6050_2agn_cfg)}, {IWL_PCI_DEVICE(0x0089, 0x1316, iwl6050_2abg_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index d0f091519793..273adee81cf1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -64,7 +64,6 @@ extern struct iwl_cfg iwl6000i_2bg_cfg; extern struct iwl_cfg iwl6000_3agn_cfg; extern struct iwl_cfg iwl6050_2agn_cfg; extern struct iwl_cfg iwl6050_2abg_cfg; -extern struct iwl_cfg iwl6050_3agn_cfg; extern struct iwl_cfg iwl1000_bgn_cfg; extern struct iwl_cfg iwl1000_bg_cfg; -- cgit v1.2.3 From 7d2ed110a80991849a2824a6dc3c063ffca9dbe4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:27 -0800 Subject: iwlwifi: remove external reference for non-exist data structure Number of data structure for 6000 series no longer in production, the data structure already being removed; also need to remove the external reference define in iwl-dev.h Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 273adee81cf1..774a315996e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -55,9 +55,6 @@ extern struct iwl_cfg iwl5350_agn_cfg; extern struct iwl_cfg iwl5100_bg_cfg; extern struct iwl_cfg iwl5100_abg_cfg; extern struct iwl_cfg iwl5150_agn_cfg; -extern struct iwl_cfg iwl6000h_2agn_cfg; -extern struct iwl_cfg iwl6000h_2abg_cfg; -extern struct iwl_cfg iwl6000h_2bg_cfg; extern struct iwl_cfg iwl6000i_2agn_cfg; extern struct iwl_cfg iwl6000i_2abg_cfg; extern struct iwl_cfg iwl6000i_2bg_cfg; -- cgit v1.2.3 From ef8d5529b015d4c5db7fad1adfc91edfd5abad56 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:28 -0800 Subject: iwlwifi: update reply_statistics_cmd with 'clear' parameter When issue REPLY_STATISTICS_CMD to uCode, two possible flag can be set in the configuration flags bit 0: Clear statistics 0: Do not clear Statistics counters 1: Clear to zero Statistics counters Allow "clear" parameter to be set from the caller. Add debugfs file to clear the statistics counters to help monitor and debug the uCode behavior. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 ++--- drivers/net/wireless/iwlwifi/iwl-calib.c | 2 +- drivers/net/wireless/iwlwifi/iwl-commands.h | 4 +++ drivers/net/wireless/iwlwifi/iwl-core.c | 21 ++++++++++------ drivers/net/wireless/iwlwifi/iwl-core.h | 5 +++- drivers/net/wireless/iwlwifi/iwl-debug.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 39 +++++++++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-power.c | 2 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 18 +++++++++++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 10 files changed, 77 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6532e9e68951..f586e7e83131 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -612,7 +612,7 @@ static void iwl_bg_statistics_periodic(unsigned long data) if (!iwl_is_ready_rf(priv)) return; - iwl_send_statistics_request(priv, CMD_ASYNC); + iwl_send_statistics_request(priv, CMD_ASYNC, false); } static void iwl_rx_beacon_notif(struct iwl_priv *priv, @@ -729,7 +729,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) * statistics request from the host as well as for the periodic * statistics notifications (after received beacons) from the uCode. */ - priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics; + priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_reply_statistics; priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; iwl_setup_spectrum_handlers(priv); @@ -2892,7 +2892,7 @@ static ssize_t show_statistics(struct device *d, return -EAGAIN; mutex_lock(&priv->mutex); - rc = iwl_send_statistics_request(priv, 0); + rc = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (rc) { diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index d994de7438d8..95a57b36a7ea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -900,7 +900,7 @@ void iwl_reset_run_time_calib(struct iwl_priv *priv) /* Ask for statistics now, the uCode will send notification * periodically after association */ - iwl_send_statistics_request(priv, CMD_ASYNC); + iwl_send_statistics_request(priv, CMD_ASYNC, true); } EXPORT_SYMBOL(iwl_reset_run_time_calib); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 2857287be4fd..6e23a2b5cb8a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -3071,6 +3071,10 @@ struct statistics_general { __le32 reserved3; } __attribute__ ((packed)); +#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0) +#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1) +#define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2) + /* * REPLY_STATISTICS_CMD = 0x9c, * 3945 and 4965 identical. diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index d09e74815323..1736c60c3e21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1990,16 +1990,21 @@ int iwl_send_bt_config(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_send_bt_config); -int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) +int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) { - u32 stat_flags = 0; - struct iwl_host_cmd cmd = { - .id = REPLY_STATISTICS_CMD, - .flags = flags, - .len = sizeof(stat_flags), - .data = (u8 *) &stat_flags, + struct iwl_statistics_cmd statistics_cmd = { + .configuration_flags = + clear ? IWL_STATS_CONF_CLEAR_STATS : 0, }; - return iwl_send_cmd(priv, &cmd); + + if (flags & CMD_ASYNC) + return iwl_send_cmd_pdu_async(priv, REPLY_STATISTICS_CMD, + sizeof(struct iwl_statistics_cmd), + &statistics_cmd, NULL); + else + return iwl_send_cmd_pdu(priv, REPLY_STATISTICS_CMD, + sizeof(struct iwl_statistics_cmd), + &statistics_cmd); } EXPORT_SYMBOL(iwl_send_statistics_request); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3f97036ac29b..584a376b96c5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -425,6 +425,8 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); void iwl_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); +void iwl_reply_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb); void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); /* TX helpers */ @@ -669,7 +671,8 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv) extern void iwl_rf_kill_ct_config(struct iwl_priv *priv); extern int iwl_send_bt_config(struct iwl_priv *priv); -extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags); +extern int iwl_send_statistics_request(struct iwl_priv *priv, + u8 flags, bool clear); extern int iwl_verify_ucode(struct iwl_priv *priv); extern int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_link_quality_cmd *lq, u8 flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 96c92eab692a..25a0e73314f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -107,6 +107,7 @@ struct iwl_debugfs { struct dentry *file_chain_noise; struct dentry *file_tx_power; struct dentry *file_power_save_status; + struct dentry *file_clear_statistics; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 8784911fd56e..45a5edd1b1a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -1042,10 +1042,6 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0) -#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1) -#define UCODE_STATISTICS_NARROW_BAND_MSK (0x1 << 2) - static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) { @@ -1092,7 +1088,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, /* make request to uCode to retrieve statistics information */ mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, 0); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (ret) { @@ -1398,7 +1394,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, /* make request to uCode to retrieve statistics information */ mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, 0); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (ret) { @@ -1542,7 +1538,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, /* make request to uCode to retrieve statistics information */ mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, 0); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (ret) { @@ -1770,7 +1766,7 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file, else { /* make request to uCode to retrieve statistics information */ mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, 0); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (ret) { @@ -1828,6 +1824,30 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t iwl_dbgfs_clear_statistics_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + int clear; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &clear) != 1) + return -EFAULT; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + iwl_send_statistics_request(priv, CMD_SYNC, true); + mutex_unlock(&priv->mutex); + + return count; +} + DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); @@ -1840,6 +1860,7 @@ DEBUGFS_READ_FILE_OPS(sensitivity); DEBUGFS_READ_FILE_OPS(chain_noise); DEBUGFS_READ_FILE_OPS(tx_power); DEBUGFS_READ_FILE_OPS(power_save_status); +DEBUGFS_WRITE_FILE_OPS(clear_statistics); /* * Create the debugfs files and directories @@ -1888,6 +1909,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(tx_queue, debug); DEBUGFS_ADD_FILE(tx_power, debug); DEBUGFS_ADD_FILE(power_save_status, debug); + DEBUGFS_ADD_FILE(clear_statistics, debug); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_ADD_FILE(ucode_rx_stats, debug); DEBUGFS_ADD_FILE(ucode_tx_stats, debug); @@ -1941,6 +1963,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_clear_statistics); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_rx_stats); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 9bce2c1625e3..8ccc0bb1d9ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -506,7 +506,7 @@ static void iwl_prepare_ct_kill_task(struct iwl_priv *priv) { IWL_DEBUG_POWER(priv, "Prepare to enter IWL_TI_CT_KILL\n"); /* make request to retrieve statistics information */ - iwl_send_statistics_request(priv, 0); + iwl_send_statistics_request(priv, CMD_SYNC, false); /* Reschedule the ct_kill wait timer */ mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm, jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION)); diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 61b3b0e6ed73..9d010a0d83af 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -635,6 +635,24 @@ void iwl_rx_statistics(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_rx_statistics); +void iwl_reply_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + + if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { + memset(&priv->statistics, 0, + sizeof(struct iwl_notif_statistics)); +#ifdef CONFIG_IWLWIFI_DEBUG + memset(&priv->accum_statistics, 0, + sizeof(struct iwl_notif_statistics)); +#endif + IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); + } + iwl_rx_statistics(priv, rxb); +} +EXPORT_SYMBOL(iwl_reply_statistics); + #define PERFECT_RSSI (-20) /* dBm */ #define WORST_RSSI (-95) /* dBm */ #define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 05f118529fea..93bb4d341be3 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3649,7 +3649,7 @@ static ssize_t show_statistics(struct device *d, return -EAGAIN; mutex_lock(&priv->mutex); - rc = iwl_send_statistics_request(priv, 0); + rc = iwl_send_statistics_request(priv, CMD_SYNC, false); mutex_unlock(&priv->mutex); if (rc) { -- cgit v1.2.3 From 4d6ccbf57ff7653217b7149976aa31e19f996544 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 13 Nov 2009 11:56:29 -0800 Subject: iwl3945: Reset saved POWER_TABLE_CMD in "up" Power-saving logic will not re-issue a POWER_TABLE_CMD if a new command matches the prior one. This can be bad if we re-start the device due to e.g. uCode error; the new POWER_TABLE_CMD (required to invoke power-saving) may match the prior POWER_TABLE_CMD issued before the uCode error. Ensure the POWER_TABLE_CMD is sent to device when uCode is up. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 93bb4d341be3..31f3c42b835c 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2493,7 +2493,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; - iwl_power_update_mode(priv, false); + iwl_power_update_mode(priv, true); if (iwl_is_associated(priv)) { struct iwl3945_rxon_cmd *active_rxon = -- cgit v1.2.3 From ae16fc3c3184bf27f0462e1951df918122498829 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:30 -0800 Subject: iwlwifi: eliminate the possible 1/2 dBm tx power loss in 6x00 & 6x50 series In both 6x00 and 6x50 series, the enhanced/extended tx power table in EEPROM is used to set the max. tx power limit. This new tx power table is in 1/2 dBm format, which creates an issue of possibility of 1/2 dBm loss when driver set the tx power limit; because of driver keep track and report the tx power in dBm format. In order to prevent the 1/2 dBm loss, keep track of the true max tx power in 1/2 dBm format in driver; do the comparison and adjust the tx power if needed when send tx power command to uCode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 16 ++++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl-eeprom.c | 49 ++++++++++++++++++++++--------- 3 files changed, 52 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 6eaf26b07636..48982fb44995 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1250,6 +1250,22 @@ int iwl5000_send_tx_power(struct iwl_priv *priv) /* half dBm need to multiply */ tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt); + + if (priv->tx_power_lmt_in_half_dbm && + priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) { + /* + * For the newer devices which using enhanced/extend tx power + * table in EEPROM, the format is in half dBm. driver need to + * convert to dBm format before report to mac80211. + * By doing so, there is a possibility of 1/2 dBm resolution + * lost. driver will perform "round-up" operation before + * reporting, but it will cause 1/2 dBm tx power over the + * regulatory limit. Perform the checking here, if the + * "tx_power_user_lmt" is higher than EEPROM value (in + * half-dBm format), lower the tx power based on EEPROM + */ + tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm; + } tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED; tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 774a315996e6..a474383ec0b8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1247,6 +1247,7 @@ struct iwl_priv { /* TX Power */ s8 tx_power_user_lmt; s8 tx_power_device_lmt; + s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */ #ifdef CONFIG_IWLWIFI_DEBUG diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index e42eb6499f0e..ac88ff042d46 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -762,7 +762,8 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, * find the highest tx power from all chains for the channel */ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, - struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, int element) + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int element, s8 *max_txpower_in_half_dbm) { s8 max_txpower_avg = 0; /* (dBm) */ @@ -794,10 +795,14 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, (enhanced_txpower[element].mimo3_max > max_txpower_avg)) max_txpower_avg = enhanced_txpower[element].mimo3_max; - /* max. tx power in EEPROM is in 1/2 dBm format - * convert from 1/2 dBm to dBm + /* + * max. tx power in EEPROM is in 1/2 dBm format + * convert from 1/2 dBm to dBm (round-up convert) + * but we also do not want to loss 1/2 dBm resolution which + * will impact performance */ - return max_txpower_avg >> 1; + *max_txpower_in_half_dbm = max_txpower_avg; + return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1); } /** @@ -806,7 +811,7 @@ static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, */ static s8 iwl_update_common_txpower(struct iwl_priv *priv, struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, - int section, int element) + int section, int element, s8 *max_txpower_in_half_dbm) { struct iwl_channel_info *ch_info; int ch; @@ -820,20 +825,22 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv, if (element == EEPROM_TXPOWER_COMMON_HT40_INDEX) is_ht40 = true; max_txpower_avg = - iwl_get_max_txpower_avg(priv, enhanced_txpower, element); + iwl_get_max_txpower_avg(priv, enhanced_txpower, + element, max_txpower_in_half_dbm); + ch_info = priv->channel_info; for (ch = 0; ch < priv->channel_count; ch++) { /* find matching band and update tx power if needed */ if ((ch_info->band == enhinfo[section].band) && - (ch_info->max_power_avg < max_txpower_avg) && (!is_ht40)) { + (ch_info->max_power_avg < max_txpower_avg) && + (!is_ht40)) { /* Update regulatory-based run-time data */ ch_info->max_power_avg = ch_info->curr_txpow = - max_txpower_avg; + max_txpower_avg; ch_info->scan_power = max_txpower_avg; } if ((ch_info->band == enhinfo[section].band) && is_ht40 && - ch_info->ht40_max_power_avg && (ch_info->ht40_max_power_avg < max_txpower_avg)) { /* Update regulatory-based run-time data */ ch_info->ht40_max_power_avg = max_txpower_avg; @@ -849,7 +856,7 @@ static s8 iwl_update_common_txpower(struct iwl_priv *priv, */ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, - int section, int element) + int section, int element, s8 *max_txpower_in_half_dbm) { struct iwl_channel_info *ch_info; int ch; @@ -858,7 +865,8 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, channel = enhinfo[section].iwl_eeprom_section_channel[element]; max_txpower_avg = - iwl_get_max_txpower_avg(priv, enhanced_txpower, element); + iwl_get_max_txpower_avg(priv, enhanced_txpower, + element, max_txpower_in_half_dbm); ch_info = priv->channel_info; for (ch = 0; ch < priv->channel_count; ch++) { @@ -872,7 +880,6 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, ch_info->scan_power = max_txpower_avg; } if ((enhinfo[section].is_ht40) && - (ch_info->ht40_max_power_avg) && (ch_info->ht40_max_power_avg < max_txpower_avg)) { /* Update regulatory-based run-time data */ ch_info->ht40_max_power_avg = max_txpower_avg; @@ -894,6 +901,7 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) struct iwl_eeprom_enhanced_txpwr *enhanced_txpower; u32 offset; s8 max_txpower_avg; /* (dBm) */ + s8 max_txpower_in_half_dbm; /* (half-dBm) */ /* Loop through all the sections * adjust bands and channel's max tx power @@ -920,16 +928,29 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) if (enhinfo[section].is_common) max_txpower_avg = iwl_update_common_txpower(priv, - enhanced_txpower, section, element); + enhanced_txpower, section, + element, + &max_txpower_in_half_dbm); else max_txpower_avg = iwl_update_channel_txpower(priv, - enhanced_txpower, section, element); + enhanced_txpower, section, + element, + &max_txpower_in_half_dbm); /* Update the tx_power_user_lmt to the highest power * supported by any channel */ if (max_txpower_avg > priv->tx_power_user_lmt) priv->tx_power_user_lmt = max_txpower_avg; + + /* + * Update the tx_power_lmt_in_half_dbm to + * the highest power supported by any channel + */ + if (max_txpower_in_half_dbm > + priv->tx_power_lmt_in_half_dbm) + priv->tx_power_lmt_in_half_dbm = + max_txpower_in_half_dbm; } } } -- cgit v1.2.3 From 98a7b43be19faa7b92576c62614c45e38517331c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 13 Nov 2009 11:56:31 -0800 Subject: iwlwifi: align tx/rx statistics debugfs format Align the format for tx_statistics and rx_statistics debugfs output for better readability Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 45a5edd1b1a7..ba9c96ff27ca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -131,21 +131,22 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, int cnt; ssize_t ret; - const size_t bufsz = 100 + sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); + const size_t bufsz = 100 + + sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX); buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { pos += scnprintf(buf + pos, bufsz - pos, - "\t%s\t\t: %u\n", + "\t%25s\t\t: %u\n", get_mgmt_string(cnt), priv->tx_stats.mgmt[cnt]); } pos += scnprintf(buf + pos, bufsz - pos, "Control\n"); for (cnt = 0; cnt < CONTROL_MAX; cnt++) { pos += scnprintf(buf + pos, bufsz - pos, - "\t%s\t\t: %u\n", + "\t%25s\t\t: %u\n", get_ctrl_string(cnt), priv->tx_stats.ctrl[cnt]); } @@ -190,7 +191,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, int cnt; ssize_t ret; const size_t bufsz = 100 + - sizeof(char) * 24 * (MANAGEMENT_MAX + CONTROL_MAX); + sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX); buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -198,14 +199,14 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, "Management:\n"); for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { pos += scnprintf(buf + pos, bufsz - pos, - "\t%s\t\t: %u\n", + "\t%25s\t\t: %u\n", get_mgmt_string(cnt), priv->rx_stats.mgmt[cnt]); } pos += scnprintf(buf + pos, bufsz - pos, "Control:\n"); for (cnt = 0; cnt < CONTROL_MAX; cnt++) { pos += scnprintf(buf + pos, bufsz - pos, - "\t%s\t\t: %u\n", + "\t%25s\t\t: %u\n", get_ctrl_string(cnt), priv->rx_stats.ctrl[cnt]); } -- cgit v1.2.3 From e43ab94d2ea01a74e60c3423334687c2156c39b2 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 13 Nov 2009 11:56:32 -0800 Subject: iwlagn: power up device before initializing EEPROM A recent change optimized the power usage by the device by only powering it up during EEPROM load if it is required (for OTP devices). This change causes an error on the 1000 series devices during module load. The error looks as follows: [ 1624.024524] iwlagn: Intel(R) Wireless WiFi Link AGN driver for Linux, 1.3.27kds [ 1624.024527] iwlagn: Copyright(c) 2003-2009 Intel Corporation [ 1624.024711] iwlagn 0000:01:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16 [ 1624.024749] iwlagn 0000:01:00.0: setting latency timer to 64 [ 1624.024909] iwlagn 0000:01:00.0: Detected Intel Wireless WiFi Link 1000 Series BGN REV=0x6C [ 1624.081263] iwlagn 0000:01:00.0: MAC is in deep sleep!. CSR_GP_CNTRL = 0x080003D8 [ 1624.092967] iwlagn 0000:01:00.0: OTP is empty [ 1624.092988] iwlagn 0000:01:00.0: Unable to init EEPROM [ 1624.093033] iwlagn 0000:01:00.0: PCI INT A disabled [ 1624.093065] iwlagn: probe of 0000:01:00.0 failed with error -2 Adding a dump_stack() to where that error is printed shows the following: [ 1624.024524] iwlagn: Intel(R) Wireless WiFi Link AGN driver for Linux, 1.3.27kds [ 1624.024527] iwlagn: Copyright(c) 2003-2009 Intel Corporation [ 1624.024711] iwlagn 0000:01:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16 [ 1624.024749] iwlagn 0000:01:00.0: setting latency timer to 64 [ 1624.024909] iwlagn 0000:01:00.0: Detected Intel Wireless WiFi Link 1000 Series BGN REV=0x6C [ 1624.081263] iwlagn 0000:01:00.0: MAC is in deep sleep!. CSR_GP_CNTRL = 0x080003D8 [ 1624.081263] Pid: 3073, comm: work_for_cpu Tainted: G W 2.6.31.5 #4 [ 1624.081263] Call Trace: [ 1624.081263] [] T.726+0x22b/0x420 [iwlcore] [ 1624.081263] [] iwlcore_eeprom_acquire_semaphore+0x8a/0x190 [iwlcore] [ 1624.081263] [] ? __kmalloc+0x194/0x1c0 [ 1624.081263] [] ? iwlcore_eeprom_verify_signature+0x25/0xf0 [iwlcore] [ 1624.081263] [] iwl_eeprom_init+0x107/0xf40 [iwlcore] [ 1624.081263] [] ? iwl_prepare_card_hw+0x11c/0x470 [iwlagn] [ 1624.081263] [] ? pci_bus_write_config_byte+0x64/0x80 [ 1624.081263] [] iwl_pci_probe+0x308/0xac0 [iwlagn] [ 1624.081263] [] ? do_work_for_cpu+0x0/0x30 [ 1624.081263] [] local_pci_probe+0x12/0x20 [ 1624.081263] [] do_work_for_cpu+0x13/0x30 [ 1624.081263] [] kthread+0xa6/0xb0 [ 1624.081263] [] child_rip+0xa/0x20 [ 1624.081263] [] ? kthread+0x0/0xb0 [ 1624.081263] [] ? child_rip+0x0/0x20 [ 1624.092967] iwlagn 0000:01:00.0: OTP is empty [ 1624.092988] iwlagn 0000:01:00.0: Unable to init EEPROM [ 1624.093033] iwlagn 0000:01:00.0: PCI INT A disabled [ 1624.093065] iwlagn: probe of 0000:01:00.0 failed with error -2 We know that the routines in this trace, iwlcore_eeprom_acquire_semaphore and iwlcore_eeprom_verify_signature, only access CSR registers and thus do not need the device to be awake if it is EEPROM. But for OTP it is required for the device to be awake to read these registers. Ensure device is awake before accessing these registers. Signed-off-by: Reinette Chatre Acked-by: Ben Cahill Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-eeprom.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index ac88ff042d46..3946e5c03f81 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -518,6 +518,11 @@ int iwl_eeprom_init(struct iwl_priv *priv) } e = (u16 *)priv->eeprom; + if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { + /* OTP reads require powered-up chip */ + priv->cfg->ops->lib->apm_ops.init(priv); + } + ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv); if (ret < 0) { IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); @@ -532,10 +537,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) ret = -ENOENT; goto err; } - if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { - /* OTP reads require powered-up chip */ - priv->cfg->ops->lib->apm_ops.init(priv); + if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { ret = iwl_init_otp_access(priv); if (ret) { -- cgit v1.2.3 From 47ff65c48748086a5e9cde6032451691a28ab19f Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 13 Nov 2009 11:56:33 -0800 Subject: iwlwifi: fix bugs in beacon configuration When sending beacon commands to the uCode, we must inform it of the offset in the beacon frame of the TIM Element so it can transmit packets from the correct queue. This functionality is implemented in iwl_set_beacon_tim(). Fix a bug setting the rate_n_flags for the beacon packet. First, it should not use the station table's rate (it's a management frame), and second it needs to properly configure the TX antennas. Finally, also, clean up and comment relevant functions. Signed-off-by: Daniel C Halperin Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 83 ++++++++++++++++++++++++--------- drivers/net/wireless/iwlwifi/iwl-core.c | 1 + 2 files changed, 63 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f586e7e83131..29f3b73c7560 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -310,7 +310,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) list_add(&frame->list, &priv->free_frames); } -static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, +static u32 iwl_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, int left) { @@ -327,34 +327,74 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, return priv->ibss_beacon->len; } +/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */ +static void iwl_set_beacon_tim(struct iwl_priv *priv, + struct iwl_tx_beacon_cmd *tx_beacon_cmd, + u8 *beacon, u32 frame_size) +{ + u16 tim_idx; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon; + + /* + * The index is relative to frame start but we start looking at the + * variable-length part of the beacon. + */ + tim_idx = mgmt->u.beacon.variable - beacon; + + /* Parse variable-length elements of beacon to find WLAN_EID_TIM */ + while ((tim_idx < (frame_size - 2)) && + (beacon[tim_idx] != WLAN_EID_TIM)) + tim_idx += beacon[tim_idx+1] + 2; + + /* If TIM field was found, set variables */ + if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) { + tx_beacon_cmd->tim_idx = cpu_to_le16(tim_idx); + tx_beacon_cmd->tim_size = beacon[tim_idx+1]; + } else + IWL_WARN(priv, "Unable to find TIM Element in beacon\n"); +} + static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame, u8 rate) + struct iwl_frame *frame) { struct iwl_tx_beacon_cmd *tx_beacon_cmd; - unsigned int frame_size; + u32 frame_size; + u32 rate_flags; + u32 rate; + /* + * We have to set up the TX command, the TX Beacon command, and the + * beacon contents. + */ + /* Initialize memory */ tx_beacon_cmd = &frame->u.beacon; memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); - tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id; - tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - + /* Set up TX beacon contents */ frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); + if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE)) + return 0; - BUG_ON(frame_size > MAX_MPDU_SIZE); + /* Set up TX command fields */ tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); + tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id; + tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK | + TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK; - if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) - tx_beacon_cmd->tx.rate_n_flags = - iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); - else - tx_beacon_cmd->tx.rate_n_flags = - iwl_hw_set_rate_n_flags(rate, 0); + /* Set up TX beacon command fields */ + iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame, + frame_size); - tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK | - TX_CMD_FLG_TSF_MSK | - TX_CMD_FLG_STA_RATE_MSK; + /* Set up packet rate and flags */ + rate = iwl_rate_get_lowest_plcp(priv); + priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); + rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant); + if ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE)) + rate_flags |= RATE_MCS_CCK_MSK; + tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, + rate_flags); return sizeof(*tx_beacon_cmd) + frame_size; } @@ -363,19 +403,20 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv) struct iwl_frame *frame; unsigned int frame_size; int rc; - u8 rate; frame = iwl_get_free_frame(priv); - if (!frame) { IWL_ERR(priv, "Could not obtain free frame buffer for beacon " "command.\n"); return -ENOMEM; } - rate = iwl_rate_get_lowest_plcp(priv); - - frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); + frame_size = iwl_hw_get_beacon_cmd(priv, frame); + if (!frame_size) { + IWL_ERR(priv, "Error configuring the beacon command\n"); + iwl_free_frame(priv, frame); + return -EINVAL; + } rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 1736c60c3e21..33da44f96e9f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -208,6 +208,7 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant) } return ant; } +EXPORT_SYMBOL(iwl_toggle_tx_ant); const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; EXPORT_SYMBOL(iwl_bcast_addr); -- cgit v1.2.3 From f513dfff9622ac72c461770e1fa01d291ba6ba5a Mon Sep 17 00:00:00 2001 From: Daniel C Halperin Date: Fri, 13 Nov 2009 11:56:34 -0800 Subject: iwlwifi: make iwlwifi send beacons Handle BSS_CHANGED_BEACON_ENABLED to enable the sending of beacons. Also set the correct HT RXON and QoS config. Signed-off-by: Daniel C Halperin Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 5 +++++ drivers/net/wireless/iwlwifi/iwl-core.c | 8 ++++++++ 2 files changed, 13 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 29f3b73c7560..1c6506529b6e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2563,6 +2563,10 @@ void iwl_config_ap(struct iwl_priv *priv) IWL_WARN(priv, "REPLY_RXON_TIMING failed - " "Attempting to continue.\n"); + /* AP has all antennas */ + priv->chain_noise_data.active_chains = + priv->hw_params.valid_rx_ant; + iwl_set_rxon_ht(priv, &priv->current_ht_config); if (priv->cfg->ops->hcmd->set_rxon_chain) priv->cfg->ops->hcmd->set_rxon_chain(priv); @@ -2591,6 +2595,7 @@ void iwl_config_ap(struct iwl_priv *priv) /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv); + iwl_reset_qos(priv); spin_lock_irqsave(&priv->lock, flags); iwl_activate_qos(priv, 1); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 33da44f96e9f..a2636f4b068f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2497,6 +2497,14 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, } } + if ((changes & BSS_CHANGED_BEACON_ENABLED) && + vif->bss_conf.enable_beacon) { + memcpy(priv->staging_rxon.bssid_addr, + bss_conf->bssid, ETH_ALEN); + memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); + iwlcore_config_ap(priv); + } + mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); -- cgit v1.2.3 From c397bf15a6067ecf39f8a771907f4721a64fd61f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 13 Nov 2009 11:56:35 -0800 Subject: iwlwifi: report PS filtered status When a frame is sent to a sleeping station, the microcode reports TX_STATUS_FAIL_DEST_PS as its status -- we need to translate that to the flag that mac80211 expects. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 6 ++---- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 ++---- drivers/net/wireless/iwlwifi/iwl-commands.h | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1d22ea390c00..0efde87b4597 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1864,8 +1864,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_is_tx_success(status) ? - IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_tx_status_to_mac80211(status); iwl_hwrate_to_tx_control(priv, rate_n_flags, info); /* FIXME: code repetition end */ @@ -2020,8 +2019,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, } } else { info->status.rates[0].count = tx_resp->failure_frame + 1; - info->flags |= iwl_is_tx_success(status) ? - IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_tx_status_to_mac80211(status); iwl_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 48982fb44995..570eaa08531f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -993,8 +993,7 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_is_tx_success(status) ? - IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_tx_status_to_mac80211(status); iwl_hwrate_to_tx_control(priv, rate_n_flags, info); /* FIXME: code repetition end */ @@ -1139,8 +1138,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, BUG_ON(txq_id != txq->swq_id); info->status.rates[0].count = tx_resp->failure_frame + 1; - info->flags |= iwl_is_tx_success(status) ? - IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_tx_status_to_mac80211(status); iwl_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6e23a2b5cb8a..87a7f2832c53 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1690,6 +1690,21 @@ enum { TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ }; +static inline u32 iwl_tx_status_to_mac80211(u32 status) +{ + status &= TX_STATUS_MSK; + + switch (status) { + case TX_STATUS_SUCCESS: + case TX_STATUS_DIRECT_DONE: + return IEEE80211_TX_STAT_ACK; + case TX_STATUS_FAIL_DEST_PS: + return IEEE80211_TX_STAT_TX_FILTERED; + default: + return 0; + } +} + static inline bool iwl_is_tx_success(u32 status) { status &= TX_STATUS_MSK; -- cgit v1.2.3 From 9bb487b406692e172b15eba58de7d69358ac2005 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 13 Nov 2009 11:56:36 -0800 Subject: iwlwifi: add sleep_tx_count ucode station API This field was marked as reserved before since we didn't use it, but is present in all released firmwares afaict. We're going to need it soon, so add it now. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-commands.h | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 0efde87b4597..1e58c49dd768 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1817,6 +1817,7 @@ static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid; addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid; addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn; + addsta->sleep_tx_count = cmd->sleep_tx_count; addsta->reserved1 = cpu_to_le16(0); addsta->reserved2 = cpu_to_le32(0); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 87a7f2832c53..aa4e38cbf071 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1107,7 +1107,14 @@ struct iwl4965_addsta_cmd { * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ __le16 add_immediate_ba_ssn; - __le32 reserved2; + /* + * Number of packets OK to transmit to station even though + * it is asleep -- used to synchronise PS-poll and u-APSD + * responses while ucode keeps track of STA sleep state. + */ + __le16 sleep_tx_count; + + __le16 reserved2; } __attribute__ ((packed)); /* 5000 */ @@ -1138,7 +1145,14 @@ struct iwl_addsta_cmd { * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ __le16 add_immediate_ba_ssn; - __le32 reserved2; + /* + * Number of packets OK to transmit to station even though + * it is asleep -- used to synchronise PS-poll and u-APSD + * responses while ucode keeps track of STA sleep state. + */ + __le16 sleep_tx_count; + + __le16 reserved2; } __attribute__ ((packed)); -- cgit v1.2.3 From 6ab10ff8738dfb098fd32132b7ebcf5cdb43ebde Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 13 Nov 2009 11:56:37 -0800 Subject: iwlwifi: handle unicast PS buffering Using the new mac80211 functionality, this makes iwlwifi handle unicast PS buffering correctly. The device works like this: * when a station goes to sleep, the microcode notices this and marks the station as asleep * when the station is marked asleep, the microcode refuses to transmit to the station and rejects all frames queued to it with the failure status code TX_STATUS_FAIL_DEST_PS (a previous patch handled this correctly) * when we need to send frames to the station _although_ it is asleep, we need to tell the ucode how many, and this is asynchronous with sending so we cannot just send the frames, we need to wait for all other frames to be flushed, and then update the counter before sending out the poll response frames. This is handled partially in the driver and partially in mac80211. In order to do all this correctly, we need to * keep track of how many frames are pending for each associated client station (avoid doing it for other stations to avoid the atomic ops) * tell mac80211 that we driver-block the PS status while there are still frames pending on the queues, and once they are all rejected (due to the dest sta being in PS) unblock mac80211 Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 42 +++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-commands.h | 1 + drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 -- drivers/net/wireless/iwlwifi/iwl-dev.h | 10 ++---- drivers/net/wireless/iwlwifi/iwl-rx.c | 17 ++-------- drivers/net/wireless/iwlwifi/iwl-sta.c | 29 ++++++++-------- drivers/net/wireless/iwlwifi/iwl-sta.h | 3 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 51 ++++++++++++++++++++++++++++- 8 files changed, 113 insertions(+), 42 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1c6506529b6e..6385cdf24d13 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2744,6 +2744,45 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, return 0; } +static void iwl_mac_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; + int sta_id; + + /* + * TODO: We really should use this callback to + * actually maintain the station table in + * the device. + */ + + switch (cmd) { + case STA_NOTIFY_ADD: + atomic_set(&sta_priv->pending_frames, 0); + if (vif->type == NL80211_IFTYPE_AP) + sta_priv->client = true; + break; + case STA_NOTIFY_SLEEP: + WARN_ON(!sta_priv->client); + sta_priv->asleep = true; + if (atomic_read(&sta_priv->pending_frames) > 0) + ieee80211_sta_block_awake(hw, sta, true); + break; + case STA_NOTIFY_AWAKE: + WARN_ON(!sta_priv->client); + sta_priv->asleep = false; + sta_id = iwl_find_station(priv, sta->addr); + if (sta_id != IWL_INVALID_STATION) + iwl_sta_modify_ps_wake(priv, sta_id); + break; + default: + break; + } +} + /***************************************************************************** * * sysfs attributes @@ -3175,7 +3214,8 @@ static struct ieee80211_ops iwl_hw_ops = { .reset_tsf = iwl_mac_reset_tsf, .bss_info_changed = iwl_bss_info_changed, .ampdu_action = iwl_mac_ampdu_action, - .hw_scan = iwl_mac_hw_scan + .hw_scan = iwl_mac_hw_scan, + .sta_notify = iwl_mac_sta_notify, }; static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index aa4e38cbf071..e91507531923 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -977,6 +977,7 @@ struct iwl_qosparam_cmd { #define STA_MODIFY_TX_RATE_MSK 0x04 #define STA_MODIFY_ADDBA_TID_MSK 0x08 #define STA_MODIFY_DELBA_TID_MSK 0x10 +#define STA_MODIFY_SLEEP_TX_COUNT_MSK 0x20 /* Receiver address (actually, Rx station's index into station table), * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index ba9c96ff27ca..9a5ca25d72c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -336,8 +336,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, pos += scnprintf(buf + pos, bufsz - pos, "flags: 0x%x\n", station->sta.station_flags_msk); - pos += scnprintf(buf + pos, bufsz - pos, - "ps_status: %u\n", station->ps_status); pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n"); pos += scnprintf(buf + pos, bufsz - pos, "seq_num\t\ttxq_id"); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index a474383ec0b8..f1601cfebc29 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -545,15 +545,11 @@ struct iwl_qos_info { struct iwl_qosparam_cmd def_qos_parm; }; -#define STA_PS_STATUS_WAKE 0 -#define STA_PS_STATUS_SLEEP 1 - struct iwl3945_station_entry { struct iwl3945_addsta_cmd sta; struct iwl_tid_data tid[MAX_TID_COUNT]; u8 used; - u8 ps_status; struct iwl_hw_key keyinfo; }; @@ -561,7 +557,6 @@ struct iwl_station_entry { struct iwl_addsta_cmd sta; struct iwl_tid_data tid[MAX_TID_COUNT]; u8 used; - u8 ps_status; struct iwl_hw_key keyinfo; }; @@ -571,11 +566,12 @@ struct iwl_station_entry { * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is places in that * space. - * - * At the moment use it for the station's rate scaling information. */ struct iwl_station_priv { struct iwl_lq_sta lq_sta; + atomic_t pending_frames; + bool client; + bool asleep; }; /* one for each uCode image (inst/data, boot/init/runtime) */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 9d010a0d83af..cc980d5d57c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -1028,7 +1028,6 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, struct iwl4965_rx_mpdu_res_start *amsdu; u32 len; u32 ampdu_status; - u16 fc; u32 rate_n_flags; /** @@ -1161,20 +1160,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, priv->last_tsf = le64_to_cpu(phy_res->timestamp); } - fc = le16_to_cpu(header->frame_control); - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_MGMT: - case IEEE80211_FTYPE_DATA: - if (priv->iw_mode == NL80211_IFTYPE_AP) - iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, - header->addr2); - /* fall through */ - default: - iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, - rxb, &rx_status); - break; - - } + iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, + rxb, &rx_status); } EXPORT_SYMBOL(iwl_rx_reply_rx); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index eba36f737388..cd6a6901216e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -1216,7 +1216,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) } EXPORT_SYMBOL(iwl_sta_rx_agg_stop); -static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) { unsigned long flags; @@ -1224,27 +1224,26 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.sleep_tx_count = 0; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } +EXPORT_SYMBOL(iwl_sta_modify_ps_wake); -void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) +void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) { - /* FIXME: need locking over ps_status ??? */ - u8 sta_id = iwl_find_station(priv, addr); + unsigned long flags; - if (sta_id != IWL_INVALID_STATION) { - u8 sta_awake = priv->stations[sta_id]. - ps_status == STA_PS_STATUS_WAKE; + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = + STA_MODIFY_SLEEP_TX_COUNT_MSK; + priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); - if (sta_awake && ps_bit) - priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; - else if (!sta_awake && !ps_bit) { - iwl_sta_modify_ps_wake(priv, sta_id); - priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; - } - } + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } - diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 1c382de80d49..8d052de2d405 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -66,5 +66,6 @@ void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); int iwl_sta_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn); int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); -void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr); +void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id); +void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt); #endif /* __iwl_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9370e062000d..ebfc460115d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -709,6 +709,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->control.sta; + struct iwl_station_priv *sta_priv = NULL; struct iwl_tx_queue *txq; struct iwl_queue *q; struct iwl_device_cmd *out_cmd; @@ -771,6 +773,24 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); + if (sta) + sta_priv = (void *)sta->drv_priv; + + if (sta_priv && sta_id != priv->hw_params.bcast_sta_id && + sta_priv->asleep) { + WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)); + /* + * This sends an asynchronous command to the device, + * but we can rely on it being processed before the + * next frame is processed -- and the next frame to + * this station is the one that will consume this + * counter. + * For now set the counter to just 1 since we do not + * support uAPSD yet. + */ + iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); + } + txq_id = skb_get_queue_mapping(skb); if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); @@ -930,6 +950,17 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) ret = iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); + /* + * At this point the frame is "transmitted" successfully + * and we will get a TX status notification eventually, + * regardless of the value of ret. "ret" only indicates + * whether or not we should update the write pointer. + */ + + /* avoid atomic ops if it isn't an associated client */ + if (sta_priv && sta_priv->client) + atomic_inc(&sta_priv->pending_frames); + if (ret) return ret; @@ -1074,6 +1105,24 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return ret ? ret : idx; } +static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_sta *sta; + struct iwl_station_priv *sta_priv; + + sta = ieee80211_find_sta(priv->vif, hdr->addr1); + if (sta) { + sta_priv = (void *)sta->drv_priv; + /* avoid atomic ops if this isn't a client */ + if (sta_priv->client && + atomic_dec_return(&sta_priv->pending_frames) == 0) + ieee80211_sta_block_awake(priv->hw, sta, false); + } + + ieee80211_tx_status_irqsafe(priv->hw, skb); +} + int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) { struct iwl_tx_queue *txq = &priv->txq[txq_id]; @@ -1093,7 +1142,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); + iwl_tx_status(priv, tx_info->skb[0]); tx_info->skb[0] = NULL; if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) -- cgit v1.2.3 From 9e595d24b13a021ead42bedd5edba8801b0da6cd Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 13 Nov 2009 11:56:38 -0800 Subject: iwlwifi: Add comments about CSR registers Also regroup CSR_EEPROM and CSR_OTP bit field definitions. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-csr.h | 177 ++++++++++++++++++++++++++++----- 1 file changed, 150 insertions(+), 27 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index b6ed5a3147a1..68ed82206723 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -62,11 +62,29 @@ *****************************************************************************/ #ifndef __iwl_csr_h__ #define __iwl_csr_h__ -/*=== CSR (control and status registers) ===*/ +/* + * CSR (control and status registers) + * + * CSR registers are mapped directly into PCI bus space, and are accessible + * whenever platform supplies power to device, even when device is in + * low power states due to driver-invoked device resets + * (e.g. CSR_RESET_REG_FLAG_SW_RESET) or uCode-driven power-saving modes. + * + * Use iwl_write32() and iwl_read32() family to access these registers; + * these provide simple PCI bus access, without waking up the MAC. + * Do not use iwl_write_direct32() family for these registers; + * no need to "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ. + * The MAC (uCode processor, etc.) does not need to be powered up for accessing + * the CSR registers. + * + * NOTE: Newer devices using one-time-programmable (OTP) memory + * require device to be awake in order to read this memory + * via CSR_EEPROM and CSR_OTP registers + */ #define CSR_BASE (0x000) #define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ -#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ +#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ #define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ #define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ #define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ @@ -74,42 +92,65 @@ #define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ #define CSR_GP_CNTRL (CSR_BASE+0x024) +/* 2nd byte of CSR_INT_COALESCING, not accessible via iwl_write32()! */ +#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005) + /* * Hardware revision info * Bit fields: * 31-8: Reserved - * 7-4: Type of device: 0x0 = 4965, 0xd = 3945 + * 7-4: Type of device: see CSR_HW_REV_TYPE_xxx definitions * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D - * 1-0: "Dash" value, as in A-1, etc. + * 1-0: "Dash" (-) value, as in A-1, etc. * * NOTE: Revision step affects calculation of CCK txpower for 4965. + * NOTE: See also CSR_HW_REV_WA_REG (work-around for bug in 4965). */ #define CSR_HW_REV (CSR_BASE+0x028) -/* EEPROM reads */ +/* + * EEPROM and OTP (one-time-programmable) memory reads + * + * NOTE: For (newer) devices using OTP, device must be awake, initialized via + * apm_ops.init() in order to read. Older devices (3945/4965/5000) + * use EEPROM and do not require this. + */ #define CSR_EEPROM_REG (CSR_BASE+0x02c) #define CSR_EEPROM_GP (CSR_BASE+0x030) #define CSR_OTP_GP_REG (CSR_BASE+0x034) + #define CSR_GIO_REG (CSR_BASE+0x03C) #define CSR_GP_UCODE_REG (CSR_BASE+0x048) #define CSR_GP_DRIVER_REG (CSR_BASE+0x050) + +/* + * UCODE-DRIVER GP (general purpose) mailbox registers. + * SET/CLR registers set/clear bit(s) if "1" is written. + */ #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) #define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) + #define CSR_LED_REG (CSR_BASE+0x094) #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) + +/* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) -#define CSR_INT_PERIODIC_REG (CSR_BASE+0x005) /* Analog phase-lock-loop configuration */ #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) + /* - * Indicates hardware rev, to determine CCK backoff for txpower calculation. + * CSR Hardware Revision Workaround Register. Indicates hardware rev; + * "step" determines CCK backoff for txpower calculation. Used for 4965 only. + * See also CSR_HW_REV register. * Bit fields: * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step + * 1-0: "Dash" (-) value, as in C-1, etc. */ #define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) + #define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240) #define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250) @@ -126,11 +167,11 @@ #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) #define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) -#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) -#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) -#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) -#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) -#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) +#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) +#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) +#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ +#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ +#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ #define CSR_INT_PERIODIC_DIS (0x00) #define CSR_INT_PERIODIC_ENA (0xFF) @@ -198,7 +239,44 @@ #define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) #define CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000) -/* GP (general purpose) CONTROL */ +/* + * GP (general purpose) CONTROL REGISTER + * Bit fields: + * 27: HW_RF_KILL_SW + * Indicates state of (platform's) hardware RF-Kill switch + * 26-24: POWER_SAVE_TYPE + * Indicates current power-saving mode: + * 000 -- No power saving + * 001 -- MAC power-down + * 010 -- PHY (radio) power-down + * 011 -- Error + * 9-6: SYS_CONFIG + * Indicates current system configuration, reflecting pins on chip + * as forced high/low by device circuit board. + * 4: GOING_TO_SLEEP + * Indicates MAC is entering a power-saving sleep power-down. + * Not a good time to access device-internal resources. + * 3: MAC_ACCESS_REQ + * Host sets this to request and maintain MAC wakeup, to allow host + * access to device-internal resources. Host must wait for + * MAC_CLOCK_READY (and !GOING_TO_SLEEP) before accessing non-CSR + * device registers. + * 2: INIT_DONE + * Host sets this to put device into fully operational D0 power mode. + * Host resets this after SW_RESET to put device into low power mode. + * 0: MAC_CLOCK_READY + * Indicates MAC (ucode processor, etc.) is powered up and can run. + * Internal resources are accessible. + * NOTE: This does not indicate that the processor is actually running. + * NOTE: This does not indicate that 4965 or 3945 has completed + * init or post-power-down restore of internal SRAM memory. + * Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that + * SRAM is restored and uCode is in normal operation mode. + * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and + * do not need to save/restore it. + * NOTE: After device reset, this bit remains "0" until host sets + * INIT_DONE + */ #define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) #define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) #define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) @@ -231,28 +309,58 @@ #define CSR_EEPROM_REG_MSK_DATA (0xFFFF0000) /* EEPROM GP */ -#define CSR_EEPROM_GP_VALID_MSK (0x00000007) +#define CSR_EEPROM_GP_VALID_MSK (0x00000007) /* signature */ #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) +#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000) +#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001) +#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002) +#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004) + +/* One-time-programmable memory general purpose reg */ #define CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */ #define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ #define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ #define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ + +/* GP REG */ #define CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */ #define CSR_GP_REG_NO_POWER_SAVE (0x00000000) #define CSR_GP_REG_MAC_POWER_SAVE (0x01000000) #define CSR_GP_REG_PHY_POWER_SAVE (0x02000000) #define CSR_GP_REG_POWER_SAVE_ERROR (0x03000000) -/* EEPROM signature */ -#define CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000) -#define CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001) -#define CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002) -#define CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004) /* CSR GIO */ #define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002) -/* UCODE DRV GP */ +/* + * UCODE-DRIVER GP (general purpose) mailbox register 1 + * Host driver and uCode write and/or read this register to communicate with + * each other. + * Bit fields: + * 4: UCODE_DISABLE + * Host sets this to request permanent halt of uCode, same as + * sending CARD_STATE command with "halt" bit set. + * 3: CT_KILL_EXIT + * Host sets this to request exit from CT_KILL state, i.e. host thinks + * device temperature is low enough to continue normal operation. + * 2: CMD_BLOCKED + * Host sets this during RF KILL power-down sequence (HW, SW, CT KILL) + * to release uCode to clear all Tx and command queues, enter + * unassociated mode, and power down. + * NOTE: Some devices also use HBUS_TARG_MBX_C register for this bit. + * 1: SW_BIT_RFKILL + * Host sets this when issuing CARD_STATE command to request + * device sleep. + * 0: MAC_SLEEP + * uCode sets this when preparing a power-saving power-down. + * uCode resets this when power-up is complete and SRAM is sane. + * NOTE: 3945/4965 saves internal SRAM data to host when powering down, + * and must restore this data after powering back up. + * MAC_SLEEP is the best indication that restore is complete. + * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and + * do not need to save/restore it. + */ #define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) #define CSR_UCODE_SW_BIT_RFKILL (0x00000002) #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) @@ -265,7 +373,7 @@ #define CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002) -/* GI Chicken Bits */ +/* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) @@ -285,8 +393,23 @@ #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) -/*=== HBUS (Host-side Bus) ===*/ +/* + * HBUS (Host-side Bus) + * + * HBUS registers are mapped directly into PCI bus space, but are used + * to indirectly access device's internal memory or registers that + * may be powered-down. + * + * Use iwl_write_direct32()/iwl_read_direct32() family for these registers; + * host must "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ + * to make sure the MAC (uCode processor, etc.) is powered up for accessing + * internal resources. + * + * Do not use iwl_write32()/iwl_read32() family to access these registers; + * these provide only simple PCI bus access, without waking up the MAC. + */ #define HBUS_BASE (0x400) + /* * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM * structures, error log, event log, verifying uCode load). @@ -301,6 +424,10 @@ #define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) #define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) +/* Mailbox C, used as workaround alternative to CSR_UCODE_DRV_GP1 mailbox */ +#define HBUS_TARG_MBX_C (HBUS_BASE+0x030) +#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) + /* * Registers for accessing device's internal peripheral registers * (e.g. SCD, BSM, etc.). First write to address register, @@ -315,16 +442,12 @@ #define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) /* - * Per-Tx-queue write pointer (index, really!) (3945 and 4965). + * Per-Tx-queue write pointer (index, really!) * Indicates index to next TFD that driver will fill (1 past latest filled). * Bit usage: * 0-7: queue write index * 11-8: queue selector */ #define HBUS_TARG_WRPTR (HBUS_BASE+0x060) -#define HBUS_TARG_MBX_C (HBUS_BASE+0x030) - -#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) - #endif /* !__iwl_csr_h__ */ -- cgit v1.2.3 From 7d57b73a73040525dfe22c56d823f146711ff971 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 14 Nov 2009 00:57:58 +0100 Subject: ar9170: do not discard valuable DUPOFDM frames This patch enables the driver to process all incoming dupofdm-modulated frames when operating in HT40 mode. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 7e59b82e64d3..bd2a276c870a 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -850,6 +850,7 @@ static int ar9170_rx_mac_status(struct ar9170 *ar, } break; + case AR9170_RX_STATUS_MODULATION_DUPOFDM: case AR9170_RX_STATUS_MODULATION_OFDM: switch (head->plcp[0] & 0xf) { case 0xb: @@ -897,8 +898,7 @@ static int ar9170_rx_mac_status(struct ar9170 *ar, status->flag |= RX_FLAG_HT; break; - case AR9170_RX_STATUS_MODULATION_DUPOFDM: - /* XXX */ + default: if (ar9170_nag_limiter(ar)) printk(KERN_ERR "%s: invalid modulation\n", wiphy_name(ar->hw->wiphy)); -- cgit v1.2.3 From 827e69bf6734193d7a6f47f0435db7ebef1b636e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 15 Nov 2009 23:09:25 +0100 Subject: ath9k: get rid of tx_info_priv This patch removes the need for separately allocated private tx info data in ath9k and brings the driver one small step closer to using the mac80211 rate control API properly. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common.h | 1 + drivers/net/wireless/ath/ath9k/debug.c | 11 +++-- drivers/net/wireless/ath/ath9k/rc.c | 71 ++++++++++++++++---------------- drivers/net/wireless/ath/ath9k/rc.h | 18 +++----- drivers/net/wireless/ath/ath9k/virtual.c | 9 +--- drivers/net/wireless/ath/ath9k/xmit.c | 70 ++++++++++++++----------------- 6 files changed, 83 insertions(+), 97 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 292e3d860c0e..4e1176029356 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -81,6 +81,7 @@ struct ath_buf { u16 bf_flags; struct ath_buf_state bf_state; dma_addr_t bf_dmacontext; + struct ath_wiphy *aphy; }; struct ath_atx_tid { diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 84f44269de47..06f1fcfb03e9 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -257,14 +257,17 @@ static const struct file_operations fops_interrupt = { void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) { - struct ath_tx_info_priv *tx_info_priv = NULL; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rates = tx_info->status.rates; - int final_ts_idx, idx; + int final_ts_idx = 0, idx, i; struct ath_rc_stats *stats; - tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - final_ts_idx = tx_info_priv->tx.ts_rateindex; + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + if (!rates[i].count) + break; + + final_ts_idx = i; + } idx = rates[final_ts_idx].idx; stats = &sc->debug.stats.rcstats[idx]; stats->success++; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index bb72b46567f9..ea4b9081b4d0 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -859,12 +859,12 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, static bool ath_rc_update_per(struct ath_softc *sc, const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv, - struct ath_tx_info_priv *tx_info_priv, + struct ieee80211_tx_info *tx_info, int tx_rate, int xretries, int retries, u32 now_msec) { bool state_change = false; - int count; + int count, n_bad_frames; u8 last_per; static u32 nretry_to_per_lookup[10] = { 100 * 0 / 1, @@ -880,6 +880,7 @@ static bool ath_rc_update_per(struct ath_softc *sc, }; last_per = ath_rc_priv->per[tx_rate]; + n_bad_frames = tx_info->status.ampdu_len - tx_info->status.ampdu_ack_len; if (xretries) { if (xretries == 1) { @@ -907,7 +908,7 @@ static bool ath_rc_update_per(struct ath_softc *sc, if (retries >= count) retries = count - 1; - if (tx_info_priv->n_bad_frames) { + if (n_bad_frames) { /* new_PER = 7/8*old_PER + 1/8*(currentPER) * Assuming that n_frames is not 0. The current PER * from the retries is 100 * retries / (retries+1), @@ -920,14 +921,14 @@ static bool ath_rc_update_per(struct ath_softc *sc, * the above PER. The expression below is a * simplified version of the sum of these two terms. */ - if (tx_info_priv->n_frames > 0) { - int n_frames, n_bad_frames; + if (tx_info->status.ampdu_len > 0) { + int n_frames, n_bad_tries; u8 cur_per, new_per; - n_bad_frames = retries * tx_info_priv->n_frames + - tx_info_priv->n_bad_frames; - n_frames = tx_info_priv->n_frames * (retries + 1); - cur_per = (100 * n_bad_frames / n_frames) >> 3; + n_bad_tries = retries * tx_info->status.ampdu_len + + n_bad_frames; + n_frames = tx_info->status.ampdu_len * (retries + 1); + cur_per = (100 * n_bad_tries / n_frames) >> 3; new_per = (u8)(last_per - (last_per >> 3) + cur_per); ath_rc_priv->per[tx_rate] = new_per; } @@ -943,8 +944,7 @@ static bool ath_rc_update_per(struct ath_softc *sc, * this was a probe. Otherwise, ignore the probe. */ if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { - if (retries > 0 || 2 * tx_info_priv->n_bad_frames > - tx_info_priv->n_frames) { + if (retries > 0 || 2 * n_bad_frames > tx_info->status.ampdu_len) { /* * Since we probed with just a single attempt, * any retries means the probe failed. Also, @@ -1003,7 +1003,7 @@ static bool ath_rc_update_per(struct ath_softc *sc, static void ath_rc_update_ht(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, - struct ath_tx_info_priv *tx_info_priv, + struct ieee80211_tx_info *tx_info, int tx_rate, int xretries, int retries) { u32 now_msec = jiffies_to_msecs(jiffies); @@ -1020,7 +1020,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Update PER first */ state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, - tx_info_priv, tx_rate, xretries, + tx_info, tx_rate, xretries, retries, now_msec); /* @@ -1098,7 +1098,6 @@ static void ath_rc_tx_status(struct ath_softc *sc, struct ieee80211_tx_info *tx_info, int final_ts_idx, int xretries, int long_retry) { - struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); const struct ath_rate_table *rate_table; struct ieee80211_tx_rate *rates = tx_info->status.rates; u8 flags; @@ -1124,9 +1123,8 @@ static void ath_rc_tx_status(struct ath_softc *sc, return; rix = ath_rc_get_rateindex(rate_table, &rates[i]); - ath_rc_update_ht(sc, ath_rc_priv, - tx_info_priv, rix, - xretries ? 1 : 2, + ath_rc_update_ht(sc, ath_rc_priv, tx_info, + rix, xretries ? 1 : 2, rates[i].count); } } @@ -1149,8 +1147,7 @@ static void ath_rc_tx_status(struct ath_softc *sc, return; rix = ath_rc_get_rateindex(rate_table, &rates[i]); - ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix, - xretries, long_retry); + ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry); } static const @@ -1301,23 +1298,30 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, { struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; - struct ath_tx_info_priv *tx_info_priv = NULL; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr; - int final_ts_idx, tx_status = 0, is_underrun = 0; + int final_ts_idx = 0, tx_status = 0, is_underrun = 0; + int long_retry = 0; __le16 fc; + int i; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - final_ts_idx = tx_info_priv->tx.ts_rateindex; + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; + if (!rate->count) + break; + + final_ts_idx = i; + long_retry = rate->count - 1; + } if (!priv_sta || !ieee80211_is_data(fc) || - !tx_info_priv->update_rc) - goto exit; + !(tx_info->pad[0] & ATH_TX_INFO_UPDATE_RC)) + return; - if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT) - goto exit; + if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) + return; /* * If underrun error is seen assume it as an excessive retry only @@ -1325,20 +1329,17 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, * Adjust the long retry as if the frame was tried hw->max_rate_tries * times. This affects how ratectrl updates PER for the failed rate. */ - if (tx_info_priv->tx.ts_flags & - (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) && - ((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) { + if ((tx_info->pad[0] & ATH_TX_INFO_UNDERRUN) && + (sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) { tx_status = 1; is_underrun = 1; } - if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) || - (tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO)) + if (tx_info->pad[0] & ATH_TX_INFO_XRETRY) tx_status = 1; ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, - (is_underrun) ? sc->hw->max_rate_tries : - tx_info_priv->tx.ts_longretry); + (is_underrun) ? sc->hw->max_rate_tries : long_retry); /* Check if aggregation has to be enabled for this tid */ if (conf_is_ht(&sc->hw->conf) && @@ -1357,8 +1358,6 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, } ath_debug_stat_rc(sc, skb); -exit: - kfree(tx_info_priv); } static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 94cb9f8d2446..51f85ecbe88d 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -167,24 +167,18 @@ struct ath_rate_priv { struct ath_rate_softc *asc; }; +#define ATH_TX_INFO_FRAME_TYPE_INTERNAL (1 << 0) +#define ATH_TX_INFO_FRAME_TYPE_PAUSE (1 << 1) +#define ATH_TX_INFO_UPDATE_RC (1 << 2) +#define ATH_TX_INFO_XRETRY (1 << 3) +#define ATH_TX_INFO_UNDERRUN (1 << 4) + enum ath9k_internal_frame_type { ATH9K_NOT_INTERNAL, ATH9K_INT_PAUSE, ATH9K_INT_UNPAUSE }; -struct ath_tx_info_priv { - struct ath_wiphy *aphy; - struct ath_tx_status tx; - int n_frames; - int n_bad_frames; - bool update_rc; - enum ath9k_internal_frame_type frame_type; -}; - -#define ATH_TX_INFO_PRIV(tx_info) \ - ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0])) - void ath_rate_attach(struct ath_softc *sc); u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate); int ath_rate_control_register(void); diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 0a36b572294c..cd26caaf44e7 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -338,13 +338,11 @@ void ath9k_wiphy_chan_work(struct work_struct *work) void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath_wiphy *aphy = hw->priv; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE && + if ((tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_PAUSE) && aphy->state == ATH_WIPHY_PAUSING) { - if (!(info->flags & IEEE80211_TX_STAT_ACK)) { + if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) { printk(KERN_DEBUG "ath9k: %s: no ACK for pause " "frame\n", wiphy_name(hw->wiphy)); /* @@ -363,9 +361,6 @@ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) } } - kfree(tx_info_priv); - tx_info->rate_driver_data[0] = NULL; - dev_kfree_skb(skb); } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 86b54ddd01cb..2db0fa878c26 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -251,6 +251,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) ATH_TXBUF_RESET(tbf); + tbf->aphy = bf->aphy; tbf->bf_mpdu = bf->bf_mpdu; tbf->bf_buf_addr = bf->bf_buf_addr; *(tbf->bf_desc) = *(bf->bf_desc); @@ -270,7 +271,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ieee80211_hw *hw; struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; - struct ath_tx_info_priv *tx_info_priv; struct ath_atx_tid *tid = NULL; struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; struct ath_desc *ds = bf_last->bf_desc; @@ -284,8 +284,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, hdr = (struct ieee80211_hdr *)skb->data; tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *) tx_info->rate_driver_data[0]; - hw = tx_info_priv->aphy->hw; + hw = bf->aphy->hw; rcu_read_lock(); @@ -464,7 +463,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; - struct ath_tx_info_priv *tx_info_priv; u32 max_4ms_framelen, frmlen; u16 aggr_limit, legacy = 0; int i; @@ -472,7 +470,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); rates = tx_info->control.rates; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; /* * Find the lowest frame length among the rate series that will have a @@ -1560,21 +1557,26 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, struct ath_softc *sc = aphy->sc; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ath_tx_info_priv *tx_info_priv; int hdrlen; __le16 fc; - tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); - if (unlikely(!tx_info_priv)) - return -ENOMEM; - tx_info->rate_driver_data[0] = tx_info_priv; - tx_info_priv->aphy = aphy; - tx_info_priv->frame_type = txctl->frame_type; + tx_info->pad[0] = 0; + switch (txctl->frame_type) { + case ATH9K_NOT_INTERNAL: + break; + case ATH9K_INT_PAUSE: + tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE; + /* fall through */ + case ATH9K_INT_UNPAUSE: + tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL; + break; + } hdrlen = ieee80211_get_hdrlen_from_skb(skb); fc = hdr->frame_control; ATH_TXBUF_RESET(bf); + bf->aphy = aphy; bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); if (conf_is_ht(&hw->conf) && !is_pae(skb)) @@ -1599,8 +1601,6 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, skb->len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) { bf->bf_mpdu = NULL; - kfree(tx_info_priv); - tx_info->rate_driver_data[0] = NULL; ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, "dma_mapping_error() on TX\n"); return -ENOMEM; @@ -1781,27 +1781,17 @@ exit: /*****************/ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - int tx_flags) + struct ath_wiphy *aphy, int tx_flags) { struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); struct ath_common *common = ath9k_hw_common(sc->sc_ah); int hdrlen, padsize; - int frame_type = ATH9K_NOT_INTERNAL; ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); - if (tx_info_priv) { - hw = tx_info_priv->aphy->hw; - frame_type = tx_info_priv->frame_type; - } - - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || - tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - kfree(tx_info_priv); - tx_info->rate_driver_data[0] = NULL; - } + if (aphy) + hw = aphy->hw; if (tx_flags & ATH_TX_BAR) tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; @@ -1833,10 +1823,10 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, SC_OP_WAIT_FOR_TX_ACK)); } - if (frame_type == ATH9K_NOT_INTERNAL) - ieee80211_tx_status(hw, skb); - else + if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL)) ath9k_tx_status(hw, skb); + else + ieee80211_tx_status(hw, skb); } static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, @@ -1859,7 +1849,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, } dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); - ath_tx_complete(sc, skb, tx_flags); + ath_tx_complete(sc, skb, bf->aphy, tx_flags); ath_debug_stat_tx(sc, txq, bf); /* @@ -1907,8 +1897,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); - struct ieee80211_hw *hw = tx_info_priv->aphy->hw; + struct ieee80211_hw *hw = bf->aphy->hw; u8 i, tx_rateindex; if (txok) @@ -1917,17 +1906,22 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, tx_rateindex = ds->ds_txstat.ts_rateindex; WARN_ON(tx_rateindex >= hw->max_rates); - tx_info_priv->update_rc = update_rc; + if (update_rc) + tx_info->pad[0] |= ATH_TX_INFO_UPDATE_RC; if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { if (ieee80211_is_data(hdr->frame_control)) { - memcpy(&tx_info_priv->tx, &ds->ds_txstat, - sizeof(tx_info_priv->tx)); - tx_info_priv->n_frames = bf->bf_nframes; - tx_info_priv->n_bad_frames = nbad; + if (ds->ds_txstat.ts_flags & + (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN)) + tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN; + if ((ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) || + (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO)) + tx_info->pad[0] |= ATH_TX_INFO_XRETRY; + tx_info->status.ampdu_len = bf->bf_nframes; + tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad; } } -- cgit v1.2.3 From c6089ccc22377bcbf055ece6a45b931a02630824 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 16 Nov 2009 11:40:48 +0530 Subject: ath9k: Cleanup bss_info_changed callback * Remove a code chunk dealing with operating mode changes. As noted, all such policy changes are to be done in add_interface. * Remove pointless check for empty BSSID. Also, remove mode checks - mac80211 does all the needed checks. * Handle enabling/disabling beacon transmission properly. * Handle beacon interval changes for AP mode. The original code depended on config_interface() to update the HW TSF. Since that callback has been removed, handle it properly. * Remove unneeded code dealing with key/privacy. * Set the chainmasks to 1x1 for IBSS when the BSSID is set. This was happening uncondionally before. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 114 +++++++++++----------------------- 1 file changed, 37 insertions(+), 77 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3c02b977a613..3229c3993568 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2956,90 +2956,62 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; - u32 rfilt = 0; - int error, i; + int error; mutex_lock(&sc->mutex); - /* - * TODO: Need to decide which hw opmode to use for - * multi-interface cases - * XXX: This belongs into add_interface! - */ - if (vif->type == NL80211_IFTYPE_AP && - ah->opmode != NL80211_IFTYPE_AP) { - ah->opmode = NL80211_IFTYPE_STATION; - ath9k_hw_setopmode(ah); - memcpy(common->curbssid, common->macaddr, ETH_ALEN); + if (changed & BSS_CHANGED_BSSID) { + /* Set BSSID */ + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); common->curaid = 0; ath9k_hw_write_associd(ah); - /* Request full reset to get hw opmode changed properly */ - sc->sc_flags |= SC_OP_FULL_RESET; - } - if ((changed & BSS_CHANGED_BSSID) && - !is_zero_ether_addr(bss_conf->bssid)) { - switch (vif->type) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - /* Set BSSID */ - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); - common->curaid = 0; - ath9k_hw_write_associd(ah); + /* Set aggregation protection mode parameters */ + sc->config.ath_aggr_prot = 0; - /* Set aggregation protection mode parameters */ - sc->config.ath_aggr_prot = 0; + /* Only legacy IBSS for now */ + if (vif->type == NL80211_IFTYPE_ADHOC) + ath_update_chainmask(sc, 0); - ath_print(common, ATH_DBG_CONFIG, - "RX filter 0x%x bssid %pM aid 0x%x\n", - rfilt, common->curbssid, common->curaid); + ath_print(common, ATH_DBG_CONFIG, + "BSSID: %pM aid: 0x%x\n", + common->curbssid, common->curaid); - /* need to reconfigure the beacon */ - sc->sc_flags &= ~SC_OP_BEACONS ; + /* need to reconfigure the beacon */ + sc->sc_flags &= ~SC_OP_BEACONS ; + } - break; - default: - break; - } + /* Enable transmission of beacons (AP, IBSS, MESH) */ + if ((changed & BSS_CHANGED_BEACON) || + ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) { + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + error = ath_beacon_alloc(aphy, vif); + if (!error) + ath_beacon_config(sc, vif); } - if ((vif->type == NL80211_IFTYPE_ADHOC) || - (vif->type == NL80211_IFTYPE_AP) || - (vif->type == NL80211_IFTYPE_MESH_POINT)) { - if ((changed & BSS_CHANGED_BEACON) || - (changed & BSS_CHANGED_BEACON_ENABLED && - bss_conf->enable_beacon)) { - /* - * Allocate and setup the beacon frame. - * - * Stop any previous beacon DMA. This may be - * necessary, for example, when an ibss merge - * causes reconfiguration; we may be called - * with beacon transmission active. - */ - ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + /* Disable transmission of beacons */ + if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + if (changed & BSS_CHANGED_BEACON_INT) { + sc->beacon_interval = bss_conf->beacon_int; + /* + * In case of AP mode, the HW TSF has to be reset + * when the beacon interval changes. + */ + if (vif->type == NL80211_IFTYPE_AP) { + sc->sc_flags |= SC_OP_TSF_RESET; + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); error = ath_beacon_alloc(aphy, vif); if (!error) ath_beacon_config(sc, vif); + } else { + ath_beacon_config(sc, vif); } } - /* Check for WLAN_CAPABILITY_PRIVACY ? */ - if ((avp->av_opmode != NL80211_IFTYPE_STATION)) { - for (i = 0; i < IEEE80211_WEP_NKID; i++) - if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i)) - ath9k_hw_keysetmac(sc->sc_ah, - (u16)i, - common->curbssid); - } - - /* Only legacy IBSS for now */ - if (vif->type == NL80211_IFTYPE_ADHOC) - ath_update_chainmask(sc, 0); - if (changed & BSS_CHANGED_ERP_PREAMBLE) { ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", bss_conf->use_short_preamble); @@ -3065,18 +3037,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_bss_assoc_info(sc, vif, bss_conf); } - /* - * The HW TSF has to be reset when the beacon interval changes. - * We set the flag here, and ath_beacon_config_ap() would take this - * into account when it gets called through the subsequent - * config_interface() call - with IFCC_BEACON in the changed field. - */ - - if (changed & BSS_CHANGED_BEACON_INT) { - sc->sc_flags |= SC_OP_TSF_RESET; - sc->beacon_interval = bss_conf->beacon_int; - } - mutex_unlock(&sc->mutex); } -- cgit v1.2.3 From 7c82a186b48882c2a21a3eda25f3dab2d6040a09 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 16 Nov 2009 11:40:51 +0530 Subject: ath9k: Remove a few unused variables axq_linkbuf, axq_aggr_depth, axq_lastdsWithCTS and axq_gatingds are unused. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 10 ---------- drivers/net/wireless/ath/ath9k/xmit.c | 13 ------------- 2 files changed, 23 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index d9bcc3abb425..2a40fa2cd914 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -198,18 +198,8 @@ struct ath_txq { struct list_head axq_q; spinlock_t axq_lock; u32 axq_depth; - u8 axq_aggr_depth; bool stopped; bool axq_tx_inprogress; - struct ath_buf *axq_linkbuf; - - /* first desc of the last descriptor that contains CTS */ - struct ath_desc *axq_lastdsWithCTS; - - /* final desc of the gating desc that determines whether - lastdsWithCTS has been DMA'ed or not */ - struct ath_desc *axq_gatingds; - struct list_head axq_acq; }; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2db0fa878c26..745d91995d78 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -699,7 +699,6 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, /* anchor last desc of aggregate */ ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc); - txq->axq_aggr_depth++; ath_tx_txqaddbuf(sc, txq, &bf_q); TX_STAT_INC(txq->axq_qnum, a_aggr); @@ -875,8 +874,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) INIT_LIST_HEAD(&txq->axq_acq); spin_lock_init(&txq->axq_lock); txq->axq_depth = 0; - txq->axq_aggr_depth = 0; - txq->axq_linkbuf = NULL; txq->axq_tx_inprogress = false; sc->tx.txqsetup |= 1<axq_q)) { txq->axq_link = NULL; - txq->axq_linkbuf = NULL; spin_unlock_bh(&txq->axq_lock); break; } @@ -1196,7 +1192,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, list_splice_tail_init(head, &txq->axq_q); txq->axq_depth++; - txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); ath_print(common, ATH_DBG_QUEUE, "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); @@ -1965,7 +1960,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) spin_lock_bh(&txq->axq_lock); if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; - txq->axq_linkbuf = NULL; spin_unlock_bh(&txq->axq_lock); break; } @@ -1999,10 +1993,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) spin_unlock_bh(&txq->axq_lock); break; } - if (bf->bf_desc == txq->axq_lastdsWithCTS) - txq->axq_lastdsWithCTS = NULL; - if (ds == txq->axq_gatingds) - txq->axq_gatingds = NULL; /* * Remove ath_buf's of the same transmit unit from txq, @@ -2016,9 +2006,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) &txq->axq_q, lastbf->list.prev); txq->axq_depth--; - if (bf_isaggr(bf)) - txq->axq_aggr_depth--; - txok = (ds->ds_txstat.ts_status == 0); txq->axq_tx_inprogress = false; spin_unlock_bh(&txq->axq_lock); -- cgit v1.2.3 From 201cd6cce4f67ccead6240eb04ffa2f311661174 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 16 Nov 2009 11:40:53 +0530 Subject: ath9k: Remove a few unused functions ATH9K_ANT_VARIABLE is the default diversity control used. Consequently ath9k_hw_decrease_chain_power() does nothing. ath9k_hw_setantennaswitch() is unused too. Also, gbeacon_rate is unused. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 53 --------------------- drivers/net/wireless/ath/ath9k/hw.h | 23 --------- drivers/net/wireless/ath/ath9k/phy.c | 90 ------------------------------------ drivers/net/wireless/ath/ath9k/phy.h | 3 -- 4 files changed, 169 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index b25eedf67e0b..ffcc4f039fa2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -390,8 +390,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.cck_trig_high = 200; ah->config.cck_trig_low = 100; ah->config.enable_ani = 1; - ah->config.diversity_control = ATH9K_ANT_VARIABLE; - ah->config.antenna_switch_swap = 0; for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { ah->config.spurchans[i][0] = AR_NO_SPUR; @@ -446,9 +444,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->acktimeout = (u32) -1; ah->ctstimeout = (u32) -1; ah->globaltxtimeout = (u32) -1; - - ah->gbeacon_rate = 0; - ah->power_mode = ATH9K_PM_UNDEFINED; } @@ -2056,9 +2051,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ah->ath9k_hw_spur_mitigate_freq(ah, chan); ah->eep_ops->set_board_values(ah, chan); - if (AR_SREV_5416(ah)) - ath9k_hw_decrease_chain_power(ah, chan); - REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr)); REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4) | macStaId1 @@ -3518,51 +3510,6 @@ void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna) } EXPORT_SYMBOL(ath9k_hw_setantenna); -bool ath9k_hw_setantennaswitch(struct ath_hw *ah, - enum ath9k_ant_setting settings, - struct ath9k_channel *chan, - u8 *tx_chainmask, - u8 *rx_chainmask, - u8 *antenna_cfgd) -{ - static u8 tx_chainmask_cfg, rx_chainmask_cfg; - - if (AR_SREV_9280(ah)) { - if (!tx_chainmask_cfg) { - - tx_chainmask_cfg = *tx_chainmask; - rx_chainmask_cfg = *rx_chainmask; - } - - switch (settings) { - case ATH9K_ANT_FIXED_A: - *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK; - *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK; - *antenna_cfgd = true; - break; - case ATH9K_ANT_FIXED_B: - if (ah->caps.tx_chainmask > - ATH9K_ANTENNA1_CHAINMASK) { - *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK; - } - *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK; - *antenna_cfgd = true; - break; - case ATH9K_ANT_VARIABLE: - *tx_chainmask = tx_chainmask_cfg; - *rx_chainmask = rx_chainmask_cfg; - *antenna_cfgd = true; - break; - default: - break; - } - } else { - ah->config.diversity_control = settings; - } - - return true; -} - /*********************/ /* General Operation */ /*********************/ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index abaa2f09a3bc..f8f5e997162c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -148,21 +148,6 @@ enum wireless_mode { ATH9K_MODE_MAX, }; -/** - * ath9k_ant_setting - transmit antenna settings - * - * Configures the antenna setting to use for transmit. - * - * @ATH9K_ANT_VARIABLE: this means transmit on all active antennas - * @ATH9K_ANT_FIXED_A: this means transmit on the first antenna only - * @ATH9K_ANT_FIXED_B: this means transmit on the second antenna only - */ -enum ath9k_ant_setting { - ATH9K_ANT_VARIABLE = 0, - ATH9K_ANT_FIXED_A, - ATH9K_ANT_FIXED_B -}; - enum ath9k_hw_caps { ATH9K_HW_CAP_MIC_AESCCM = BIT(0), ATH9K_HW_CAP_MIC_CKIP = BIT(1), @@ -226,8 +211,6 @@ struct ath9k_ops_config { u32 cck_trig_high; u32 cck_trig_low; u32 enable_ani; - enum ath9k_ant_setting diversity_control; - u16 antenna_switch_swap; int serialize_regmode; bool intr_mitigation; #define SPUR_DISABLE 0 @@ -572,7 +555,6 @@ struct ath_hw { u32 acktimeout; u32 ctstimeout; u32 globaltxtimeout; - u8 gbeacon_rate; /* ANI */ u32 proc_phyerr; @@ -659,11 +641,6 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); u32 ath9k_hw_getdefantenna(struct ath_hw *ah); void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); -bool ath9k_hw_setantennaswitch(struct ath_hw *ah, - enum ath9k_ant_setting settings, - struct ath9k_channel *chan, - u8 *tx_chainmask, u8 *rx_chainmask, - u8 *antenna_cfgd); /* General Operation */ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c index 13ab4d7eb7aa..c3b59390fe38 100644 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ b/drivers/net/wireless/ath/ath9k/phy.c @@ -527,95 +527,6 @@ static void ath9k_hw_force_bias(struct ath_hw *ah, u16 synth_freq) REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes); } -/** - * ath9k_hw_decrease_chain_power() - * - * @ah: atheros hardware structure - * @chan: - * - * Only used on the AR5416 and AR5418 with the external AR2133/AR5133 radios. - * - * Sets a chain internal RF path to the lowest output power. Any - * further writes to bank6 after this setting will override these - * changes. Thus this function must be the last function in the - * sequence to modify bank 6. - * - * This function must be called after ar5416SetRfRegs() which is - * called from ath9k_hw_process_ini() due to swizzling of bank 6. - * Depends on ah->analogBank6Data being initialized by - * ath9k_hw_set_rf_regs() - * - * Additional additive reduction in power - - * change chain's switch table so chain's tx state is actually the rx - * state value. May produce different results in 2GHz/5GHz as well as - * board to board but in general should be a reduction. - * - * Activated by #ifdef ALTER_SWITCH. Not tried yet. If so, must be - * called after ah->eep_ops->set_board_values() due to RMW of - * PHY_SWITCH_CHAIN_0. - */ -void ath9k_hw_decrease_chain_power(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - int i, regWrites = 0; - u32 bank6SelMask; - u32 *bank6Temp = ah->bank6Temp; - - BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); - - switch (ah->config.diversity_control) { - case ATH9K_ANT_FIXED_A: - bank6SelMask = - (ah->config.antenna_switch_swap & ANTSWAP_AB) ? - REDUCE_CHAIN_0 : /* swapped, reduce chain 0 */ - REDUCE_CHAIN_1; /* normal, select chain 1/2 to reduce */ - break; - case ATH9K_ANT_FIXED_B: - bank6SelMask = - (ah->config.antenna_switch_swap & ANTSWAP_AB) ? - REDUCE_CHAIN_1 : /* swapped, reduce chain 1/2 */ - REDUCE_CHAIN_0; /* normal, select chain 0 to reduce */ - break; - case ATH9K_ANT_VARIABLE: - return; /* do not change anything */ - break; - default: - return; /* do not change anything */ - break; - } - - for (i = 0; i < ah->iniBank6.ia_rows; i++) - bank6Temp[i] = ah->analogBank6Data[i]; - - /* Write Bank 5 to switch Bank 6 write to selected chain only */ - REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask); - - /* - * Modify Bank6 selected chain to use lowest amplification. - * Modifies the parameters to a value of 1. - * Depends on existing bank 6 values to be cached in - * ah->analogBank6Data - */ - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0); - ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0); - - REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites); - - REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053); -#ifdef ALTER_SWITCH - REG_WRITE(ah, PHY_SWITCH_CHAIN_0, - (REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38) - | ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38)); -#endif -} - /** * ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios * @ah: atheros hardware stucture @@ -687,7 +598,6 @@ int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) } ath9k_hw_force_bias(ah, freq); - ath9k_hw_decrease_chain_power(ah, chan); reg32 = (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index dc145a135dc7..31de27dc0c4a 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -35,9 +35,6 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, u16 modesIndex); -void ath9k_hw_decrease_chain_power(struct ath_hw *ah, - struct ath9k_channel *chan); - #define AR_PHY_BASE 0x9800 #define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) -- cgit v1.2.3 From cb53a150caa3068ce366b75dd354718145f5e893 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 16 Nov 2009 11:40:57 +0530 Subject: ath9k: Fix bug in initializing chain masks Check for AR5416 ver 1.0 before calibrating 3 chains for multi-chain. This is a WAR for calibration failure. Signed-off-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ffcc4f039fa2..53a7b980d8f6 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1146,7 +1146,7 @@ static void ath9k_hw_init_chain_masks(struct ath_hw *ah) REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); case 0x3: - if (((ah)->hw_version.macVersion <= AR_SREV_VERSION_9160)) { + if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) { REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); break; -- cgit v1.2.3 From c951ad3550ab40071bb0f222ba6125845769c08a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 16 Nov 2009 12:00:38 +0100 Subject: mac80211: convert aggregation to operate on vifs/stas The entire aggregation code currently operates on the hw pointer and station addresses, but that needs to change to make stations purely per-vif; As one step preparing for that make the aggregation code callable with the station, or by the combination of virtual interface and station address. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/main.c | 5 +- drivers/net/wireless/ath/ath9k/main.c | 5 +- drivers/net/wireless/ath/ath9k/rc.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 1 + drivers/net/wireless/iwlwifi/iwl-tx.c | 8 +-- include/net/mac80211.h | 28 +++++---- net/mac80211/agg-rx.c | 6 +- net/mac80211/agg-tx.c | 96 ++++++++++++------------------- net/mac80211/driver-ops.h | 5 +- net/mac80211/driver-trace.h | 9 ++- net/mac80211/ht.c | 3 +- net/mac80211/ieee80211_i.h | 3 +- net/mac80211/main.c | 8 +-- 14 files changed, 84 insertions(+), 97 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index bd2a276c870a..f9d6db8d013e 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -2441,6 +2441,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, } static int ar9170_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { @@ -2470,7 +2471,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw, tid_info->state = AR9170_TID_STATE_PROGRESS; tid_info->active = false; spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: @@ -2480,7 +2481,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw, tid_info->active = false; skb_queue_purge(&tid_info->queue); spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3229c3993568..16bdb1b549b4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -3078,6 +3078,7 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw) } static int ath9k_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) @@ -3095,11 +3096,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, break; case IEEE80211_AMPDU_TX_START: ath_tx_aggr_start(sc, sta, tid, ssn); - ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: ath_tx_aggr_stop(sc, sta, tid); - ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: ath_tx_aggr_resume(sc, sta, tid); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index ea4b9081b4d0..1d96777b4cd2 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1353,7 +1353,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, an = (struct ath_node *)sta->drv_priv; if(ath_tx_aggr_check(sc, an, tid)) - ieee80211_start_tx_ba_session(sc->hw, hdr->addr1, tid); + ieee80211_start_tx_ba_session(sta, tid); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 43edd8fd4405..2f09e3b7f0eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -301,7 +301,7 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n", sta->addr, tid); - ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); + ieee80211_start_tx_ba_session(sta, tid); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 6385cdf24d13..b80cd0bc5845 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2691,6 +2691,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index ebfc460115d6..f3dff2ecc406 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1312,7 +1312,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) if (tid_data->tfds_in_queue == 0) { IWL_DEBUG_HT(priv, "HW queue is empty\n"); tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid); + ieee80211_start_tx_ba_cb_irqsafe(priv->vif, ra, tid); } else { IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n", tid_data->tfds_in_queue); @@ -1377,7 +1377,7 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) if (ret) return ret; - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid); + ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid); return 0; } @@ -1401,7 +1401,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, tx_fifo); tid_data->agg.state = IWL_AGG_OFF; - ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid); + ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid); } break; case IWL_EMPTYING_HW_QUEUE_ADDBA: @@ -1409,7 +1409,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) if (tid_data->tfds_in_queue == 0) { IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n"); tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid); + ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid); } break; } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3b3defbe6fc1..4af0ffb98aaf 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1508,6 +1508,7 @@ struct ieee80211_ops { void (*reset_tsf)(struct ieee80211_hw *hw); int (*tx_last_beacon)(struct ieee80211_hw *hw); int (*ampdu_action)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn); @@ -2029,8 +2030,7 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, /** * ieee80211_start_tx_ba_session - Start a tx Block Ack session. - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @ra: receiver address of the BA session recipient + * @sta: the station for which to start a BA session * @tid: the TID to BA on. * * Return: success if addBA request was sent, failure otherwise @@ -2039,22 +2039,22 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, * the need to start aggregation on a certain RA/TID, the session level * will be managed by the mac80211. */ -int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid); +int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid); /** * ieee80211_start_tx_ba_cb - low level driver ready to aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the TID to BA on. * * This function must be called by low level driver once it has * finished with preparations for the BA session. */ -void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid); +void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); /** * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the TID to BA on. * @@ -2062,13 +2062,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid); * finished with preparations for the BA session. * This version of the function is IRQ-safe. */ -void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid); /** * ieee80211_stop_tx_ba_session - Stop a Block Ack session. - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @ra: receiver address of the BA session recipient + * @sta: the station whose BA session to stop * @tid: the TID to stop BA. * @initiator: if indicates initiator DELBA frame will be sent. * @@ -2078,24 +2077,23 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, * the need to stop aggregation on a certain RA/TID, the session level * will be managed by the mac80211. */ -int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, - u8 *ra, u16 tid, +int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid, enum ieee80211_back_parties initiator); /** * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the desired TID to BA on. * * This function must be called by low level driver once it has * finished with preparations for the BA session tear down. */ -void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); +void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); /** * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. - * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf * @ra: receiver address of the BA session recipient. * @tid: the desired TID to BA on. * @@ -2103,7 +2101,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); * finished with preparations for the BA session tear down. * This version of the function is IRQ-safe. */ -void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid); /** diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index bc064d7933ff..f3a5c9e0578d 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -41,7 +41,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, sta->sta.addr, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - if (drv_ampdu_action(local, IEEE80211_AMPDU_RX_STOP, + if (drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_RX_STOP, &sta->sta, tid, NULL)) printk(KERN_DEBUG "HW problem - can not stop rx " "aggregation for tid %d\n", tid); @@ -284,7 +285,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, goto end; } - ret = drv_ampdu_action(local, IEEE80211_AMPDU_RX_START, + ret = drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_RX_START, &sta->sta, tid, &start_seq_num); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index b09948ceec4a..6ddd11466df2 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -138,7 +138,8 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, *state = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_STOP, + ret = drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_TX_STOP, &sta->sta, tid, NULL); /* HW shall not deny going back to legacy */ @@ -196,11 +197,11 @@ static inline int ieee80211_ac_from_tid(int tid) return ieee802_1d_to_ac[tid & 7]; } -int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) +int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata; + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; u8 *state; int ret = 0; u16 start_seq_num; @@ -208,52 +209,37 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) if (WARN_ON(!local->ops->ampdu_action)) return -EINVAL; - if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) + if ((tid >= STA_TID_NUM) || + !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) return -EINVAL; #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n", - ra, tid); + pubsta->addr, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - rcu_read_lock(); - - sta = sta_info_get(local, ra); - if (!sta) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Could not find the station\n"); -#endif - ret = -ENOENT; - goto unlock; - } - /* * The aggregation code is not prepared to handle * anything but STA/AP due to the BSSID handling. * IBSS could work in the code but isn't supported * by drivers or the standard. */ - if (sta->sdata->vif.type != NL80211_IFTYPE_STATION && - sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN && - sta->sdata->vif.type != NL80211_IFTYPE_AP) { - ret = -EINVAL; - goto unlock; - } + if (sdata->vif.type != NL80211_IFTYPE_STATION && + sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + sdata->vif.type != NL80211_IFTYPE_AP) + return -EINVAL; if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Suspend in progress. " "Denying BA session request\n"); #endif - ret = -EINVAL; - goto unlock; + return -EINVAL; } spin_lock_bh(&sta->lock); spin_lock(&local->ampdu_lock); - sdata = sta->sdata; - /* we have tried too many times, receiver does not want A-MPDU */ if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { ret = -EBUSY; @@ -310,8 +296,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) start_seq_num = sta->tid_seq[tid]; - ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START, - &sta->sta, tid, &start_seq_num); + ret = drv_ampdu_action(local, &sdata->vif, + IEEE80211_AMPDU_TX_START, + pubsta, tid, &start_seq_num); if (ret) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -336,7 +323,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta->ampdu_mlme.dialog_token_allocator; sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; - ieee80211_send_addba_request(sta->sdata, ra, tid, + ieee80211_send_addba_request(sdata, pubsta->addr, tid, sta->ampdu_mlme.tid_tx[tid]->dialog_token, sta->ampdu_mlme.tid_tx[tid]->ssn, 0x40, 5000); @@ -348,7 +335,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); #endif - goto unlock; + return 0; err_free: kfree(sta->ampdu_mlme.tid_tx[tid]); @@ -360,8 +347,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) err_unlock_sta: spin_unlock(&local->ampdu_lock); spin_unlock_bh(&sta->lock); - unlock: - rcu_read_unlock(); return ret; } EXPORT_SYMBOL(ieee80211_start_tx_ba_session); @@ -428,13 +413,15 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, ieee80211_agg_splice_finish(local, sta, tid); spin_unlock(&local->ampdu_lock); - drv_ampdu_action(local, IEEE80211_AMPDU_TX_OPERATIONAL, + drv_ampdu_action(local, &sta->sdata->vif, + IEEE80211_AMPDU_TX_OPERATIONAL, &sta->sta, tid, NULL); } -void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) +void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; u8 *state; @@ -483,10 +470,11 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) } EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); -void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct ieee80211_ra_tid *ra_tid; struct sk_buff *skb = dev_alloc_skb(0); @@ -535,13 +523,12 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, return ret; } -int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, - u8 *ra, u16 tid, +int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, enum ieee80211_back_parties initiator) { - struct ieee80211_local *local = hw_to_local(hw); - struct sta_info *sta; - int ret = 0; + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; if (WARN_ON(!local->ops->ampdu_action)) return -EINVAL; @@ -549,22 +536,14 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, if (tid >= STA_TID_NUM) return -EINVAL; - rcu_read_lock(); - sta = sta_info_get(local, ra); - if (!sta) { - rcu_read_unlock(); - return -ENOENT; - } - - ret = __ieee80211_stop_tx_ba_session(sta, tid, initiator); - rcu_read_unlock(); - return ret; + return __ieee80211_stop_tx_ba_session(sta, tid, initiator); } EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); -void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) +void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; u8 *state; @@ -627,10 +606,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) } EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); -void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_local *local = sdata->local; struct ieee80211_ra_tid *ra_tid; struct sk_buff *skb = dev_alloc_skb(0); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 020a94a31106..921dd9c9ff62 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -239,15 +239,16 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local) } static inline int drv_ampdu_action(struct ieee80211_local *local, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { int ret = -EOPNOTSUPP; if (local->ops->ampdu_action) - ret = local->ops->ampdu_action(&local->hw, action, + ret = local->ops->ampdu_action(&local->hw, vif, action, sta, tid, ssn); - trace_drv_ampdu_action(local, action, sta, tid, ssn, ret); + trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret); return ret; } diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 37b9051afcf3..b8fef1d11369 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -634,11 +634,12 @@ TRACE_EVENT(drv_tx_last_beacon, TRACE_EVENT(drv_ampdu_action, TP_PROTO(struct ieee80211_local *local, + struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, int ret), - TP_ARGS(local, action, sta, tid, ssn, ret), + TP_ARGS(local, vif, action, sta, tid, ssn, ret), TP_STRUCT__entry( LOCAL_ENTRY @@ -647,10 +648,12 @@ TRACE_EVENT(drv_ampdu_action, __field(u16, tid) __field(u16, ssn) __field(int, ret) + VIF_ENTRY ), TP_fast_assign( LOCAL_ASSIGN; + VIF_ASSIGN; STA_ASSIGN; __entry->ret = ret; __entry->action = action; @@ -659,8 +662,8 @@ TRACE_EVENT(drv_ampdu_action, ), TP_printk( - LOCAL_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d", - LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d", + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret ) ); #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 48ef1a282b91..345c8ee50175 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -141,7 +141,6 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_mgmt *mgmt, size_t len) { - struct ieee80211_local *local = sdata->local; u16 tid, params; u16 initiator; @@ -164,7 +163,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, sta->ampdu_mlme.tid_state_tx[tid] = HT_AGG_STATE_OPERATIONAL; spin_unlock_bh(&sta->lock); - ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, tid, + ieee80211_stop_tx_ba_session(&sta->sta, tid, WLAN_BACK_RECIPIENT); } } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b63b99fb2fd3..b7598db5ade2 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -771,8 +771,9 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) return netdev_priv(dev); } -/* this struct represents 802.11n's RA/TID combination */ +/* this struct represents 802.11n's RA/TID combination along with our vif */ struct ieee80211_ra_tid { + struct ieee80211_vif *vif; u8 ra[ETH_ALEN]; u16 tid; }; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c74a6a1935b3..f4be97c3b747 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -296,14 +296,14 @@ static void ieee80211_tasklet_handler(unsigned long data) break; case IEEE80211_DELBA_MSG: ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - ieee80211_stop_tx_ba_cb(local_to_hw(local), - ra_tid->ra, ra_tid->tid); + ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra, + ra_tid->tid); dev_kfree_skb(skb); break; case IEEE80211_ADDBA_MSG: ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - ieee80211_start_tx_ba_cb(local_to_hw(local), - ra_tid->ra, ra_tid->tid); + ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra, + ra_tid->tid); dev_kfree_skb(skb); break ; default: -- cgit v1.2.3 From 2edcb7ff8d7d84a3797bcecc7094da0fa9828a16 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Tue, 17 Nov 2009 13:43:16 +0100 Subject: rt2x00: more ids to rt2800usb.c taken from windows inf file (09/15/2009, 1.04.07.0000) Signed-off-by: Xose Vazquez Perez Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 39 +++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index b1d63935f44d..9ab15c480701 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -824,17 +824,23 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Amit */ { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Askey */ + { USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, /* ASUS */ { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, /* AzureWave */ { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Belkin */ { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -843,6 +849,8 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Buffalo */ { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Cisco */ + { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Conceptronic */ { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -858,6 +866,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, /* D-Link */ @@ -869,18 +879,24 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Edimax */ { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Encore */ { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) }, /* EnGenius */ { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Gemtek */ { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -894,7 +910,10 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, /* I-O DATA */ + { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) }, /* LevelOne */ { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -909,8 +928,18 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Motorola */ { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* MSI */ + { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Ovislink */ { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Para */ + { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Pegatron */ { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -926,8 +955,6 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Quanta */ { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Ralink */ - { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -951,7 +978,12 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x004a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x004d), USB_DEVICE_DATA(&rt2800usb_ops) }, /* SMC */ { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -960,6 +992,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sparklan */ @@ -977,6 +1011,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zyxel */ { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) }, -- cgit v1.2.3 From 15295380f45aa0d35665f6e5596ac98c081d95b9 Mon Sep 17 00:00:00 2001 From: Thomas Klute Date: Tue, 17 Nov 2009 11:58:18 +0100 Subject: ar9170: Add support for D-Link DWA 160 A2 At least two revisions of the D-Link DWA 160 exist, called A1 and A2. A1 (USB-ID 07d1:3c10) is already listed in usb.c as D-Link DWA 160A. A2 (USB-ID 07d1:3a09) works if added to ar9170_usb_ids. I didn't do much testing until now, but I was able to connect to APs using WPA or WEP and transmit data. Summary: * Add model revision number to the comment for D-Link DWA 160 A1 (07d1:3c10) * Add support for D-Link DWA 160 A2 (07d1:3a09) Signed-off-by: Thomas Klute Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ar9170/usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 6bdcdf6d1cc0..e0799d924057 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -68,8 +68,10 @@ static struct usb_device_id ar9170_usb_ids[] = { { USB_DEVICE(0x0cf3, 0x1002) }, /* Cace Airpcap NX */ { USB_DEVICE(0xcace, 0x0300) }, - /* D-Link DWA 160A */ + /* D-Link DWA 160 A1 */ { USB_DEVICE(0x07d1, 0x3c10) }, + /* D-Link DWA 160 A2 */ + { USB_DEVICE(0x07d1, 0x3a09) }, /* Netgear WNDA3100 */ { USB_DEVICE(0x0846, 0x9010) }, /* Netgear WN111 v2 */ -- cgit v1.2.3 From 474c48c9f2118e637477b3b1c70003cb5cbda983 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 17 Nov 2009 18:48:14 +0200 Subject: wl1251: Add connection monitoring configuration Add configuration for connection monitor (number of allowed beacons, and timeout after last received beacon.) Signed-off-by: Juuso Oikarinen Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_acx.c | 29 +++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_acx.h | 11 +++++++++++ drivers/net/wireless/wl12xx/wl1251_init.c | 5 +++++ 3 files changed, 45 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 10b26c4532c9..4a9c70889a45 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -550,6 +550,35 @@ out: return ret; } +int wl1251_acx_conn_monit_params(struct wl1251 *wl) +{ + struct acx_conn_monit_params *acx; + int ret; + + wl1251_debug(DEBUG_ACX, "acx connection monitor parameters"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->synch_fail_thold = SYNCH_FAIL_DEFAULT_THRESHOLD; + acx->bss_lose_timeout = NO_BEACON_DEFAULT_TIMEOUT; + + ret = wl1251_cmd_configure(wl, ACX_CONN_MONIT_PARAMS, + acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("failed to set connection monitor " + "parameters: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + int wl1251_acx_sg_enable(struct wl1251 *wl) { struct acx_bt_wlan_coex *pta; diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index cafb91459504..926789ccc27f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -458,6 +458,16 @@ struct acx_beacon_filter_ie_table { u8 pad[3]; } __attribute__ ((packed)); +#define SYNCH_FAIL_DEFAULT_THRESHOLD 5 /* number of beacons */ +#define NO_BEACON_DEFAULT_TIMEOUT (100) /* TU */ + +struct acx_conn_monit_params { + struct acx_header header; + + u32 synch_fail_thold; /* number of beacons missed */ + u32 bss_lose_timeout; /* number of TU's from synch fail */ +}; + enum { SG_ENABLE = 0, SG_DISABLE, @@ -1275,6 +1285,7 @@ int wl1251_acx_service_period_timeout(struct wl1251 *wl); int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); int wl1251_acx_beacon_filter_opt(struct wl1251 *wl); int wl1251_acx_beacon_filter_table(struct wl1251 *wl); +int wl1251_acx_conn_monit_params(struct wl1251 *wl); int wl1251_acx_sg_enable(struct wl1251 *wl); int wl1251_acx_sg_cfg(struct wl1251 *wl); int wl1251_acx_cca_threshold(struct wl1251 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index b2ee4f468fc4..035ab1140b43 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -364,6 +364,11 @@ int wl1251_hw_init(struct wl1251 *wl) if (ret < 0) goto out_free_data_path; + /* Initialize connection monitoring thresholds */ + ret = wl1251_acx_conn_monit_params(wl); + if (ret < 0) + goto out_free_data_path; + /* Beacon filtering */ ret = wl1251_hw_init_beacon_filter(wl); if (ret < 0) -- cgit v1.2.3 From 287f6f9672635f4e948c0aa96754a2ce448ebdb2 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 17 Nov 2009 18:48:23 +0200 Subject: wl1251: Enable beacon filtering with the stack Enable beacon filtering with the mac80211 stack. Signed-off-by: Juuso Oikarinen Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251.h | 2 ++ drivers/net/wireless/wl12xx/wl1251_event.c | 7 +++++++ drivers/net/wireless/wl12xx/wl1251_main.c | 12 ++++++++++++ 3 files changed, 21 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index 998e4b6252bd..fc2871c5a25b 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -374,6 +374,8 @@ struct wl1251 { u8 buffer_busyword[WL1251_BUSY_WORD_LEN]; struct wl1251_rx_descriptor *rx_descriptor; + struct ieee80211_vif *vif; + u32 chip_id; char fw_ver[21]; }; diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 00076c4a8a21..18c301ddcd74 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -79,6 +79,13 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) } } + if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) { + wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); + + /* indicate to the stack, that beacons have been lost */ + ieee80211_beacon_loss(wl->vif); + } + return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index d03a07e1be7c..601c43070296 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -509,6 +509,12 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, conf->type, conf->mac_addr); mutex_lock(&wl->mutex); + if (wl->vif) { + ret = -EBUSY; + goto out; + } + + wl->vif = conf->vif; switch (conf->type) { case NL80211_IFTYPE_STATION: @@ -538,7 +544,12 @@ out: static void wl1251_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { + struct wl1251 *wl = hw->priv; + + mutex_lock(&wl->mutex); wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface"); + wl->vif = NULL; + mutex_unlock(&wl->mutex); } static int wl1251_build_null_data(struct wl1251 *wl) @@ -1372,6 +1383,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) wl->power_level = WL1251_DEFAULT_POWER_LEVEL; wl->beacon_int = WL1251_DEFAULT_BEACON_INT; wl->dtim_period = WL1251_DEFAULT_DTIM_PERIOD; + wl->vif = NULL; for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++) wl->tx_frames[i] = NULL; -- cgit v1.2.3 From 6b21a2cd315e2e56a1748bd3ef9d910fe4f2e711 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 17 Nov 2009 18:48:30 +0200 Subject: wl1251: Configure beacon filtering on if PSM used Enable beacon filtering when PSM is enabled Signed-off-by: Juuso Oikarinen Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_acx.c | 11 +++++++---- drivers/net/wireless/wl12xx/wl1251_acx.h | 7 ++++++- drivers/net/wireless/wl12xx/wl1251_init.c | 3 ++- drivers/net/wireless/wl12xx/wl1251_main.c | 3 ++- drivers/net/wireless/wl12xx/wl1251_ps.c | 10 ++++++++++ 5 files changed, 27 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 4a9c70889a45..50633e043cfd 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -494,7 +494,7 @@ out: return ret; } -int wl1251_acx_beacon_filter_opt(struct wl1251 *wl) +int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter) { struct acx_beacon_filter_option *beacon_filter; int ret; @@ -507,7 +507,7 @@ int wl1251_acx_beacon_filter_opt(struct wl1251 *wl) goto out; } - beacon_filter->enable = 0; + beacon_filter->enable = enable_filter; beacon_filter->max_num_beacons = 0; ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT, @@ -525,6 +525,7 @@ out: int wl1251_acx_beacon_filter_table(struct wl1251 *wl) { struct acx_beacon_filter_ie_table *ie_table; + int idx = 0; int ret; wl1251_debug(DEBUG_ACX, "acx beacon filter table"); @@ -535,8 +536,10 @@ int wl1251_acx_beacon_filter_table(struct wl1251 *wl) goto out; } - ie_table->num_ie = 0; - memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE); + /* configure default beacon pass-through rules */ + ie_table->num_ie = 1; + ie_table->table[idx++] = BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN; + ie_table->table[idx++] = BEACON_RULE_PASS_ON_APPEARANCE; ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE, ie_table, sizeof(*ie_table)); diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 926789ccc27f..ce1c995e08d8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -450,6 +450,11 @@ struct acx_beacon_filter_option { (BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \ BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE)) +#define BEACON_RULE_PASS_ON_CHANGE BIT(0) +#define BEACON_RULE_PASS_ON_APPEARANCE BIT(1) + +#define BEACON_FILTER_IE_ID_CHANNEL_SWITCH_ANN (37) + struct acx_beacon_filter_ie_table { struct acx_header header; @@ -1283,7 +1288,7 @@ int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); int wl1251_acx_group_address_tbl(struct wl1251 *wl); int wl1251_acx_service_period_timeout(struct wl1251 *wl); int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); -int wl1251_acx_beacon_filter_opt(struct wl1251 *wl); +int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter); int wl1251_acx_beacon_filter_table(struct wl1251 *wl); int wl1251_acx_conn_monit_params(struct wl1251 *wl); int wl1251_acx_sg_enable(struct wl1251 *wl); diff --git a/drivers/net/wireless/wl12xx/wl1251_init.c b/drivers/net/wireless/wl12xx/wl1251_init.c index 035ab1140b43..5cb573383eeb 100644 --- a/drivers/net/wireless/wl12xx/wl1251_init.c +++ b/drivers/net/wireless/wl12xx/wl1251_init.c @@ -147,7 +147,8 @@ int wl1251_hw_init_beacon_filter(struct wl1251 *wl) { int ret; - ret = wl1251_acx_beacon_filter_opt(wl); + /* disable beacon filtering at this stage */ + ret = wl1251_acx_beacon_filter_opt(wl, false); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 601c43070296..900e6e2796fc 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1323,7 +1323,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl) wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | - IEEE80211_HW_SUPPORTS_PS; + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_BEACON_FILTER; wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wl->hw->wiphy->max_scan_ssids = 1; diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index c53e28727ed4..c3e348a12322 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -119,6 +119,11 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) case STATION_POWER_SAVE_MODE: wl1251_debug(DEBUG_PSM, "entering psm"); + /* enable beacon filtering */ + ret = wl1251_acx_beacon_filter_opt(wl, true); + if (ret < 0) + return ret; + ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, wl->listen_int); @@ -142,6 +147,11 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) if (ret < 0) return ret; + /* disable beacon filtering */ + ret = wl1251_acx_beacon_filter_opt(wl, false); + if (ret < 0) + return ret; + ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP, wl->listen_int); -- cgit v1.2.3 From d5da79ac1f5050cccaa68d814ccce292371f25fa Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 17 Nov 2009 18:48:37 +0200 Subject: wl1251: Implement delayed entry into ELP mode Implement (slightly) delayed entry into ELP. This will cure several problems: - It works around a firmware race condition if ELP is entered too fast after commands (resulting in ELP timeout -traces) - It will reduce the number of sleep-wake cycles between already scheduled events such as interrupts and tx, hence improving performance (less delay in switching between RX and TX) Signed-off-by: Juuso Oikarinen Reviewed-by: Vidhya Govindan Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251.h | 2 ++ drivers/net/wireless/wl12xx/wl1251_main.c | 1 + drivers/net/wireless/wl12xx/wl1251_ps.c | 34 ++++++++++++++++++++++++++----- drivers/net/wireless/wl12xx/wl1251_ps.h | 1 + 4 files changed, 33 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index fc2871c5a25b..a839466664f0 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -354,6 +354,8 @@ struct wl1251 { /* is firmware in elp mode */ bool elp; + struct delayed_work elp_work; + /* we can be in psm, but not in elp, we have to differentiate */ bool psm; diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 900e6e2796fc..b5e3bdb08448 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1367,6 +1367,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) skb_queue_head_init(&wl->tx_queue); INIT_WORK(&wl->filter_work, wl1251_filter_work); + INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work); wl->channel = WL1251_DEFAULT_CHANNEL; wl->scanning = false; wl->default_key = 0; diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c index c3e348a12322..9931b197ff77 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.c +++ b/drivers/net/wireless/wl12xx/wl1251_ps.c @@ -28,17 +28,41 @@ #define WL1251_WAKEUP_TIMEOUT 2000 -/* Routines to toggle sleep mode while in ELP */ -void wl1251_ps_elp_sleep(struct wl1251 *wl) +void wl1251_elp_work(struct work_struct *work) { + struct delayed_work *dwork; + struct wl1251 *wl; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1251, elp_work); + + wl1251_debug(DEBUG_PSM, "elp work"); + + mutex_lock(&wl->mutex); + if (wl->elp || !wl->psm) - return; + goto out; wl1251_debug(DEBUG_PSM, "chip to elp"); - wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); - wl->elp = true; + +out: + mutex_unlock(&wl->mutex); +} + +#define ELP_ENTRY_DELAY 5 + +/* Routines to toggle sleep mode while in ELP */ +void wl1251_ps_elp_sleep(struct wl1251 *wl) +{ + unsigned long delay; + + if (wl->psm) { + cancel_delayed_work(&wl->elp_work); + delay = msecs_to_jiffies(ELP_ENTRY_DELAY); + ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); + } } int wl1251_ps_elp_wakeup(struct wl1251 *wl) diff --git a/drivers/net/wireless/wl12xx/wl1251_ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h index db036fe12f25..c688ac57aee4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_ps.h +++ b/drivers/net/wireless/wl12xx/wl1251_ps.h @@ -31,6 +31,7 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode); void wl1251_ps_elp_sleep(struct wl1251 *wl); int wl1251_ps_elp_wakeup(struct wl1251 *wl); +void wl1251_elp_work(struct work_struct *work); #endif /* __WL1251_PS_H__ */ -- cgit v1.2.3 From c74ddfd5ea9c0c67d0aae77eeb5b610188cb8bc4 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 17 Nov 2009 18:48:45 +0200 Subject: wl1251: allocate space for firmware with vmalloc() Earlier firmware was stored to a memory area allocated with kmalloc() but finding a a contiguous area of memory long enough for the firmware is very difficult in certain cases. better to allocate the memory for firmware with vmalloc() instead and use a small buffer for DMA transfers. Thanks to Eero Tamminen for the idea. Signed-off-by: Kalle Valo Reviewed-by: Vidhya Govindan Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_boot.c | 27 ++++++++++++++++++++++----- drivers/net/wireless/wl12xx/wl1251_main.c | 5 +++-- 2 files changed, 25 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 452d748e42c6..8febf27ab28d 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -314,8 +314,8 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) static int wl1251_boot_upload_firmware(struct wl1251 *wl) { int addr, chunk_num, partition_limit; - size_t fw_data_len; - u8 *p; + size_t fw_data_len, len; + u8 *p, *buf; /* whal_FwCtrl_LoadFwImageSm() */ @@ -334,6 +334,12 @@ static int wl1251_boot_upload_firmware(struct wl1251 *wl) return -EIO; } + buf = kmalloc(CHUNK_SIZE, GFP_KERNEL); + if (!buf) { + wl1251_error("allocation for firmware upload chunk failed"); + return -ENOMEM; + } + wl1251_set_partition(wl, WL1251_PART_DOWN_MEM_START, WL1251_PART_DOWN_MEM_SIZE, WL1251_PART_DOWN_REG_START, @@ -364,7 +370,11 @@ static int wl1251_boot_upload_firmware(struct wl1251 *wl) p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", p, addr); - wl1251_mem_write(wl, addr, p, CHUNK_SIZE); + + /* need to copy the chunk for dma */ + len = CHUNK_SIZE; + memcpy(buf, p, len); + wl1251_mem_write(wl, addr, buf, len); chunk_num++; } @@ -372,9 +382,16 @@ static int wl1251_boot_upload_firmware(struct wl1251 *wl) /* 10.4 upload the last chunk */ addr = WL1251_PART_DOWN_MEM_START + chunk_num * CHUNK_SIZE; p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE; + + /* need to copy the chunk for dma */ + len = fw_data_len % CHUNK_SIZE; + memcpy(buf, p, len); + wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x", - fw_data_len % CHUNK_SIZE, p, addr); - wl1251_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE); + len, p, addr); + wl1251_mem_write(wl, addr, buf, len); + + kfree(buf); return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index b5e3bdb08448..1f4c238a3371 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "wl1251.h" #include "wl12xx_80211.h" @@ -83,7 +84,7 @@ static int wl1251_fetch_firmware(struct wl1251 *wl) } wl->fw_len = fw->size; - wl->fw = kmalloc(wl->fw_len, GFP_KERNEL); + wl->fw = vmalloc(wl->fw_len); if (!wl->fw) { wl1251_error("could not allocate memory for the firmware"); @@ -1427,7 +1428,7 @@ int wl1251_free_hw(struct wl1251 *wl) kfree(wl->target_mem_map); kfree(wl->data_path); - kfree(wl->fw); + vfree(wl->fw); wl->fw = NULL; kfree(wl->nvs); wl->nvs = NULL; -- cgit v1.2.3 From 2410378a4c8e978823354ab3e44cd07c3c18a237 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 17 Nov 2009 18:49:00 +0200 Subject: wl1251: mask aid bits 14 and 15 in ps-poll template In ps-poll template aid bits 14 and 15 were not masked as required by the standard. Mask them so that aid is sent in correct format. Signed-off-by: Kalle Valo Reviewed-by: Juuso Oikarinen Reviewed-by: Vidhya Govindan Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 1f4c238a3371..41f5ad49f480 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -580,7 +580,10 @@ static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid) memcpy(template.bssid, wl->bssid, ETH_ALEN); memcpy(template.ta, wl->mac_addr, ETH_ALEN); - template.aid = aid; + + /* aid in PS-Poll has its two MSBs each set to 1 */ + template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid); + template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template, -- cgit v1.2.3 From d531cf303f765bf3477330e58fbeab75da668931 Mon Sep 17 00:00:00 2001 From: Vidhya Govindan Date: Tue, 17 Nov 2009 18:49:08 +0200 Subject: wl1251: Add acx command to set tbtt and dtim period The dtim period obtained from the mac80211 is not set to the firmware. This patch implements the acx command to set correct tbtt and dtim value to the firmware. Signed-off-by: Vidhya Govindan Signed-off-by: Kalle Valo Reviewed-by: Janne Ylalehto Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_acx.c | 28 ++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1251_acx.h | 18 ++++++++++++++++++ 2 files changed, 46 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c index 50633e043cfd..acfa086dbfc5 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.c +++ b/drivers/net/wireless/wl12xx/wl1251_acx.c @@ -948,3 +948,31 @@ out: kfree(mem_conf); return ret; } + +int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim) +{ + struct wl1251_acx_wr_tbtt_and_dtim *acx; + int ret; + + wl1251_debug(DEBUG_ACX, "acx tbtt and dtim"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->tbtt = tbtt; + acx->dtim = dtim; + + ret = wl1251_cmd_configure(wl, ACX_WR_TBTT_AND_DTIM, + acx, sizeof(*acx)); + if (ret < 0) { + wl1251_warning("failed to set tbtt and dtim: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index ce1c995e08d8..44a4b0494592 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -1149,6 +1149,23 @@ struct wl1251_acx_mem_map { u32 num_rx_mem_blocks; } __attribute__ ((packed)); + +struct wl1251_acx_wr_tbtt_and_dtim { + + struct acx_header header; + + /* Time in TUs between two consecutive beacons */ + u16 tbtt; + + /* + * DTIM period + * For BSS: Number of TBTTs in a DTIM period (range: 1-10) + * For IBSS: value shall be set to 1 + */ + u8 dtim; + u8 padding; +} __attribute__ ((packed)); + /************************************************************************* Host Interrupt Register (WiLink -> Host) @@ -1304,5 +1321,6 @@ int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); int wl1251_acx_rate_policies(struct wl1251 *wl); int wl1251_acx_mem_cfg(struct wl1251 *wl); +int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); #endif /* __WL1251_ACX_H__ */ -- cgit v1.2.3 From 72b57344a2a1f98c6838c2268fdc5ed5fae54cd8 Mon Sep 17 00:00:00 2001 From: Vidhya Govindan Date: Tue, 17 Nov 2009 18:49:16 +0200 Subject: wl1251: Set the correct dtim period to the firmware This patch sets the dtim period obtained from the mac80211 to firmware. Signed-off-by: Vidhya Govindan Reviewed-by: Janne Ylalehto Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 41f5ad49f480..cc32ba679098 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -1105,8 +1105,8 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, wl->beacon_int = bss_conf->beacon_int; wl->dtim_period = bss_conf->dtim_period; - /* FIXME: call join */ - + ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int, + wl->dtim_period); wl->aid = bss_conf->aid; ret = wl1251_build_ps_poll(wl, wl->aid); -- cgit v1.2.3 From 33d51facad8360cb9c55fd696431e2a477f16cc1 Mon Sep 17 00:00:00 2001 From: Vidhya Govindan Date: Tue, 17 Nov 2009 18:49:23 +0200 Subject: wl1251: Increase the beacon loss timeout value and handle regain event This patch increases the number of beacons to be missed before generating SYNC TIMEOUT event. It increases the beacon timeout period to 500 microseconds, which gives enough time for the firmware to receive probe response or beacon. Also handled the regain event from firmware once it receives a probe response or beacon. Signed-off-by: Vidhya Govindan Reviewed-by: Janne Ylalehto Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_acx.h | 4 ++-- drivers/net/wireless/wl12xx/wl1251_event.c | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h index 44a4b0494592..652371432cd8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_acx.h +++ b/drivers/net/wireless/wl12xx/wl1251_acx.h @@ -463,8 +463,8 @@ struct acx_beacon_filter_ie_table { u8 pad[3]; } __attribute__ ((packed)); -#define SYNCH_FAIL_DEFAULT_THRESHOLD 5 /* number of beacons */ -#define NO_BEACON_DEFAULT_TIMEOUT (100) /* TU */ +#define SYNCH_FAIL_DEFAULT_THRESHOLD 10 /* number of beacons */ +#define NO_BEACON_DEFAULT_TIMEOUT (500) /* in microseconds */ struct acx_conn_monit_params { struct acx_header header; diff --git a/drivers/net/wireless/wl12xx/wl1251_event.c b/drivers/net/wireless/wl12xx/wl1251_event.c index 18c301ddcd74..020d764f9c13 100644 --- a/drivers/net/wireless/wl12xx/wl1251_event.c +++ b/drivers/net/wireless/wl12xx/wl1251_event.c @@ -86,6 +86,14 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) ieee80211_beacon_loss(wl->vif); } + if (vector & REGAINED_BSS_EVENT_ID) { + if (wl->psm_requested) { + ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + if (ret < 0) + return ret; + } + } + return 0; } -- cgit v1.2.3 From dcea4dbe54f5bbea2ef0bb265072754ccd934a1e Mon Sep 17 00:00:00 2001 From: Janne Ylalehto Date: Tue, 17 Nov 2009 18:49:31 +0200 Subject: wl1251: Add IRQ looping support Add support for IRQ looping. Helps in the case that we have e.g. multiple packets coming from the network when we wake up from the ELP. Signed-off-by: Janne Ylalehto Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 127 ++++++++++++++++-------------- 1 file changed, 67 insertions(+), 60 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index cc32ba679098..dad010d114f8 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -212,9 +212,10 @@ out: return ret; } +#define WL1251_IRQ_LOOP_COUNT 10 static void wl1251_irq_work(struct work_struct *work) { - u32 intr; + u32 intr, ctr = WL1251_IRQ_LOOP_COUNT; struct wl1251 *wl = container_of(work, struct wl1251, irq_work); int ret; @@ -235,78 +236,84 @@ static void wl1251_irq_work(struct work_struct *work) intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); - if (wl->data_path) { - wl->rx_counter = - wl1251_mem_read32(wl, wl->data_path->rx_control_addr); - - /* We handle a frmware bug here */ - switch ((wl->rx_counter - wl->rx_handled) & 0xf) { - case 0: - wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); - intr &= ~WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 1: - wl1251_debug(DEBUG_IRQ, "RX: FW +1"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr &= ~WL1251_ACX_INTR_RX1_DATA; - break; - case 2: - wl1251_debug(DEBUG_IRQ, "RX: FW +2"); - intr |= WL1251_ACX_INTR_RX0_DATA; - intr |= WL1251_ACX_INTR_RX1_DATA; - break; - default: - wl1251_warning("RX: FW and host out of sync: %d", - wl->rx_counter - wl->rx_handled); - break; - } - - wl->rx_handled = wl->rx_counter; + do { + if (wl->data_path) { + wl->rx_counter = wl1251_mem_read32( + wl, wl->data_path->rx_control_addr); + + /* We handle a frmware bug here */ + switch ((wl->rx_counter - wl->rx_handled) & 0xf) { + case 0: + wl1251_debug(DEBUG_IRQ, + "RX: FW and host in sync"); + intr &= ~WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 1: + wl1251_debug(DEBUG_IRQ, "RX: FW +1"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr &= ~WL1251_ACX_INTR_RX1_DATA; + break; + case 2: + wl1251_debug(DEBUG_IRQ, "RX: FW +2"); + intr |= WL1251_ACX_INTR_RX0_DATA; + intr |= WL1251_ACX_INTR_RX1_DATA; + break; + default: + wl1251_warning( + "RX: FW and host out of sync: %d", + wl->rx_counter - wl->rx_handled); + break; + } + wl->rx_handled = wl->rx_counter; - wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); - } + wl1251_debug(DEBUG_IRQ, "RX counter: %d", + wl->rx_counter); + } - intr &= wl->intr_mask; + intr &= wl->intr_mask; - if (intr == 0) { - wl1251_debug(DEBUG_IRQ, "INTR is 0"); - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, - ~(wl->intr_mask)); + if (intr == 0) { + wl1251_debug(DEBUG_IRQ, "INTR is 0"); + goto out_sleep; + } - goto out_sleep; - } + if (intr & WL1251_ACX_INTR_RX0_DATA) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); + wl1251_rx(wl); + } - if (intr & WL1251_ACX_INTR_RX0_DATA) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); - wl1251_rx(wl); - } + if (intr & WL1251_ACX_INTR_RX1_DATA) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); + wl1251_rx(wl); + } - if (intr & WL1251_ACX_INTR_RX1_DATA) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); - wl1251_rx(wl); - } + if (intr & WL1251_ACX_INTR_TX_RESULT) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); + wl1251_tx_complete(wl); + } - if (intr & WL1251_ACX_INTR_TX_RESULT) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); - wl1251_tx_complete(wl); - } + if (intr & (WL1251_ACX_INTR_EVENT_A | + WL1251_ACX_INTR_EVENT_B)) { + wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", + intr); + if (intr & WL1251_ACX_INTR_EVENT_A) + wl1251_event_handle(wl, 0); + else + wl1251_event_handle(wl, 1); + } - if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); - if (intr & WL1251_ACX_INTR_EVENT_A) - wl1251_event_handle(wl, 0); - else - wl1251_event_handle(wl, 1); - } + if (intr & WL1251_ACX_INTR_INIT_COMPLETE) + wl1251_debug(DEBUG_IRQ, + "WL1251_ACX_INTR_INIT_COMPLETE"); - if (intr & WL1251_ACX_INTR_INIT_COMPLETE) - wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); - wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); + } while (intr && --ctr); out_sleep: + wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); wl1251_ps_elp_sleep(wl); out: -- cgit v1.2.3 From a1590f2404d1c8d16f8ceed4fccc32ab9831e484 Mon Sep 17 00:00:00 2001 From: Janne Ylalehto Date: Tue, 17 Nov 2009 18:49:38 +0200 Subject: wl1251: Filter out unwanted events Filter out unwanted events to reduce wakeups. Signed-off-by: Janne Ylalehto Reviewed-by: Vidhya Govindan Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_boot.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 8febf27ab28d..5094f24ad034 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -296,8 +296,12 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) WL1251_ACX_INTR_INIT_COMPLETE; wl1251_boot_target_enable_interrupts(wl); - /* unmask all mbox events */ - wl->event_mask = 0xffffffff; + wl->event_mask = SCAN_COMPLETE_EVENT_ID | BSS_LOSE_EVENT_ID | + SYNCHRONIZATION_TIMEOUT_EVENT_ID | + ROAMING_TRIGGER_LOW_RSSI_EVENT_ID | + ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID | + REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID | + BT_PTA_PREDICTION_EVENT_ID; ret = wl1251_event_unmask(wl); if (ret < 0) { -- cgit v1.2.3 From 79553f82c993ed511450748f01e16e4dccdc8c02 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 17 Nov 2009 18:49:46 +0200 Subject: wl1251: Fix regression in IRQ loop handling In some cases, the IRQ loop handler could acknowledge an interrupt to the chipset, but not service it. Signed-off-by: Juuso Oikarinen Reviewed-by: Janne Ylalehto Signed-off-by: Luciano Coelho Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index dad010d114f8..2e1c10f9670a 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -308,9 +308,11 @@ static void wl1251_irq_work(struct work_struct *work) wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); - intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + if (--ctr == 0) + break; - } while (intr && --ctr); + intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); + } while (intr); out_sleep: wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); -- cgit v1.2.3 From 06cc5d3bb01350466f7a1bf64d9afe06870b6480 Mon Sep 17 00:00:00 2001 From: Vidhya Govindan Date: Tue, 17 Nov 2009 18:49:54 +0200 Subject: wl1251: Send null data packet with "TODS" bit set According to IEEE80211 standard all the data packets have to be sent with TODS bit set. This patch fixes the null data packet format which was sent without TODS bit set. This should fix many problems associated with power save. Janne Ylalehto also found this fix in the same time as mine, for a different bug he was working on. Signed-off-by: Vidhya Govindan Reviewed-by: Janne Ylalehto Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 2e1c10f9670a..ff4be7bf5d36 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c @@ -576,7 +576,8 @@ static int wl1251_build_null_data(struct wl1251 *wl) memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_NULLFUNC); + IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template, sizeof(template)); -- cgit v1.2.3 From 7010193ad8e64dfbc006b167c2ee712d4441292c Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 17 Nov 2009 18:50:01 +0200 Subject: wl1251: remove depcreated qual usage Fixes warnings: drivers/net/wireless/wl12xx/wl1251_rx.c: In function 'wl1251_rx_status': drivers/net/wireless/wl12xx/wl1251_rx.c:75: warning: 'qual' is deprecated (declared at include/net/mac80211.h:555) drivers/net/wireless/wl12xx/wl1251_rx.c:77: warning: 'qual' is deprecated (declared at include/net/mac80211.h:555) drivers/net/wireless/wl12xx/wl1251_rx.c:77: warning: 'qual' is deprecated (declared at include/net/mac80211.h:555) drivers/net/wireless/wl12xx/wl1251_rx.c:77: warning: 'qual' is deprecated (declared at include/net/mac80211.h:555) drivers/net/wireless/wl12xx/wl1251_rx.c:78: warning: 'qual' is deprecated (declared at include/net/mac80211.h:555) drivers/net/wireless/wl12xx/wl1251_rx.c:78: warning: 'qual' is deprecated (declared at include/net/mac80211.h:555) drivers/net/wireless/wl12xx/wl1251_rx.c:78: warning: 'qual' is deprecated (declared at include/net/mac80211.h:555) Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_rx.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c index 601fe0d67827..f84cc89cbffc 100644 --- a/drivers/net/wireless/wl12xx/wl1251_rx.c +++ b/drivers/net/wireless/wl12xx/wl1251_rx.c @@ -72,10 +72,6 @@ static void wl1251_rx_status(struct wl1251 *wl, } status->signal = desc->rssi; - status->qual = (desc->rssi - WL1251_RX_MIN_RSSI) * 100 / - (WL1251_RX_MAX_RSSI - WL1251_RX_MIN_RSSI); - status->qual = min(status->qual, 100); - status->qual = max(status->qual, 0); /* * FIXME: guessing that snr needs to be divided by two, otherwise -- cgit v1.2.3 From c95cf3d09adc9afe7816a13a920b6df36062a3fe Mon Sep 17 00:00:00 2001 From: David-John Willis Date: Tue, 17 Nov 2009 18:50:09 +0200 Subject: wl1251: add NVS in EEPROM support wl1251 supports also that NVS is stored in a separate EEPROM, add support for that. kvalo: use platform data instead Kconfig and use kernel style Signed-off-by: David-John Willis Signed-off-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251.h | 1 + drivers/net/wireless/wl12xx/wl1251_boot.c | 20 +++++++++++++------- drivers/net/wireless/wl12xx/wl1251_reg.h | 6 ++++++ drivers/net/wireless/wl12xx/wl1251_spi.c | 2 ++ include/linux/spi/wl12xx.h | 1 + 5 files changed, 23 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h index a839466664f0..054533f7a124 100644 --- a/drivers/net/wireless/wl12xx/wl1251.h +++ b/drivers/net/wireless/wl12xx/wl1251.h @@ -269,6 +269,7 @@ struct wl1251 { void (*set_power)(bool enable); int irq; + bool use_eeprom; enum wl1251_state state; struct mutex mutex; diff --git a/drivers/net/wireless/wl12xx/wl1251_boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c index 5094f24ad034..2e733e7bdfd4 100644 --- a/drivers/net/wireless/wl12xx/wl1251_boot.c +++ b/drivers/net/wireless/wl12xx/wl1251_boot.c @@ -494,13 +494,19 @@ int wl1251_boot(struct wl1251 *wl) goto out; /* 2. start processing NVS file */ - ret = wl1251_boot_upload_nvs(wl); - if (ret < 0) - goto out; - - /* write firmware's last address (ie. it's length) to - * ACX_EEPROMLESS_IND_REG */ - wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); + if (wl->use_eeprom) { + wl1251_reg_write32(wl, ACX_REG_EE_START, START_EEPROM_MGR); + msleep(4000); + wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, USE_EEPROM); + } else { + ret = wl1251_boot_upload_nvs(wl); + if (ret < 0) + goto out; + + /* write firmware's last address (ie. it's length) to + * ACX_EEPROMLESS_IND_REG */ + wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len); + } /* 6. read the EEPROM parameters */ tmp = wl1251_reg_read32(wl, SCR_PAD2); diff --git a/drivers/net/wireless/wl12xx/wl1251_reg.h b/drivers/net/wireless/wl12xx/wl1251_reg.h index 06e1bd94a739..0ca3b4326056 100644 --- a/drivers/net/wireless/wl12xx/wl1251_reg.h +++ b/drivers/net/wireless/wl12xx/wl1251_reg.h @@ -370,6 +370,7 @@ enum wl12xx_acx_int_reg { EEPROM location specified in the EE_ADDR register. The Wlan hardware hardware clears this bit automatically. *===============================================*/ +#define EE_CTL (REGISTERS_BASE + 0x2000) #define ACX_EE_CTL_REG EE_CTL #define EE_WRITE 0x00000001ul #define EE_READ 0x00000002ul @@ -380,6 +381,7 @@ enum wl12xx_acx_int_reg { This register specifies the address within the EEPROM from/to which to read/write data. ===============================================*/ +#define EE_ADDR (REGISTERS_BASE + 0x2008) #define ACX_EE_ADDR_REG EE_ADDR /*=============================================== @@ -389,8 +391,12 @@ enum wl12xx_acx_int_reg { data from the EEPROM or the write data to be written to the EEPROM. ===============================================*/ +#define EE_DATA (REGISTERS_BASE + 0x2004) #define ACX_EE_DATA_REG EE_DATA +#define EEPROM_ACCESS_TO 10000 /* timeout counter */ +#define START_EEPROM_MGR 0x00000001 + /*=============================================== EEPROM Base Address - 32bit RW ------------------------------------------ diff --git a/drivers/net/wireless/wl12xx/wl1251_spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c index 2cf8a2169d43..9cc8c323830f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_spi.c +++ b/drivers/net/wireless/wl12xx/wl1251_spi.c @@ -270,6 +270,8 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi) return -ENODEV; } + wl->use_eeprom = pdata->use_eeprom; + ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); if (ret < 0) { wl1251_error("request_irq() failed: %d", ret); diff --git a/include/linux/spi/wl12xx.h b/include/linux/spi/wl12xx.h index 11430cab2aad..aed64ed3dc8a 100644 --- a/include/linux/spi/wl12xx.h +++ b/include/linux/spi/wl12xx.h @@ -26,6 +26,7 @@ struct wl12xx_platform_data { void (*set_power)(bool enable); + bool use_eeprom; }; #endif -- cgit v1.2.3 From a2fb0ad30aa52bdfd6e0870702444bae6090520f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 18 Nov 2009 16:37:22 -0500 Subject: wl3501_cs: remove pedantic build warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/wireless/wl3501_cs.c: In function ‘wl3501_esbq_exec’: drivers/net/wireless/wl3501_cs.c:387: warning: ‘tmp’ is used uninitialized in this function drivers/net/wireless/wl3501_cs.c:384: note: ‘tmp’ was declared here Signed-off-by: John W. Linville --- drivers/net/wireless/wl3501_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 4f1e0cfe609b..891bdab49887 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -381,7 +381,7 @@ static void wl3501_free_tx_buffer(struct wl3501_card *this, u16 ptr) static int wl3501_esbq_req_test(struct wl3501_card *this) { - u8 tmp; + u8 tmp = 0; wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp)); return tmp & 0x80; -- cgit v1.2.3 From 9bd568a50c446433038dec2a5186c5c57c3dbd23 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 18 Nov 2009 20:53:05 +0100 Subject: b43: Enforce DMA descriptor memory constraints Enforce all device constraints on the descriptor memory region. There are several constraints on the descriptor memory, as documented in the specification. The current code does not enforce them and/or incorrectly enforces them. Those constraints are: - The address limitations on 30/32bit engines, that also apply to the skbs. - The 4k alignment requirement on 30/32bit engines. - The 8k alignment requirement on 64bit engines. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 197 +++++++++++++++++++++++++++++++---------- drivers/net/wireless/b43/dma.h | 7 +- 2 files changed, 158 insertions(+), 46 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index b5cd7f57055b..18b97c02b8af 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -383,44 +383,160 @@ static inline } } +/* Check if a DMA region fits the device constraints. + * Returns true, if the region is OK for usage with this device. */ +static inline bool b43_dma_address_ok(struct b43_dmaring *ring, + dma_addr_t addr, size_t size) +{ + switch (ring->type) { + case B43_DMA_30BIT: + if ((u64)addr + size > (1ULL << 30)) + return 0; + break; + case B43_DMA_32BIT: + if ((u64)addr + size > (1ULL << 32)) + return 0; + break; + case B43_DMA_64BIT: + /* Currently we can't have addresses beyond + * 64bit in the kernel. */ + break; + } + return 1; +} + +#define is_4k_aligned(addr) (((u64)(addr) & 0x0FFFull) == 0) +#define is_8k_aligned(addr) (((u64)(addr) & 0x1FFFull) == 0) + +static void b43_unmap_and_free_ringmem(struct b43_dmaring *ring, void *base, + dma_addr_t dmaaddr, size_t size) +{ + ssb_dma_unmap_single(ring->dev->dev, dmaaddr, size, DMA_TO_DEVICE); + free_pages((unsigned long)base, get_order(size)); +} + +static void * __b43_get_and_map_ringmem(struct b43_dmaring *ring, + dma_addr_t *dmaaddr, size_t size, + gfp_t gfp_flags) +{ + void *base; + + base = (void *)__get_free_pages(gfp_flags, get_order(size)); + if (!base) + return NULL; + memset(base, 0, size); + *dmaaddr = ssb_dma_map_single(ring->dev->dev, base, size, + DMA_TO_DEVICE); + if (ssb_dma_mapping_error(ring->dev->dev, *dmaaddr)) { + free_pages((unsigned long)base, get_order(size)); + return NULL; + } + + return base; +} + +static void * b43_get_and_map_ringmem(struct b43_dmaring *ring, + dma_addr_t *dmaaddr, size_t size) +{ + void *base; + + base = __b43_get_and_map_ringmem(ring, dmaaddr, size, + GFP_KERNEL); + if (!base) { + b43err(ring->dev->wl, "Failed to allocate or map pages " + "for DMA ringmemory\n"); + return NULL; + } + if (!b43_dma_address_ok(ring, *dmaaddr, size)) { + /* The memory does not fit our device constraints. + * Retry with GFP_DMA set to get lower memory. */ + b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size); + base = __b43_get_and_map_ringmem(ring, dmaaddr, size, + GFP_KERNEL | GFP_DMA); + if (!base) { + b43err(ring->dev->wl, "Failed to allocate or map pages " + "in the GFP_DMA region for DMA ringmemory\n"); + return NULL; + } + if (!b43_dma_address_ok(ring, *dmaaddr, size)) { + b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size); + b43err(ring->dev->wl, "Failed to allocate DMA " + "ringmemory that fits device constraints\n"); + return NULL; + } + } + /* We expect the memory to be 4k aligned, at least. */ + if (B43_WARN_ON(!is_4k_aligned(*dmaaddr))) { + b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size); + return NULL; + } + + return base; +} + static int alloc_ringmemory(struct b43_dmaring *ring) { - gfp_t flags = GFP_KERNEL; - - /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K - * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing - * has shown that 4K is sufficient for the latter as long as the buffer - * does not cross an 8K boundary. - * - * For unknown reasons - possibly a hardware error - the BCM4311 rev - * 02, which uses 64-bit DMA, needs the ring buffer in very low memory, - * which accounts for the GFP_DMA flag below. - * - * The flags here must match the flags in free_ringmemory below! + unsigned int required; + void *base; + dma_addr_t dmaaddr; + + /* There are several requirements to the descriptor ring memory: + * - The memory region needs to fit the address constraints for the + * device (same as for frame buffers). + * - For 30/32bit DMA devices, the descriptor ring must be 4k aligned. + * - For 64bit DMA devices, the descriptor ring must be 8k aligned. */ + if (ring->type == B43_DMA_64BIT) - flags |= GFP_DMA; - ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev, - B43_DMA_RINGMEMSIZE, - &(ring->dmabase), flags); - if (!ring->descbase) { - b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); + required = ring->nr_slots * sizeof(struct b43_dmadesc64); + else + required = ring->nr_slots * sizeof(struct b43_dmadesc32); + if (B43_WARN_ON(required > 0x1000)) + return -ENOMEM; + + ring->alloc_descsize = 0x1000; + base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize); + if (!base) + return -ENOMEM; + ring->alloc_descbase = base; + ring->alloc_dmabase = dmaaddr; + + if ((ring->type != B43_DMA_64BIT) || is_8k_aligned(dmaaddr)) { + /* We're on <=32bit DMA, or we already got 8k aligned memory. + * That's all we need, so we're fine. */ + ring->descbase = base; + ring->dmabase = dmaaddr; + return 0; + } + b43_unmap_and_free_ringmem(ring, base, dmaaddr, ring->alloc_descsize); + + /* Ok, we failed at the 8k alignment requirement. + * Try to force-align the memory region now. */ + ring->alloc_descsize = 0x2000; + base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize); + if (!base) return -ENOMEM; + ring->alloc_descbase = base; + ring->alloc_dmabase = dmaaddr; + + if (is_8k_aligned(dmaaddr)) { + /* We're already 8k aligned. That Ok, too. */ + ring->descbase = base; + ring->dmabase = dmaaddr; + return 0; } - memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE); + /* Force-align it to 8k */ + ring->descbase = (void *)((u8 *)base + 0x1000); + ring->dmabase = dmaaddr + 0x1000; + B43_WARN_ON(!is_8k_aligned(ring->dmabase)); return 0; } static void free_ringmemory(struct b43_dmaring *ring) { - gfp_t flags = GFP_KERNEL; - - if (ring->type == B43_DMA_64BIT) - flags |= GFP_DMA; - - ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE, - ring->descbase, ring->dmabase, flags); + b43_unmap_and_free_ringmem(ring, ring->alloc_descbase, + ring->alloc_dmabase, ring->alloc_descsize); } /* Reset the RX DMA channel */ @@ -530,29 +646,14 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr))) return 1; - switch (ring->type) { - case B43_DMA_30BIT: - if ((u64)addr + buffersize > (1ULL << 30)) - goto address_error; - break; - case B43_DMA_32BIT: - if ((u64)addr + buffersize > (1ULL << 32)) - goto address_error; - break; - case B43_DMA_64BIT: - /* Currently we can't have addresses beyond - * 64bit in the kernel. */ - break; + if (!b43_dma_address_ok(ring, addr, buffersize)) { + /* We can't support this address. Unmap it again. */ + unmap_descbuffer(ring, addr, buffersize, dma_to_device); + return 1; } /* The address is OK. */ return 0; - -address_error: - /* We can't support this address. Unmap it again. */ - unmap_descbuffer(ring, addr, buffersize, dma_to_device); - - return 1; } static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb) @@ -614,6 +715,9 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, meta->dmaaddr = dmaaddr; ring->ops->fill_descriptor(ring, desc, dmaaddr, ring->rx_buffersize, 0, 0, 0); + ssb_dma_sync_single_for_device(ring->dev->dev, + ring->alloc_dmabase, + ring->alloc_descsize, DMA_TO_DEVICE); return 0; } @@ -1246,6 +1350,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring, } /* Now transfer the whole frame. */ wmb(); + ssb_dma_sync_single_for_device(ring->dev->dev, + ring->alloc_dmabase, + ring->alloc_descsize, DMA_TO_DEVICE); ops->poke_tx(ring, next_slot(ring, slot)); return 0; diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index f0b0838fb5ba..356a0ff8f044 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -157,7 +157,6 @@ struct b43_dmadesc_generic { } __attribute__ ((__packed__)); /* Misc DMA constants */ -#define B43_DMA_RINGMEMSIZE PAGE_SIZE #define B43_DMA0_RX_FRAMEOFFSET 30 /* DMA engine tuning knobs */ @@ -243,6 +242,12 @@ struct b43_dmaring { /* The QOS priority assigned to this ring. Only used for TX rings. * This is the mac80211 "queue" value. */ u8 queue_prio; + /* Pointers and size of the originally allocated and mapped memory + * region for the descriptor ring. */ + void *alloc_descbase; + dma_addr_t alloc_dmabase; + unsigned int alloc_descsize; + /* Pointer to our wireless device. */ struct b43_wldev *dev; #ifdef CONFIG_B43_DEBUG /* Maximum number of used slots. */ -- cgit v1.2.3 From a0607fd3a25ba1848a63a0d925e36d914735ab47 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 18 Nov 2009 23:29:17 -0800 Subject: drivers/net: request_irq - Remove unnecessary leading & from second arg Not as fancy as coccinelle. Checkpatch errors ignored. Compile tested allyesconfig x86, not all files compiled. grep -rPl --include=*.[ch] "\brequest_irq\s*\([^,\)]+,\s*\&" drivers/net | while read file ; do \ perl -i -e 'local $/; while (<>) { s@(\brequest_irq\s*\([^,\)]+,\s*)\&@\1@g ; print ; }' $file ;\ done Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/3c501.c | 2 +- drivers/net/3c505.c | 2 +- drivers/net/3c507.c | 2 +- drivers/net/3c509.c | 2 +- drivers/net/3c515.c | 4 ++-- drivers/net/3c523.c | 2 +- drivers/net/3c527.c | 2 +- drivers/net/appletalk/cops.c | 2 +- drivers/net/appletalk/ltpc.c | 2 +- drivers/net/arcnet/arc-rimi.c | 2 +- drivers/net/arcnet/com20020.c | 2 +- drivers/net/arcnet/com90io.c | 2 +- drivers/net/arcnet/com90xx.c | 2 +- drivers/net/at1700.c | 2 +- drivers/net/atl1e/atl1e_main.c | 2 +- drivers/net/atlx/atl1.c | 2 +- drivers/net/atlx/atl2.c | 2 +- drivers/net/atp.c | 2 +- drivers/net/au1000_eth.c | 2 +- drivers/net/cs89x0.c | 2 +- drivers/net/declance.c | 4 ++-- drivers/net/depca.c | 2 +- drivers/net/dl2k.c | 2 +- drivers/net/dm9000.c | 2 +- drivers/net/e1000/e1000_ethtool.c | 4 ++-- drivers/net/e1000e/ethtool.c | 4 ++-- drivers/net/e1000e/netdev.c | 12 ++++++------ drivers/net/eepro.c | 2 +- drivers/net/eexpress.c | 2 +- drivers/net/epic100.c | 2 +- drivers/net/fealnx.c | 2 +- drivers/net/fec_mpc52xx.c | 6 +++--- drivers/net/forcedeth.c | 6 +++--- drivers/net/hamachi.c | 2 +- drivers/net/ibmveth.c | 2 +- drivers/net/igb/igb_ethtool.c | 8 ++++---- drivers/net/igb/igb_main.c | 8 ++++---- drivers/net/igbvf/netdev.c | 6 +++--- drivers/net/irda/au1k_ir.c | 4 ++-- drivers/net/isa-skeleton.c | 4 ++-- drivers/net/ixgb/ixgb_main.c | 2 +- drivers/net/ixgbe/ixgbe_ethtool.c | 6 +++--- drivers/net/ixgbe/ixgbe_main.c | 6 +++--- drivers/net/jazzsonic.c | 2 +- drivers/net/korina.c | 8 ++++---- drivers/net/lance.c | 2 +- drivers/net/lib82596.c | 2 +- drivers/net/lp486e.c | 2 +- drivers/net/mac89x0.c | 2 +- drivers/net/macsonic.c | 4 ++-- drivers/net/mipsnet.c | 2 +- drivers/net/myri_sbus.c | 2 +- drivers/net/natsemi.c | 2 +- drivers/net/netx-eth.c | 2 +- drivers/net/ni5010.c | 2 +- drivers/net/ni52.c | 2 +- drivers/net/ni65.c | 2 +- drivers/net/pasemi_mac.c | 4 ++-- drivers/net/pcnet32.c | 2 +- drivers/net/s6gmac.c | 2 +- drivers/net/sb1000.c | 2 +- drivers/net/sb1250-mac.c | 2 +- drivers/net/seeq8005.c | 4 ++-- drivers/net/sh_eth.c | 2 +- drivers/net/sis900.c | 2 +- drivers/net/smc911x.c | 2 +- drivers/net/smc9194.c | 2 +- drivers/net/smc91x.c | 2 +- drivers/net/starfire.c | 2 +- drivers/net/stmmac/stmmac_main.c | 2 +- drivers/net/sun3_82586.c | 2 +- drivers/net/sunbmac.c | 2 +- drivers/net/sundance.c | 2 +- drivers/net/sunhme.c | 2 +- drivers/net/sunlance.c | 2 +- drivers/net/sunqe.c | 2 +- drivers/net/tc35815.c | 2 +- drivers/net/tehuti.c | 2 +- drivers/net/tokenring/ibmtr.c | 2 +- drivers/net/tokenring/lanstreamer.c | 2 +- drivers/net/tulip/dmfe.c | 2 +- drivers/net/tulip/tulip_core.c | 4 ++-- drivers/net/tulip/uli526x.c | 2 +- drivers/net/tulip/winbond-840.c | 2 +- drivers/net/tulip/xircom_cb.c | 2 +- drivers/net/wan/hostess_sv11.c | 2 +- drivers/net/wan/lmc/lmc_main.c | 2 +- drivers/net/wan/n2.c | 2 +- drivers/net/wan/sdla.c | 2 +- drivers/net/wan/sealevel.c | 2 +- drivers/net/wireless/mwl8k.c | 4 ++-- drivers/net/wireless/prism54/islpci_hotplug.c | 2 +- drivers/net/xilinx_emaclite.c | 2 +- drivers/net/xtsonic.c | 2 +- drivers/net/yellowfin.c | 2 +- drivers/net/znet.c | 2 +- 96 files changed, 131 insertions(+), 131 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index f60309175ef5..62ceb2b4820c 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -345,7 +345,7 @@ static int el_open(struct net_device *dev) if (el_debug > 2) pr_debug("%s: Doing el_open()...\n", dev->name); - retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev); + retval = request_irq(dev->irq, el_interrupt, 0, dev->name, dev); if (retval) return retval; diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index a21c9d15ef8a..9257d7ce0378 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -886,7 +886,7 @@ static int elp_open(struct net_device *dev) /* * install our interrupt service routine */ - if ((retval = request_irq(dev->irq, &elp_interrupt, 0, dev->name, dev))) { + if ((retval = request_irq(dev->irq, elp_interrupt, 0, dev->name, dev))) { pr_err("%s: could not allocate IRQ%d\n", dev->name, dev->irq); return retval; } diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index a6dc8bcbc7df..605f1d17a8f3 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -399,7 +399,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) irq = inb(ioaddr + IRQ_CONFIG) & 0x0f; - irqval = request_irq(irq, &el16_interrupt, 0, DRV_NAME, dev); + irqval = request_irq(irq, el16_interrupt, 0, DRV_NAME, dev); if (irqval) { pr_cont("\n"); pr_err("3c507: unable to get IRQ %d (irqval=%d).\n", irq, irqval); diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 3b00a4e927aa..8d4ce0964073 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -780,7 +780,7 @@ el3_open(struct net_device *dev) outw(RxReset, ioaddr + EL3_CMD); outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); - i = request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev); + i = request_irq(dev->irq, el3_interrupt, 0, dev->name, dev); if (i) return i; diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 4adcb950f5f1..37faf36e2457 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -766,11 +766,11 @@ static int corkscrew_open(struct net_device *dev) /* Corkscrew: Cannot share ISA resources. */ if (dev->irq == 0 || dev->dma == 0 - || request_irq(dev->irq, &corkscrew_interrupt, 0, + || request_irq(dev->irq, corkscrew_interrupt, 0, vp->product_name, dev)) return -EAGAIN; enable_dma(dev->dma); set_dma_mode(dev->dma, DMA_MODE_CASCADE); - } else if (request_irq(dev->irq, &corkscrew_interrupt, IRQF_SHARED, + } else if (request_irq(dev->irq, corkscrew_interrupt, IRQF_SHARED, vp->product_name, dev)) { return -EAGAIN; } diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index cb0b730799ba..27d80ca5e4c0 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -288,7 +288,7 @@ static int elmc_open(struct net_device *dev) elmc_id_attn586(); /* disable interrupts */ - ret = request_irq(dev->irq, &elmc_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, + ret = request_irq(dev->irq, elmc_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); if (ret) { pr_err("%s: couldn't get irq %d\n", dev->name, dev->irq); diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 6021e6dded8f..d91c3464fe72 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -443,7 +443,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) * Grab the IRQ */ - err = request_irq(dev->irq, &mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev); + err = request_irq(dev->irq, mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev); if (err) { release_region(dev->base_addr, MC32_IO_EXTENT); pr_err("%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq); diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index b5dc7f550725..50cecf417471 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -328,7 +328,7 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr) /* Reserve any actual interrupt. */ if (dev->irq) { - retval = request_irq(dev->irq, &cops_interrupt, 0, dev->name, dev); + retval = request_irq(dev->irq, cops_interrupt, 0, dev->name, dev); if (retval) goto err_out; } diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index 08760baece7a..dbfbd3b7ff86 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -1158,7 +1158,7 @@ struct net_device * __init ltpc_probe(void) } /* grab it and don't let go :-) */ - if (irq && request_irq( irq, <pc_interrupt, 0, "ltpc", dev) >= 0) + if (irq && request_irq( irq, ltpc_interrupt, 0, "ltpc", dev) >= 0) { (void) inb_p(io+7); /* enable interrupts from board */ (void) inb_p(io+7); /* and reset irq line */ diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index e3082a9350fc..c5b988140a91 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -156,7 +156,7 @@ static int __init arcrimi_found(struct net_device *dev) } /* reserve the irq */ - if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (RIM I)", dev)) { + if (request_irq(dev->irq, arcnet_interrupt, 0, "arcnet (RIM I)", dev)) { iounmap(p); release_mem_region(dev->mem_start, MIRROR_SIZE); BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 651275a5f3d2..0a74f21409c5 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -200,7 +200,7 @@ int com20020_found(struct net_device *dev, int shared) outb(dev->dev_addr[0], _XREG); /* reserve the irq */ - if (request_irq(dev->irq, &arcnet_interrupt, shared, + if (request_irq(dev->irq, arcnet_interrupt, shared, "arcnet (COM20020)", dev)) { BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); return -ENODEV; diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 89de29b3b1dc..28dea518d554 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -238,7 +238,7 @@ static int __init com90io_found(struct net_device *dev) int err; /* Reserve the irq */ - if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (COM90xx-IO)", dev)) { + if (request_irq(dev->irq, arcnet_interrupt, 0, "arcnet (COM90xx-IO)", dev)) { BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); return -ENODEV; } diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index d762fe46251e..112e230cb13d 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -501,7 +501,7 @@ static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem goto err_free_dev; /* reserve the irq */ - if (request_irq(airq, &arcnet_interrupt, 0, "arcnet (90xx)", dev)) { + if (request_irq(airq, arcnet_interrupt, 0, "arcnet (90xx)", dev)) { BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", airq); goto err_release_mem; } diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 544d5af6950e..d4ab69f032be 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -468,7 +468,7 @@ found: lp->jumpered = is_fmv18x; lp->mca_slot = slot; /* Snarf the interrupt vector now. */ - ret = request_irq(irq, &net_interrupt, 0, DRV_NAME, dev); + ret = request_irq(irq, net_interrupt, 0, DRV_NAME, dev); if (ret) { printk(KERN_ERR "AT1700 at %#3x is unusable due to a " "conflict on IRQ %d.\n", diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 8b889ab544b0..ad17e74e5662 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1930,7 +1930,7 @@ static int atl1e_request_irq(struct atl1e_adapter *adapter) if (!adapter->have_msi) flags |= IRQF_SHARED; - err = request_irq(adapter->pdev->irq, &atl1e_intr, flags, + err = request_irq(adapter->pdev->irq, atl1e_intr, flags, netdev->name, netdev); if (err) { dev_dbg(&pdev->dev, diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 963df502260a..e547f788a266 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2589,7 +2589,7 @@ static s32 atl1_up(struct atl1_adapter *adapter) irq_flags |= IRQF_SHARED; } - err = request_irq(adapter->pdev->irq, &atl1_intr, irq_flags, + err = request_irq(adapter->pdev->irq, atl1_intr, irq_flags, netdev->name, netdev); if (unlikely(err)) goto err_up; diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index 0d268075bad5..c0451d75cdcf 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -651,7 +651,7 @@ static int atl2_request_irq(struct atl2_adapter *adapter) if (adapter->have_msi) flags &= ~IRQF_SHARED; - return request_irq(adapter->pdev->irq, &atl2_intr, flags, netdev->name, + return request_irq(adapter->pdev->irq, atl2_intr, flags, netdev->name, netdev); } diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 9043294fe617..001791775be3 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -437,7 +437,7 @@ static int net_open(struct net_device *dev) /* The interrupt line is turned off (tri-stated) when the device isn't in use. That's especially important for "attached" interfaces where the port or interrupt may be shared. */ - ret = request_irq(dev->irq, &atp_interrupt, 0, dev->name, dev); + ret = request_irq(dev->irq, atp_interrupt, 0, dev->name, dev); if (ret) return ret; diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index ce6f1ac25df8..e67533cf78d8 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -881,7 +881,7 @@ static int au1000_open(struct net_device *dev) if (au1000_debug > 4) printk("%s: open: dev=%p\n", dev->name, dev); - if ((retval = request_irq(dev->irq, &au1000_interrupt, 0, + if ((retval = request_irq(dev->irq, au1000_interrupt, 0, dev->name, dev))) { printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 0c54219960e2..af9321617ce4 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1323,7 +1323,7 @@ net_open(struct net_device *dev) writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); #endif write_irq(dev, lp->chip_type, dev->irq); - ret = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev); + ret = request_irq(dev->irq, net_interrupt, 0, dev->name, dev); if (ret) { if (net_debug) printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq); diff --git a/drivers/net/declance.c b/drivers/net/declance.c index a31696a3928e..be9590253aa1 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -801,14 +801,14 @@ static int lance_open(struct net_device *dev) netif_start_queue(dev); /* Associate IRQ with lance_interrupt */ - if (request_irq(dev->irq, &lance_interrupt, 0, "lance", dev)) { + if (request_irq(dev->irq, lance_interrupt, 0, "lance", dev)) { printk("%s: Can't get IRQ %d\n", dev->name, dev->irq); return -EAGAIN; } if (lp->dma_irq >= 0) { unsigned long flags; - if (request_irq(lp->dma_irq, &lance_dma_merr_int, 0, + if (request_irq(lp->dma_irq, lance_dma_merr_int, 0, "lance error", dev)) { free_irq(dev->irq, dev); printk("%s: Can't get DMA IRQ %d\n", dev->name, diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 7a3bdac84abe..0c1f491d20bf 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -849,7 +849,7 @@ static int depca_open(struct net_device *dev) depca_dbg_open(dev); - if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name, dev)) { + if (request_irq(dev->irq, depca_interrupt, 0, lp->adapter_name, dev)) { printk("depca_open(): Requested IRQ%d is busy\n", dev->irq); status = -EAGAIN; } else { diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index ce8fef184f2c..a2f1860fdd16 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -411,7 +411,7 @@ rio_open (struct net_device *dev) int i; u16 macctrl; - i = request_irq (dev->irq, &rio_interrupt, IRQF_SHARED, dev->name, dev); + i = request_irq (dev->irq, rio_interrupt, IRQF_SHARED, dev->name, dev); if (i) return i; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 3aab2e466008..81590fbb9943 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1175,7 +1175,7 @@ dm9000_open(struct net_device *dev) irqflags |= IRQF_SHARED; - if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev)) + if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev)) return -EAGAIN; /* Initialize DM9000 board */ diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index ffbae0a0b4f1..13e9ece16889 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -869,10 +869,10 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* NOTE: we don't test MSI interrupts here, yet */ /* Hook up test interrupt handler just for this test */ - if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, + if (!request_irq(irq, e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, netdev)) shared_int = false; - else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED, + else if (request_irq(irq, e1000_test_intr, IRQF_SHARED, netdev->name, netdev)) { *data = 1; return -1; diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 0364b91488af..c430dc8b70a3 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -937,10 +937,10 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) e1000e_set_interrupt_capability(adapter); } /* Hook up test interrupt handler just for this test */ - if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, + if (!request_irq(irq, e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, netdev)) { shared_int = 0; - } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED, + } else if (request_irq(irq, e1000_test_intr, IRQF_SHARED, netdev->name, netdev)) { *data = 1; ret_val = -1; diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 376924804f3f..3caa1d5893c4 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -1458,7 +1458,7 @@ static int e1000_request_msix(struct e1000_adapter *adapter) else memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, - &e1000_intr_msix_rx, 0, adapter->rx_ring->name, + e1000_intr_msix_rx, 0, adapter->rx_ring->name, netdev); if (err) goto out; @@ -1471,7 +1471,7 @@ static int e1000_request_msix(struct e1000_adapter *adapter) else memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, - &e1000_intr_msix_tx, 0, adapter->tx_ring->name, + e1000_intr_msix_tx, 0, adapter->tx_ring->name, netdev); if (err) goto out; @@ -1480,7 +1480,7 @@ static int e1000_request_msix(struct e1000_adapter *adapter) vector++; err = request_irq(adapter->msix_entries[vector].vector, - &e1000_msix_other, 0, netdev->name, netdev); + e1000_msix_other, 0, netdev->name, netdev); if (err) goto out; @@ -1511,7 +1511,7 @@ static int e1000_request_irq(struct e1000_adapter *adapter) e1000e_set_interrupt_capability(adapter); } if (adapter->flags & FLAG_MSI_ENABLED) { - err = request_irq(adapter->pdev->irq, &e1000_intr_msi, 0, + err = request_irq(adapter->pdev->irq, e1000_intr_msi, 0, netdev->name, netdev); if (!err) return err; @@ -1521,7 +1521,7 @@ static int e1000_request_irq(struct e1000_adapter *adapter) adapter->int_mode = E1000E_INT_MODE_LEGACY; } - err = request_irq(adapter->pdev->irq, &e1000_intr, IRQF_SHARED, + err = request_irq(adapter->pdev->irq, e1000_intr, IRQF_SHARED, netdev->name, netdev); if (err) e_err("Unable to allocate interrupt, Error: %d\n", err); @@ -2970,7 +2970,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter) if (err) goto msi_test_failed; - err = request_irq(adapter->pdev->irq, &e1000_intr_msi_test, 0, + err = request_irq(adapter->pdev->irq, e1000_intr_msi_test, 0, netdev->name, netdev); if (err) { pci_disable_msi(adapter->pdev); diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 1e934160062c..94c59498cdb6 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -990,7 +990,7 @@ static int eepro_open(struct net_device *dev) return -EAGAIN; } - if (request_irq(dev->irq , &eepro_interrupt, 0, dev->name, dev)) { + if (request_irq(dev->irq , eepro_interrupt, 0, dev->name, dev)) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 592de8f1668a..6fbfc8eee632 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -457,7 +457,7 @@ static int eexp_open(struct net_device *dev) if (!dev->irq || !irqrmap[dev->irq]) return -ENXIO; - ret = request_irq(dev->irq, &eexp_irq, 0, dev->name, dev); + ret = request_irq(dev->irq, eexp_irq, 0, dev->name, dev); if (ret) return ret; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 641a10d2e843..703b4c8e9b4d 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -668,7 +668,7 @@ static int epic_open(struct net_device *dev) outl(0x4001, ioaddr + GENCTL); napi_enable(&ep->napi); - if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev))) { + if ((retval = request_irq(dev->irq, epic_interrupt, IRQF_SHARED, dev->name, dev))) { napi_disable(&ep->napi); return retval; } diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 18d5fbb9673e..e173515790c0 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -839,7 +839,7 @@ static int netdev_open(struct net_device *dev) iowrite32(0x00000001, ioaddr + BCR); /* Reset */ - if (request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev)) + if (request_irq(dev->irq, intr_handler, IRQF_SHARED, dev->name, dev)) return -EAGAIN; for (i = 0; i < 3; i++) diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 66dace6d324f..6407672b28e9 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -226,17 +226,17 @@ static int mpc52xx_fec_open(struct net_device *dev) phy_start(priv->phydev); } - if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED, + if (request_irq(dev->irq, mpc52xx_fec_interrupt, IRQF_SHARED, DRIVER_NAME "_ctrl", dev)) { dev_err(&dev->dev, "ctrl interrupt request failed\n"); goto free_phy; } - if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, 0, + if (request_irq(priv->r_irq, mpc52xx_fec_rx_interrupt, 0, DRIVER_NAME "_rx", dev)) { dev_err(&dev->dev, "rx interrupt request failed\n"); goto free_ctrl_irq; } - if (request_irq(priv->t_irq, &mpc52xx_fec_tx_interrupt, 0, + if (request_irq(priv->t_irq, mpc52xx_fec_tx_interrupt, 0, DRIVER_NAME "_tx", dev)) { dev_err(&dev->dev, "tx interrupt request failed\n"); goto free_2irqs; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 3116601dbfea..3c340489804a 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -4004,7 +4004,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test) /* Request irq for rx handling */ sprintf(np->name_rx, "%s-rx", dev->name); if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, - &nv_nic_irq_rx, IRQF_SHARED, np->name_rx, dev) != 0) { + nv_nic_irq_rx, IRQF_SHARED, np->name_rx, dev) != 0) { printk(KERN_INFO "forcedeth: request_irq failed for rx %d\n", ret); pci_disable_msix(np->pci_dev); np->msi_flags &= ~NV_MSI_X_ENABLED; @@ -4013,7 +4013,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test) /* Request irq for tx handling */ sprintf(np->name_tx, "%s-tx", dev->name); if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, - &nv_nic_irq_tx, IRQF_SHARED, np->name_tx, dev) != 0) { + nv_nic_irq_tx, IRQF_SHARED, np->name_tx, dev) != 0) { printk(KERN_INFO "forcedeth: request_irq failed for tx %d\n", ret); pci_disable_msix(np->pci_dev); np->msi_flags &= ~NV_MSI_X_ENABLED; @@ -4022,7 +4022,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test) /* Request irq for link and timer handling */ sprintf(np->name_other, "%s-other", dev->name); if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, - &nv_nic_irq_other, IRQF_SHARED, np->name_other, dev) != 0) { + nv_nic_irq_other, IRQF_SHARED, np->name_other, dev) != 0) { printk(KERN_INFO "forcedeth: request_irq failed for link %d\n", ret); pci_disable_msix(np->pci_dev); np->msi_flags &= ~NV_MSI_X_ENABLED; diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index c9ac46118e6f..5d8c6333070e 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -872,7 +872,7 @@ static int hamachi_open(struct net_device *dev) u32 rx_int_var, tx_int_var; u16 fifo_info; - i = request_irq(dev->irq, &hamachi_interrupt, IRQF_SHARED, dev->name, dev); + i = request_irq(dev->irq, hamachi_interrupt, IRQF_SHARED, dev->name, dev); if (i) return i; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 5862282ab2fe..a86693906ac8 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -625,7 +625,7 @@ static int ibmveth_open(struct net_device *netdev) } ibmveth_debug_printk("registering irq 0x%x\n", netdev->irq); - if((rc = request_irq(netdev->irq, &ibmveth_interrupt, 0, netdev->name, netdev)) != 0) { + if((rc = request_irq(netdev->irq, ibmveth_interrupt, 0, netdev->name, netdev)) != 0) { ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc); do { rc = h_free_logical_lan(adapter->vdev->unit_address); diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 88e13f7e566f..2e238bfa1f91 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -1133,21 +1133,21 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) /* Hook up test interrupt handler just for this test */ if (adapter->msix_entries) { if (request_irq(adapter->msix_entries[0].vector, - &igb_test_intr, 0, netdev->name, adapter)) { + igb_test_intr, 0, netdev->name, adapter)) { *data = 1; return -1; } } else if (adapter->flags & IGB_FLAG_HAS_MSI) { shared_int = false; if (request_irq(irq, - &igb_test_intr, 0, netdev->name, adapter)) { + igb_test_intr, 0, netdev->name, adapter)) { *data = 1; return -1; } - } else if (!request_irq(irq, &igb_test_intr, IRQF_PROBE_SHARED, + } else if (!request_irq(irq, igb_test_intr, IRQF_PROBE_SHARED, netdev->name, adapter)) { shared_int = false; - } else if (request_irq(irq, &igb_test_intr, IRQF_SHARED, + } else if (request_irq(irq, igb_test_intr, IRQF_SHARED, netdev->name, adapter)) { *data = 1; return -1; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 0cab5e2b0894..958305e92d67 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -525,7 +525,7 @@ static int igb_request_msix(struct igb_adapter *adapter) int i, err = 0, vector = 0; err = request_irq(adapter->msix_entries[vector].vector, - &igb_msix_other, 0, netdev->name, adapter); + igb_msix_other, 0, netdev->name, adapter); if (err) goto out; vector++; @@ -548,7 +548,7 @@ static int igb_request_msix(struct igb_adapter *adapter) sprintf(q_vector->name, "%s-unused", netdev->name); err = request_irq(adapter->msix_entries[vector].vector, - &igb_msix_ring, 0, q_vector->name, + igb_msix_ring, 0, q_vector->name, q_vector); if (err) goto out; @@ -875,7 +875,7 @@ static int igb_request_irq(struct igb_adapter *adapter) } if (adapter->flags & IGB_FLAG_HAS_MSI) { - err = request_irq(adapter->pdev->irq, &igb_intr_msi, 0, + err = request_irq(adapter->pdev->irq, igb_intr_msi, 0, netdev->name, adapter); if (!err) goto request_done; @@ -885,7 +885,7 @@ static int igb_request_irq(struct igb_adapter *adapter) adapter->flags &= ~IGB_FLAG_HAS_MSI; } - err = request_irq(adapter->pdev->irq, &igb_intr, IRQF_SHARED, + err = request_irq(adapter->pdev->irq, igb_intr, IRQF_SHARED, netdev->name, adapter); if (err) diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index fad7f348dd1b..e01f44597a26 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -1043,7 +1043,7 @@ static int igbvf_request_msix(struct igbvf_adapter *adapter) } err = request_irq(adapter->msix_entries[vector].vector, - &igbvf_intr_msix_tx, 0, adapter->tx_ring->name, + igbvf_intr_msix_tx, 0, adapter->tx_ring->name, netdev); if (err) goto out; @@ -1053,7 +1053,7 @@ static int igbvf_request_msix(struct igbvf_adapter *adapter) vector++; err = request_irq(adapter->msix_entries[vector].vector, - &igbvf_intr_msix_rx, 0, adapter->rx_ring->name, + igbvf_intr_msix_rx, 0, adapter->rx_ring->name, netdev); if (err) goto out; @@ -1063,7 +1063,7 @@ static int igbvf_request_msix(struct igbvf_adapter *adapter) vector++; err = request_irq(adapter->msix_entries[vector].vector, - &igbvf_msix_other, 0, netdev->name, netdev); + igbvf_msix_other, 0, netdev->name, netdev); if (err) goto out; diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index eb424681202d..9b2eebdbb25b 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -353,13 +353,13 @@ static int au1k_irda_start(struct net_device *dev) return retval; } - if ((retval = request_irq(AU1000_IRDA_TX_INT, &au1k_irda_interrupt, + if ((retval = request_irq(AU1000_IRDA_TX_INT, au1k_irda_interrupt, 0, dev->name, dev))) { printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); return retval; } - if ((retval = request_irq(AU1000_IRDA_RX_INT, &au1k_irda_interrupt, + if ((retval = request_irq(AU1000_IRDA_RX_INT, au1k_irda_interrupt, 0, dev->name, dev))) { free_irq(AU1000_IRDA_TX_INT, dev); printk(KERN_ERR "%s: unable to get IRQ %d\n", diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 9706e64e367b..0e71e2a93160 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -260,7 +260,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) dev->irq = 9; { - int irqval = request_irq(dev->irq, &net_interrupt, 0, cardname, dev); + int irqval = request_irq(dev->irq, net_interrupt, 0, cardname, dev); if (irqval) { printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, irqval); @@ -378,7 +378,7 @@ net_open(struct net_device *dev) * This is used if the interrupt line can turned off (shared). * See 3c503.c for an example of selecting the IRQ at config-time. */ - if (request_irq(dev->irq, &net_interrupt, 0, cardname, dev)) { + if (request_irq(dev->irq, net_interrupt, 0, cardname, dev)) { return -EAGAIN; } /* diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 1bd0ca1b0465..73646062e8dd 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -233,7 +233,7 @@ ixgb_up(struct ixgb_adapter *adapter) /* proceed to try to request regular interrupt */ } - err = request_irq(adapter->pdev->irq, &ixgb_intr, irq_flags, + err = request_irq(adapter->pdev->irq, ixgb_intr, irq_flags, netdev->name, netdev); if (err) { if (adapter->have_msi) diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 9d2cc833691b..74f04e183545 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1274,15 +1274,15 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) return 0; } else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { shared_int = false; - if (request_irq(irq, &ixgbe_test_intr, 0, netdev->name, + if (request_irq(irq, ixgbe_test_intr, 0, netdev->name, netdev)) { *data = 1; return -1; } - } else if (!request_irq(irq, &ixgbe_test_intr, IRQF_PROBE_SHARED, + } else if (!request_irq(irq, ixgbe_test_intr, IRQF_PROBE_SHARED, netdev->name, netdev)) { shared_int = false; - } else if (request_irq(irq, &ixgbe_test_intr, IRQF_SHARED, + } else if (request_irq(irq, ixgbe_test_intr, IRQF_SHARED, netdev->name, netdev)) { *data = 1; return -1; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index dceed80f16fb..ebcec30e0783 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1661,7 +1661,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) sprintf(adapter->name[vector], "%s:lsc", netdev->name); err = request_irq(adapter->msix_entries[vector].vector, - &ixgbe_msix_lsc, 0, adapter->name[vector], netdev); + ixgbe_msix_lsc, 0, adapter->name[vector], netdev); if (err) { DPRINTK(PROBE, ERR, "request_irq for msix_lsc failed: %d\n", err); @@ -1832,10 +1832,10 @@ static int ixgbe_request_irq(struct ixgbe_adapter *adapter) if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { err = ixgbe_request_msix_irqs(adapter); } else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { - err = request_irq(adapter->pdev->irq, &ixgbe_intr, 0, + err = request_irq(adapter->pdev->irq, ixgbe_intr, 0, netdev->name, netdev); } else { - err = request_irq(adapter->pdev->irq, &ixgbe_intr, IRQF_SHARED, + err = request_irq(adapter->pdev->irq, ixgbe_intr, IRQF_SHARED, netdev->name, netdev); } diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 6e5b3f30527f..35d5bed450da 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -81,7 +81,7 @@ static unsigned short known_revisions[] = static int jazzsonic_open(struct net_device* dev) { - if (request_irq(dev->irq, &sonic_interrupt, IRQF_DISABLED, "sonic", dev)) { + if (request_irq(dev->irq, sonic_interrupt, IRQF_DISABLED, "sonic", dev)) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } diff --git a/drivers/net/korina.c b/drivers/net/korina.c index a07a5972b57e..25e2af6997e4 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -1014,14 +1014,14 @@ static int korina_open(struct net_device *dev) /* Install the interrupt handler * that handles the Done Finished * Ovr and Und Events */ - ret = request_irq(lp->rx_irq, &korina_rx_dma_interrupt, + ret = request_irq(lp->rx_irq, korina_rx_dma_interrupt, IRQF_DISABLED, "Korina ethernet Rx", dev); if (ret < 0) { printk(KERN_ERR "%s: unable to get Rx DMA IRQ %d\n", dev->name, lp->rx_irq); goto err_release; } - ret = request_irq(lp->tx_irq, &korina_tx_dma_interrupt, + ret = request_irq(lp->tx_irq, korina_tx_dma_interrupt, IRQF_DISABLED, "Korina ethernet Tx", dev); if (ret < 0) { printk(KERN_ERR "%s: unable to get Tx DMA IRQ %d\n", @@ -1030,7 +1030,7 @@ static int korina_open(struct net_device *dev) } /* Install handler for overrun error. */ - ret = request_irq(lp->ovr_irq, &korina_ovr_interrupt, + ret = request_irq(lp->ovr_irq, korina_ovr_interrupt, IRQF_DISABLED, "Ethernet Overflow", dev); if (ret < 0) { printk(KERN_ERR "%s: unable to get OVR IRQ %d\n", @@ -1039,7 +1039,7 @@ static int korina_open(struct net_device *dev) } /* Install handler for underflow error. */ - ret = request_irq(lp->und_irq, &korina_und_interrupt, + ret = request_irq(lp->und_irq, korina_und_interrupt, IRQF_DISABLED, "Ethernet Underflow", dev); if (ret < 0) { printk(KERN_ERR "%s: unable to get UND IRQ %d\n", diff --git a/drivers/net/lance.c b/drivers/net/lance.c index dcda30338b65..7b2c42992c35 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -755,7 +755,7 @@ lance_open(struct net_device *dev) int i; if (dev->irq == 0 || - request_irq(dev->irq, &lance_interrupt, 0, lp->name, dev)) { + request_irq(dev->irq, lance_interrupt, 0, lp->name, dev)) { return -EAGAIN; } diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index 5b24c67de25e..7a07430206e3 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -588,7 +588,7 @@ static int init_i596_mem(struct net_device *dev) "%s: i82596 initialization successful\n", dev->name)); - if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) { + if (request_irq(dev->irq, i596_interrupt, 0, "i82596", dev)) { printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq); goto failed; } diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index cc3ed9cf28be..e20fefc73c8b 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -845,7 +845,7 @@ static int i596_open(struct net_device *dev) { int i; - i = request_irq(dev->irq, &i596_interrupt, IRQF_SHARED, dev->name, dev); + i = request_irq(dev->irq, i596_interrupt, IRQF_SHARED, dev->name, dev); if (i) { printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq); return i; diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 149e0ed4a055..c244ec34fc43 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -337,7 +337,7 @@ net_open(struct net_device *dev) writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ); /* Grab the interrupt */ - if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) + if (request_irq(dev->irq, net_interrupt, 0, "cs89x0", dev)) return -EAGAIN; /* Set up the IRQ - Apparently magic */ diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index b3d7d8d77f46..875d361fb79d 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -140,7 +140,7 @@ static irqreturn_t macsonic_interrupt(int irq, void *dev_id) static int macsonic_open(struct net_device* dev) { - if (request_irq(dev->irq, &sonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { + if (request_irq(dev->irq, sonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } @@ -149,7 +149,7 @@ static int macsonic_open(struct net_device* dev) * rupt as well, which must prevent re-entrance of the sonic handler. */ if (dev->irq == IRQ_AUTO_3) - if (request_irq(IRQ_NUBUS_9, &macsonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { + if (request_irq(IRQ_NUBUS_9, macsonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, IRQ_NUBUS_9); free_irq(dev->irq, dev); return -EAGAIN; diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index 8ea98bd89ff1..8e9704f5c122 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -211,7 +211,7 @@ static int mipsnet_open(struct net_device *dev) { int err; - err = request_irq(dev->irq, &mipsnet_interrupt, + err = request_irq(dev->irq, mipsnet_interrupt, IRQF_SHARED, dev->name, (void *) dev); if (err) { release_region(dev->base_addr, sizeof(struct mipsnet_regs)); diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 29ebebc6a95b..b3513ad3b703 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -1084,7 +1084,7 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic /* Register interrupt handler now. */ DET(("Requesting MYRIcom IRQ line.\n")); - if (request_irq(dev->irq, &myri_interrupt, + if (request_irq(dev->irq, myri_interrupt, IRQF_SHARED, "MyriCOM Ethernet", (void *) dev)) { printk("MyriCOM: Cannot register interrupt handler.\n"); goto err; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index b2722c44337e..9a8d3ab4709b 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -1535,7 +1535,7 @@ static int netdev_open(struct net_device *dev) /* Reset the chip, just in case. */ natsemi_reset(dev); - i = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev); + i = request_irq(dev->irq, intr_handler, IRQF_SHARED, dev->name, dev); if (i) return i; if (netif_msg_ifup(np)) diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index a0d65f592a12..64770298c4f7 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -212,7 +212,7 @@ static int netx_eth_open(struct net_device *ndev) struct netx_eth_priv *priv = netdev_priv(ndev); if (request_irq - (ndev->irq, &netx_eth_interrupt, IRQF_SHARED, ndev->name, ndev)) + (ndev->irq, netx_eth_interrupt, IRQF_SHARED, ndev->name, ndev)) return -EAGAIN; writel(ndev->dev_addr[0] | diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 462d20f26436..6a87d810e59d 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -377,7 +377,7 @@ static int ni5010_open(struct net_device *dev) PRINTK2((KERN_DEBUG "%s: entering ni5010_open()\n", dev->name)); - if (request_irq(dev->irq, &ni5010_interrupt, 0, boardname, dev)) { + if (request_irq(dev->irq, ni5010_interrupt, 0, boardname, dev)) { printk(KERN_WARNING "%s: Cannot get irq %#2x\n", dev->name, dev->irq); return -EAGAIN; } diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index aad3b370c562..305f4ba36999 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -284,7 +284,7 @@ static int ni52_open(struct net_device *dev) startrecv586(dev); ni_enaint(); - ret = request_irq(dev->irq, &ni52_interrupt, 0, dev->name, dev); + ret = request_irq(dev->irq, ni52_interrupt, 0, dev->name, dev); if (ret) { ni_reset586(); return ret; diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 752c2e4d9cf4..ae19aafd2c7e 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -294,7 +294,7 @@ static void ni65_set_performance(struct priv *p) static int ni65_open(struct net_device *dev) { struct priv *p = dev->ml_priv; - int irqval = request_irq(dev->irq, &ni65_interrupt,0, + int irqval = request_irq(dev->irq, ni65_interrupt,0, cards[p->cardno].cardname,dev); if (irqval) { printk(KERN_ERR "%s: unable to get IRQ %d (irqval=%d).\n", diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index c254a7f5b9f5..1673eb045e1e 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -1216,7 +1216,7 @@ static int pasemi_mac_open(struct net_device *dev) snprintf(mac->tx_irq_name, sizeof(mac->tx_irq_name), "%s tx", dev->name); - ret = request_irq(mac->tx->chan.irq, &pasemi_mac_tx_intr, IRQF_DISABLED, + ret = request_irq(mac->tx->chan.irq, pasemi_mac_tx_intr, IRQF_DISABLED, mac->tx_irq_name, mac->tx); if (ret) { dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", @@ -1227,7 +1227,7 @@ static int pasemi_mac_open(struct net_device *dev) snprintf(mac->rx_irq_name, sizeof(mac->rx_irq_name), "%s rx", dev->name); - ret = request_irq(mac->rx->chan.irq, &pasemi_mac_rx_intr, IRQF_DISABLED, + ret = request_irq(mac->rx->chan.irq, pasemi_mac_rx_intr, IRQF_DISABLED, mac->rx_irq_name, mac->rx); if (ret) { dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index c1b3f09f452c..076f23a10517 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -2095,7 +2095,7 @@ static int pcnet32_open(struct net_device *dev) int rc; unsigned long flags; - if (request_irq(dev->irq, &pcnet32_interrupt, + if (request_irq(dev->irq, pcnet32_interrupt, lp->shared_irq ? IRQF_SHARED : 0, dev->name, (void *)dev)) { return -EAGAIN; diff --git a/drivers/net/s6gmac.c b/drivers/net/s6gmac.c index 4525cbe8dd69..d81706e91aa7 100644 --- a/drivers/net/s6gmac.c +++ b/drivers/net/s6gmac.c @@ -984,7 +984,7 @@ static int __devinit s6gmac_probe(struct platform_device *pdev) pd->rx_dma = DMA_MASK_DMAC(i); pd->rx_chan = DMA_INDEX_CHNL(i); pd->io = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; - res = request_irq(dev->irq, &s6gmac_interrupt, 0, dev->name, dev); + res = request_irq(dev->irq, s6gmac_interrupt, 0, dev->name, dev); if (res) { printk(KERN_ERR DRV_PRMT "irq request failed: %d\n", dev->irq); goto errirq; diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index c9c70ab0cce0..9f83a1197375 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -973,7 +973,7 @@ sb1000_open(struct net_device *dev) lp->rx_frame_id[1] = 0; lp->rx_frame_id[2] = 0; lp->rx_frame_id[3] = 0; - if (request_irq(dev->irq, &sb1000_interrupt, 0, "sb1000", dev)) { + if (request_irq(dev->irq, sb1000_interrupt, 0, "sb1000", dev)) { return -EAGAIN; } diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 7269a875326e..564d4d7f855b 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2410,7 +2410,7 @@ static int sbmac_open(struct net_device *dev) */ __raw_readq(sc->sbm_isr); - err = request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev); + err = request_irq(dev->irq, sbmac_intr, IRQF_SHARED, dev->name, dev); if (err) { printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 39246d457ac2..fe806bd9b95f 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -335,7 +335,7 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr) #if 0 { - int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005", dev); + int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev); if (irqval) { printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, irqval); @@ -367,7 +367,7 @@ static int seeq8005_open(struct net_device *dev) struct net_local *lp = netdev_priv(dev); { - int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005", dev); + int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev); if (irqval) { printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, irqval); diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 5783f50d18e9..c88bc1013047 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1016,7 +1016,7 @@ static int sh_eth_open(struct net_device *ndev) pm_runtime_get_sync(&mdp->pdev->dev); - ret = request_irq(ndev->irq, &sh_eth_interrupt, + ret = request_irq(ndev->irq, sh_eth_interrupt, #if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764) IRQF_SHARED, #else diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index c072f7f36acf..9a12d88ac2d9 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1016,7 +1016,7 @@ sis900_open(struct net_device *net_dev) /* Equalizer workaround Rule */ sis630_set_eq(net_dev, sis_priv->chipset_rev); - ret = request_irq(net_dev->irq, &sis900_interrupt, IRQF_SHARED, + ret = request_irq(net_dev->irq, sis900_interrupt, IRQF_SHARED, net_dev->name, net_dev); if (ret) return ret; diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 2a6b6de95339..44ebbaa7457b 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1984,7 +1984,7 @@ static int __devinit smc911x_probe(struct net_device *dev) #endif /* Grab the IRQ */ - retval = request_irq(dev->irq, &smc911x_interrupt, + retval = request_irq(dev->irq, smc911x_interrupt, irq_flags, dev->name, dev); if (retval) goto err_out; diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index 934a12012829..8371b82323ac 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -1050,7 +1050,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) memset(netdev_priv(dev), 0, sizeof(struct smc_local)); /* Grab the IRQ */ - retval = request_irq(dev->irq, &smc_interrupt, 0, DRV_NAME, dev); + retval = request_irq(dev->irq, smc_interrupt, 0, DRV_NAME, dev); if (retval) { printk("%s: unable to get IRQ %d (irqval=%d).\n", DRV_NAME, dev->irq, retval); diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 05c91ee6921e..0b56ab468d28 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -2031,7 +2031,7 @@ static int __devinit smc_probe(struct net_device *dev, void __iomem *ioaddr, } /* Grab the IRQ */ - retval = request_irq(dev->irq, &smc_interrupt, irq_flags, dev->name, dev); + retval = request_irq(dev->irq, smc_interrupt, irq_flags, dev->name, dev); if (retval) goto err_out; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index a36e2b51e88c..aa10158adb9e 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -928,7 +928,7 @@ static int netdev_open(struct net_device *dev) /* Do we ever need to reset the chip??? */ - retval = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev); + retval = request_irq(dev->irq, intr_handler, IRQF_SHARED, dev->name, dev); if (retval) return retval; diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index c2f14dc9ba28..e961e7593c1f 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -1022,7 +1022,7 @@ static int stmmac_open(struct net_device *dev) } /* Request the IRQ lines */ - ret = request_irq(dev->irq, &stmmac_interrupt, + ret = request_irq(dev->irq, stmmac_interrupt, IRQF_SHARED, dev->name, dev); if (unlikely(ret < 0)) { pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index 2f1eaaf7a727..b447a8719427 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -191,7 +191,7 @@ static int sun3_82586_open(struct net_device *dev) startrecv586(dev); sun3_enaint(); - ret = request_irq(dev->irq, &sun3_82586_interrupt,0,dev->name,dev); + ret = request_irq(dev->irq, sun3_82586_interrupt,0,dev->name,dev); if (ret) { sun3_reset586(); diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 536cf7e06bfd..25e81ebd9cd8 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -919,7 +919,7 @@ static int bigmac_open(struct net_device *dev) struct bigmac *bp = netdev_priv(dev); int ret; - ret = request_irq(dev->irq, &bigmac_interrupt, IRQF_SHARED, dev->name, bp); + ret = request_irq(dev->irq, bigmac_interrupt, IRQF_SHARED, dev->name, bp); if (ret) { printk(KERN_ERR "BIGMAC: Can't order irq %d to go.\n", dev->irq); return ret; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index e13685a570f4..5c396c2e6e76 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -819,7 +819,7 @@ static int netdev_open(struct net_device *dev) /* Do we need to reset the chip??? */ - i = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev); + i = request_irq(dev->irq, intr_handler, IRQF_SHARED, dev->name, dev); if (i) return i; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 37d721bbdb35..1f842a78acd1 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2184,7 +2184,7 @@ static int happy_meal_open(struct net_device *dev) * into a single source which we register handling at probe time. */ if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) { - if (request_irq(dev->irq, &happy_meal_interrupt, + if (request_irq(dev->irq, happy_meal_interrupt, IRQF_SHARED, dev->name, (void *)dev)) { HMD(("EAGAIN\n")); printk(KERN_ERR "happy_meal(SBUS): Can't order irq %d to go.\n", diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 9d6fd4760eab..64e7d08c878f 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -923,7 +923,7 @@ static int lance_open(struct net_device *dev) STOP_LANCE(lp); - if (request_irq(dev->irq, &lance_interrupt, IRQF_SHARED, + if (request_irq(dev->irq, lance_interrupt, IRQF_SHARED, lancestr, (void *) dev)) { printk(KERN_ERR "Lance: Can't get irq %d\n", dev->irq); return -EAGAIN; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index dcefb608a9f4..45c383f285ee 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -807,7 +807,7 @@ static struct sunqec * __devinit get_qec(struct of_device *child) qec_init_once(qecp, op); - if (request_irq(op->irqs[0], &qec_interrupt, + if (request_irq(op->irqs[0], qec_interrupt, IRQF_SHARED, "qec", (void *) qecp)) { printk(KERN_ERR "qec: Can't register irq.\n"); goto fail; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 6572e8a54520..75a669d48e5e 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -1248,7 +1248,7 @@ tc35815_open(struct net_device *dev) * This is used if the interrupt line can turned off (shared). * See 3c503.c for an example of selecting the IRQ at config-time. */ - if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, + if (request_irq(dev->irq, tc35815_interrupt, IRQF_SHARED, dev->name, dev)) return -EAGAIN; diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 492bff68bf2d..2fbac31767fa 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -420,7 +420,7 @@ static int bdx_hw_start(struct bdx_priv *priv) GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB); #define BDX_IRQ_TYPE ((priv->nic->irq_type == IRQ_MSI)?0:IRQF_SHARED) - if ((rc = request_irq(priv->pdev->irq, &bdx_isr_napi, BDX_IRQ_TYPE, + if ((rc = request_irq(priv->pdev->irq, bdx_isr_napi, BDX_IRQ_TYPE, ndev->name, ndev))) goto err_irq; bdx_enable_interrupts(priv); diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 75fa32e34fd0..5db0270957ac 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -680,7 +680,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) /* The PCMCIA has already got the interrupt line and the io port, so no chance of anybody else getting it - MLP */ - if (request_irq(dev->irq = irq, &tok_interrupt, 0, "ibmtr", dev) != 0) { + if (request_irq(dev->irq = irq, tok_interrupt, 0, "ibmtr", dev) != 0) { DPRINTK("Could not grab irq %d. Halting Token Ring driver.\n", irq); iounmap(t_mmio); diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 26dca2b2bdbd..7b1fe9412b6f 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -596,7 +596,7 @@ static int streamer_open(struct net_device *dev) rc=streamer_reset(dev); } - if (request_irq(dev->irq, &streamer_interrupt, IRQF_SHARED, "lanstreamer", dev)) { + if (request_irq(dev->irq, streamer_interrupt, IRQF_SHARED, "lanstreamer", dev)) { return -EAGAIN; } #if STREAMER_DEBUG diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index a45ded0538b8..ad63621913c3 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -543,7 +543,7 @@ static int dmfe_open(struct DEVICE *dev) DMFE_DBUG(0, "dmfe_open", 0); - ret = request_irq(dev->irq, &dmfe_interrupt, + ret = request_irq(dev->irq, dmfe_interrupt, IRQF_SHARED, dev->name, dev); if (ret) return ret; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 6b2330e4206e..0df983bc03a6 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -506,7 +506,7 @@ tulip_open(struct net_device *dev) tulip_init_ring (dev); - retval = request_irq(dev->irq, &tulip_interrupt, IRQF_SHARED, dev->name, dev); + retval = request_irq(dev->irq, tulip_interrupt, IRQF_SHARED, dev->name, dev); if (retval) goto free_ring; @@ -1782,7 +1782,7 @@ static int tulip_resume(struct pci_dev *pdev) return retval; } - if ((retval = request_irq(dev->irq, &tulip_interrupt, IRQF_SHARED, dev->name, dev))) { + if ((retval = request_irq(dev->irq, tulip_interrupt, IRQF_SHARED, dev->name, dev))) { printk (KERN_ERR "tulip: request_irq failed in resume\n"); return retval; } diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index c457a0ca55ad..fa019cabc355 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -461,7 +461,7 @@ static int uli526x_open(struct net_device *dev) /* Initialize ULI526X board */ uli526x_init(dev); - ret = request_irq(dev->irq, &uli526x_interrupt, IRQF_SHARED, dev->name, dev); + ret = request_irq(dev->irq, uli526x_interrupt, IRQF_SHARED, dev->name, dev); if (ret) return ret; diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index b38d3b7f6e35..1a52729c9466 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -639,7 +639,7 @@ static int netdev_open(struct net_device *dev) iowrite32(0x00000001, ioaddr + PCIBusCfg); /* Reset */ netif_device_detach(dev); - i = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev); + i = request_irq(dev->irq, intr_handler, IRQF_SHARED, dev->name, dev); if (i) goto out_err; diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 0f2ca5980c3c..9924c4c7e2d6 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -458,7 +458,7 @@ static int xircom_open(struct net_device *dev) int retval; enter("xircom_open"); printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq); - retval = request_irq(dev->irq, &xircom_interrupt, IRQF_SHARED, dev->name, dev); + retval = request_irq(dev->irq, xircom_interrupt, IRQF_SHARED, dev->name, dev); if (retval) { leave("xircom_open - No IRQ"); return retval; diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index 15002c3d0d95..74164d29524c 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -218,7 +218,7 @@ static struct z8530_dev *sv11_init(int iobase, int irq) /* We want a fast IRQ for this device. Actually we'd like an even faster IRQ ;) - This is one driver RtLinux is made for */ - if (request_irq(irq, &z8530_interrupt, IRQF_DISABLED, + if (request_irq(irq, z8530_interrupt, IRQF_DISABLED, "Hostess SV11", sv) < 0) { printk(KERN_WARNING "hostess: IRQ %d already in use.\n", irq); goto err_irq; diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 7ea71b33d2e9..2ebe935d1058 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1028,7 +1028,7 @@ static int lmc_open(struct net_device *dev) lmc_softreset (sc); /* Since we have to use PCI bus, this should work on x86,alpha,ppc */ - if (request_irq (dev->irq, &lmc_interrupt, IRQF_SHARED, dev->name, dev)){ + if (request_irq (dev->irq, lmc_interrupt, IRQF_SHARED, dev->name, dev)){ printk(KERN_WARNING "%s: could not get irq: %d\n", dev->name, dev->irq); lmc_trace(dev, "lmc_open irq failed out"); return -EAGAIN; diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index 58c66819f39b..5394b51bdb2f 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c @@ -376,7 +376,7 @@ static int __init n2_run(unsigned long io, unsigned long irq, } card->io = io; - if (request_irq(irq, &sca_intr, 0, devname, card)) { + if (request_irq(irq, sca_intr, 0, devname, card)) { printk(KERN_ERR "n2: could not allocate IRQ\n"); n2_destroy_card(card); return(-EBUSY); diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 2b15a7e40d5b..31c41af2246d 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -1457,7 +1457,7 @@ got_type: } err = -EAGAIN; - if (request_irq(dev->irq, &sdla_isr, 0, dev->name, dev)) + if (request_irq(dev->irq, sdla_isr, 0, dev->name, dev)) goto fail; if (flp->type == SDLA_S507) { diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index 0c525e24b247..3b3ee05bc462 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c @@ -266,7 +266,7 @@ static __init struct slvl_board *slvl_init(int iobase, int irq, /* We want a fast IRQ for this device. Actually we'd like an even faster IRQ ;) - This is one driver RtLinux is made for */ - if (request_irq(irq, &z8530_interrupt, IRQF_DISABLED, + if (request_irq(irq, z8530_interrupt, IRQF_DISABLED, "SeaLevel", dev) < 0) { printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq); goto err_request_irq; diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 9e64dd43a3be..0cb5ecc822a8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -2817,7 +2817,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) struct mwl8k_priv *priv = hw->priv; int rc; - rc = request_irq(priv->pdev->irq, &mwl8k_interrupt, + rc = request_irq(priv->pdev->irq, mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { printk(KERN_ERR "%s: failed to register IRQ handler\n", @@ -3482,7 +3482,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); - rc = request_irq(priv->pdev->irq, &mwl8k_interrupt, + rc = request_irq(priv->pdev->irq, mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { printk(KERN_ERR "%s: failed to register IRQ handler\n", diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index 83d366258c81..e4f2bb7368f2 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -181,7 +181,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) isl38xx_disable_interrupts(priv->device_base); /* request for the interrupt before uploading the firmware */ - rvalue = request_irq(pdev->irq, &islpci_interrupt, + rvalue = request_irq(pdev->irq, islpci_interrupt, IRQF_SHARED, ndev->name, priv); if (rvalue) { diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index 83a044dbd1d7..8c777ba4e2b3 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -660,7 +660,7 @@ static int xemaclite_open(struct net_device *dev) xemaclite_set_mac_address(lp, dev->dev_addr); /* Grab the IRQ */ - retval = request_irq(dev->irq, &xemaclite_interrupt, 0, dev->name, dev); + retval = request_irq(dev->irq, xemaclite_interrupt, 0, dev->name, dev); if (retval) { dev_err(&lp->ndev->dev, "Could not allocate interrupt %d\n", dev->irq); diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c index 0c44135c0b1f..389ba9df7120 100644 --- a/drivers/net/xtsonic.c +++ b/drivers/net/xtsonic.c @@ -92,7 +92,7 @@ static unsigned short known_revisions[] = static int xtsonic_open(struct net_device *dev) { - if (request_irq(dev->irq,&sonic_interrupt,IRQF_DISABLED,"sonic",dev)) { + if (request_irq(dev->irq,sonic_interrupt,IRQF_DISABLED,"sonic",dev)) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 40ad0dee0406..d831dfca0976 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -579,7 +579,7 @@ static int yellowfin_open(struct net_device *dev) /* Reset the chip. */ iowrite32(0x80000000, ioaddr + DMACtrl); - ret = request_irq(dev->irq, &yellowfin_interrupt, IRQF_SHARED, dev->name, dev); + ret = request_irq(dev->irq, yellowfin_interrupt, IRQF_SHARED, dev->name, dev); if (ret) return ret; diff --git a/drivers/net/znet.c b/drivers/net/znet.c index 443c4eee28c1..a97d894d26fb 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -169,7 +169,7 @@ static int znet_request_resources (struct net_device *dev) { struct znet_private *znet = netdev_priv(dev); - if (request_irq (dev->irq, &znet_interrupt, 0, "ZNet", dev)) + if (request_irq (dev->irq, znet_interrupt, 0, "ZNet", dev)) goto failed; if (request_dma (znet->rx_dma, "ZNet rx")) goto free_irq; -- cgit v1.2.3 From 5be83de54c16944dea9c16c6a5a53c1fa75ed304 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Nov 2009 00:56:28 +0100 Subject: cfg80211: convert bools into flags We've accumulated a number of options for wiphys which make more sense as flags as we keep adding more. Convert the existing ones. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd.c | 5 +-- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 +-- drivers/net/wireless/mac80211_hwsim.c | 18 ++++----- drivers/net/wireless/p54/main.c | 2 +- include/net/cfg80211.h | 62 ++++++++++++++++------------- net/mac80211/main.c | 2 +- net/wireless/Kconfig | 6 --- net/wireless/core.c | 13 ++++-- net/wireless/nl80211.c | 2 +- net/wireless/reg.c | 13 +++--- 11 files changed, 70 insertions(+), 67 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 077bcc142cde..039ac490465c 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -450,7 +450,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, const struct ieee80211_regdomain *regd; wiphy->reg_notifier = reg_notifier; - wiphy->strict_regulatory = true; + wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; if (ath_is_world_regd(reg)) { /* @@ -458,8 +458,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, * saved on the wiphy orig_* parameters */ regd = ath_world_regdomain(reg); - wiphy->custom_regulatory = true; - wiphy->strict_regulatory = false; + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; } else { /* * This gets applied in the case of the absense of CRDA, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b80cd0bc5845..e8f405a01e3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2400,16 +2400,14 @@ static int iwl_setup_mac(struct iwl_priv *priv) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->custom_regulatory = true; - - /* Firmware does not support this */ - hw->wiphy->disable_beacon_hints = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | + WIPHY_FLAG_DISABLE_BEACON_HINTS; /* * For now, disable PS by default because it affects * RX performance significantly. */ - hw->wiphy->ps_default = false; + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; /* we create the 802.11 header and a zero-length SSID element */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 31f3c42b835c..5b7e80e5bab4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3904,10 +3904,8 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->custom_regulatory = true; - - /* Firmware does not support this */ - hw->wiphy->disable_beacon_hints = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY | + WIPHY_FLAG_DISABLE_BEACON_HINTS; hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945; /* we create the 802.11 header and a zero-length SSID element */ diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index fc4ec48eda12..88e41176e7fd 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1146,46 +1146,46 @@ static int __init init_mac80211_hwsim(void) break; case HWSIM_REGTEST_WORLD_ROAM: if (i == 0) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } break; case HWSIM_REGTEST_CUSTOM_WORLD: - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); break; case HWSIM_REGTEST_CUSTOM_WORLD_2: if (i == 0) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } else if (i == 1) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_02); } break; case HWSIM_REGTEST_STRICT_ALL: - hw->wiphy->strict_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; break; case HWSIM_REGTEST_STRICT_FOLLOW: case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: if (i == 0) - hw->wiphy->strict_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; break; case HWSIM_REGTEST_ALL: if (i == 0) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } else if (i == 1) { - hw->wiphy->custom_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_02); } else if (i == 4) - hw->wiphy->strict_regulatory = true; + hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; break; default: break; diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 4d486bf9f725..18012dbfb45d 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -579,7 +579,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) * For now, disable PS by default because it affects * link stability significantly. */ - dev->wiphy->ps_default = false; + dev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; mutex_init(&priv->conf_mutex); mutex_init(&priv->eeprom_mutex); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 21710fc17eaf..eca36abca8f5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1108,27 +1108,45 @@ struct cfg80211_ops { */ /** - * struct wiphy - wireless hardware description - * @idx: the wiphy index assigned to this item - * @class_dev: the class device representing /sys/class/ieee80211/ - * @custom_regulatory: tells us the driver for this device + * enum wiphy_flags - wiphy capability flags + * + * @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device * has its own custom regulatory domain and cannot identify the * ISO / IEC 3166 alpha2 it belongs to. When this is enabled * we will disregard the first regulatory hint (when the * initiator is %REGDOM_SET_BY_CORE). - * @strict_regulatory: tells us the driver for this device will ignore - * regulatory domain settings until it gets its own regulatory domain - * via its regulatory_hint(). After its gets its own regulatory domain - * it will only allow further regulatory domain settings to further - * enhance compliance. For example if channel 13 and 14 are disabled - * by this regulatory domain no user regulatory domain can enable these - * channels at a later time. This can be used for devices which do not - * have calibration information gauranteed for frequencies or settings - * outside of its regulatory domain. - * @disable_beacon_hints: enable this if your driver needs to ensure that - * passive scan flags and beaconing flags may not be lifted by cfg80211 - * due to regulatory beacon hints. For more information on beacon + * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will + * ignore regulatory domain settings until it gets its own regulatory + * domain via its regulatory_hint(). After its gets its own regulatory + * domain it will only allow further regulatory domain settings to + * further enhance compliance. For example if channel 13 and 14 are + * disabled by this regulatory domain no user regulatory domain can + * enable these channels at a later time. This can be used for devices + * which do not have calibration information gauranteed for frequencies + * or settings outside of its regulatory domain. + * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure + * that passive scan flags and beaconing flags may not be lifted by + * cfg80211 due to regulatory beacon hints. For more information on beacon * hints read the documenation for regulatory_hint_found_beacon() + * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this + * wiphy at all + * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled + * by default -- this flag will be set depending on the kernel's default + * on wiphy_new(), but can be changed by the driver if it has a good + * reason to override the default + */ +enum wiphy_flags { + WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), + WIPHY_FLAG_STRICT_REGULATORY = BIT(1), + WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2), + WIPHY_FLAG_NETNS_OK = BIT(3), + WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), +}; + +/** + * struct wiphy - wireless hardware description + * @idx: the wiphy index assigned to this item + * @class_dev: the class device representing /sys/class/ieee80211/ * @reg_notifier: the driver's regulatory notification callback * @regd: the driver's regulatory domain, if one was requested via * the regulatory_hint() API. This can be used by the driver @@ -1143,11 +1161,6 @@ struct cfg80211_ops { * -1 = fragmentation disabled, only odd values >= 256 used * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled * @net: the network namespace this wiphy currently lives in - * @netnsok: if set to false, do not allow changing the netns of this - * wiphy at all - * @ps_default: default for powersave, will be set depending on the - * kernel's default on wiphy_new(), but can be changed by the - * driver if it has a good reason to override the default */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -1158,12 +1171,7 @@ struct wiphy { /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ u16 interface_modes; - bool custom_regulatory; - bool strict_regulatory; - bool disable_beacon_hints; - - bool netnsok; - bool ps_default; + u32 flags; enum cfg80211_signal_type signal_type; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e843a912849c..8084b622e97e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -328,7 +328,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, if (!wiphy) return NULL; - wiphy->netnsok = true; + wiphy->flags |= WIPHY_FLAG_NETNS_OK; wiphy->privid = mac80211_wiphy_privid; /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 614bdcec1c80..90e93a5701aa 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -74,12 +74,6 @@ config CFG80211_REG_DEBUG If unsure, say N. -config CFG80211_DEFAULT_PS_VALUE - int - default 1 if CFG80211_DEFAULT_PS - default 0 - depends on CFG80211 - config CFG80211_DEFAULT_PS bool "enable powersave by default" depends on CFG80211 diff --git a/net/wireless/core.c b/net/wireless/core.c index 02835172b227..e2cc6e7522dd 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -230,7 +230,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev; int err = 0; - if (!rdev->wiphy.netnsok) + if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) return -EOPNOTSUPP; list_for_each_entry(wdev, &rdev->netdev_list, list) { @@ -367,7 +367,9 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) rdev->wiphy.dev.class = &ieee80211_class; rdev->wiphy.dev.platform_data = rdev; - rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE; +#ifdef CONFIG_CFG80211_DEFAULT_PS + rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; +#endif wiphy_net_set(&rdev->wiphy, &init_net); @@ -482,7 +484,7 @@ int wiphy_register(struct wiphy *wiphy) if (IS_ERR(rdev->wiphy.debugfsdir)) rdev->wiphy.debugfsdir = NULL; - if (wiphy->custom_regulatory) { + if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { struct regulatory_request request; request.wiphy_idx = get_wiphy_idx(wiphy); @@ -680,7 +682,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, wdev->wext.default_key = -1; wdev->wext.default_mgmt_key = -1; wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; - wdev->wext.ps = wdev->wiphy->ps_default; + if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT) + wdev->wext.ps = true; + else + wdev->wext.ps = false; wdev->wext.ps_timeout = 100; if (rdev->ops->set_power_mgmt) if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 37264d56bace..6634188f9453 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -561,7 +561,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, CMD(deauth, DEAUTHENTICATE); CMD(disassoc, DISASSOCIATE); CMD(join_ibss, JOIN_IBSS); - if (dev->wiphy.netnsok) { + if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { i++; NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); } diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f256dfffbf46..1f33017737fd 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1008,7 +1008,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && request_wiphy && request_wiphy == wiphy && - request_wiphy->strict_regulatory) { + request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { /* * This gaurantees the driver's requested regulatory domain * will always be used as a base for further regulatory @@ -1051,13 +1051,13 @@ static bool ignore_reg_update(struct wiphy *wiphy, if (!last_request) return true; if (initiator == NL80211_REGDOM_SET_BY_CORE && - wiphy->custom_regulatory) + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) return true; /* * wiphy->regd will be set once the device has its own * desired regulatory domain set */ - if (wiphy->strict_regulatory && !wiphy->regd && + if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && !is_world_regdom(last_request->alpha2)) return true; return false; @@ -1093,7 +1093,7 @@ static void handle_reg_beacon(struct wiphy *wiphy, chan->beacon_found = true; - if (wiphy->disable_beacon_hints) + if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS) return; chan_before.center_freq = chan->center_freq; @@ -1164,7 +1164,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy) return true; if (last_request && last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && - wiphy->custom_regulatory) + wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) return true; return false; } @@ -1591,7 +1591,8 @@ static void reg_process_hint(struct regulatory_request *reg_request) r = __regulatory_hint(wiphy, reg_request); /* This is required so that the orig_* parameters are saved */ - if (r == -EALREADY && wiphy && wiphy->strict_regulatory) + if (r == -EALREADY && wiphy && + wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) wiphy_update_regulatory(wiphy, reg_request->initiator); out: mutex_unlock(®_mutex); -- cgit v1.2.3 From 7351c6bd482712e5e3ec9dffc547de0e0863efb0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Nov 2009 01:08:30 +0100 Subject: mac80211: request TX status where needed Right now all frames mac80211 hands to the driver have the IEEE80211_TX_CTL_REQ_TX_STATUS flag set to request TX status. This isn't really necessary, only the injected frames need TX status (the latter for hostapd) so move setting this flag. The rate control algorithms also need TX status, but they don't require it. Also, rt2x00 uses that bit for its own purposes and seems to require it being set for all frames, but that can be fixed in rt2x00. This doesn't really change anything for any drivers but in the future drivers using hw-rate control may opt to not report TX status for frames that don't have the IEEE80211_TX_CTL_REQ_TX_STATUS flag set. Signed-off-by: Johannes Berg Acked-by: Ivo van Doorn [rt2x00 bits] Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 11 ++++++----- drivers/net/wireless/rt2x00/rt2x00lib.h | 4 +++- drivers/net/wireless/rt2x00/rt2x00mac.c | 5 ++--- drivers/net/wireless/rt2x00/rt2x00queue.c | 6 +++++- drivers/net/wireless/rt2x00/rt2x00queue.h | 5 ++++- include/net/mac80211.h | 2 +- net/mac80211/tx.c | 4 ++-- 7 files changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 6c6d0ac35549..4a4b7e42fe6e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -205,6 +205,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb); u8 rate_idx, rate_flags, retry_rates; + u8 skbdesc_flags = skbdesc->flags; unsigned int i; bool success; @@ -287,12 +288,12 @@ void rt2x00lib_txdone(struct queue_entry *entry, } /* - * Only send the status report to mac80211 when TX status was - * requested by it. If this was a extra frame coming through - * a mac80211 library call (RTS/CTS) then we should not send the - * status report back. + * Only send the status report to mac80211 when it's a frame + * that originated in mac80211. If this was a extra frame coming + * through a mac80211 library call (RTS/CTS) then we should not + * send the status report back. */ - if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) + if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); else dev_kfree_skb_irq(entry->skb); diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index c1f48acaee41..be2e37fb4071 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -162,8 +162,10 @@ void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length); * rt2x00queue_write_tx_frame - Write TX frame to hardware * @queue: Queue over which the frame should be send * @skb: The skb to send + * @local: frame is not from mac80211 */ -int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb); +int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, + bool local); /** * rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index eed093d34532..9c90ceb0ffcc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -66,7 +66,6 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, rts_info = IEEE80211_SKB_CB(skb); rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT; - rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) rts_info->flags |= IEEE80211_TX_CTL_NO_ACK; @@ -91,7 +90,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, frag_skb->data, data_length, tx_info, (struct ieee80211_rts *)(skb->data)); - retval = rt2x00queue_write_tx_frame(queue, skb); + retval = rt2x00queue_write_tx_frame(queue, skb, true); if (retval) { dev_kfree_skb_any(skb); WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); @@ -153,7 +152,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) goto exit_fail; } - if (rt2x00queue_write_tx_frame(queue, skb)) + if (rt2x00queue_write_tx_frame(queue, skb, false)) goto exit_fail; if (rt2x00queue_threshold(queue)) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 02972a036bce..eaedee8c05c8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -454,7 +454,8 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid); } -int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) +int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, + bool local) { struct ieee80211_tx_info *tx_info; struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); @@ -495,6 +496,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) skbdesc->tx_rate_idx = rate_idx; skbdesc->tx_rate_flags = rate_flags; + if (local) + skbdesc->flags |= SKBDESC_NOT_MAC80211; + /* * When hardware encryption is supported, and this frame * is to be encrypted, we should strip the IV/EIV data from diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 97c7895c0ece..70775e5ba1ac 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -94,12 +94,15 @@ enum data_queue_qid { * mac80211 but was stripped for processing by the driver. * @SKBDESC_L2_PADDED: Payload has been padded for 4-byte alignment, * the padded bytes are located between header and payload. + * @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211, + * don't try to pass it back. */ enum skb_frame_desc_flags { SKBDESC_DMA_MAPPED_RX = 1 << 0, SKBDESC_DMA_MAPPED_TX = 1 << 1, SKBDESC_IV_STRIPPED = 1 << 2, - SKBDESC_L2_PADDED = 1 << 3 + SKBDESC_L2_PADDED = 1 << 3, + SKBDESC_NOT_MAC80211 = 1 << 4, }; /** diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f34f4ca7016c..3754ea405c88 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -219,7 +219,7 @@ struct ieee80211_bss_conf { * * These flags are used with the @flags member of &ieee80211_tx_info. * - * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame. + * @IEEE80211_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame. * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence * number to this frame, taking care of not overwriting the fragment * number and increasing the sequence number only when the diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5af2f40ea4db..943def2b07df 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1443,8 +1443,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); } - info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - rcu_read_lock(); if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { @@ -1575,6 +1573,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, memset(info, 0, sizeof(*info)); + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + /* pass the radiotap header up to xmit */ ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb); return NETDEV_TX_OK; -- cgit v1.2.3 From a3caa99e6c68f466c13cfea74097f6fb01b45e25 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 25 Aug 2009 14:12:25 -0400 Subject: libipw: initiate cfg80211 API conversion (v2) Initiate the conversion of libipw to the new cfg80211 configuration API. For now, leave CONFIG_IPW2200_PROMISCUOUS stuff alone. Eventually migrate it to cfg80211 when the add/del/change_virtual_intf methods are implemented. (v2: Fix unconditional wiphy_unregister in libipw which was causing problems for ipw2100, somewhat based on prior attempted fix by Zhu Yi . Previously both original version of this patch and Zhu Yi's fix attempt were reverted due to discovery of regressions. -- JWL) Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 6 +- drivers/net/wireless/ipw2x00/ipw2200.c | 145 +++++++++++++++++++++------ drivers/net/wireless/ipw2x00/libipw.h | 8 +- drivers/net/wireless/ipw2x00/libipw_module.c | 38 ++++++- 4 files changed, 161 insertions(+), 36 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index b7408370cf82..a9bc8a97c4e1 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -6029,7 +6029,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, struct ipw2100_priv *priv; struct net_device *dev; - dev = alloc_ieee80211(sizeof(struct ipw2100_priv)); + dev = alloc_ieee80211(sizeof(struct ipw2100_priv), 0); if (!dev) return NULL; priv = libipw_priv(dev); @@ -6342,7 +6342,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); - free_ieee80211(dev); + free_ieee80211(dev, 0); pci_set_drvdata(pci_dev, NULL); } @@ -6400,7 +6400,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) if (dev->base_addr) iounmap((void __iomem *)dev->base_addr); - free_ieee80211(dev); + free_ieee80211(dev, 0); } pci_release_regions(pci_dev); diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 9b398db2d740..2dfe78acda97 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -108,6 +108,25 @@ static int antenna = CFG_SYS_ANTENNA_BOTH; static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */ #endif +static struct ieee80211_rate ipw2200_rates[] = { + { .bitrate = 10 }, + { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60 }, + { .bitrate = 90 }, + { .bitrate = 120 }, + { .bitrate = 180 }, + { .bitrate = 240 }, + { .bitrate = 360 }, + { .bitrate = 480 }, + { .bitrate = 540 } +}; + +#define ipw2200_a_rates (ipw2200_rates + 4) +#define ipw2200_num_a_rates 8 +#define ipw2200_bg_rates (ipw2200_rates + 0) +#define ipw2200_num_bg_rates 12 #ifdef CONFIG_IPW2200_QOS static int qos_enable = 0; @@ -8659,24 +8678,6 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) * */ -static int ipw_wx_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = libipw_priv(dev); - mutex_lock(&priv->mutex); - if (priv->status & STATUS_RF_KILL_MASK) - strcpy(wrqu->name, "radio off"); - else if (!(priv->status & STATUS_ASSOCIATED)) - strcpy(wrqu->name, "unassociated"); - else - snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", - ipw_modes[priv->assoc_request.ieee_mode]); - IPW_DEBUG_WX("Name: %s\n", wrqu->name); - mutex_unlock(&priv->mutex); - return 0; -} - static int ipw_set_channel(struct ipw_priv *priv, u8 channel) { if (channel == 0) { @@ -9976,7 +9977,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, /* Rebase the WE IOCTLs to zero for the handler array */ #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] static iw_handler ipw_wx_handlers[] = { - IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name, + IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq, IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, @@ -11421,16 +11422,100 @@ static void ipw_bg_down(struct work_struct *work) /* Called by register_netdev() */ static int ipw_net_init(struct net_device *dev) { + int i, rc = 0; struct ipw_priv *priv = libipw_priv(dev); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); + struct wireless_dev *wdev = &priv->ieee->wdev; mutex_lock(&priv->mutex); if (ipw_up(priv)) { - mutex_unlock(&priv->mutex); - return -EIO; + rc = -EIO; + goto out; } + memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN); + + /* fill-out priv->ieee->bg_band */ + if (geo->bg_channels) { + struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band; + + bg_band->band = IEEE80211_BAND_2GHZ; + bg_band->n_channels = geo->bg_channels; + bg_band->channels = + kzalloc(geo->bg_channels * + sizeof(struct ieee80211_channel), GFP_KERNEL); + /* translate geo->bg to bg_band.channels */ + for (i = 0; i < geo->bg_channels; i++) { + bg_band->channels[i].band = IEEE80211_BAND_2GHZ; + bg_band->channels[i].center_freq = geo->bg[i].freq; + bg_band->channels[i].hw_value = geo->bg[i].channel; + bg_band->channels[i].max_power = geo->bg[i].max_power; + if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) + bg_band->channels[i].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS) + bg_band->channels[i].flags |= + IEEE80211_CHAN_NO_IBSS; + if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT) + bg_band->channels[i].flags |= + IEEE80211_CHAN_RADAR; + /* No equivalent for LIBIPW_CH_80211H_RULES, + LIBIPW_CH_UNIFORM_SPREADING, or + LIBIPW_CH_B_ONLY... */ + } + /* point at bitrate info */ + bg_band->bitrates = ipw2200_bg_rates; + bg_band->n_bitrates = ipw2200_num_bg_rates; + + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band; + } + + /* fill-out priv->ieee->a_band */ + if (geo->a_channels) { + struct ieee80211_supported_band *a_band = &priv->ieee->a_band; + + a_band->band = IEEE80211_BAND_5GHZ; + a_band->n_channels = geo->a_channels; + a_band->channels = + kzalloc(geo->a_channels * + sizeof(struct ieee80211_channel), GFP_KERNEL); + /* translate geo->bg to a_band.channels */ + for (i = 0; i < geo->a_channels; i++) { + a_band->channels[i].band = IEEE80211_BAND_2GHZ; + a_band->channels[i].center_freq = geo->a[i].freq; + a_band->channels[i].hw_value = geo->a[i].channel; + a_band->channels[i].max_power = geo->a[i].max_power; + if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) + a_band->channels[i].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + if (geo->a[i].flags & LIBIPW_CH_NO_IBSS) + a_band->channels[i].flags |= + IEEE80211_CHAN_NO_IBSS; + if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT) + a_band->channels[i].flags |= + IEEE80211_CHAN_RADAR; + /* No equivalent for LIBIPW_CH_80211H_RULES, + LIBIPW_CH_UNIFORM_SPREADING, or + LIBIPW_CH_B_ONLY... */ + } + /* point at bitrate info */ + a_band->bitrates = ipw2200_a_rates; + a_band->n_bitrates = ipw2200_num_a_rates; + + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = a_band; + } + + set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); + + /* With that information in place, we can now register the wiphy... */ + if (wiphy_register(wdev->wiphy)) { + rc = -EIO; + goto out; + } + +out: mutex_unlock(&priv->mutex); - return 0; + return rc; } /* PCI driver stuff */ @@ -11561,7 +11646,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv) if (priv->prom_net_dev) return -EPERM; - priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv)); + priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv), 1); if (priv->prom_net_dev == NULL) return -ENOMEM; @@ -11580,7 +11665,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv) rc = register_netdev(priv->prom_net_dev); if (rc) { - free_ieee80211(priv->prom_net_dev); + free_ieee80211(priv->prom_net_dev, 1); priv->prom_net_dev = NULL; return rc; } @@ -11594,7 +11679,7 @@ static void ipw_prom_free(struct ipw_priv *priv) return; unregister_netdev(priv->prom_net_dev); - free_ieee80211(priv->prom_net_dev); + free_ieee80211(priv->prom_net_dev, 1); priv->prom_net_dev = NULL; } @@ -11622,7 +11707,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, struct ipw_priv *priv; int i; - net_dev = alloc_ieee80211(sizeof(struct ipw_priv)); + net_dev = alloc_ieee80211(sizeof(struct ipw_priv), 0); if (net_dev == NULL) { err = -ENOMEM; goto out; @@ -11770,7 +11855,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); out_free_ieee80211: - free_ieee80211(priv->net_dev); + free_ieee80211(priv->net_dev, 0); out: return err; } @@ -11837,7 +11922,11 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - free_ieee80211(priv->net_dev); + /* wiphy_unregister needs to be here, before free_ieee80211 */ + wiphy_unregister(priv->ieee->wdev.wiphy); + kfree(priv->ieee->a_band.channels); + kfree(priv->ieee->bg_band.channels); + free_ieee80211(priv->net_dev, 0); free_firmware(); } diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h index 1e334ff6bd52..bf45391172f3 100644 --- a/drivers/net/wireless/ipw2x00/libipw.h +++ b/drivers/net/wireless/ipw2x00/libipw.h @@ -31,6 +31,7 @@ #include #include +#include #define LIBIPW_VERSION "git-1.1.13" @@ -783,12 +784,15 @@ struct libipw_geo { struct libipw_device { struct net_device *dev; + struct wireless_dev wdev; struct libipw_security sec; /* Bookkeeping structures */ struct libipw_stats ieee_stats; struct libipw_geo geo; + struct ieee80211_supported_band bg_band; + struct ieee80211_supported_band a_band; /* Probe / Beacon management */ struct list_head network_free_list; @@ -1014,8 +1018,8 @@ static inline int libipw_is_cck_rate(u8 rate) } /* ieee80211.c */ -extern void free_ieee80211(struct net_device *dev); -extern struct net_device *alloc_ieee80211(int sizeof_priv); +extern void free_ieee80211(struct net_device *dev, int monitor); +extern struct net_device *alloc_ieee80211(int sizeof_priv, int monitor); extern int libipw_change_mtu(struct net_device *dev, int new_mtu); extern void libipw_networks_age(struct libipw_device *ieee, diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index eb2b60834c17..e8a1ac5f8e11 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -62,6 +62,9 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); +struct cfg80211_ops libipw_config_ops = { }; +void *libipw_wiphy_privid = &libipw_wiphy_privid; + static int libipw_networks_allocate(struct libipw_device *ieee) { if (ieee->networks) @@ -140,7 +143,7 @@ int libipw_change_mtu(struct net_device *dev, int new_mtu) } EXPORT_SYMBOL(libipw_change_mtu); -struct net_device *alloc_ieee80211(int sizeof_priv) +struct net_device *alloc_ieee80211(int sizeof_priv, int monitor) { struct libipw_device *ieee; struct net_device *dev; @@ -157,10 +160,31 @@ struct net_device *alloc_ieee80211(int sizeof_priv) ieee->dev = dev; + if (!monitor) { + ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0); + if (!ieee->wdev.wiphy) { + LIBIPW_ERROR("Unable to allocate wiphy.\n"); + goto failed_free_netdev; + } + + ieee->dev->ieee80211_ptr = &ieee->wdev; + ieee->wdev.iftype = NL80211_IFTYPE_STATION; + + /* Fill-out wiphy structure bits we know... Not enough info + here to call set_wiphy_dev or set MAC address or channel info + -- have to do that in ->ndo_init... */ + ieee->wdev.wiphy->privid = libipw_wiphy_privid; + + ieee->wdev.wiphy->max_scan_ssids = 1; + ieee->wdev.wiphy->max_scan_ie_len = 0; + ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC); + } + err = libipw_networks_allocate(ieee); if (err) { LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err); - goto failed_free_netdev; + goto failed_free_wiphy; } libipw_networks_initialize(ieee); @@ -193,19 +217,27 @@ struct net_device *alloc_ieee80211(int sizeof_priv) return dev; +failed_free_wiphy: + if (!monitor) + wiphy_free(ieee->wdev.wiphy); failed_free_netdev: free_netdev(dev); failed: return NULL; } -void free_ieee80211(struct net_device *dev) +void free_ieee80211(struct net_device *dev, int monitor) { struct libipw_device *ieee = netdev_priv(dev); lib80211_crypt_info_free(&ieee->crypt_info); libipw_networks_free(ieee); + + /* free cfg80211 resources */ + if (!monitor) + wiphy_free(ieee->wdev.wiphy); + free_netdev(dev); } -- cgit v1.2.3 From c26409a919e2a338f0cff6ea0e1a96e658a3bfaa Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 11 Nov 2009 14:36:30 -0500 Subject: ipw2100: Register the wiphy device libipw unconditionally calls wiphy_unregister, but it's up to the driver to register it in the first place. ipw2100 fails to do so. Add the necessary glue code, and also ensure that rfkill statuses get set up appropriately. (Augmented for proper wiphy_unregister placement. -- JWL) Signed-off-by: Matthew Garrett Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 124 +++++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 29 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index a9bc8a97c4e1..6c836c892e43 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -296,6 +296,33 @@ static const char *command_types[] = { }; #endif +#define WEXT_USECHANNELS 1 + +static const long ipw2100_frequencies[] = { + 2412, 2417, 2422, 2427, + 2432, 2437, 2442, 2447, + 2452, 2457, 2462, 2467, + 2472, 2484 +}; + +#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies) + +static const long ipw2100_rates_11b[] = { + 1000000, + 2000000, + 5500000, + 11000000 +}; + +static struct ieee80211_rate ipw2100_bg_rates[] = { + { .bitrate = 10 }, + { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, +}; + +#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b) + /* Pre-decl until we get the code solid and then we can clean it up */ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv); static void ipw2100_tx_send_data(struct ipw2100_priv *priv); @@ -1141,6 +1168,7 @@ static int rf_kill_active(struct ipw2100_priv *priv) int i; if (!(priv->hw_features & HW_FEATURE_RFKILL)) { + wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false); priv->status &= ~STATUS_RF_KILL_HW; return 0; } @@ -1151,10 +1179,13 @@ static int rf_kill_active(struct ipw2100_priv *priv) value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1); } - if (value == 0) + if (value == 0) { + wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true); priv->status |= STATUS_RF_KILL_HW; - else + } else { + wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false); priv->status &= ~STATUS_RF_KILL_HW; + } return (value == 0); } @@ -1814,13 +1845,6 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) return rc; } -/* Called by register_netdev() */ -static int ipw2100_net_init(struct net_device *dev) -{ - struct ipw2100_priv *priv = libipw_priv(dev); - return ipw2100_up(priv, 1); -} - static void ipw2100_down(struct ipw2100_priv *priv) { unsigned long flags; @@ -1875,6 +1899,64 @@ static void ipw2100_down(struct ipw2100_priv *priv) netif_stop_queue(priv->net_dev); } +/* Called by register_netdev() */ +static int ipw2100_net_init(struct net_device *dev) +{ + struct ipw2100_priv *priv = libipw_priv(dev); + const struct libipw_geo *geo = libipw_get_geo(priv->ieee); + struct wireless_dev *wdev = &priv->ieee->wdev; + int ret; + int i; + + ret = ipw2100_up(priv, 1); + if (ret) + return ret; + + memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN); + + /* fill-out priv->ieee->bg_band */ + if (geo->bg_channels) { + struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band; + + bg_band->band = IEEE80211_BAND_2GHZ; + bg_band->n_channels = geo->bg_channels; + bg_band->channels = + kzalloc(geo->bg_channels * + sizeof(struct ieee80211_channel), GFP_KERNEL); + /* translate geo->bg to bg_band.channels */ + for (i = 0; i < geo->bg_channels; i++) { + bg_band->channels[i].band = IEEE80211_BAND_2GHZ; + bg_band->channels[i].center_freq = geo->bg[i].freq; + bg_band->channels[i].hw_value = geo->bg[i].channel; + bg_band->channels[i].max_power = geo->bg[i].max_power; + if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) + bg_band->channels[i].flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS) + bg_band->channels[i].flags |= + IEEE80211_CHAN_NO_IBSS; + if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT) + bg_band->channels[i].flags |= + IEEE80211_CHAN_RADAR; + /* No equivalent for LIBIPW_CH_80211H_RULES, + LIBIPW_CH_UNIFORM_SPREADING, or + LIBIPW_CH_B_ONLY... */ + } + /* point at bitrate info */ + bg_band->bitrates = ipw2100_bg_rates; + bg_band->n_bitrates = RATE_COUNT; + + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = bg_band; + } + + set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); + if (wiphy_register(wdev->wiphy)) { + ipw2100_down(priv); + return -EIO; + } + return 0; +} + static void ipw2100_reset_adapter(struct work_struct *work) { struct ipw2100_priv *priv = @@ -2090,6 +2172,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status) priv->net_dev->name); /* RF_KILL is now enabled (else we wouldn't be here) */ + wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true); priv->status |= STATUS_RF_KILL_HW; /* Make sure the RF Kill check timer is running */ @@ -6400,6 +6483,9 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) if (dev->base_addr) iounmap((void __iomem *)dev->base_addr); + /* wiphy_unregister needs to be here, before free_ieee80211 */ + wiphy_unregister(priv->ieee->wdev.wiphy); + kfree(priv->ieee->bg_band.channels); free_ieee80211(dev, 0); } @@ -6601,26 +6687,6 @@ static void __exit ipw2100_exit(void) module_init(ipw2100_init); module_exit(ipw2100_exit); -#define WEXT_USECHANNELS 1 - -static const long ipw2100_frequencies[] = { - 2412, 2417, 2422, 2427, - 2432, 2437, 2442, 2447, - 2452, 2457, 2462, 2467, - 2472, 2484 -}; - -#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies) - -static const long ipw2100_rates_11b[] = { - 1000000, - 2000000, - 5500000, - 11000000 -}; - -#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b) - static int ipw2100_wx_get_name(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -- cgit v1.2.3 From 25f94aeaa3b20e804efbea0fe74d75bb15ecde4a Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 11 Nov 2009 14:36:31 -0500 Subject: ipw2200: Set core hw rfkill status when hardware changes state ipw2200 is able to detect when it's been hard-killed, but doesn't update the core rfkill state or update userspace. Ensure that the state is updated, allowing the rfkill core to notify userspace. Signed-off-by: Matthew Garrett Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 2dfe78acda97..5b01b5b2e159 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -1757,10 +1757,13 @@ static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO, static int rf_kill_active(struct ipw_priv *priv) { - if (0 == (ipw_read32(priv, 0x30) & 0x10000)) + if (0 == (ipw_read32(priv, 0x30) & 0x10000)) { priv->status |= STATUS_RF_KILL_HW; - else + wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true); + } else { priv->status &= ~STATUS_RF_KILL_HW; + wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false); + } return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0; } @@ -2043,6 +2046,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) if (inta & IPW_INTA_BIT_RF_KILL_DONE) { IPW_DEBUG_RF_KILL("RF_KILL_DONE\n"); priv->status |= STATUS_RF_KILL_HW; + wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true); wake_up_interruptible(&priv->wait_command_queue); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); cancel_delayed_work(&priv->request_scan); -- cgit v1.2.3 From 8c35024aa65c079f800df7778869a8dbda074182 Mon Sep 17 00:00:00 2001 From: Benoit PAPILLAULT Date: Thu, 19 Nov 2009 22:19:26 +0100 Subject: ath9k: This patch fix RX unpadding for any received frame. It has been tested with a 802.11 frame generator and by checking the FCS field of each received frame with the value reported by the Atheros hardware. This patch is useful if you are trying to analyze non standard 802.11 frame going over the air. Signed-off-by: Benoit PAPILLAULT Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 2f1e1612e2ad..4a13632e3e4d 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -231,26 +231,35 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, { struct ath_hw *ah = common->ah; struct ieee80211_hdr *hdr; - int hdrlen, padsize; + int hdrlen, padpos, padsize; u8 keyix; __le16 fc; /* see if any padding is done by the hw and remove it */ hdr = (struct ieee80211_hdr *) skb->data; hdrlen = ieee80211_get_hdrlen_from_skb(skb); + padpos = 24; fc = hdr->frame_control; + if ((fc & cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) == + cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) { + padpos += 6; /* ETH_ALEN */ + } + if ((fc & cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FCTL_FTYPE)) == + cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) { + padpos += 2; + } /* The MAC header is padded to have 32-bit boundary if the * packet payload is non-zero. The general calculation for * padsize would take into account odd header lengths: - * padsize = (4 - hdrlen % 4) % 4; However, since only + * padsize = (4 - padpos % 4) % 4; However, since only * even-length headers are used, padding can only be 0 or 2 * bytes and we can optimize this a bit. In addition, we must * not try to remove padding from short control frames that do * not have payload. */ - padsize = hdrlen & 3; - if (padsize && hdrlen >= 24) { - memmove(skb->data + padsize, skb->data, hdrlen); + padsize = padpos & 3; + if (padsize && skb->len>=padpos+padsize+FCS_LEN) { + memmove(skb->data + padsize, skb->data, padpos); skb_pull(skb, padsize); } -- cgit v1.2.3 From 07681e211d736ba2394ab7f29f77e93adecd22c5 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 19 Nov 2009 22:24:29 +0100 Subject: b43: Rewrite DMA Tx status handling sanity checks This rewrites the error handling policies in the TX status handler. It tries to be error-tolerant as in "try hard to not crash the machine". It won't recover from errors (that are bugs in the firmware or driver), because that's impossible. However, it will return a more or less useful error message and bail out. It also tries hard to use rate-limited messages to not flood the syslog in case of a failure. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 67 ++++++++++++++++++++++++++++++++++-------- drivers/net/wireless/b43/dma.h | 6 +++- 2 files changed, 59 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 18b97c02b8af..027be275e035 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -874,7 +874,7 @@ static void free_all_descbuffers(struct b43_dmaring *ring) for (i = 0; i < ring->nr_slots; i++) { desc = ring->ops->idx2desc(ring, i, &meta); - if (!meta->skb) { + if (!meta->skb || b43_dma_ptr_is_poisoned(meta->skb)) { B43_WARN_ON(!ring->tx); continue; } @@ -926,7 +926,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, enum b43_dmatype type) { struct b43_dmaring *ring; - int err; + int i, err; dma_addr_t dma_test; ring = kzalloc(sizeof(*ring), GFP_KERNEL); @@ -941,6 +941,8 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, GFP_KERNEL); if (!ring->meta) goto err_kfree_ring; + for (i = 0; i < ring->nr_slots; i++) + ring->meta->skb = B43_DMA_PTR_POISON; ring->type = type; ring->dev = dev; @@ -1251,11 +1253,13 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) case 0x5000: ring = dma->tx_ring_mcast; break; - default: - B43_WARN_ON(1); } *slot = (cookie & 0x0FFF); - B43_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots)); + if (unlikely(!ring || *slot < 0 || *slot >= ring->nr_slots)) { + b43dbg(dev->wl, "TX-status contains " + "invalid cookie: 0x%04X\n", cookie); + return NULL; + } return ring; } @@ -1494,19 +1498,40 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, struct b43_dmaring *ring; struct b43_dmadesc_generic *desc; struct b43_dmadesc_meta *meta; - int slot; + int slot, firstused; bool frame_succeed; ring = parse_cookie(dev, status->cookie, &slot); if (unlikely(!ring)) return; - B43_WARN_ON(!ring->tx); + + /* Sanity check: TX packets are processed in-order on one ring. + * Check if the slot deduced from the cookie really is the first + * used slot. */ + firstused = ring->current_slot - ring->used_slots + 1; + if (firstused < 0) + firstused = ring->nr_slots + firstused; + if (unlikely(slot != firstused)) { + /* This possibly is a firmware bug and will result in + * malfunction, memory leaks and/or stall of DMA functionality. */ + b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. " + "Expected %d, but got %d\n", + ring->index, firstused, slot); + return; + } + ops = ring->ops; while (1) { - B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); + B43_WARN_ON(slot < 0 || slot >= ring->nr_slots); desc = ops->idx2desc(ring, slot, &meta); + if (b43_dma_ptr_is_poisoned(meta->skb)) { + b43dbg(dev->wl, "Poisoned TX slot %d (first=%d) " + "on ring %d\n", + slot, firstused, ring->index); + break; + } if (meta->skb) { struct b43_private_tx_info *priv_info = b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb)); @@ -1522,7 +1547,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, if (meta->is_last_fragment) { struct ieee80211_tx_info *info; - BUG_ON(!meta->skb); + if (unlikely(!meta->skb)) { + /* This is a scatter-gather fragment of a frame, so + * the skb pointer must not be NULL. */ + b43dbg(dev->wl, "TX status unexpected NULL skb " + "at slot %d (first=%d) on ring %d\n", + slot, firstused, ring->index); + break; + } info = IEEE80211_SKB_CB(meta->skb); @@ -1540,20 +1572,29 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, #endif /* DEBUG */ ieee80211_tx_status(dev->wl->hw, meta->skb); - /* skb is freed by ieee80211_tx_status() */ - meta->skb = NULL; + /* skb will be freed by ieee80211_tx_status(). + * Poison our pointer. */ + meta->skb = B43_DMA_PTR_POISON; } else { /* No need to call free_descriptor_buffer here, as * this is only the txhdr, which is not allocated. */ - B43_WARN_ON(meta->skb); + if (unlikely(meta->skb)) { + b43dbg(dev->wl, "TX status unexpected non-NULL skb " + "at slot %d (first=%d) on ring %d\n", + slot, firstused, ring->index); + break; + } } /* Everything unmapped and free'd. So it's not used anymore. */ ring->used_slots--; - if (meta->is_last_fragment) + if (meta->is_last_fragment) { + /* This is the last scatter-gather + * fragment of the frame. We are done. */ break; + } slot = next_slot(ring, slot); } if (ring->stopped) { diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index 356a0ff8f044..e607b392314c 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -1,7 +1,7 @@ #ifndef B43_DMA_H_ #define B43_DMA_H_ -#include +#include #include "b43.h" @@ -164,6 +164,10 @@ struct b43_dmadesc_generic { #define B43_RXRING_SLOTS 64 #define B43_DMA0_RX_BUFFERSIZE IEEE80211_MAX_FRAME_LEN +/* Pointer poison */ +#define B43_DMA_PTR_POISON ((void *)ERR_PTR(-ENOMEM)) +#define b43_dma_ptr_is_poisoned(ptr) (unlikely((ptr) == B43_DMA_PTR_POISON)) + struct sk_buff; struct b43_private; -- cgit v1.2.3 From f1cf2dbd0f798b71b1590e7aca6647f2caef1649 Mon Sep 17 00:00:00 2001 From: Lukáš Turek <8an@praha12.net> Date: Thu, 19 Nov 2009 23:02:02 +0100 Subject: ath5k: Fix I/Q calibration The sign of correction coefficients was lost in the calculations, which caused high packetloss in 802.11a mode after the results were applied. Fixed by removing unneccesary and broken AND with a bit mask. Signed-off-by: Lukas Turek <8an@praha12.net> Acked-by: Nick Kossifidis Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 721ec5ee381d..bbfdcd5e7cb1 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1399,7 +1399,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, if (i_coffd == 0 || q_coffd == 0) goto done; - i_coff = ((-iq_corr) / i_coffd) & 0x3f; + i_coff = ((-iq_corr) / i_coffd); /* Boundary check */ if (i_coff > 31) @@ -1407,7 +1407,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, if (i_coff < -32) i_coff = -32; - q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f; + q_coff = (((s32)i_pwr / q_coffd) - 128); /* Boundary check */ if (q_coff > 15) -- cgit v1.2.3 From 4e03185fb8e85d5624d3a68feced70cc9c9e2136 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 20 Nov 2009 12:04:52 -0800 Subject: iwlwifi: Add iwl_write8() To support byte writes to CSR_INT_COALESCING and CSR_INT_PERIODIC registers, add iwl_write8(), including debug/trace support. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-devtrace.c | 1 + drivers/net/wireless/iwlwifi/iwl-devtrace.h | 16 ++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-io.h | 20 ++++++++++++++++++++ 3 files changed, 37 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 4ef5acaa556d..e7d88d1da15d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -5,6 +5,7 @@ #define CREATE_TRACE_POINTS #include "iwl-devtrace.h" +EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx); diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 8c7159208da1..f2d4b01ba466 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -32,6 +32,22 @@ TRACE_EVENT(iwlwifi_dev_ioread32, TP_printk("[%p] read io[%#x] = %#x", __entry->priv, __entry->offs, __entry->val) ); +TRACE_EVENT(iwlwifi_dev_iowrite8, + TP_PROTO(struct iwl_priv *priv, u32 offs, u8 val), + TP_ARGS(priv, offs, val), + TP_STRUCT__entry( + PRIV_ENTRY + __field(u32, offs) + __field(u8, val) + ), + TP_fast_assign( + PRIV_ASSIGN; + __entry->offs = offs; + __entry->val = val; + ), + TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val) +); + TRACE_EVENT(iwlwifi_dev_iowrite32, TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val), TP_ARGS(priv, offs, val), diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index d0a358c9d96b..e552d4c4bdbe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -62,6 +62,26 @@ * */ +static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) +{ + trace_iwlwifi_dev_iowrite8(priv, ofs, val); + iowrite8(val, priv->hw_base + ofs); +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv, + u32 ofs, u8 val) +{ + IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l); + _iwl_write8(priv, ofs, val); +} +#define iwl_write8(priv, ofs, val) \ + __iwl_write8(__FILE__, __LINE__, priv, ofs, val) +#else +#define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val) +#endif + + static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) { trace_iwlwifi_dev_iowrite32(priv, ofs, val); -- cgit v1.2.3 From 74ba67edfcb235c0415a62d37493866c8380dc1d Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Fri, 20 Nov 2009 12:04:53 -0800 Subject: iwlagn: Use iwl_write8() for CSR_INT_COALESCING register CSR_INT_COALESCING previously had only one, but now has two single-byte fields. With only one single-byte field (lowest order byte) it was okay to write via iwl_write32(), but now with two, an iwl_write32() to the lower order field clobbers the other field (odd-address CSR_INT_PERIODIC_REG, offset 0x5), and an iwl_write32() to CSR_INT_PERIODIC_REG could clobber the lowest byte of the next-higher register (CSR_INT, offset 0x8). Fortunately, no bad side effects have been produced by the iwl_write32() usage, due to order of execution (low order byte was always written before higher order byte), and the fact that writing "0" to the low byte of the next higher register has no effect (only action is when writing "1"s). Nonetheless, this cleans up the accesses so no bad side effects might occur in the future, if execution order changes, or more bit fields get added to CSR_INT_COALESCING. Add some comments regarding periodic interrupt usage. Signed-off-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 19 ++++++++++++++----- drivers/net/wireless/iwlwifi/iwl-core.c | 5 ++++- drivers/net/wireless/iwlwifi/iwl-csr.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl-rx.c | 3 ++- 4 files changed, 22 insertions(+), 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e8f405a01e3d..a4e8db35a559 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1266,15 +1266,24 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) * 3- update RX shared data to indicate last write index. * 4- send interrupt. * This could lead to RX race, driver could receive RX interrupt - * but the shared data changes does not reflect this. - * this could lead to RX race, RX periodic will solve this race + * but the shared data changes does not reflect this; + * periodic interrupt will detect any dangling Rx activity. */ - iwl_write32(priv, CSR_INT_PERIODIC_REG, + + /* Disable periodic interrupt; we use it as just a one-shot. */ + iwl_write8(priv, CSR_INT_PERIODIC_REG, CSR_INT_PERIODIC_DIS); iwl_rx_handle(priv); - /* Only set RX periodic if real RX is received. */ + + /* + * Enable periodic interrupt in 8 msec only if we received + * real RX interrupt (instead of just periodic int), to catch + * any dangling Rx interrupt. If it was just the periodic + * interrupt, there was no dangling Rx activity, and no need + * to extend the periodic interrupt; one-shot is enough. + */ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) - iwl_write32(priv, CSR_INT_PERIODIC_REG, + iwl_write8(priv, CSR_INT_PERIODIC_REG, CSR_INT_PERIODIC_ENA); priv->isr_stats.rx++; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a2636f4b068f..c25cab5d0451 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -255,7 +255,10 @@ int iwl_hw_nic_init(struct iwl_priv *priv) /* nic_init */ spin_lock_irqsave(&priv->lock, flags); priv->cfg->ops->lib->apm_ops.init(priv); - iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); + + /* Set interrupt coalescing timer to 512 usecs */ + iwl_write8(priv, CSR_INT_COALESCING, 512 / 32); + spin_unlock_irqrestore(&priv->lock, flags); ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 68ed82206723..a7bfae01f19b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -173,8 +173,8 @@ #define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ -#define CSR_INT_PERIODIC_DIS (0x00) -#define CSR_INT_PERIODIC_ENA (0xFF) +#define CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ +#define CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), * acknowledged (reset) by host writing "1" to flagged bits. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index cc980d5d57c2..6090bc15a6d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -477,7 +477,8 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); - iwl_write32(priv, CSR_INT_COALESCING, 0x40); + /* Set interrupt coalescing timer to 64 x 32 = 2048 usecs */ + iwl_write8(priv, CSR_INT_COALESCING, 0x40); return 0; } -- cgit v1.2.3 From d5f4cf71f7b70e13f96cc8aac65b390707d5d80b Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:04:54 -0800 Subject: iwlwifi: control led while update tx/rx bytes counts LED blinking rate is based on tx/rx traffic, the most reasonable place to do it is after update the traffic byte counts This fixes the recent LED blinking breakage on 3945 introduced by "iwlwifi: separate led function from statistic notification" Signed-off-by: Wey-Yi Guy Tested-by: Maxim Levitsky Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 -- drivers/net/wireless/iwlwifi/iwl-core.c | 1 + drivers/net/wireless/iwlwifi/iwl-core.h | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a4e8db35a559..c41ec5e258b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1078,7 +1078,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { iwl_rx_handle(priv); priv->isr_stats.rx++; - iwl_leds_background(priv); handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } @@ -1287,7 +1286,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) CSR_INT_PERIODIC_ENA); priv->isr_stats.rx++; - iwl_leds_background(priv); } /* This "Tx" DMA channel is used only for loading uCode */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c25cab5d0451..7ac6b369890a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -3187,6 +3187,7 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) stats->data_cnt++; stats->data_bytes += len; } + iwl_leds_background(priv); } EXPORT_SYMBOL(iwl_update_stats); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 584a376b96c5..f271663c1d2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -390,6 +390,7 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx, /* data */ stats->data_bytes += len; } + iwl_leds_background(priv); } #endif /***************************************************** -- cgit v1.2.3 From c15d20c1d19616f73b6fee4befd254d0c37b4d87 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:04:55 -0800 Subject: iwlwifi: set sm_ps_mode as part of cfg parameters Setting "Spatial multiplexing Power Save" as part of per device configuration parameter. Report to uCode based on priv->conf setting, so driver can have more control of how different devices should operate in power save mode. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 4 +++ drivers/net/wireless/iwlwifi/iwl-6000.c | 4 ++- drivers/net/wireless/iwlwifi/iwl-agn.c | 4 --- drivers/net/wireless/iwlwifi/iwl-core.c | 45 ++++++++++++++------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 4 +-- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 - 8 files changed, 30 insertions(+), 34 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 8f82537045bf..8414178bcff4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -173,6 +173,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .use_rts_for_ht = true, /* use rts/cts protection */ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl1000_bg_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1e58c49dd768..d1fab4e19204 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2238,6 +2238,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .broken_powersave = true, .led_compensation = 61, .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; /* Module firmware */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 570eaa08531f..90c7b897736d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1597,6 +1597,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5100_bg_cfg = { @@ -1666,6 +1667,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5350_agn_cfg = { @@ -1689,6 +1691,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl5150_agn_cfg = { @@ -1712,6 +1715,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 4ab9897f4fe1..74e571049273 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -306,6 +306,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; struct iwl_cfg iwl6000i_2abg_cfg = { @@ -394,7 +395,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, - .support_sm_ps = true, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DYNAMIC, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -454,6 +455,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .supports_idle = true, .adv_thermal_throttle = true, .support_ct_kill_exit = true, + .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c41ec5e258b1..7301aa73ab7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3135,10 +3135,6 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->band = IEEE80211_BAND_2GHZ; priv->iw_mode = NL80211_IFTYPE_STATION; - if (priv->cfg->support_sm_ps) - priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DYNAMIC; - else - priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ if (priv->cfg->ops->hcmd->set_rxon_chain) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 7ac6b369890a..dbe41cf8943c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -449,13 +449,8 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, if (priv->cfg->ht_greenfield_support) ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - if (priv->cfg->support_sm_ps) - ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & - (WLAN_HT_CAP_SM_PS_DYNAMIC << 2)); - else - ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & - (WLAN_HT_CAP_SM_PS_DISABLED << 2)); - + ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & + (priv->cfg->sm_ps_mode << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; if (priv->hw_params.ht40_channel & BIT(band)) { ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; @@ -1010,25 +1005,23 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) int idle_cnt = active_cnt; bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); - if (priv->cfg->support_sm_ps) { - /* # Rx chains when idling and maybe trying to save power */ - switch (priv->current_ht_config.sm_ps) { - case WLAN_HT_CAP_SM_PS_STATIC: - case WLAN_HT_CAP_SM_PS_DYNAMIC: - idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : - IWL_NUM_IDLE_CHAINS_SINGLE; - break; - case WLAN_HT_CAP_SM_PS_DISABLED: - idle_cnt = (is_cam) ? active_cnt : - IWL_NUM_IDLE_CHAINS_SINGLE; - break; - case WLAN_HT_CAP_SM_PS_INVALID: - default: - IWL_ERR(priv, "invalid sm_ps mode %d\n", - priv->current_ht_config.sm_ps); - WARN_ON(1); - break; - } + /* # Rx chains when idling and maybe trying to save power */ + switch (priv->cfg->sm_ps_mode) { + case WLAN_HT_CAP_SM_PS_STATIC: + idle_cnt = (is_cam) ? active_cnt : IWL_NUM_IDLE_CHAINS_SINGLE; + break; + case WLAN_HT_CAP_SM_PS_DYNAMIC: + idle_cnt = (is_cam) ? IWL_NUM_IDLE_CHAINS_DUAL : + IWL_NUM_IDLE_CHAINS_SINGLE; + break; + case WLAN_HT_CAP_SM_PS_DISABLED: + break; + case WLAN_HT_CAP_SM_PS_INVALID: + default: + IWL_ERR(priv, "invalid sm_ps mode %u\n", + priv->cfg->sm_ps_mode); + WARN_ON(1); + break; } return idle_cnt; } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f271663c1d2f..334da64d968d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -228,7 +228,7 @@ struct iwl_mod_params { * @chain_noise_num_beacons: number of beacons used to compute chain noise * @adv_thermal_throttle: support advance thermal throttle * @support_ct_kill_exit: support ct kill exit condition - * @support_sm_ps: support spatial multiplexing power save + * @sm_ps_mode: spatial multiplexing power save mode * @support_wimax_coexist: support wimax/wifi co-exist * * We enable the driver to be backward compatible wrt API version. The @@ -285,7 +285,7 @@ struct iwl_cfg { const bool supports_idle; bool adv_thermal_throttle; bool support_ct_kill_exit; - bool support_sm_ps; + u8 sm_ps_mode; const bool support_wimax_coexist; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f1601cfebc29..1c1ed4bfcb08 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -511,7 +511,6 @@ struct iwl_ht_config { bool is_ht; bool is_40mhz; bool single_chain_sufficient; - u8 sm_ps; /* BSS related data */ u8 extension_chan_offset; u8 ht_protection; -- cgit v1.2.3 From 7163b8a4ec995dabda3e92c6fed7b8600060618c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:04:56 -0800 Subject: iwlwifi: reset led_tpt when clear tx/rx traffic byte counts LED blink rate is based on the traffic load, when tx/rx traffic counts got reset, we also need to reset the led_tpt to prevent incorrect blink rate being calculated. Merge both clear_tx_statistics() and clear_rx_statistics() into single clear_traffic_statistics() function, when reset the traffic byte counts, both tx and rx need to be reset at the same time, to make sure calculated the correct led blink rate. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 8 ++---- drivers/net/wireless/iwlwifi/iwl-core.h | 3 +-- drivers/net/wireless/iwlwifi/iwl-debug.h | 3 ++- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 42 +++++++++--------------------- 4 files changed, 18 insertions(+), 38 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index dbe41cf8943c..c2263180614e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -3079,15 +3079,11 @@ const char *get_ctrl_string(int cmd) } } -void iwl_clear_tx_stats(struct iwl_priv *priv) +void iwl_clear_traffic_stats(struct iwl_priv *priv) { memset(&priv->tx_stats, 0, sizeof(struct traffic_stats)); - -} - -void iwl_clear_rx_stats(struct iwl_priv *priv) -{ memset(&priv->rx_stats, 0, sizeof(struct traffic_stats)); + priv->led_tpt = 0; } /* diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 334da64d968d..0779158fed2f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -353,8 +353,7 @@ void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, u16 length, struct ieee80211_hdr *header); const char *get_mgmt_string(int cmd); const char *get_ctrl_string(int cmd); -void iwl_clear_tx_stats(struct iwl_priv *priv); -void iwl_clear_rx_stats(struct iwl_priv *priv); +void iwl_clear_traffic_stats(struct iwl_priv *priv); void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len); #else diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 25a0e73314f7..d61293ab67c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -107,7 +107,8 @@ struct iwl_debugfs { struct dentry *file_chain_noise; struct dentry *file_tx_power; struct dentry *file_power_save_status; - struct dentry *file_clear_statistics; + struct dentry *file_clear_ucode_statistics; + struct dentry *file_clear_traffic_statistics; } dbgfs_debug_files; u32 sram_offset; u32 sram_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 9a5ca25d72c3..b8f9edc3d998 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -160,7 +160,7 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, return ret; } -static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file, +static ssize_t iwl_dbgfs_clear_traffic_statistics_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -175,8 +175,7 @@ static ssize_t iwl_dbgfs_tx_statistics_write(struct file *file, return -EFAULT; if (sscanf(buf, "%x", &clear_flag) != 1) return -EFAULT; - if (clear_flag == 1) - iwl_clear_tx_stats(priv); + iwl_clear_traffic_stats(priv); return count; } @@ -221,26 +220,6 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, return ret; } -static ssize_t iwl_dbgfs_rx_statistics_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - u32 clear_flag; - char buf[8]; - int buf_size; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%x", &clear_flag) != 1) - return -EFAULT; - if (clear_flag == 1) - iwl_clear_rx_stats(priv); - return count; -} - #define BYTE1_MASK 0x000000ff; #define BYTE2_MASK 0x0000ffff; #define BYTE3_MASK 0x00ffffff; @@ -1823,7 +1802,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_clear_statistics_write(struct file *file, +static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -1847,8 +1826,8 @@ static ssize_t iwl_dbgfs_clear_statistics_write(struct file *file, return count; } -DEBUGFS_READ_WRITE_FILE_OPS(rx_statistics); -DEBUGFS_READ_WRITE_FILE_OPS(tx_statistics); +DEBUGFS_READ_FILE_OPS(rx_statistics); +DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); DEBUGFS_READ_FILE_OPS(rx_queue); DEBUGFS_READ_FILE_OPS(tx_queue); @@ -1859,7 +1838,8 @@ DEBUGFS_READ_FILE_OPS(sensitivity); DEBUGFS_READ_FILE_OPS(chain_noise); DEBUGFS_READ_FILE_OPS(tx_power); DEBUGFS_READ_FILE_OPS(power_save_status); -DEBUGFS_WRITE_FILE_OPS(clear_statistics); +DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics); +DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); /* * Create the debugfs files and directories @@ -1908,7 +1888,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(tx_queue, debug); DEBUGFS_ADD_FILE(tx_power, debug); DEBUGFS_ADD_FILE(power_save_status, debug); - DEBUGFS_ADD_FILE(clear_statistics, debug); + DEBUGFS_ADD_FILE(clear_ucode_statistics, debug); + DEBUGFS_ADD_FILE(clear_traffic_statistics, debug); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_ADD_FILE(ucode_rx_stats, debug); DEBUGFS_ADD_FILE(ucode_tx_stats, debug); @@ -1962,7 +1943,10 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_queue); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_tx_power); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_power_save_status); - DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_clear_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_clear_ucode_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. + file_clear_traffic_statistics); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. file_ucode_rx_stats); -- cgit v1.2.3 From bc6c94f609d2f63347d4a05f28993792ae38caad Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Fri, 20 Nov 2009 12:04:57 -0800 Subject: iwl3945: removed unused struct and definitions Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 9 --------- drivers/net/wireless/iwlwifi/iwl-dev.h | 8 -------- 2 files changed, 17 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 2b0d65c5780a..a41f0e098cf6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -221,19 +221,10 @@ struct iwl3945_ibss_seq { * for use by iwl-*.c * *****************************************************************************/ -extern int iwl3945_power_init_handle(struct iwl_priv *priv); -extern int iwl3945_eeprom_init(struct iwl_priv *priv); extern int iwl3945_calc_db_from_ratio(int sig_ratio); extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm); -extern int iwl3945_tx_queue_init(struct iwl_priv *priv, - struct iwl_tx_queue *txq, int count, u32 id); extern void iwl3945_rx_replenish(void *data); extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); -extern void iwl3945_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq); -extern int iwl3945_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, - const void *data); -extern int __must_check iwl3945_send_cmd(struct iwl_priv *priv, - struct iwl_host_cmd *cmd); extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr,int left); extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1c1ed4bfcb08..4ded1900540d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -544,14 +544,6 @@ struct iwl_qos_info { struct iwl_qosparam_cmd def_qos_parm; }; - -struct iwl3945_station_entry { - struct iwl3945_addsta_cmd sta; - struct iwl_tid_data tid[MAX_TID_COUNT]; - u8 used; - struct iwl_hw_key keyinfo; -}; - struct iwl_station_entry { struct iwl_addsta_cmd sta; struct iwl_tid_data tid[MAX_TID_COUNT]; -- cgit v1.2.3 From 43e851157adb966dd633e983b24040f72877737e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:04:58 -0800 Subject: iwlwifi: set read/write permission for debugfs files Set the correct Read/Write file permission for iwlwifi debugfs files based on the functionality of the files Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 8 ++--- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 58 +++++++++++++++--------------- 2 files changed, 33 insertions(+), 33 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 2f09e3b7f0eb..fe511cbf012e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -2964,16 +2964,16 @@ static void rs_add_debugfs(void *priv, void *priv_sta, { struct iwl_lq_sta *lq_sta = priv_sta; lq_sta->rs_sta_dbgfs_scale_table_file = - debugfs_create_file("rate_scale_table", 0600, dir, + debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, lq_sta, &rs_sta_dbgfs_scale_table_ops); lq_sta->rs_sta_dbgfs_stats_table_file = - debugfs_create_file("rate_stats_table", 0600, dir, + debugfs_create_file("rate_stats_table", S_IRUSR, dir, lq_sta, &rs_sta_dbgfs_stats_table_ops); lq_sta->rs_sta_dbgfs_rate_scale_data_file = - debugfs_create_file("rate_scale_data", 0600, dir, + debugfs_create_file("rate_scale_data", S_IRUSR, dir, lq_sta, &rs_sta_dbgfs_rate_scale_data_ops); lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = - debugfs_create_u8("tx_agg_tid_enable", 0600, dir, + debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, &lq_sta->tx_agg_tid_en); } diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index b8f9edc3d998..e6194c8e7f72 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -47,9 +47,9 @@ goto err; \ } while (0) -#define DEBUGFS_ADD_FILE(name, parent) do { \ +#define DEBUGFS_ADD_FILE(name, parent, mode) do { \ dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_file(#name, S_IWUSR | S_IRUSR, \ + debugfs_create_file(#name, mode, \ dbgfs->dir_##parent, priv, \ &iwl_dbgfs_##name##_ops); \ if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \ @@ -1868,34 +1868,34 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); DEBUGFS_ADD_DIR(debug, dbgfs->dir_drv); - DEBUGFS_ADD_FILE(nvm, data); - DEBUGFS_ADD_FILE(sram, data); - DEBUGFS_ADD_FILE(log_event, data); - DEBUGFS_ADD_FILE(stations, data); - DEBUGFS_ADD_FILE(channels, data); - DEBUGFS_ADD_FILE(status, data); - DEBUGFS_ADD_FILE(interrupt, data); - DEBUGFS_ADD_FILE(qos, data); - DEBUGFS_ADD_FILE(led, data); - DEBUGFS_ADD_FILE(sleep_level_override, data); - DEBUGFS_ADD_FILE(current_sleep_command, data); - DEBUGFS_ADD_FILE(thermal_throttling, data); - DEBUGFS_ADD_FILE(disable_ht40, data); - DEBUGFS_ADD_FILE(rx_statistics, debug); - DEBUGFS_ADD_FILE(tx_statistics, debug); - DEBUGFS_ADD_FILE(traffic_log, debug); - DEBUGFS_ADD_FILE(rx_queue, debug); - DEBUGFS_ADD_FILE(tx_queue, debug); - DEBUGFS_ADD_FILE(tx_power, debug); - DEBUGFS_ADD_FILE(power_save_status, debug); - DEBUGFS_ADD_FILE(clear_ucode_statistics, debug); - DEBUGFS_ADD_FILE(clear_traffic_statistics, debug); + DEBUGFS_ADD_FILE(nvm, data, S_IRUSR); + DEBUGFS_ADD_FILE(sram, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(log_event, data, S_IWUSR); + DEBUGFS_ADD_FILE(stations, data, S_IRUSR); + DEBUGFS_ADD_FILE(channels, data, S_IRUSR); + DEBUGFS_ADD_FILE(status, data, S_IRUSR); + DEBUGFS_ADD_FILE(interrupt, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(qos, data, S_IRUSR); + DEBUGFS_ADD_FILE(led, data, S_IRUSR); + DEBUGFS_ADD_FILE(sleep_level_override, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(current_sleep_command, data, S_IRUSR); + DEBUGFS_ADD_FILE(thermal_throttling, data, S_IRUSR); + DEBUGFS_ADD_FILE(disable_ht40, data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rx_statistics, debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_statistics, debug, S_IRUSR); + DEBUGFS_ADD_FILE(traffic_log, debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rx_queue, debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_queue, debug, S_IRUSR); + DEBUGFS_ADD_FILE(tx_power, debug, S_IRUSR); + DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR); + DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR); + DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR); if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { - DEBUGFS_ADD_FILE(ucode_rx_stats, debug); - DEBUGFS_ADD_FILE(ucode_tx_stats, debug); - DEBUGFS_ADD_FILE(ucode_general_stats, debug); - DEBUGFS_ADD_FILE(sensitivity, debug); - DEBUGFS_ADD_FILE(chain_noise, debug); + DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); + DEBUGFS_ADD_FILE(ucode_general_stats, debug, S_IRUSR); + DEBUGFS_ADD_FILE(sensitivity, debug, S_IRUSR); + DEBUGFS_ADD_FILE(chain_noise, debug, S_IRUSR); } DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, -- cgit v1.2.3 From d23db556819c00d297c0f447bdd75b282d563122 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:04:59 -0800 Subject: iwlwifi: increase tx_queue debugfs buffer size For tx_queue, need to increase the buffer size allocated for it, so all the queues information can be displayed Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index e6194c8e7f72..4630094b4ca1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -964,7 +964,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, int pos = 0; int cnt; int ret; - const size_t bufsz = sizeof(char) * 60 * priv->cfg->num_of_queues; + const size_t bufsz = sizeof(char) * 64 * priv->cfg->num_of_queues; if (!priv->txq) { IWL_ERR(priv, "txq not ready\n"); -- cgit v1.2.3 From 2943f136ffe29adb08162197b129bf8106e8191c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:00 -0800 Subject: iwlwifi: dynamically allocate buffer for sram debugfs file Dynamically allocate memory for dumping SRAM based on the length of memory to be displayed. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 4630094b4ca1..016ff4014a7b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -228,13 +228,21 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, size_t count, loff_t *ppos) { u32 val; - char buf[1024]; + char *buf; ssize_t ret; int i; int pos = 0; struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - const size_t bufsz = sizeof(buf); + size_t bufsz; + bufsz = 30 + priv->dbgfs->sram_len * sizeof(char) * 12; + buf = kmalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + pos += scnprintf(buf + pos, bufsz - pos, "sram_len: %d\n", + priv->dbgfs->sram_len); + pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: %d\n", + priv->dbgfs->sram_offset); for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ priv->dbgfs->sram_len - i); @@ -251,11 +259,14 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, break; } } + if (!(i % 16)) + pos += scnprintf(buf + pos, bufsz - pos, "\n"); pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val); } pos += scnprintf(buf + pos, bufsz - pos, "\n"); ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); return ret; } -- cgit v1.2.3 From 6262408392aa66083c9d5db101755fe753c97d4e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:01 -0800 Subject: iwlwifi: fix reserved2 field in iwl4965_addsta reserved2 field in "struct iwl4965_addsta_cmd" is __le16. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d1fab4e19204..a8914898133e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1819,7 +1819,7 @@ static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn; addsta->sleep_tx_count = cmd->sleep_tx_count; addsta->reserved1 = cpu_to_le16(0); - addsta->reserved2 = cpu_to_le32(0); + addsta->reserved2 = cpu_to_le16(0); return (u16)sizeof(struct iwl4965_addsta_cmd); } -- cgit v1.2.3 From 0fd95afc7b8ae19045dc03ffeafb3afda78cb681 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Nov 2009 12:05:02 -0800 Subject: iwlwifi: separate IO tracing Since IO tracing is usually not needed and generates a lot of data, separate it into its own trace system so that we can always enable iwlwifi:* and not have to worry about getting too much data. If IO tracing is then really needed we can enable iwlwifi_io:* in addition and get that data. Signed-off-by: Johannes Berg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-devtrace.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index f2d4b01ba466..21361968ab7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -14,7 +14,7 @@ static inline void trace_ ## name(proto) {} #define PRIV_ASSIGN __entry->priv = priv #undef TRACE_SYSTEM -#define TRACE_SYSTEM iwlwifi +#define TRACE_SYSTEM iwlwifi_io TRACE_EVENT(iwlwifi_dev_ioread32, TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val), @@ -64,6 +64,9 @@ TRACE_EVENT(iwlwifi_dev_iowrite32, TP_printk("[%p] write io[%#x] = %#x)", __entry->priv, __entry->offs, __entry->val) ); +#undef TRACE_SYSTEM +#define TRACE_SYSTEM iwlwifi + TRACE_EVENT(iwlwifi_dev_hcmd, TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags), TP_ARGS(priv, hcmd, len, flags), -- cgit v1.2.3 From ac592574a577162183b5c1dd040a188caa068a29 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:03 -0800 Subject: iwlwifi: update supported PCI_ID list for 5xx0 series Update the PCI_ID list for 5xx0 series. Remove all the PCI_IDs which never made into production or not longer in production. Also make sure the supported bands(a/b/g/n) match specified PCI_IDs Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 29 +++++++++++-- drivers/net/wireless/iwlwifi/iwl-agn.c | 74 +++++++++++++++++++++++++-------- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 +- 3 files changed, 84 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 90c7b897736d..9175158f3580 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1600,12 +1600,12 @@ struct iwl_cfg iwl5300_agn_cfg = { .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; -struct iwl_cfg iwl5100_bg_cfg = { - .name = "5100BG", +struct iwl_cfg iwl5100_bgn_cfg = { + .name = "5100BGN", .fw_name_pre = IWL5000_FW_PRE, .ucode_api_max = IWL5000_UCODE_API_MAX, .ucode_api_min = IWL5000_UCODE_API_MIN, - .sku = IWL_SKU_G, + .sku = IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, .eeprom_ver = EEPROM_5000_EEPROM_VERSION, @@ -1641,7 +1641,6 @@ struct iwl_cfg iwl5100_abg_cfg = { .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .set_l0s = true, .use_bsm = false, - .ht_greenfield_support = true, .led_compensation = 51, .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, }; @@ -1718,6 +1717,28 @@ struct iwl_cfg iwl5150_agn_cfg = { .sm_ps_mode = WLAN_HT_CAP_SM_PS_DISABLED, }; +struct iwl_cfg iwl5150_abg_cfg = { + .name = "5150ABG", + .fw_name_pre = IWL5150_FW_PRE, + .ucode_api_max = IWL5150_UCODE_API_MAX, + .ucode_api_min = IWL5150_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G, + .ops = &iwl5150_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, + .num_of_queues = IWL50_NUM_QUEUES, + .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, + .mod_params = &iwl50_mod_params, + .valid_tx_ant = ANT_A, + .valid_rx_ant = ANT_AB, + .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, + .set_l0s = true, + .use_bsm = false, + .led_compensation = 51, + .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, +}; + MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 7301aa73ab7e..92f9df6a04a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3541,23 +3541,63 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)}, #endif /* CONFIG_IWL4965 */ #ifdef CONFIG_IWL5000 - {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, - {IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)}, - {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)}, - {IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)}, - {IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)}, -/* 5350 WiFi/WiMax */ - {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, - {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, - {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, -/* 5150 Wifi/WiMax */ - {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)}, - {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, +/* 5100 Series WiFi */ + {IWL_PCI_DEVICE(0x4232, 0x1201, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1301, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1204, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1304, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bgn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bgn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1221, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1321, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1224, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1324, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1225, iwl5100_bgn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1325, iwl5100_bgn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1226, iwl5100_abg_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1211, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1311, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1214, iwl5100_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1314, iwl5100_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1215, iwl5100_bgn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1315, iwl5100_bgn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4237, 0x1316, iwl5100_abg_cfg)}, /* Half Mini Card */ + +/* 5300 Series WiFi */ + {IWL_PCI_DEVICE(0x4235, 0x1021, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1121, iwl5300_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1024, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1124, iwl5300_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1001, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1101, iwl5300_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1004, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4235, 0x1104, iwl5300_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4236, 0x1011, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4236, 0x1111, iwl5300_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x4236, 0x1014, iwl5300_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x4236, 0x1114, iwl5300_agn_cfg)}, /* Half Mini Card */ + +/* 5350 Series WiFi/WiMax */ + {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, /* Mini Card */ + +/* 5150 Series Wifi/WiMax */ + {IWL_PCI_DEVICE(0x423C, 0x1201, iwl5150_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1301, iwl5150_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1206, iwl5150_abg_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */ + + {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x423D, 0x1216, iwl5150_abg_cfg)}, /* Mini Card */ + {IWL_PCI_DEVICE(0x423D, 0x1316, iwl5150_abg_cfg)}, /* Half Mini Card */ /* 6x00 Series */ {IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 4ded1900540d..2673e9a4db92 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -52,9 +52,10 @@ extern struct iwl_cfg iwl4965_agn_cfg; extern struct iwl_cfg iwl5300_agn_cfg; extern struct iwl_cfg iwl5100_agn_cfg; extern struct iwl_cfg iwl5350_agn_cfg; -extern struct iwl_cfg iwl5100_bg_cfg; +extern struct iwl_cfg iwl5100_bgn_cfg; extern struct iwl_cfg iwl5100_abg_cfg; extern struct iwl_cfg iwl5150_agn_cfg; +extern struct iwl_cfg iwl5150_abg_cfg; extern struct iwl_cfg iwl6000i_2agn_cfg; extern struct iwl_cfg iwl6000i_2abg_cfg; extern struct iwl_cfg iwl6000i_2bg_cfg; -- cgit v1.2.3 From 5ade1e4dd1df436c3a441d17321c24aac8497306 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:04 -0800 Subject: iwlwifi: by default, dump entire sram data portion For "sram" debugfs file, if user did not specify the offset and length, dump the entire data portion of sram by default. Data portion is 0x800000 - 0x80ffff, but the actual data size is known to the driver from the ucode file. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 016ff4014a7b..5adf0b606202 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -235,13 +235,21 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, struct iwl_priv *priv = (struct iwl_priv *)file->private_data; size_t bufsz; - bufsz = 30 + priv->dbgfs->sram_len * sizeof(char) * 12; + /* default is to dump the entire data segment */ + if (!priv->dbgfs->sram_offset && !priv->dbgfs->sram_len) { + priv->dbgfs->sram_offset = 0x800000; + if (priv->ucode_type == UCODE_INIT) + priv->dbgfs->sram_len = priv->ucode_init_data.len; + else + priv->dbgfs->sram_len = priv->ucode_data.len; + } + bufsz = 30 + priv->dbgfs->sram_len * sizeof(char) * 10; buf = kmalloc(bufsz, GFP_KERNEL); if (!buf) return -ENOMEM; - pos += scnprintf(buf + pos, bufsz - pos, "sram_len: %d\n", + pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", priv->dbgfs->sram_len); - pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: %d\n", + pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", priv->dbgfs->sram_offset); for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ -- cgit v1.2.3 From 3a3ff72c18085563ce64f7456ae3afff3a83397e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:05 -0800 Subject: iwlwifi: dump error log when uCode error occurred uCode error log contain information as to what the error was and where it occurred necessary to debug any uCode issues. Always log the information without special debug flag, this can help to capture the important information when error happened. Signed-off-by: Wey-Yi Guy Acked-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 3 ++- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.h | 6 +----- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 92f9df6a04a6..927131192572 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1604,7 +1604,6 @@ static int iwl_read_ucode(struct iwl_priv *priv) return ret; } -#ifdef CONFIG_IWLWIFI_DEBUG static const char *desc_lookup_text[] = { "OK", "FAIL", @@ -1697,6 +1696,8 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) } +#ifdef CONFIG_IWLWIFI_DEBUG + #define EVENT_START_OFFSET (4 * sizeof(u32)) /** diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c2263180614e..05a0c413cdf9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1361,9 +1361,9 @@ void iwl_irq_handle_error(struct iwl_priv *priv) /* Cancel currently queued command. */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + priv->cfg->ops->lib->dump_nic_error_log(priv); #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) { - priv->cfg->ops->lib->dump_nic_error_log(priv); priv->cfg->ops->lib->dump_nic_event_log(priv); iwl_print_rx_config_cmd(priv); } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 0779158fed2f..ecba0f46bac5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -578,19 +578,15 @@ int iwl_pci_resume(struct pci_dev *pdev); /***************************************************** * Error Handling Debugging ******************************************************/ +void iwl_dump_nic_error_log(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUG void iwl_dump_nic_event_log(struct iwl_priv *priv); -void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_print_rx_config_cmd(struct iwl_priv *priv); #else static inline void iwl_dump_nic_event_log(struct iwl_priv *priv) { } -static inline void iwl_dump_nic_error_log(struct iwl_priv *priv) -{ -} - static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv) { } -- cgit v1.2.3 From 644c77f0cfa333e58fd4a09450434e89a52d8931 Mon Sep 17 00:00:00 2001 From: Jay Sternberg Date: Fri, 20 Nov 2009 12:05:06 -0800 Subject: iwlwifi: Tell the ucode immediately when association state changes When we get a state change of associated or not, we need to tell the ucode via the RX_ON command using the filter flags. This will prevent the ucode from sending any packets when not associated, specifically not sending NULL QOS packets after a deauthentication which causes the AP to repeatedly send deauth's in some situations. Signed-off-by: Jay Sternberg Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 05a0c413cdf9..2e0fb2804ad0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2478,6 +2478,16 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, } else { priv->assoc_id = 0; iwl_led_disassociate(priv); + + /* + * inform the ucode that there is no longer an + * association and that no more packets should be + * send + */ + priv->staging_rxon.filter_flags &= + ~RXON_FILTER_ASSOC_MSK; + priv->staging_rxon.assoc_id = 0; + iwlcore_commit_rxon(priv); } } -- cgit v1.2.3 From c341ddb283b9e1a6d217e73fa36738629ca8f4fb Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:07 -0800 Subject: iwlwifi: print limited number of event log when uCode error To help iwlagn uCode debugging, event log will dump to syslog when driver detect uCode error occurred, but this only happen when compile with CONFIG_IWLWIFI_DEBUG and debug flag is enabled; which is not always the case. Also, there is another problem, if the flag is set, the entire event log buffer will be dump to syslog, it can flood the syslog and make it very difficult to debug the problem. Change the default to only dump last 20 entries of event log to syslog unless the following condition meets: 1. both compile with CONFIG_IWLWIFI_DEBUG and debug flag is enabled, and then dump the entire event buffer to syslog. 2. dump event log request from debugfs Signed-off-by: Wey-Yi Guy Acked-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.h | 2 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 76 +++++++++++++++++++++++------ drivers/net/wireless/iwlwifi/iwl-core.c | 5 +- drivers/net/wireless/iwlwifi/iwl-core.h | 8 +-- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 2 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 74 +++++++++++++++++++++++----- 6 files changed, 130 insertions(+), 37 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index a41f0e098cf6..ecc23ec1f6a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -227,7 +227,7 @@ extern void iwl3945_rx_replenish(void *data); extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr,int left); -extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv); +extern void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log); extern void iwl3945_dump_nic_error_log(struct iwl_priv *priv); /* diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 927131192572..9b04b25f0e57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1696,8 +1696,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) } -#ifdef CONFIG_IWLWIFI_DEBUG - #define EVENT_START_OFFSET (4 * sizeof(u32)) /** @@ -1758,10 +1756,42 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } +/** + * iwl_print_last_event_logs - Dump the newest # of event log to syslog + */ +static void iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, + u32 num_wraps, u32 next_entry, + u32 size, u32 mode) +{ + /* + * display the newest DEFAULT_LOG_ENTRIES entries + * i.e the entries just before the next ont that uCode would fill. + */ + if (num_wraps) { + if (next_entry < size) { + iwl_print_event_log(priv, + capacity - (size - next_entry), + size - next_entry, mode); + iwl_print_event_log(priv, 0, + next_entry, mode); + } else + iwl_print_event_log(priv, next_entry - size, + size, mode); + } else { + if (next_entry < size) + iwl_print_event_log(priv, 0, next_entry, mode); + else + iwl_print_event_log(priv, next_entry - size, + size, mode); + } +} + /* For sanity check only. Actual size is determined by uCode, typ. 512 */ #define MAX_EVENT_LOG_SIZE (512) -void iwl_dump_nic_event_log(struct iwl_priv *priv) +#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) + +void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) { u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ @@ -1806,19 +1836,37 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) return; } - IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n", - size, num_wraps); - - /* if uCode has wrapped back to top of log, start at the oldest entry, - * i.e the next one that uCode would fill. */ - if (num_wraps) - iwl_print_event_log(priv, next_entry, - capacity - next_entry, mode); - /* (then/else) start at top of log */ - iwl_print_event_log(priv, 0, next_entry, mode); +#ifdef CONFIG_IWLWIFI_DEBUG + if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)) + size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; +#else + size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; +#endif + IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n", + size); -} +#ifdef CONFIG_IWLWIFI_DEBUG + if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { + /* + * if uCode has wrapped back to top of log, + * start at the oldest entry, + * i.e the next one that uCode would fill. + */ + if (num_wraps) + iwl_print_event_log(priv, next_entry, + capacity - next_entry, mode); + /* (then/else) start at top of log */ + iwl_print_event_log(priv, 0, next_entry, mode); + } else + iwl_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); +#else + iwl_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); #endif +} /** * iwl_alive_start - called after REPLY_ALIVE notification received diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2e0fb2804ad0..3629aea250ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1362,11 +1362,10 @@ void iwl_irq_handle_error(struct iwl_priv *priv) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); priv->cfg->ops->lib->dump_nic_error_log(priv); + priv->cfg->ops->lib->dump_nic_event_log(priv, false); #ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) { - priv->cfg->ops->lib->dump_nic_event_log(priv); + if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) iwl_print_rx_config_cmd(priv); - } #endif wake_up_interruptible(&priv->wait_command_queue); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index ecba0f46bac5..cf7d3df0744e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -167,7 +167,7 @@ struct iwl_lib_ops { int (*is_valid_rtc_data_addr)(u32 addr); /* 1st ucode load */ int (*load_ucode)(struct iwl_priv *priv); - void (*dump_nic_event_log)(struct iwl_priv *priv); + void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log); void (*dump_nic_error_log)(struct iwl_priv *priv); int (*set_channel_switch)(struct iwl_priv *priv, u16 channel); /* power management */ @@ -579,14 +579,10 @@ int iwl_pci_resume(struct pci_dev *pdev); * Error Handling Debugging ******************************************************/ void iwl_dump_nic_error_log(struct iwl_priv *priv); +void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log); #ifdef CONFIG_IWLWIFI_DEBUG -void iwl_dump_nic_event_log(struct iwl_priv *priv); void iwl_print_rx_config_cmd(struct iwl_priv *priv); #else -static inline void iwl_dump_nic_event_log(struct iwl_priv *priv) -{ -} - static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv) { } diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 5adf0b606202..21e0f6699daf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -436,7 +436,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, if (sscanf(buf, "%d", &event_log_flag) != 1) return -EFAULT; if (event_log_flag == 1) - priv->cfg->ops->lib->dump_nic_event_log(priv); + priv->cfg->ops->lib->dump_nic_event_log(priv, true); return count; } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5b7e80e5bab4..5e3c35314ffe 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1482,7 +1482,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) tasklet_kill(&priv->irq_tasklet); } -#ifdef CONFIG_IWLWIFI_DEBUG static const char *desc_lookup(int i) { switch (i) { @@ -1613,10 +1612,42 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, spin_unlock_irqrestore(&priv->reg_lock, reg_flags); } +/** + * iwl3945_print_last_event_logs - Dump the newest # of event log to syslog + */ +static void iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity, + u32 num_wraps, u32 next_entry, + u32 size, u32 mode) +{ + /* + * display the newest DEFAULT_LOG_ENTRIES entries + * i.e the entries just before the next ont that uCode would fill. + */ + if (num_wraps) { + if (next_entry < size) { + iwl3945_print_event_log(priv, + capacity - (size - next_entry), + size - next_entry, mode); + iwl3945_print_event_log(priv, 0, + next_entry, mode); + } else + iwl3945_print_event_log(priv, next_entry - size, + size, mode); + } else { + if (next_entry < size) + iwl3945_print_event_log(priv, 0, next_entry, mode); + else + iwl3945_print_event_log(priv, next_entry - size, + size, mode); + } +} + /* For sanity check only. Actual size is determined by uCode, typ. 512 */ #define IWL3945_MAX_EVENT_LOG_SIZE (512) -void iwl3945_dump_nic_event_log(struct iwl_priv *priv) +#define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20) + +void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log) { u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ @@ -1657,8 +1688,17 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv) return; } - IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n", - size, num_wraps); +#ifdef CONFIG_IWLWIFI_DEBUG + if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)) + size = (size > DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES : size; +#else + size = (size > DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES : size; +#endif + + IWL_ERR(priv, "Start IWL Event Log Dump: display last %d count\n", + size); /* if uCode has wrapped back to top of log, start at the oldest entry, * i.e the next one that uCode would fill. */ @@ -1669,18 +1709,28 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv) /* (then/else) start at top of log */ iwl3945_print_event_log(priv, 0, next_entry, mode); -} +#ifdef CONFIG_IWLWIFI_DEBUG + if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { + /* if uCode has wrapped back to top of log, + * start at the oldest entry, + * i.e the next one that uCode would fill. + */ + if (num_wraps) + iwl3945_print_event_log(priv, next_entry, + capacity - next_entry, mode); + + /* (then/else) start at top of log */ + iwl3945_print_event_log(priv, 0, next_entry, mode); + } else + iwl3945_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); #else -void iwl3945_dump_nic_event_log(struct iwl_priv *priv) -{ -} + iwl3945_print_last_event_logs(priv, capacity, num_wraps, + next_entry, size, mode); +#endif -void iwl3945_dump_nic_error_log(struct iwl_priv *priv) -{ } -#endif - static void iwl3945_irq_tasklet(struct iwl_priv *priv) { u32 inta, handled = 0; -- cgit v1.2.3 From 2d237f71b00bdc9044b5853d79f8cbef6c8df3ed Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:08 -0800 Subject: iwlwifi: change message for cmd queue full error Change error message for command queue full Signed-off-by: Wey-Yi Guy Acked-by: Ben Cahill Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index f3dff2ecc406..2eee950e0195 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1022,7 +1022,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) } if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { - IWL_ERR(priv, "No space for Tx\n"); + IWL_ERR(priv, "No space in command queue\n"); if (iwl_within_ct_kill_margin(priv)) iwl_tt_enter_ct_kill(priv); else { -- cgit v1.2.3 From 3681165235aae95a2e6d5407bb4e9426d68a37dd Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 20 Nov 2009 12:05:09 -0800 Subject: iwlwifi: remove reset led_tpt from iwl_leds_init() Current blinking rate is calculated based on the difference between current tx/rx byte counts and priv->led_tpt. priv->led_tpt should not get reset in iwl_leds_init(), this function can be called by bring interface "up" or "down", or when uCode sysassert occurred. resetting the led_tpt parameter will introduce incorrect led blinking behavior. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-led.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 478c90511ebf..46c7a95b88f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -219,7 +219,6 @@ EXPORT_SYMBOL(iwl_leds_background); void iwl_leds_init(struct iwl_priv *priv) { priv->last_blink_rate = 0; - priv->led_tpt = 0; priv->last_blink_time = 0; priv->allow_blinking = 0; } -- cgit v1.2.3 From c1f8ca1d837148bf061d6ffa2038366e3cf0e4d7 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Sun, 22 Nov 2009 20:16:42 +0200 Subject: rndis_wlan: fix buffer overflow in rndis_query_oid rndis_query_oid overwrites *len which stores buffer size to return full size of received command and then uses *len with memcpy to fill buffer with command. Ofcourse memcpy should be done before replacing buffer size. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index aa1880add186..8b09b043bc4e 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -733,12 +733,13 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len) le32_to_cpu(u.get_c->status)); if (ret == 0) { + memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len); + ret = le32_to_cpu(u.get_c->len); if (ret > *len) *len = ret; - memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len); - ret = rndis_error_status(u.get_c->status); + ret = rndis_error_status(u.get_c->status); if (ret < 0) devdbg(dev, "rndis_query_oid(%s): device returned " "error, 0x%08x (%d)", oid_to_string(oid), -- cgit v1.2.3 From 77593ae28c4c134eaf28ef34ecac3cd4464ecd6e Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Sun, 22 Nov 2009 20:16:47 +0200 Subject: rndis_wlan: disable stall workaround Stall workaround doesn't work with bcm4320a devices like with bcm4320b. This workaround actually causes more stalls/device freeze on bcm4320a. Therefore disable stall workaround by default. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 8b09b043bc4e..2ecbedb26e15 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -83,11 +83,11 @@ MODULE_PARM_DESC(roamdelta, "set roaming tendency: 0=aggressive, 1=moderate, " "2=conservative (default: moderate)"); -static int modparam_workaround_interval = 500; +static int modparam_workaround_interval; module_param_named(workaround_interval, modparam_workaround_interval, int, 0444); MODULE_PARM_DESC(workaround_interval, - "set stall workaround interval in msecs (default: 500)"); + "set stall workaround interval in msecs (0=disabled) (default: 0)"); /* various RNDIS OID defs */ @@ -2550,7 +2550,7 @@ static void rndis_device_poller(struct work_struct *work) /* Workaround transfer stalls on poor quality links. * TODO: find right way to fix these stalls (as stalls do not happen * with ndiswrapper/windows driver). */ - if (priv->last_qual <= 25) { + if (priv->param_workaround_interval > 0 && priv->last_qual <= 25) { /* Decrease stats worker interval to catch stalls. * faster. Faster than 400-500ms causes packet loss, * Slower doesn't catch stalls fast enough. -- cgit v1.2.3 From 18b6c9a2213d3b6e0212e8b225abf95f7564206a Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 23 Nov 2009 16:15:19 -0500 Subject: ath9k: set ps_default as false Copied from original one-line patch here: http://bugzilla.kernel.org/show_bug.cgi?id=14267#c26 (This is for 2.6.33 and beyond, where the bool was changed to a flag by "cfg80211: convert bools into flags". -- JWL) Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 16bdb1b549b4..cbf5d2a1bb26 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1893,6 +1893,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + hw->queues = 4; hw->max_rates = 4; hw->channel_change_time = 5000; -- cgit v1.2.3 From 04658fba2314d6d70d5fa05c0b5995e6428aacc3 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 13 Nov 2009 13:12:59 -0500 Subject: ath9k: remove warnings related to signed/unsigned type mismatch CC [M] drivers/net/wireless/ath/ath9k/recv.o drivers/net/wireless/ath/ath9k/recv.c: In function `ath_rx_prepare': drivers/net/wireless/ath/ath9k/recv.c:208: warning: comparison is always true due to limited range of data type drivers/net/wireless/ath/ath9k/recv.c:220: warning: comparison is always false due to limited range of data type Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common.c | 2 -- drivers/net/wireless/ath/ath9k/hw.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 4a13632e3e4d..d96751ccee96 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -181,8 +181,6 @@ static void ath9k_process_rssi(struct ath_common *common, ATH_RSSI_EP_MULTIPLIER); if (rx_stats->rs_rssi < 0) rx_stats->rs_rssi = 0; - else if (rx_stats->rs_rssi > 127) - rx_stats->rs_rssi = 127; /* Update Beacon RSSI, this is used by ANI. */ if (ieee80211_is_beacon(fc)) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f8f5e997162c..a22ed766b6ae 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -60,7 +60,7 @@ #define ATH_DEFAULT_NOISE_FLOOR -95 -#define ATH9K_RSSI_BAD 0x80 +#define ATH9K_RSSI_BAD -128 /* Register read/write primitives */ #define REG_WRITE(_ah, _reg, _val) \ -- cgit v1.2.3 From 545750d36fa78203e28acefb4bab61ebb7c4d197 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 23 Nov 2009 22:21:01 +0100 Subject: ath9k: properly use the mac80211 rate control api This patch changes ath9k to pass proper MCS indexes and flags between the RC and the rest of the driver code. sc->cur_rate_table remains, as it's used by the RC code internally, but the rest of the driver code no longer uses it, so a potential new RC for ath9k would not have to update it. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 5 +- drivers/net/wireless/ath/ath9k/beacon.c | 10 +- drivers/net/wireless/ath/ath9k/debug.c | 14 +- drivers/net/wireless/ath/ath9k/debug.h | 5 +- drivers/net/wireless/ath/ath9k/hw.c | 12 +- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/mac.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 112 +++++------- drivers/net/wireless/ath/ath9k/rc.c | 311 ++++++++++++++++---------------- drivers/net/wireless/ath/ath9k/rc.h | 3 +- drivers/net/wireless/ath/ath9k/xmit.c | 110 +++++++---- 11 files changed, 291 insertions(+), 294 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2a40fa2cd914..9ff53c9c4119 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -21,7 +21,6 @@ #include #include -#include "rc.h" #include "debug.h" #include "common.h" @@ -423,6 +422,7 @@ struct ath_led { #define SC_OP_BT_PRIORITY_DETECTED BIT(21) struct ath_wiphy; +struct ath_rate_table; struct ath_softc { struct ieee80211_hw *hw; @@ -467,9 +467,8 @@ struct ath_softc { struct ath_rx rx; struct ath_tx tx; struct ath_beacon beacon; - struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; - const struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; const struct ath_rate_table *cur_rate_table; + enum wireless_mode cur_rate_mode; struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; struct ath_led radio_led; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index b10c884f2933..cb774cc828a3 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -65,9 +65,9 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, struct ath_common *common = ath9k_hw_common(ah); struct ath_desc *ds; struct ath9k_11n_rate_series series[4]; - const struct ath_rate_table *rt; int flags, antenna, ctsrate = 0, ctsduration = 0; - u8 rate; + struct ieee80211_supported_band *sband; + u8 rate = 0; ds = bf->bf_desc; flags = ATH9K_TXDESC_NOACK; @@ -91,10 +91,10 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, ds->ds_data = bf->bf_buf_addr; - rt = sc->cur_rate_table; - rate = rt->info[0].ratecode; + sband = &sc->sbands[common->hw->conf.channel->band]; + rate = sband->bitrates[0].hw_value; if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - rate |= rt->info[0].short_preamble; + rate |= sband->bitrates[0].hw_value_short; ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN, ATH9K_PKT_TYPE_BEACON, diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 06f1fcfb03e9..608fa06e531c 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -255,21 +255,11 @@ static const struct file_operations fops_interrupt = { .owner = THIS_MODULE }; -void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) +void ath_debug_stat_rc(struct ath_softc *sc, int final_rate) { - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->status.rates; - int final_ts_idx = 0, idx, i; struct ath_rc_stats *stats; - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - if (!rates[i].count) - break; - - final_ts_idx = i; - } - idx = rates[final_ts_idx].idx; - stats = &sc->debug.stats.rcstats[idx]; + stats = &sc->debug.stats.rcstats[final_rate]; stats->success++; } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 749e85d57551..f282eeef669b 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -18,6 +18,7 @@ #define DEBUG_H #include "hw.h" +#include "rc.h" struct ath_txq; struct ath_buf; @@ -138,7 +139,7 @@ void ath9k_exit_debug(struct ath_hw *ah); int ath9k_debug_create_root(void); void ath9k_debug_remove_root(void); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); -void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb); +void ath_debug_stat_rc(struct ath_softc *sc, int final_rate); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf); void ath_debug_stat_retries(struct ath_softc *sc, int rix, @@ -170,7 +171,7 @@ static inline void ath_debug_stat_interrupt(struct ath_softc *sc, } static inline void ath_debug_stat_rc(struct ath_softc *sc, - struct sk_buff *skb) + int final_rate) { } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 53a7b980d8f6..63d84613dc96 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -148,22 +148,19 @@ bool ath9k_get_channel_edges(struct ath_hw *ah, } u16 ath9k_hw_computetxtime(struct ath_hw *ah, - const struct ath_rate_table *rates, + u8 phy, int kbps, u32 frameLen, u16 rateix, bool shortPreamble) { u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; - u32 kbps; - - kbps = rates->info[rateix].ratekbps; if (kbps == 0) return 0; - switch (rates->info[rateix].phy) { + switch (phy) { case WLAN_RC_PHY_CCK: phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; - if (shortPreamble && rates->info[rateix].short_preamble) + if (shortPreamble) phyTime >>= 1; numBits = frameLen << 3; txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps); @@ -194,8 +191,7 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, break; default: ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, - "Unknown phy %u (rate ix %u)\n", - rates->info[rateix].phy, rateix); + "Unknown phy %u (rate ix %u)\n", phy, rateix); txTime = 0; break; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index a22ed766b6ae..b12634262d97 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -647,7 +647,7 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); u32 ath9k_hw_reverse_bits(u32 val, u32 n); bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); u16 ath9k_hw_computetxtime(struct ath_hw *ah, - const struct ath_rate_table *rates, + u8 phy, int kbps, u32 frameLen, u16 rateix, bool shortPreamble); void ath9k_hw_get_channel_centers(struct ath_hw *ah, struct ath9k_channel *chan, diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index fefb65dafb1c..29dfe14751a7 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -616,7 +616,6 @@ enum ath9k_cipher { struct ath_hw; struct ath9k_channel; -struct ath_rate_table; u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cbf5d2a1bb26..bd1e2de3a1f9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -104,37 +104,55 @@ static struct ieee80211_channel ath9k_5ghz_chantable[] = { CHAN5G(5825, 37), /* Channel 165 */ }; +/* Atheros hardware rate code addition for short premble */ +#define SHPCHECK(__hw_rate, __flags) \ + ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) + +#define RATE(_bitrate, _hw_rate, _flags) { \ + .bitrate = (_bitrate), \ + .flags = (_flags), \ + .hw_value = (_hw_rate), \ + .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ +} + +static struct ieee80211_rate ath9k_legacy_rates[] = { + RATE(10, 0x1b, 0), + RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(60, 0x0b, 0), + RATE(90, 0x0f, 0), + RATE(120, 0x0a, 0), + RATE(180, 0x0e, 0), + RATE(240, 0x09, 0), + RATE(360, 0x0d, 0), + RATE(480, 0x08, 0), + RATE(540, 0x0c, 0), +}; + static void ath_cache_conf_rate(struct ath_softc *sc, struct ieee80211_conf *conf) { switch (conf->channel->band) { case IEEE80211_BAND_2GHZ: if (conf_is_ht20(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NG_HT20]; + sc->cur_rate_mode = ATH9K_MODE_11NG_HT20; else if (conf_is_ht40_minus(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS]; + sc->cur_rate_mode = ATH9K_MODE_11NG_HT40MINUS; else if (conf_is_ht40_plus(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS]; + sc->cur_rate_mode = ATH9K_MODE_11NG_HT40PLUS; else - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11G]; + sc->cur_rate_mode = ATH9K_MODE_11G; break; case IEEE80211_BAND_5GHZ: if (conf_is_ht20(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NA_HT20]; + sc->cur_rate_mode = ATH9K_MODE_11NA_HT20; else if (conf_is_ht40_minus(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS]; + sc->cur_rate_mode = ATH9K_MODE_11NA_HT40MINUS; else if (conf_is_ht40_plus(conf)) - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS]; + sc->cur_rate_mode = ATH9K_MODE_11NA_HT40PLUS; else - sc->cur_rate_table = - sc->hw_rate_table[ATH9K_MODE_11A]; + sc->cur_rate_mode = ATH9K_MODE_11A; break; default: BUG_ON(1); @@ -190,51 +208,6 @@ static u8 parse_mpdudensity(u8 mpdudensity) } } -static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) -{ - const struct ath_rate_table *rate_table = NULL; - struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate; - int i, maxrates; - - switch (band) { - case IEEE80211_BAND_2GHZ: - rate_table = sc->hw_rate_table[ATH9K_MODE_11G]; - break; - case IEEE80211_BAND_5GHZ: - rate_table = sc->hw_rate_table[ATH9K_MODE_11A]; - break; - default: - break; - } - - if (rate_table == NULL) - return; - - sband = &sc->sbands[band]; - rate = sc->rates[band]; - - if (rate_table->rate_cnt > ATH_RATE_MAX) - maxrates = ATH_RATE_MAX; - else - maxrates = rate_table->rate_cnt; - - for (i = 0; i < maxrates; i++) { - rate[i].bitrate = rate_table->info[i].ratekbps / 100; - rate[i].hw_value = rate_table->info[i].ratecode; - if (rate_table->info[i].short_preamble) { - rate[i].hw_value_short = rate_table->info[i].ratecode | - rate_table->info[i].short_preamble; - rate[i].flags = IEEE80211_RATE_SHORT_PREAMBLE; - } - sband->n_bitrates++; - - ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, - "Rate: %2dMbps, ratecode: %2d\n", - rate[i].bitrate / 10, rate[i].hw_value); - } -} - static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc, struct ieee80211_hw *hw) { @@ -1701,12 +1674,6 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, /* default to MONITOR mode */ sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; - /* Setup rate tables */ - - ath_rate_attach(sc); - ath_setup_rates(sc, IEEE80211_BAND_2GHZ); - ath_setup_rates(sc, IEEE80211_BAND_5GHZ); - /* * Allocate hardware transmit queues: one queue for * beacon frames and one data queue for each QoS @@ -1827,19 +1794,22 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, /* setup channels and rates */ sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = - sc->rates[IEEE80211_BAND_2GHZ]; sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; sc->sbands[IEEE80211_BAND_2GHZ].n_channels = ARRAY_SIZE(ath9k_2ghz_chantable); + sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; + sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates); if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - sc->rates[IEEE80211_BAND_5GHZ]; sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; sc->sbands[IEEE80211_BAND_5GHZ].n_channels = ARRAY_SIZE(ath9k_5ghz_chantable); + sc->sbands[IEEE80211_BAND_5GHZ].bitrates = + ath9k_legacy_rates + 4; + sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates) - 4; } switch (ah->btcoex_hw.scheme) { diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 1d96777b4cd2..66d3004af2bc 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -19,132 +19,133 @@ static const struct ath_rate_table ar5416_11na_ratetable = { 42, + 8, /* MCS start */ { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0x0b, 0x00, 12, + 5400, 0, 0x00, 12, 0, 0, 0, 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 0x0f, 0x00, 18, + 7800, 1, 0x00, 18, 0, 1, 1, 1, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 0x0a, 0x00, 24, + 10000, 2, 0x00, 24, 2, 2, 2, 2, 2, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 0x0e, 0x00, 36, + 13900, 3, 0x00, 36, 2, 3, 3, 3, 3, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 0x09, 0x00, 48, + 17300, 4, 0x00, 48, 4, 4, 4, 4, 4, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 0x0d, 0x00, 72, + 23000, 5, 0x00, 72, 4, 5, 5, 5, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 0x08, 0x00, 96, + 27400, 6, 0x00, 96, 4, 6, 6, 6, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 0x0c, 0x00, 108, + 29300, 7, 0x00, 108, 4, 7, 7, 7, 7, 0 }, { VALID_2040, VALID_2040, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ - 6400, 0x80, 0x00, 0, + 6400, 0, 0x00, 0, 0, 8, 24, 8, 24, 3216 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ - 12700, 0x81, 0x00, 1, + 12700, 1, 0x00, 1, 2, 9, 25, 9, 25, 6434 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ - 18800, 0x82, 0x00, 2, + 18800, 2, 0x00, 2, 2, 10, 26, 10, 26, 9650 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ - 25000, 0x83, 0x00, 3, + 25000, 3, 0x00, 3, 4, 11, 27, 11, 27, 12868 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ - 36700, 0x84, 0x00, 4, + 36700, 4, 0x00, 4, 4, 12, 28, 12, 28, 19304 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ - 48100, 0x85, 0x00, 5, + 48100, 5, 0x00, 5, 4, 13, 29, 13, 29, 25740 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ - 53500, 0x86, 0x00, 6, + 53500, 6, 0x00, 6, 4, 14, 30, 14, 30, 28956 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ - 59000, 0x87, 0x00, 7, + 59000, 7, 0x00, 7, 4, 15, 31, 15, 32, 32180 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ - 12700, 0x88, 0x00, + 12700, 8, 0x00, 8, 3, 16, 33, 16, 33, 6430 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ - 24800, 0x89, 0x00, 9, + 24800, 9, 0x00, 9, 2, 17, 34, 17, 34, 12860 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ - 36600, 0x8a, 0x00, 10, + 36600, 10, 0x00, 10, 2, 18, 35, 18, 35, 19300 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ - 48100, 0x8b, 0x00, 11, + 48100, 11, 0x00, 11, 4, 19, 36, 19, 36, 25736 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ - 69500, 0x8c, 0x00, 12, + 69500, 12, 0x00, 12, 4, 20, 37, 20, 37, 38600 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ - 89500, 0x8d, 0x00, 13, + 89500, 13, 0x00, 13, 4, 21, 38, 21, 38, 51472 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ - 98900, 0x8e, 0x00, 14, + 98900, 14, 0x00, 14, 4, 22, 39, 22, 39, 57890 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ - 108300, 0x8f, 0x00, 15, + 108300, 15, 0x00, 15, 4, 23, 40, 23, 41, 64320 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ - 13200, 0x80, 0x00, 0, + 13200, 0, 0x00, 0, 0, 8, 24, 24, 24, 6684 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ - 25900, 0x81, 0x00, 1, + 25900, 1, 0x00, 1, 2, 9, 25, 25, 25, 13368 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ - 38600, 0x82, 0x00, 2, + 38600, 2, 0x00, 2, 2, 10, 26, 26, 26, 20052 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ - 49800, 0x83, 0x00, 3, + 49800, 3, 0x00, 3, 4, 11, 27, 27, 27, 26738 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ - 72200, 0x84, 0x00, 4, + 72200, 4, 0x00, 4, 4, 12, 28, 28, 28, 40104 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ - 92900, 0x85, 0x00, 5, + 92900, 5, 0x00, 5, 4, 13, 29, 29, 29, 53476 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ - 102700, 0x86, 0x00, 6, + 102700, 6, 0x00, 6, 4, 14, 30, 30, 30, 60156 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ - 112000, 0x87, 0x00, 7, + 112000, 7, 0x00, 7, 4, 15, 31, 32, 32, 66840 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ - 122000, 0x87, 0x00, 7, + 122000, 7, 0x00, 7, 4, 15, 31, 32, 32, 74200 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ - 25800, 0x88, 0x00, 8, + 25800, 8, 0x00, 8, 0, 16, 33, 33, 33, 13360 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ - 49800, 0x89, 0x00, 9, + 49800, 9, 0x00, 9, 2, 17, 34, 34, 34, 26720 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ - 71900, 0x8a, 0x00, 10, + 71900, 10, 0x00, 10, 2, 18, 35, 35, 35, 40080 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ - 92500, 0x8b, 0x00, 11, + 92500, 11, 0x00, 11, 4, 19, 36, 36, 36, 53440 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ - 130300, 0x8c, 0x00, 12, + 130300, 12, 0x00, 12, 4, 20, 37, 37, 37, 80160 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ - 162800, 0x8d, 0x00, 13, + 162800, 13, 0x00, 13, 4, 21, 38, 38, 38, 106880 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ - 178200, 0x8e, 0x00, 14, + 178200, 14, 0x00, 14, 4, 22, 39, 39, 39, 120240 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ - 192100, 0x8f, 0x00, 15, + 192100, 15, 0x00, 15, 4, 23, 40, 41, 41, 133600 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ - 207000, 0x8f, 0x00, 15, + 207000, 15, 0x00, 15, 4, 23, 40, 41, 41, 148400 }, }, 50, /* probe interval */ @@ -156,144 +157,145 @@ static const struct ath_rate_table ar5416_11na_ratetable = { static const struct ath_rate_table ar5416_11ng_ratetable = { 46, + 12, /* MCS start */ { { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0x1b, 0x00, 2, + 900, 0, 0x00, 2, 0, 0, 0, 0, 0, 0 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1900, 0x1a, 0x04, 4, + 1900, 1, 0x04, 4, 1, 1, 1, 1, 1, 0 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4900, 0x19, 0x04, 11, + 4900, 2, 0x04, 11, 2, 2, 2, 2, 2, 0 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 8100, 0x18, 0x04, 22, + 8100, 3, 0x04, 22, 3, 3, 3, 3, 3, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0x0b, 0x00, 12, + 5400, 4, 0x00, 12, 4, 4, 4, 4, 4, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 0x0f, 0x00, 18, + 7800, 5, 0x00, 18, 4, 5, 5, 5, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10100, 0x0a, 0x00, 24, + 10100, 6, 0x00, 24, 6, 6, 6, 6, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 14100, 0x0e, 0x00, 36, + 14100, 7, 0x00, 36, 6, 7, 7, 7, 7, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17700, 0x09, 0x00, 48, + 17700, 8, 0x00, 48, 8, 8, 8, 8, 8, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23700, 0x0d, 0x00, 72, + 23700, 9, 0x00, 72, 8, 9, 9, 9, 9, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 0x08, 0x00, 96, + 27400, 10, 0x00, 96, 8, 10, 10, 10, 10, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 30900, 0x0c, 0x00, 108, + 30900, 11, 0x00, 108, 8, 11, 11, 11, 11, 0 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ - 6400, 0x80, 0x00, 0, + 6400, 0, 0x00, 0, 4, 12, 28, 12, 28, 3216 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ - 12700, 0x81, 0x00, 1, + 12700, 1, 0x00, 1, 6, 13, 29, 13, 29, 6434 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ - 18800, 0x82, 0x00, 2, + 18800, 2, 0x00, 2, 6, 14, 30, 14, 30, 9650 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ - 25000, 0x83, 0x00, 3, + 25000, 3, 0x00, 3, 8, 15, 31, 15, 31, 12868 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ - 36700, 0x84, 0x00, 4, + 36700, 4, 0x00, 4, 8, 16, 32, 16, 32, 19304 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ - 48100, 0x85, 0x00, 5, + 48100, 5, 0x00, 5, 8, 17, 33, 17, 33, 25740 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ - 53500, 0x86, 0x00, 6, + 53500, 6, 0x00, 6, 8, 18, 34, 18, 34, 28956 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ - 59000, 0x87, 0x00, 7, + 59000, 7, 0x00, 7, 8, 19, 35, 19, 36, 32180 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ - 12700, 0x88, 0x00, 8, + 12700, 8, 0x00, 8, 4, 20, 37, 20, 37, 6430 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ - 24800, 0x89, 0x00, 9, + 24800, 9, 0x00, 9, 6, 21, 38, 21, 38, 12860 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ - 36600, 0x8a, 0x00, 10, + 36600, 10, 0x00, 10, 6, 22, 39, 22, 39, 19300 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ - 48100, 0x8b, 0x00, 11, + 48100, 11, 0x00, 11, 8, 23, 40, 23, 40, 25736 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ - 69500, 0x8c, 0x00, 12, + 69500, 12, 0x00, 12, 8, 24, 41, 24, 41, 38600 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ - 89500, 0x8d, 0x00, 13, + 89500, 13, 0x00, 13, 8, 25, 42, 25, 42, 51472 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ - 98900, 0x8e, 0x00, 14, + 98900, 14, 0x00, 14, 8, 26, 43, 26, 44, 57890 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ - 108300, 0x8f, 0x00, 15, + 108300, 15, 0x00, 15, 8, 27, 44, 27, 45, 64320 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ - 13200, 0x80, 0x00, 0, + 13200, 0, 0x00, 0, 8, 12, 28, 28, 28, 6684 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ - 25900, 0x81, 0x00, 1, + 25900, 1, 0x00, 1, 8, 13, 29, 29, 29, 13368 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ - 38600, 0x82, 0x00, 2, + 38600, 2, 0x00, 2, 8, 14, 30, 30, 30, 20052 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ - 49800, 0x83, 0x00, 3, + 49800, 3, 0x00, 3, 8, 15, 31, 31, 31, 26738 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ - 72200, 0x84, 0x00, 4, + 72200, 4, 0x00, 4, 8, 16, 32, 32, 32, 40104 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ - 92900, 0x85, 0x00, 5, + 92900, 5, 0x00, 5, 8, 17, 33, 33, 33, 53476 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ - 102700, 0x86, 0x00, 6, + 102700, 6, 0x00, 6, 8, 18, 34, 34, 34, 60156 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ - 112000, 0x87, 0x00, 7, + 112000, 7, 0x00, 7, 8, 19, 35, 36, 36, 66840 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ - 122000, 0x87, 0x00, 7, + 122000, 7, 0x00, 7, 8, 19, 35, 36, 36, 74200 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ - 25800, 0x88, 0x00, 8, + 25800, 8, 0x00, 8, 8, 20, 37, 37, 37, 13360 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ - 49800, 0x89, 0x00, 9, + 49800, 9, 0x00, 9, 8, 21, 38, 38, 38, 26720 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ - 71900, 0x8a, 0x00, 10, + 71900, 10, 0x00, 10, 8, 22, 39, 39, 39, 40080 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ - 92500, 0x8b, 0x00, 11, + 92500, 11, 0x00, 11, 8, 23, 40, 40, 40, 53440 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ - 130300, 0x8c, 0x00, 12, + 130300, 12, 0x00, 12, 8, 24, 41, 41, 41, 80160 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ - 162800, 0x8d, 0x00, 13, + 162800, 13, 0x00, 13, 8, 25, 42, 42, 42, 106880 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ - 178200, 0x8e, 0x00, 14, + 178200, 14, 0x00, 14, 8, 26, 43, 43, 43, 120240 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ - 192100, 0x8f, 0x00, 15, + 192100, 15, 0x00, 15, 8, 27, 44, 45, 45, 133600 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ - 207000, 0x8f, 0x00, 15, + 207000, 15, 0x00, 15, 8, 27, 44, 45, 45, 148400 }, }, 50, /* probe interval */ @@ -302,30 +304,31 @@ static const struct ath_rate_table ar5416_11ng_ratetable = { static const struct ath_rate_table ar5416_11a_ratetable = { 8, + 0, { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0x0b, 0x00, (0x80|12), + 5400, 0, 0x00, 12, 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 0x0f, 0x00, 18, + 7800, 1, 0x00, 18, 0, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 0x0a, 0x00, (0x80|24), + 10000, 2, 0x00, 24, 2, 2, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 0x0e, 0x00, 36, + 13900, 3, 0x00, 36, 2, 3, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 0x09, 0x00, (0x80|48), + 17300, 4, 0x00, 48, 4, 4, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 0x0d, 0x00, 72, + 23000, 5, 0x00, 72, 4, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 0x08, 0x00, 96, + 27400, 6, 0x00, 96, 4, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 0x0c, 0x00, 108, + 29300, 7, 0x00, 108, 4, 7, 0 }, }, 50, /* probe interval */ @@ -334,48 +337,63 @@ static const struct ath_rate_table ar5416_11a_ratetable = { static const struct ath_rate_table ar5416_11g_ratetable = { 12, + 0, { { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0x1b, 0x00, 2, + 900, 0, 0x00, 2, 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1900, 0x1a, 0x04, 4, + 1900, 1, 0x04, 4, 1, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4900, 0x19, 0x04, 11, + 4900, 2, 0x04, 11, 2, 2, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 8100, 0x18, 0x04, 22, + 8100, 3, 0x04, 22, 3, 3, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0x0b, 0x00, 12, + 5400, 4, 0x00, 12, 4, 4, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 0x0f, 0x00, 18, + 7800, 5, 0x00, 18, 4, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 0x0a, 0x00, 24, + 10000, 6, 0x00, 24, 6, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 0x0e, 0x00, 36, + 13900, 7, 0x00, 36, 6, 7, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 0x09, 0x00, 48, + 17300, 8, 0x00, 48, 8, 8, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 0x0d, 0x00, 72, + 23000, 9, 0x00, 72, 8, 9, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 0x08, 0x00, 96, + 27400, 10, 0x00, 96, 8, 10, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 0x0c, 0x00, 108, + 29300, 11, 0x00, 108, 8, 11, 0 }, }, 50, /* probe interval */ 0, /* Phy rates allowed initially */ }; +static const struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX] = { + [ATH9K_MODE_11A] = &ar5416_11a_ratetable, + [ATH9K_MODE_11G] = &ar5416_11g_ratetable, + [ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable, + [ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable, + [ATH9K_MODE_11NA_HT40PLUS] = &ar5416_11na_ratetable, + [ATH9K_MODE_11NA_HT40MINUS] = &ar5416_11na_ratetable, + [ATH9K_MODE_11NG_HT40PLUS] = &ar5416_11ng_ratetable, + [ATH9K_MODE_11NG_HT40MINUS] = &ar5416_11ng_ratetable, +}; + +static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, + struct ieee80211_tx_rate *rate); + static inline int8_t median(int8_t a, int8_t b, int8_t c) { if (a >= b) { @@ -534,7 +552,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, * capflag matches one of the validity * (VALID/VALID_20/VALID_40) flags */ - if (((rate & 0x7F) == (dot11rate & 0x7F)) && + if ((rate == dot11rate) && ((valid & WLAN_RC_CAP_MODE(capflag)) == WLAN_RC_CAP_MODE(capflag)) && !WLAN_RC_PHY_HT(phy)) { @@ -576,8 +594,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, u8 rate = rateset->rs_rates[i]; u8 dot11rate = rate_table->info[j].dot11rate; - if (((rate & 0x7F) != (dot11rate & 0x7F)) || - !WLAN_RC_PHY_HT(phy) || + if ((rate != dot11rate) || !WLAN_RC_PHY_HT(phy) || !WLAN_RC_PHY_HT_VALID(valid, capflag)) continue; @@ -696,18 +713,20 @@ static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table, u8 tries, u8 rix, int rtsctsenable) { rate->count = tries; - rate->idx = rix; + rate->idx = rate_table->info[rix].ratecode; if (txrc->short_preamble) rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; if (txrc->rts || rtsctsenable) rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; - if (WLAN_RC_PHY_40(rate_table->info[rix].phy)) - rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) - rate->flags |= IEEE80211_TX_RC_SHORT_GI; - if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) + + if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) { rate->flags |= IEEE80211_TX_RC_MCS; + if (WLAN_RC_PHY_40(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + } } static void ath_rc_rate_set_rtscts(struct ath_softc *sc, @@ -720,7 +739,7 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc, /* get the cix for the lowest valid rix */ for (i = 3; i >= 0; i--) { if (rates[i].count && (rates[i].idx >= 0)) { - rix = rates[i].idx; + rix = ath_rc_get_rateindex(rate_table, &rates[i]); break; } } @@ -1080,15 +1099,19 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, { int rix; + if (!(rate->flags & IEEE80211_TX_RC_MCS)) + return rate->idx; + + rix = rate->idx + rate_table->mcs_start; if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && (rate->flags & IEEE80211_TX_RC_SHORT_GI)) - rix = rate_table->info[rate->idx].ht_index; + rix = rate_table->info[rix].ht_index; else if (rate->flags & IEEE80211_TX_RC_SHORT_GI) - rix = rate_table->info[rate->idx].sgi_index; + rix = rate_table->info[rix].sgi_index; else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - rix = rate_table->info[rate->idx].cw40index; + rix = rate_table->info[rix].cw40index; else - rix = rate_table->info[rate->idx].base_index; + rix = rate_table->info[rix].base_index; return rix; } @@ -1183,7 +1206,9 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, ath_print(common, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode); - return sc->hw_rate_table[mode]; + + sc->cur_rate_mode = mode; + return hw_rate_table[mode]; } static void ath_rc_init(struct ath_softc *sc, @@ -1197,12 +1222,6 @@ static void ath_rc_init(struct ath_softc *sc, u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; u8 i, j, k, hi = 0, hthi = 0; - if (!rate_table) { - ath_print(common, ATH_DBG_FATAL, - "Rate table not initialized\n"); - return; - } - /* Initial rate table size. Will change depending * on the working rate set */ ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; @@ -1357,7 +1376,8 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, } } - ath_debug_stat_rc(sc, skb); + ath_debug_stat_rc(sc, ath_rc_get_rateindex(sc->cur_rate_table, + &tx_info->status.rates[final_ts_idx])); } static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, @@ -1365,7 +1385,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, { struct ath_softc *sc = priv; struct ath_rate_priv *ath_rc_priv = priv_sta; - const struct ath_rate_table *rate_table = NULL; + const struct ath_rate_table *rate_table; bool is_cw40, is_sgi40; int i, j = 0; @@ -1397,11 +1417,9 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) || (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) { rate_table = ath_choose_rate_table(sc, sband->band, - sta->ht_cap.ht_supported, - is_cw40); - } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { - /* cur_rate_table would be set on init through config() */ - rate_table = sc->cur_rate_table; + sta->ht_cap.ht_supported, is_cw40); + } else { + rate_table = hw_rate_table[sc->cur_rate_mode]; } ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi40); @@ -1445,6 +1463,7 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG, "Operating HT Bandwidth changed to: %d\n", sc->hw->conf.channel_type); + sc->cur_rate_table = hw_rate_table[sc->cur_rate_mode]; } } } @@ -1497,26 +1516,6 @@ static struct rate_control_ops ath_rate_ops = { .free_sta = ath_rate_free_sta, }; -void ath_rate_attach(struct ath_softc *sc) -{ - sc->hw_rate_table[ATH9K_MODE_11A] = - &ar5416_11a_ratetable; - sc->hw_rate_table[ATH9K_MODE_11G] = - &ar5416_11g_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = - &ar5416_11ng_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] = - &ar5416_11ng_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = - &ar5416_11ng_ratetable; -} - int ath_rate_control_register(void) { return ieee80211_rate_control_register(&ath_rate_ops); diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 51f85ecbe88d..d68bc946bb3a 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -104,6 +104,7 @@ enum { */ struct ath_rate_table { int rate_cnt; + int mcs_start; struct { int valid; int valid_single_stream; @@ -179,8 +180,6 @@ enum ath9k_internal_frame_type { ATH9K_INT_UNPAUSE }; -void ath_rate_attach(struct ath_softc *sc); -u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate); int ath_rate_control_register(void); void ath_rate_control_unregister(void); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 745d91995d78..2bb8c91bf4f9 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -70,6 +70,29 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad, int txok, bool update_rc); +enum { + MCS_DEFAULT, + MCS_HT40, + MCS_HT40_SGI, +}; + +static int ath_max_4ms_framelen[3][16] = { + [MCS_DEFAULT] = { + 3216, 6434, 9650, 12868, 19304, 25740, 28956, 32180, + 6430, 12860, 19300, 25736, 38600, 51472, 57890, 64320, + }, + [MCS_HT40] = { + 6684, 13368, 20052, 26738, 40104, 53476, 60156, 66840, + 13360, 26720, 40080, 53440, 80160, 106880, 120240, 133600, + }, + [MCS_HT40_SGI] = { + /* TODO: Only MCS 7 and 15 updated, recalculate the rest */ + 6684, 13368, 20052, 26738, 40104, 53476, 60156, 74200, + 13360, 26720, 40080, 53440, 80160, 106880, 120240, 148400, + } +}; + + /*********************/ /* Aggregation logic */ /*********************/ @@ -459,7 +482,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ath_atx_tid *tid) { - const struct ath_rate_table *rate_table = sc->cur_rate_table; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; @@ -480,12 +502,20 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, for (i = 0; i < 4; i++) { if (rates[i].count) { - if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) { + int modeidx; + if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) { legacy = 1; break; } - frmlen = rate_table->info[rates[i].idx].max_4ms_framelen; + if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) + modeidx = MCS_HT40_SGI; + else if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + modeidx = MCS_HT40; + else + modeidx = MCS_DEFAULT; + + frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx]; max_4ms_framelen = min(max_4ms_framelen, frmlen); } } @@ -523,12 +553,11 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, struct ath_buf *bf, u16 frmlen) { - const struct ath_rate_table *rt = sc->cur_rate_table; struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); u32 nsymbits, nsymbols; u16 minlen; - u8 rc, flags, rix; + u8 flags, rix; int width, half_gi, ndelim, mindelim; /* Select standard number of delimiters based on frame length alone */ @@ -558,7 +587,6 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, rix = tx_info->control.rates[0].idx; flags = tx_info->control.rates[0].flags; - rc = rt->info[rix].ratecode; width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0; half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; @@ -570,7 +598,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, if (nsymbols == 0) nsymbols = 1; - nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; + nsymbits = bits_per_symbol[rix][width]; minlen = (nsymbols * nsymbits) / BITS_PER_BYTE; if (frmlen < minlen) { @@ -1425,22 +1453,14 @@ static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, int width, int half_gi, bool shortPreamble) { - const struct ath_rate_table *rate_table = sc->cur_rate_table; u32 nbits, nsymbits, duration, nsymbols; - u8 rc; int streams, pktlen; pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; - rc = rate_table->info[rix].ratecode; - - /* for legacy rates, use old function to compute packet duration */ - if (!IS_HT_RATE(rc)) - return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen, - rix, shortPreamble); /* find number of symbols: PLCP + data */ nbits = (pktlen << 3) + OFDM_PLCP_BITS; - nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; + nsymbits = bits_per_symbol[rix][width]; nsymbols = (nbits + nsymbits - 1) / nsymbits; if (!half_gi) @@ -1449,7 +1469,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, duration = SYMBOL_TIME_HALFGI(nsymbols); /* addup duration for legacy/ht training and signal fields */ - streams = HT_RC_2_STREAMS(rc); + streams = HT_RC_2_STREAMS(rix); duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); return duration; @@ -1458,11 +1478,11 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - const struct ath_rate_table *rt = sc->cur_rate_table; struct ath9k_11n_rate_series series[4]; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; + const struct ieee80211_rate *rate; struct ieee80211_hdr *hdr; int i, flags = 0; u8 rix = 0, ctsrate = 0; @@ -1481,11 +1501,10 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * checking the BSS's global flag. * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. */ + rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info); + ctsrate = rate->hw_value; if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode | - rt->info[tx_info->control.rts_cts_rate_idx].short_preamble; - else - ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode; + ctsrate |= rate->hw_value_short; /* * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. @@ -1508,6 +1527,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) flags &= ~(ATH9K_TXDESC_RTSENA); for (i = 0; i < 4; i++) { + bool is_40, is_sgi, is_sp; + int phy; + if (!rates[i].count || (rates[i].idx < 0)) continue; @@ -1515,12 +1537,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) series[i].Tries = rates[i].count; series[i].ChSel = common->tx_chainmask; - if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - series[i].Rate = rt->info[rix].ratecode | - rt->info[rix].short_preamble; - else - series[i].Rate = rt->info[rix].ratecode; - if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) @@ -1528,10 +1544,36 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) series[i].RateFlags |= ATH9K_RATESERIES_HALFGI; - series[i].PktDuration = ath_pkt_duration(sc, rix, bf, - (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0, - (rates[i].flags & IEEE80211_TX_RC_SHORT_GI), - (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)); + is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI); + is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH); + is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE); + + if (rates[i].flags & IEEE80211_TX_RC_MCS) { + /* MCS rates */ + series[i].Rate = rix | 0x80; + series[i].PktDuration = ath_pkt_duration(sc, rix, bf, + is_40, is_sgi, is_sp); + continue; + } + + /* legcay rates */ + if ((tx_info->band == IEEE80211_BAND_2GHZ) && + !(rate->flags & IEEE80211_RATE_ERP_G)) + phy = WLAN_RC_PHY_CCK; + else + phy = WLAN_RC_PHY_OFDM; + + rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; + series[i].Rate = rate->hw_value; + if (rate->hw_value_short) { + if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + series[i].Rate |= rate->hw_value_short; + } else { + is_sp = false; + } + + series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, + phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp); } /* set dur_update_en for l-sig computation except for PS-Poll frames */ @@ -1920,8 +1962,10 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, } } - for (i = tx_rateindex + 1; i < hw->max_rates; i++) + for (i = tx_rateindex + 1; i < hw->max_rates; i++) { tx_info->status.rates[i].count = 0; + tx_info->status.rates[i].idx = -1; + } tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1; } -- cgit v1.2.3 From 1fe8234a376e341c378a6e1c5de65db0fb49189a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 23 Nov 2009 22:22:27 +0100 Subject: ath9k: clean up rc rate table Remove some fields from struct ath_rate_table that are now unused. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 326 ++++++++++++------------------------ drivers/net/wireless/ath/ath9k/rc.h | 2 - 2 files changed, 109 insertions(+), 219 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 66d3004af2bc..e697bd934904 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -22,131 +22,89 @@ static const struct ath_rate_table ar5416_11na_ratetable = { 8, /* MCS start */ { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0, 0x00, 12, - 0, 0, 0, 0, 0, 0 }, + 5400, 0, 12, 0, 0, 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 1, 0x00, 18, - 0, 1, 1, 1, 1, 0 }, + 7800, 1, 18, 0, 1, 1, 1, 1 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 2, 0x00, 24, - 2, 2, 2, 2, 2, 0 }, + 10000, 2, 24, 2, 2, 2, 2, 2 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 3, 0x00, 36, - 2, 3, 3, 3, 3, 0 }, + 13900, 3, 36, 2, 3, 3, 3, 3 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 4, 0x00, 48, - 4, 4, 4, 4, 4, 0 }, + 17300, 4, 48, 4, 4, 4, 4, 4 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 5, 0x00, 72, - 4, 5, 5, 5, 5, 0 }, + 23000, 5, 72, 4, 5, 5, 5, 5 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 6, 0x00, 96, - 4, 6, 6, 6, 6, 0 }, + 27400, 6, 96, 4, 6, 6, 6, 6 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 7, 0x00, 108, - 4, 7, 7, 7, 7, 0 }, + 29300, 7, 108, 4, 7, 7, 7, 7 }, { VALID_2040, VALID_2040, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ - 6400, 0, 0x00, 0, - 0, 8, 24, 8, 24, 3216 }, + 6400, 0, 0, 0, 8, 24, 8, 24 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ - 12700, 1, 0x00, 1, - 2, 9, 25, 9, 25, 6434 }, + 12700, 1, 1, 2, 9, 25, 9, 25 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ - 18800, 2, 0x00, 2, - 2, 10, 26, 10, 26, 9650 }, + 18800, 2, 2, 2, 10, 26, 10, 26 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ - 25000, 3, 0x00, 3, - 4, 11, 27, 11, 27, 12868 }, + 25000, 3, 3, 4, 11, 27, 11, 27 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ - 36700, 4, 0x00, 4, - 4, 12, 28, 12, 28, 19304 }, + 36700, 4, 4, 4, 12, 28, 12, 28 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ - 48100, 5, 0x00, 5, - 4, 13, 29, 13, 29, 25740 }, + 48100, 5, 5, 4, 13, 29, 13, 29 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ - 53500, 6, 0x00, 6, - 4, 14, 30, 14, 30, 28956 }, + 53500, 6, 6, 4, 14, 30, 14, 30 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ - 59000, 7, 0x00, 7, - 4, 15, 31, 15, 32, 32180 }, + 59000, 7, 7, 4, 15, 31, 15, 32 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ - 12700, 8, 0x00, - 8, 3, 16, 33, 16, 33, 6430 }, + 12700, 8, 8, 3, 16, 33, 16, 33 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ - 24800, 9, 0x00, 9, - 2, 17, 34, 17, 34, 12860 }, + 24800, 9, 9, 2, 17, 34, 17, 34 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ - 36600, 10, 0x00, 10, - 2, 18, 35, 18, 35, 19300 }, + 36600, 10, 10, 2, 18, 35, 18, 35 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ - 48100, 11, 0x00, 11, - 4, 19, 36, 19, 36, 25736 }, + 48100, 11, 11, 4, 19, 36, 19, 36 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ - 69500, 12, 0x00, 12, - 4, 20, 37, 20, 37, 38600 }, + 69500, 12, 12, 4, 20, 37, 20, 37 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ - 89500, 13, 0x00, 13, - 4, 21, 38, 21, 38, 51472 }, + 89500, 13, 13, 4, 21, 38, 21, 38 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ - 98900, 14, 0x00, 14, - 4, 22, 39, 22, 39, 57890 }, + 98900, 14, 14, 4, 22, 39, 22, 39 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ - 108300, 15, 0x00, 15, - 4, 23, 40, 23, 41, 64320 }, + 108300, 15, 15, 4, 23, 40, 23, 41 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ - 13200, 0, 0x00, 0, - 0, 8, 24, 24, 24, 6684 }, + 13200, 0, 0, 0, 8, 24, 24, 24 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ - 25900, 1, 0x00, 1, - 2, 9, 25, 25, 25, 13368 }, + 25900, 1, 1, 2, 9, 25, 25, 25 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ - 38600, 2, 0x00, 2, - 2, 10, 26, 26, 26, 20052 }, + 38600, 2, 2, 2, 10, 26, 26, 26 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ - 49800, 3, 0x00, 3, - 4, 11, 27, 27, 27, 26738 }, + 49800, 3, 3, 4, 11, 27, 27, 27 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ - 72200, 4, 0x00, 4, - 4, 12, 28, 28, 28, 40104 }, + 72200, 4, 4, 4, 12, 28, 28, 28 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ - 92900, 5, 0x00, 5, - 4, 13, 29, 29, 29, 53476 }, + 92900, 5, 5, 4, 13, 29, 29, 29 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ - 102700, 6, 0x00, 6, - 4, 14, 30, 30, 30, 60156 }, + 102700, 6, 6, 4, 14, 30, 30, 30 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ - 112000, 7, 0x00, 7, - 4, 15, 31, 32, 32, 66840 }, + 112000, 7, 7, 4, 15, 31, 32, 32 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ - 122000, 7, 0x00, 7, - 4, 15, 31, 32, 32, 74200 }, + 122000, 7, 7, 4, 15, 31, 32, 32 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ - 25800, 8, 0x00, 8, - 0, 16, 33, 33, 33, 13360 }, + 25800, 8, 8, 0, 16, 33, 33, 33 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ - 49800, 9, 0x00, 9, - 2, 17, 34, 34, 34, 26720 }, + 49800, 9, 9, 2, 17, 34, 34, 34 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ - 71900, 10, 0x00, 10, - 2, 18, 35, 35, 35, 40080 }, + 71900, 10, 10, 2, 18, 35, 35, 35 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ - 92500, 11, 0x00, 11, - 4, 19, 36, 36, 36, 53440 }, + 92500, 11, 11, 4, 19, 36, 36, 36 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ - 130300, 12, 0x00, 12, - 4, 20, 37, 37, 37, 80160 }, + 130300, 12, 12, 4, 20, 37, 37, 37 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ - 162800, 13, 0x00, 13, - 4, 21, 38, 38, 38, 106880 }, + 162800, 13, 13, 4, 21, 38, 38, 38 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ - 178200, 14, 0x00, 14, - 4, 22, 39, 39, 39, 120240 }, + 178200, 14, 14, 4, 22, 39, 39, 39 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ - 192100, 15, 0x00, 15, - 4, 23, 40, 41, 41, 133600 }, + 192100, 15, 15, 4, 23, 40, 41, 41 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ - 207000, 15, 0x00, 15, - 4, 23, 40, 41, 41, 148400 }, + 207000, 15, 15, 4, 23, 40, 41, 41 }, }, 50, /* probe interval */ WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ @@ -160,144 +118,98 @@ static const struct ath_rate_table ar5416_11ng_ratetable = { 12, /* MCS start */ { { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0, 0x00, 2, - 0, 0, 0, 0, 0, 0 }, + 900, 0, 2, 0, 0, 0, 0, 0 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1900, 1, 0x04, 4, - 1, 1, 1, 1, 1, 0 }, + 1900, 1, 4, 1, 1, 1, 1, 1 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4900, 2, 0x04, 11, - 2, 2, 2, 2, 2, 0 }, + 4900, 2, 11, 2, 2, 2, 2, 2 }, { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 8100, 3, 0x04, 22, - 3, 3, 3, 3, 3, 0 }, + 8100, 3, 22, 3, 3, 3, 3, 3 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 4, 0x00, 12, - 4, 4, 4, 4, 4, 0 }, + 5400, 4, 12, 4, 4, 4, 4, 4 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 5, 0x00, 18, - 4, 5, 5, 5, 5, 0 }, + 7800, 5, 18, 4, 5, 5, 5, 5 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10100, 6, 0x00, 24, - 6, 6, 6, 6, 6, 0 }, + 10100, 6, 24, 6, 6, 6, 6, 6 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 14100, 7, 0x00, 36, - 6, 7, 7, 7, 7, 0 }, + 14100, 7, 36, 6, 7, 7, 7, 7 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17700, 8, 0x00, 48, - 8, 8, 8, 8, 8, 0 }, + 17700, 8, 48, 8, 8, 8, 8, 8 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23700, 9, 0x00, 72, - 8, 9, 9, 9, 9, 0 }, + 23700, 9, 72, 8, 9, 9, 9, 9 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 10, 0x00, 96, - 8, 10, 10, 10, 10, 0 }, + 27400, 10, 96, 8, 10, 10, 10, 10 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 30900, 11, 0x00, 108, - 8, 11, 11, 11, 11, 0 }, + 30900, 11, 108, 8, 11, 11, 11, 11 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ - 6400, 0, 0x00, 0, - 4, 12, 28, 12, 28, 3216 }, + 6400, 0, 0, 4, 12, 28, 12, 28 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ - 12700, 1, 0x00, 1, - 6, 13, 29, 13, 29, 6434 }, + 12700, 1, 1, 6, 13, 29, 13, 29 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ - 18800, 2, 0x00, 2, - 6, 14, 30, 14, 30, 9650 }, + 18800, 2, 2, 6, 14, 30, 14, 30 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ - 25000, 3, 0x00, 3, - 8, 15, 31, 15, 31, 12868 }, + 25000, 3, 3, 8, 15, 31, 15, 31 }, { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ - 36700, 4, 0x00, 4, - 8, 16, 32, 16, 32, 19304 }, + 36700, 4, 4, 8, 16, 32, 16, 32 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ - 48100, 5, 0x00, 5, - 8, 17, 33, 17, 33, 25740 }, + 48100, 5, 5, 8, 17, 33, 17, 33 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ - 53500, 6, 0x00, 6, - 8, 18, 34, 18, 34, 28956 }, + 53500, 6, 6, 8, 18, 34, 18, 34 }, { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ - 59000, 7, 0x00, 7, - 8, 19, 35, 19, 36, 32180 }, + 59000, 7, 7, 8, 19, 35, 19, 36 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ - 12700, 8, 0x00, 8, - 4, 20, 37, 20, 37, 6430 }, + 12700, 8, 8, 4, 20, 37, 20, 37 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ - 24800, 9, 0x00, 9, - 6, 21, 38, 21, 38, 12860 }, + 24800, 9, 9, 6, 21, 38, 21, 38 }, { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ - 36600, 10, 0x00, 10, - 6, 22, 39, 22, 39, 19300 }, + 36600, 10, 10, 6, 22, 39, 22, 39 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ - 48100, 11, 0x00, 11, - 8, 23, 40, 23, 40, 25736 }, + 48100, 11, 11, 8, 23, 40, 23, 40 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ - 69500, 12, 0x00, 12, - 8, 24, 41, 24, 41, 38600 }, + 69500, 12, 12, 8, 24, 41, 24, 41 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ - 89500, 13, 0x00, 13, - 8, 25, 42, 25, 42, 51472 }, + 89500, 13, 13, 8, 25, 42, 25, 42 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ - 98900, 14, 0x00, 14, - 8, 26, 43, 26, 44, 57890 }, + 98900, 14, 14, 8, 26, 43, 26, 44 }, { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ - 108300, 15, 0x00, 15, - 8, 27, 44, 27, 45, 64320 }, + 108300, 15, 15, 8, 27, 44, 27, 45 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ - 13200, 0, 0x00, 0, - 8, 12, 28, 28, 28, 6684 }, + 13200, 0, 0, 8, 12, 28, 28, 28 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ - 25900, 1, 0x00, 1, - 8, 13, 29, 29, 29, 13368 }, + 25900, 1, 1, 8, 13, 29, 29, 29 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ - 38600, 2, 0x00, 2, - 8, 14, 30, 30, 30, 20052 }, + 38600, 2, 2, 8, 14, 30, 30, 30 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ - 49800, 3, 0x00, 3, - 8, 15, 31, 31, 31, 26738 }, + 49800, 3, 3, 8, 15, 31, 31, 31 }, { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ - 72200, 4, 0x00, 4, - 8, 16, 32, 32, 32, 40104 }, + 72200, 4, 4, 8, 16, 32, 32, 32 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ - 92900, 5, 0x00, 5, - 8, 17, 33, 33, 33, 53476 }, + 92900, 5, 5, 8, 17, 33, 33, 33 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ - 102700, 6, 0x00, 6, - 8, 18, 34, 34, 34, 60156 }, + 102700, 6, 6, 8, 18, 34, 34, 34 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ - 112000, 7, 0x00, 7, - 8, 19, 35, 36, 36, 66840 }, + 112000, 7, 7, 8, 19, 35, 36, 36 }, { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ - 122000, 7, 0x00, 7, - 8, 19, 35, 36, 36, 74200 }, + 122000, 7, 7, 8, 19, 35, 36, 36 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ - 25800, 8, 0x00, 8, - 8, 20, 37, 37, 37, 13360 }, + 25800, 8, 8, 8, 20, 37, 37, 37 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ - 49800, 9, 0x00, 9, - 8, 21, 38, 38, 38, 26720 }, + 49800, 9, 9, 8, 21, 38, 38, 38 }, { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ - 71900, 10, 0x00, 10, - 8, 22, 39, 39, 39, 40080 }, + 71900, 10, 10, 8, 22, 39, 39, 39 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ - 92500, 11, 0x00, 11, - 8, 23, 40, 40, 40, 53440 }, + 92500, 11, 11, 8, 23, 40, 40, 40 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ - 130300, 12, 0x00, 12, - 8, 24, 41, 41, 41, 80160 }, + 130300, 12, 12, 8, 24, 41, 41, 41 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ - 162800, 13, 0x00, 13, - 8, 25, 42, 42, 42, 106880 }, + 162800, 13, 13, 8, 25, 42, 42, 42 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ - 178200, 14, 0x00, 14, - 8, 26, 43, 43, 43, 120240 }, + 178200, 14, 14, 8, 26, 43, 43, 43 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ - 192100, 15, 0x00, 15, - 8, 27, 44, 45, 45, 133600 }, + 192100, 15, 15, 8, 27, 44, 45, 45 }, { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ - 207000, 15, 0x00, 15, - 8, 27, 44, 45, 45, 148400 }, - }, + 207000, 15, 15, 8, 27, 44, 45, 45 }, + }, 50, /* probe interval */ WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ }; @@ -307,29 +219,21 @@ static const struct ath_rate_table ar5416_11a_ratetable = { 0, { { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0, 0x00, 12, - 0, 0, 0 }, + 5400, 0, 12, 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 1, 0x00, 18, - 0, 1, 0 }, + 7800, 1, 18, 0, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 2, 0x00, 24, - 2, 2, 0 }, + 10000, 2, 24, 2, 2, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 3, 0x00, 36, - 2, 3, 0 }, + 13900, 3, 36, 2, 3, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 4, 0x00, 48, - 4, 4, 0 }, + 17300, 4, 48, 4, 4, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 5, 0x00, 72, - 4, 5, 0 }, + 23000, 5, 72, 4, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 6, 0x00, 96, - 4, 6, 0 }, + 27400, 6, 96, 4, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 7, 0x00, 108, - 4, 7, 0 }, + 29300, 7, 108, 4, 7, 0 }, }, 50, /* probe interval */ 0, /* Phy rates allowed initially */ @@ -340,41 +244,29 @@ static const struct ath_rate_table ar5416_11g_ratetable = { 0, { { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0, 0x00, 2, - 0, 0, 0 }, + 900, 0, 2, 0, 0, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1900, 1, 0x04, 4, - 1, 1, 0 }, + 1900, 1, 4, 1, 1, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4900, 2, 0x04, 11, - 2, 2, 0 }, + 4900, 2, 11, 2, 2, 0 }, { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 8100, 3, 0x04, 22, - 3, 3, 0 }, + 8100, 3, 22, 3, 3, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 4, 0x00, 12, - 4, 4, 0 }, + 5400, 4, 12, 4, 4, 0 }, { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 5, 0x00, 18, - 4, 5, 0 }, + 7800, 5, 18, 4, 5, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 6, 0x00, 24, - 6, 6, 0 }, + 10000, 6, 24, 6, 6, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 7, 0x00, 36, - 6, 7, 0 }, + 13900, 7, 36, 6, 7, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 8, 0x00, 48, - 8, 8, 0 }, + 17300, 8, 48, 8, 8, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 9, 0x00, 72, - 8, 9, 0 }, + 23000, 9, 72, 8, 9, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 10, 0x00, 96, - 8, 10, 0 }, + 27400, 10, 96, 8, 10, 0 }, { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 11, 0x00, 108, - 8, 11, 0 }, + 29300, 11, 108, 8, 11, 0 }, }, 50, /* probe interval */ 0, /* Phy rates allowed initially */ diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index d68bc946bb3a..9eb96f506998 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -112,14 +112,12 @@ struct ath_rate_table { u32 ratekbps; u32 user_ratekbps; u8 ratecode; - u8 short_preamble; u8 dot11rate; u8 ctrl_rate; u8 base_index; u8 cw40index; u8 sgi_index; u8 ht_index; - u32 max_4ms_framelen; } info[RATE_TABLE_SIZE]; u32 probe_interval; u8 initial_ratemax; -- cgit v1.2.3 From 845025634549850879d30f00e20bc8bfe63980b4 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 23 Nov 2009 23:22:12 +0200 Subject: wl1271: Decrease BET consecutive terminated beacons value to 10 Decrease the consecutive terminated beacons value for BET from 100 to 10. According to the vendor, 10 will give a more reliable connection and more reliable detection of connection problems. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 00ddcc2d37c1..43fdd45f8401 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -222,7 +222,7 @@ static struct conf_drv_settings default_conf = { .snr_pkt_avg_weight = 10 }, .bet_enable = CONF_BET_MODE_ENABLE, - .bet_max_consecutive = 100, + .bet_max_consecutive = 10, .psm_entry_retries = 3 }, .init = { -- cgit v1.2.3 From 461fa136bb120f5b6b7d5814888a7211dbbd211b Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 23 Nov 2009 23:22:13 +0200 Subject: wl1271: Prevent PSM-entry retry loop if PSM cancelled Prevent endless PSM-entry retry loops, if PSM has already been cancelled while PSM entry was attempted. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_event.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index e135d894b42a..d13fdd99c85c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -78,12 +78,16 @@ static int wl1271_event_ps_report(struct wl1271 *wl, switch (mbox->ps_status) { case EVENT_ENTER_POWER_SAVE_FAIL: + if (!wl->psm) { + wl->psm_entry_retry = 0; + break; + } + if (wl->psm_entry_retry < wl->conf.conn.psm_entry_retries) { wl->psm_entry_retry++; - wl1271_error("PSM entry failed, retrying %d\n", - wl->psm_entry_retry); ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); } else { + wl1271_error("PSM entry failed, giving up.\n"); wl->psm_entry_retry = 0; *beacon_loss = true; } -- cgit v1.2.3 From 03442a33174b1d9f6f8eb8c3c2e8a9cf4b75fffe Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 23 Nov 2009 23:22:14 +0200 Subject: wl1271: Set PSM support flags in driver configuration Set the PSM support flag in the device configuration for the mac80211 stack. This will enable usage of powersave. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 43fdd45f8401..90916ed63b45 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1753,7 +1753,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM | - IEEE80211_HW_BEACON_FILTER; + IEEE80211_HW_BEACON_FILTER | + IEEE80211_HW_SUPPORTS_PS; wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wl->hw->wiphy->max_scan_ssids = 1; -- cgit v1.2.3 From 17d7265c7582af77357bd31884cef26f9f802313 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 23 Nov 2009 23:22:15 +0200 Subject: wl1271: fix the inetdev notifier callback return values The wl1271_dev_notify() was returning 0 or -ENODEV, when it should return NOTIFY_* instead. Now we use NOTIFY_DONE when we didn't handle the event or NOTIFY_OK when we have handled it. For inetdev notifications, it doesn't matter whether we use NOTIFY_DONE or NOTIFY_OK, because it ignores the return value of the call to blocking_notifier_call_chain(). But the notify.h header says that NOTIFY_DONE is "Don't care" and NOTIFY_OK is "Suits me", so that seems to be the right way to do it. Reported-by: Johannes Berg Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 90916ed63b45..c8652eed3677 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -815,15 +815,15 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, wdev = dev->ieee80211_ptr; if (wdev == NULL) - return -ENODEV; + return NOTIFY_DONE; wiphy = wdev->wiphy; if (wiphy == NULL) - return -ENODEV; + return NOTIFY_DONE; hw = wiphy_priv(wiphy); if (hw == NULL) - return -ENODEV; + return NOTIFY_DONE; /* Check that the interface is one supported by this driver. */ wl_temp = hw->priv; @@ -832,7 +832,7 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, break; } if (wl == NULL) - return -ENODEV; + return NOTIFY_DONE; /* Get the interface IP address for the device. "ifa" will become NULL if: @@ -868,7 +868,7 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, out: mutex_unlock(&wl->mutex); - return ret; + return NOTIFY_OK; } static struct notifier_block wl1271_dev_notifier = { -- cgit v1.2.3 From cc7defa366ea770efb25add8711defe88862197b Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 23 Nov 2009 23:22:16 +0200 Subject: wl1271: set radio and general params also for PLT We need to set the radio and general parameters when starting PLT mode. This patch adds calls to TEST_CMD_INI_RADIO_PARAMS and TEST_CMD_INIT_GENERAL_PARAMS when initializing PLT mode. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_init.c | 4 ++-- drivers/net/wireless/wl12xx/wl1271_init.h | 2 ++ drivers/net/wireless/wl12xx/wl1271_main.c | 11 +++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 7c2017f480ea..95ee0368438a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -193,7 +193,7 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl) return 0; } -static int wl1271_init_general_parms(struct wl1271 *wl) +int wl1271_init_general_parms(struct wl1271 *wl) { struct wl1271_general_parms *gen_parms; struct conf_general_parms *g = &wl->conf.init.genparam; @@ -224,7 +224,7 @@ static int wl1271_init_general_parms(struct wl1271 *wl) return 0; } -static int wl1271_init_radio_parms(struct wl1271 *wl) +int wl1271_init_radio_parms(struct wl1271 *wl) { struct wl1271_radio_parms *radio_parms; struct conf_radio_parms *r = &wl->conf.init.radioparam; diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h index 6e21ceee76a6..539b57f207c6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.h +++ b/drivers/net/wireless/wl12xx/wl1271_init.h @@ -28,6 +28,8 @@ int wl1271_hw_init_power_auth(struct wl1271 *wl); int wl1271_hw_init(struct wl1271 *wl); +int wl1271_init_general_parms(struct wl1271 *wl); +int wl1271_init_radio_parms(struct wl1271 *wl); /* These are not really a TEST_CMD, but the ref driver uses them as such */ #define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index c8652eed3677..d4e603993996 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -354,6 +354,17 @@ static int wl1271_plt_init(struct wl1271 *wl) { int ret; + /* FIXME: the following parameter setting functions return error + * codes - the reason is so far unknown. The -EIO is therefore + * ignored for the time being. */ + ret = wl1271_init_general_parms(wl); + if (ret < 0 && ret != -EIO) + return ret; + + ret = wl1271_init_radio_parms(wl); + if (ret < 0 && ret != -EIO) + return ret; + ret = wl1271_acx_init_mem_config(wl); if (ret < 0) return ret; -- cgit v1.2.3 From 98b5dd5ded8cb59b598b2c0c396100054779eda7 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 23 Nov 2009 23:22:17 +0200 Subject: wl1271: fix radio and general parameters commands We were missing the command header in the radio and general parameters commands. This was causing them to fail, resulting in problems in the power levels and other PLT-related commands. Also reorganized the command functions, moving from wl1271_init.c to wl1271_cmd.c where it fits better. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_cmd.c | 107 +++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_cmd.h | 72 +++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_init.c | 110 +----------------------------- drivers/net/wireless/wl12xx/wl1271_init.h | 72 ------------------- drivers/net/wireless/wl12xx/wl1271_main.c | 4 +- 5 files changed, 183 insertions(+), 182 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index 990eb01b4c71..886a9bc39cc1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c @@ -188,6 +188,113 @@ static int wl1271_cmd_cal(struct wl1271 *wl) return ret; } +int wl1271_cmd_general_parms(struct wl1271 *wl) +{ + struct wl1271_general_parms_cmd *gen_parms; + struct conf_general_parms *g = &wl->conf.init.genparam; + int ret; + + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); + if (!gen_parms) + return -ENOMEM; + + gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; + + gen_parms->ref_clk = g->ref_clk; + gen_parms->settling_time = g->settling_time; + gen_parms->clk_valid_on_wakeup = g->clk_valid_on_wakeup; + gen_parms->dc2dcmode = g->dc2dcmode; + gen_parms->single_dual_band = g->single_dual_band; + gen_parms->tx_bip_fem_autodetect = g->tx_bip_fem_autodetect; + gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer; + gen_parms->settings = g->settings; + + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); + if (ret < 0) + wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); + + kfree(gen_parms); + return ret; +} + +int wl1271_cmd_radio_parms(struct wl1271 *wl) +{ + struct wl1271_radio_parms_cmd *radio_parms; + struct conf_radio_parms *r = &wl->conf.init.radioparam; + int i, ret; + + radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); + if (!radio_parms) + return -ENOMEM; + + radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; + + /* Static radio parameters */ + radio_parms->rx_trace_loss = r->rx_trace_loss; + radio_parms->tx_trace_loss = r->tx_trace_loss; + memcpy(radio_parms->rx_rssi_and_proc_compens, + r->rx_rssi_and_proc_compens, + CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE); + + memcpy(radio_parms->rx_trace_loss_5, r->rx_trace_loss_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->tx_trace_loss_5, r->tx_trace_loss_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->rx_rssi_and_proc_compens_5, + r->rx_rssi_and_proc_compens_5, + CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE); + + /* Dynamic radio parameters */ + radio_parms->tx_ref_pd_voltage = cpu_to_le16(r->tx_ref_pd_voltage); + radio_parms->tx_ref_power = r->tx_ref_power; + radio_parms->tx_offset_db = r->tx_offset_db; + + memcpy(radio_parms->tx_rate_limits_normal, r->tx_rate_limits_normal, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded, + CONF_NUMBER_OF_RATE_GROUPS); + + memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b, + CONF_NUMBER_OF_CHANNELS_2_4); + memcpy(radio_parms->tx_channel_limits_ofdm, r->tx_channel_limits_ofdm, + CONF_NUMBER_OF_CHANNELS_2_4); + memcpy(radio_parms->tx_pdv_rate_offsets, r->tx_pdv_rate_offsets, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS); + + radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss; + + for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++) + radio_parms->tx_ref_pd_voltage_5[i] = + cpu_to_le16(r->tx_ref_pd_voltage_5[i]); + memcpy(radio_parms->tx_ref_power_5, r->tx_ref_power_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->tx_offset_db_5, r->tx_offset_db_5, + CONF_NUMBER_OF_SUB_BANDS_5); + memcpy(radio_parms->tx_rate_limits_normal_5, + r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_rate_limits_degraded_5, + r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_channel_limits_ofdm_5, + r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5); + memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->tx_ibias_5, r->tx_ibias_5, + CONF_NUMBER_OF_RATE_GROUPS); + memcpy(radio_parms->rx_fem_insertion_loss_5, + r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5); + + wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", + radio_parms, sizeof(*radio_parms)); + + ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); + if (ret < 0) + wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); + + kfree(radio_parms); + return ret; +} + int wl1271_cmd_join(struct wl1271 *wl) { static bool do_cal = true; diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 9d7061b3c8a0..b4fa4acb9229 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h @@ -31,6 +31,8 @@ struct acx_header; int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, size_t res_len); +int wl1271_cmd_general_parms(struct wl1271 *wl); +int wl1271_cmd_radio_parms(struct wl1271 *wl); int wl1271_cmd_join(struct wl1271 *wl); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); @@ -418,6 +420,76 @@ enum wl1271_channel_tune_bands { #define TEST_CMD_P2G_CAL 0x02 #define TEST_CMD_CHANNEL_TUNE 0x0d #define TEST_CMD_UPDATE_PD_REFERENCE_POINT 0x1d +#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 +#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E + +struct wl1271_general_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + u8 ref_clk; + u8 settling_time; + u8 clk_valid_on_wakeup; + u8 dc2dcmode; + u8 single_dual_band; + + u8 tx_bip_fem_autodetect; + u8 tx_bip_fem_manufacturer; + u8 settings; +} __attribute__ ((packed)); + +struct wl1271_radio_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + /* Static radio parameters */ + /* 2.4GHz */ + u8 rx_trace_loss; + u8 tx_trace_loss; + s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; + + /* 5GHz */ + u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; + + /* Dynamic radio parameters */ + /* 2.4GHz */ + __le16 tx_ref_pd_voltage; + s8 tx_ref_power; + s8 tx_offset_db; + + s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; + + s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; + s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; + s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS]; + + u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; + u8 rx_fem_insertion_loss; + + u8 padding2; + + /* 5GHz */ + __le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; + s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; + + s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; + + s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; + s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; + + /* FIXME: this is inconsistent with the types for 2.4GHz */ + s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; + s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; + + u8 padding3[2]; +} __attribute__ ((packed)); struct wl1271_cmd_cal_channel_tune { struct wl1271_cmd_header header; diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 95ee0368438a..44896accffd4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -193,112 +193,6 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl) return 0; } -int wl1271_init_general_parms(struct wl1271 *wl) -{ - struct wl1271_general_parms *gen_parms; - struct conf_general_parms *g = &wl->conf.init.genparam; - int ret; - - gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); - if (!gen_parms) - return -ENOMEM; - - gen_parms->id = TEST_CMD_INI_FILE_GENERAL_PARAM; - - gen_parms->ref_clk = g->ref_clk; - gen_parms->settling_time = g->settling_time; - gen_parms->clk_valid_on_wakeup = g->clk_valid_on_wakeup; - gen_parms->dc2dcmode = g->dc2dcmode; - gen_parms->single_dual_band = g->single_dual_band; - gen_parms->tx_bip_fem_autodetect = g->tx_bip_fem_autodetect; - gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer; - gen_parms->settings = g->settings; - - ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); - if (ret < 0) { - wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); - return ret; - } - - kfree(gen_parms); - return 0; -} - -int wl1271_init_radio_parms(struct wl1271 *wl) -{ - struct wl1271_radio_parms *radio_parms; - struct conf_radio_parms *r = &wl->conf.init.radioparam; - int i, ret; - - radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); - if (!radio_parms) - return -ENOMEM; - - radio_parms->id = TEST_CMD_INI_FILE_RADIO_PARAM; - - /* Static radio parameters */ - radio_parms->rx_trace_loss = r->rx_trace_loss; - radio_parms->tx_trace_loss = r->tx_trace_loss; - memcpy(radio_parms->rx_rssi_and_proc_compens, - r->rx_rssi_and_proc_compens, - CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE); - - memcpy(radio_parms->rx_trace_loss_5, r->rx_trace_loss_5, - CONF_NUMBER_OF_SUB_BANDS_5); - memcpy(radio_parms->tx_trace_loss_5, r->tx_trace_loss_5, - CONF_NUMBER_OF_SUB_BANDS_5); - memcpy(radio_parms->rx_rssi_and_proc_compens_5, - r->rx_rssi_and_proc_compens_5, - CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE); - - /* Dynamic radio parameters */ - radio_parms->tx_ref_pd_voltage = cpu_to_le16(r->tx_ref_pd_voltage); - radio_parms->tx_ref_power = r->tx_ref_power; - radio_parms->tx_offset_db = r->tx_offset_db; - - memcpy(radio_parms->tx_rate_limits_normal, r->tx_rate_limits_normal, - CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded, - CONF_NUMBER_OF_RATE_GROUPS); - - memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b, - CONF_NUMBER_OF_CHANNELS_2_4); - memcpy(radio_parms->tx_channel_limits_ofdm, r->tx_channel_limits_ofdm, - CONF_NUMBER_OF_CHANNELS_2_4); - memcpy(radio_parms->tx_pdv_rate_offsets, r->tx_pdv_rate_offsets, - CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS); - - radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss; - - for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++) - radio_parms->tx_ref_pd_voltage_5[i] = - cpu_to_le16(r->tx_ref_pd_voltage_5[i]); - memcpy(radio_parms->tx_ref_power_5, r->tx_ref_power_5, - CONF_NUMBER_OF_SUB_BANDS_5); - memcpy(radio_parms->tx_offset_db_5, r->tx_offset_db_5, - CONF_NUMBER_OF_SUB_BANDS_5); - memcpy(radio_parms->tx_rate_limits_normal_5, - r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_rate_limits_degraded_5, - r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_channel_limits_ofdm_5, - r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5); - memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5, - CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->tx_ibias_5, r->tx_ibias_5, - CONF_NUMBER_OF_RATE_GROUPS); - memcpy(radio_parms->rx_fem_insertion_loss_5, - r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5); - - ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); - if (ret < 0) - wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); - - kfree(radio_parms); - return ret; -} - int wl1271_hw_init(struct wl1271 *wl) { int ret; @@ -306,11 +200,11 @@ int wl1271_hw_init(struct wl1271 *wl) /* FIXME: the following parameter setting functions return error * codes - the reason is so far unknown. The -EIO is therefore * ignored for the time being. */ - ret = wl1271_init_general_parms(wl); + ret = wl1271_cmd_general_parms(wl); if (ret < 0 && ret != -EIO) return ret; - ret = wl1271_init_radio_parms(wl); + ret = wl1271_cmd_radio_parms(wl); if (ret < 0 && ret != -EIO) return ret; diff --git a/drivers/net/wireless/wl12xx/wl1271_init.h b/drivers/net/wireless/wl12xx/wl1271_init.h index 539b57f207c6..930677fbe852 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.h +++ b/drivers/net/wireless/wl12xx/wl1271_init.h @@ -28,77 +28,5 @@ int wl1271_hw_init_power_auth(struct wl1271 *wl); int wl1271_hw_init(struct wl1271 *wl); -int wl1271_init_general_parms(struct wl1271 *wl); -int wl1271_init_radio_parms(struct wl1271 *wl); - -/* These are not really a TEST_CMD, but the ref driver uses them as such */ -#define TEST_CMD_INI_FILE_RADIO_PARAM 0x19 -#define TEST_CMD_INI_FILE_GENERAL_PARAM 0x1E - -struct wl1271_general_parms { - u8 id; - u8 padding[3]; - - u8 ref_clk; - u8 settling_time; - u8 clk_valid_on_wakeup; - u8 dc2dcmode; - u8 single_dual_band; - - u8 tx_bip_fem_autodetect; - u8 tx_bip_fem_manufacturer; - u8 settings; -} __attribute__ ((packed)); - -struct wl1271_radio_parms { - u8 id; - u8 padding[3]; - - /* Static radio parameters */ - /* 2.4GHz */ - u8 rx_trace_loss; - u8 tx_trace_loss; - s8 rx_rssi_and_proc_compens[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; - - /* 5GHz */ - u8 rx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; - u8 tx_trace_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; - s8 rx_rssi_and_proc_compens_5[CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE]; - - /* Dynamic radio parameters */ - /* 2.4GHz */ - __le16 tx_ref_pd_voltage; - s8 tx_ref_power; - s8 tx_offset_db; - - s8 tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; - - s8 tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; - s8 tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; - s8 tx_pdv_rate_offsets[CONF_NUMBER_OF_RATE_GROUPS]; - - u8 tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; - u8 rx_fem_insertion_loss; - - u8 padding2; - - /* 5GHz */ - __le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; - s8 tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; - s8 tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; - - s8 tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; - s8 tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; - - s8 tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; - s8 tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; - - /* FIXME: this is inconsistent with the types for 2.4GHz */ - s8 tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; - s8 rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; - - u8 padding3[2]; -} __attribute__ ((packed)); #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index d4e603993996..b75557e0e686 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -357,11 +357,11 @@ static int wl1271_plt_init(struct wl1271 *wl) /* FIXME: the following parameter setting functions return error * codes - the reason is so far unknown. The -EIO is therefore * ignored for the time being. */ - ret = wl1271_init_general_parms(wl); + ret = wl1271_cmd_general_parms(wl); if (ret < 0 && ret != -EIO) return ret; - ret = wl1271_init_radio_parms(wl); + ret = wl1271_cmd_radio_parms(wl); if (ret < 0 && ret != -EIO) return ret; -- cgit v1.2.3 From 4a90406b876cade9bb8d9c95b048d60fb979ba6b Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 23 Nov 2009 23:22:18 +0200 Subject: wl1271: remove workaround to ignore -EIO from radio and general params We were ignoring the -EIO return value from wl1271_cmd_radio_params() and wl1271_cmd_general_params(), because they were always returning an error and we didn't know why. Now this has been fixed, so the workaround can be removed. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_init.c | 7 ++----- drivers/net/wireless/wl12xx/wl1271_main.c | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 44896accffd4..11249b436cf1 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c @@ -197,15 +197,12 @@ int wl1271_hw_init(struct wl1271 *wl) { int ret; - /* FIXME: the following parameter setting functions return error - * codes - the reason is so far unknown. The -EIO is therefore - * ignored for the time being. */ ret = wl1271_cmd_general_parms(wl); - if (ret < 0 && ret != -EIO) + if (ret < 0) return ret; ret = wl1271_cmd_radio_parms(wl); - if (ret < 0 && ret != -EIO) + if (ret < 0) return ret; /* Template settings */ diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index b75557e0e686..64d05265f7e0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -354,15 +354,12 @@ static int wl1271_plt_init(struct wl1271 *wl) { int ret; - /* FIXME: the following parameter setting functions return error - * codes - the reason is so far unknown. The -EIO is therefore - * ignored for the time being. */ ret = wl1271_cmd_general_parms(wl); - if (ret < 0 && ret != -EIO) + if (ret < 0) return ret; ret = wl1271_cmd_radio_parms(wl); - if (ret < 0 && ret != -EIO) + if (ret < 0) return ret; ret = wl1271_acx_init_mem_config(wl); -- cgit v1.2.3 From c7c8adb53ff3e8fa3cf7a5144bd2791c4da2c07d Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 23 Nov 2009 23:22:19 +0200 Subject: wl1271: Remove REF_CLK hack This hack was totally wrong and was "needed" because of a problem in the way we were sending the GENERAL_PARMS command to the firmware. Now that that problem has been fixed, this hack can be removed. Signed-off-by: Luciano Coelho Reviewed-by: Juuso Oikarinen Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_main.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 64d05265f7e0..b62c00ff42fe 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -251,14 +251,7 @@ static struct conf_drv_settings default_conf = { }, .sr_enable = 1, .genparam = { - /* - * FIXME: The correct value CONF_REF_CLK_38_4_E - * causes the firmware to crash on boot. - * The value 5 apparently is an - * unnoficial XTAL configuration of the - * same frequency, which appears to work. - */ - .ref_clk = 5, + .ref_clk = CONF_REF_CLK_38_4_E, .settling_time = 5, .clk_valid_on_wakeup = 0, .dc2dcmode = 0, -- cgit v1.2.3 From 38a522e6bc0fcd9848b91366ec899f1c2cb23609 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 23 Nov 2009 22:44:47 +0100 Subject: rt2x00: Only initialize HT on rt2800 devices that support it. Some RT28xx/RT30xx devices don't support 802.11n, when they are combined with the RF2020 chipset. Ensure that HT is disabled for these devices. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index e94f1e13fea9..fcd0c88d5f04 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2072,7 +2072,11 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize HT information. */ - spec->ht.ht_supported = true; + if (!rt2x00_rf(chip, RF2020)) + spec->ht.ht_supported = true; + else + spec->ht.ht_supported = false; + spec->ht.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_GRN_FLD | -- cgit v1.2.3 From 6a6f455ca4120ae0c6a1bb77d58ba2f5e3e96afd Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 23 Nov 2009 22:44:48 +0100 Subject: rt2x00: Remove unused variable frame_control from rt2x00mac_tx. As additional fallout also remove the also unused variable ieee80211hdr. Reported-by: Johannes Stezenbach Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00mac.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 9c90ceb0ffcc..de549c244ed8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -103,10 +103,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; enum data_queue_qid qid = skb_get_queue_mapping(skb); struct data_queue *queue; - u16 frame_control; /* * Mac80211 might be calling this function while we are trying @@ -141,7 +139,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * either RTS or CTS-to-self frame and handles everything * inside the hardware. */ - frame_control = le16_to_cpu(ieee80211hdr->frame_control); if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS | IEEE80211_TX_RC_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { -- cgit v1.2.3 From ee303e543e7d5f0d38197298adf0c4fb079094e9 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 23 Nov 2009 22:44:49 +0100 Subject: rt2x00: Clean up use of rt2x00_intf_is_pci. RT chipsets are unique across both PCI and USB busses, and don't overlap. Therefore there is no need to test for bus type when only checking for chipset type. Remove the redundant checks. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index fcd0c88d5f04..02ffcf54bf09 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -217,14 +217,12 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, { u32 reg; - if (rt2x00_intf_is_pci(rt2x00dev)) { - /* - * RT2880 and RT3052 don't support MCU requests. - */ - if (rt2x00_rt(&rt2x00dev->chip, RT2880) || - rt2x00_rt(&rt2x00dev->chip, RT3052)) - return; - } + /* + * RT2880 and RT3052 don't support MCU requests. + */ + if (rt2x00_rt(&rt2x00dev->chip, RT2880) || + rt2x00_rt(&rt2x00dev->chip, RT3052)) + return; mutex_lock(&rt2x00dev->csr_mutex); @@ -1482,8 +1480,7 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 105, 0x05); } - if (rt2x00_intf_is_pci(rt2x00dev) && - rt2x00_rt(&rt2x00dev->chip, RT3052)) { + if (rt2x00_rt(&rt2x00dev->chip, RT3052)) { rt2800_bbp_write(rt2x00dev, 31, 0x08); rt2800_bbp_write(rt2x00dev, 78, 0x0e); rt2800_bbp_write(rt2x00dev, 80, 0x08); -- cgit v1.2.3 From 95d69aa046f75c750f18119810b6f58d397fb576 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 23 Nov 2009 22:44:50 +0100 Subject: rt2x00: Fix typo (lengt --> length) in rt2x00queue.c Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index eaedee8c05c8..32d4aeabfd4d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -162,10 +162,10 @@ void rt2x00queue_align_frame(struct sk_buff *skb) skb_trim(skb, frame_length); } -void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_lengt) +void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length) { unsigned int frame_length = skb->len; - unsigned int align = ALIGN_SIZE(skb, header_lengt); + unsigned int align = ALIGN_SIZE(skb, header_length); if (!align) return; -- cgit v1.2.3 From 04d0362e2fa9d5f1ab560d0d59d04a535b4f3973 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 23 Nov 2009 22:44:51 +0100 Subject: rt2x00: Whitespace cleanup. Clean up the use of whitespace in the initialization of the rt2x00_ops structures. This is preparatory for a later patch that adds members to that structure, which require different whitespace alignment. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 26 +++++++++++++------------- drivers/net/wireless/rt2x00/rt2500pci.c | 26 +++++++++++++------------- drivers/net/wireless/rt2x00/rt2500usb.c | 26 +++++++++++++------------- drivers/net/wireless/rt2x00/rt2800pci.c | 24 ++++++++++++------------ drivers/net/wireless/rt2x00/rt2800usb.c | 24 ++++++++++++------------ drivers/net/wireless/rt2x00/rt61pci.c | 24 ++++++++++++------------ drivers/net/wireless/rt2x00/rt73usb.c | 24 ++++++++++++------------ 7 files changed, 87 insertions(+), 87 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 6e68bc7efd4e..7f900be39e5a 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1623,20 +1623,20 @@ static const struct data_queue_desc rt2400pci_queue_atim = { }; static const struct rt2x00_ops rt2400pci_ops = { - .name = KBUILD_MODNAME, - .max_sta_intf = 1, - .max_ap_intf = 1, - .eeprom_size = EEPROM_SIZE, - .rf_size = RF_SIZE, - .tx_queues = NUM_TX_QUEUES, - .rx = &rt2400pci_queue_rx, - .tx = &rt2400pci_queue_tx, - .bcn = &rt2400pci_queue_bcn, - .atim = &rt2400pci_queue_atim, - .lib = &rt2400pci_rt2x00_ops, - .hw = &rt2400pci_mac80211_ops, + .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 1, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, + .rx = &rt2400pci_queue_rx, + .tx = &rt2400pci_queue_tx, + .bcn = &rt2400pci_queue_bcn, + .atim = &rt2400pci_queue_atim, + .lib = &rt2400pci_rt2x00_ops, + .hw = &rt2400pci_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS - .debugfs = &rt2400pci_rt2x00debug, + .debugfs = &rt2400pci_rt2x00debug, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 9a31e5e7b8df..30960fd8a449 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1922,20 +1922,20 @@ static const struct data_queue_desc rt2500pci_queue_atim = { }; static const struct rt2x00_ops rt2500pci_ops = { - .name = KBUILD_MODNAME, - .max_sta_intf = 1, - .max_ap_intf = 1, - .eeprom_size = EEPROM_SIZE, - .rf_size = RF_SIZE, - .tx_queues = NUM_TX_QUEUES, - .rx = &rt2500pci_queue_rx, - .tx = &rt2500pci_queue_tx, - .bcn = &rt2500pci_queue_bcn, - .atim = &rt2500pci_queue_atim, - .lib = &rt2500pci_rt2x00_ops, - .hw = &rt2500pci_mac80211_ops, + .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 1, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, + .rx = &rt2500pci_queue_rx, + .tx = &rt2500pci_queue_tx, + .bcn = &rt2500pci_queue_bcn, + .atim = &rt2500pci_queue_atim, + .lib = &rt2500pci_rt2x00_ops, + .hw = &rt2500pci_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS - .debugfs = &rt2500pci_rt2x00debug, + .debugfs = &rt2500pci_rt2x00debug, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index b2de43e4f656..02290f68113e 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1823,20 +1823,20 @@ static const struct data_queue_desc rt2500usb_queue_atim = { }; static const struct rt2x00_ops rt2500usb_ops = { - .name = KBUILD_MODNAME, - .max_sta_intf = 1, - .max_ap_intf = 1, - .eeprom_size = EEPROM_SIZE, - .rf_size = RF_SIZE, - .tx_queues = NUM_TX_QUEUES, - .rx = &rt2500usb_queue_rx, - .tx = &rt2500usb_queue_tx, - .bcn = &rt2500usb_queue_bcn, - .atim = &rt2500usb_queue_atim, - .lib = &rt2500usb_rt2x00_ops, - .hw = &rt2500usb_mac80211_ops, + .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 1, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, + .rx = &rt2500usb_queue_rx, + .tx = &rt2500usb_queue_tx, + .bcn = &rt2500usb_queue_bcn, + .atim = &rt2500usb_queue_atim, + .lib = &rt2500usb_rt2x00_ops, + .hw = &rt2500usb_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS - .debugfs = &rt2500usb_rt2x00debug, + .debugfs = &rt2500usb_rt2x00debug, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 87a5094ae953..029a45f0cb99 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1201,19 +1201,19 @@ static const struct data_queue_desc rt2800pci_queue_bcn = { }; static const struct rt2x00_ops rt2800pci_ops = { - .name = KBUILD_MODNAME, - .max_sta_intf = 1, - .max_ap_intf = 8, - .eeprom_size = EEPROM_SIZE, - .rf_size = RF_SIZE, - .tx_queues = NUM_TX_QUEUES, - .rx = &rt2800pci_queue_rx, - .tx = &rt2800pci_queue_tx, - .bcn = &rt2800pci_queue_bcn, - .lib = &rt2800pci_rt2x00_ops, - .hw = &rt2800_mac80211_ops, + .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 8, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, + .rx = &rt2800pci_queue_rx, + .tx = &rt2800pci_queue_tx, + .bcn = &rt2800pci_queue_bcn, + .lib = &rt2800pci_rt2x00_ops, + .hw = &rt2800_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS - .debugfs = &rt2800_rt2x00debug, + .debugfs = &rt2800_rt2x00debug, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 9ab15c480701..208316af6d99 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -790,19 +790,19 @@ static const struct data_queue_desc rt2800usb_queue_bcn = { }; static const struct rt2x00_ops rt2800usb_ops = { - .name = KBUILD_MODNAME, - .max_sta_intf = 1, - .max_ap_intf = 8, - .eeprom_size = EEPROM_SIZE, - .rf_size = RF_SIZE, - .tx_queues = NUM_TX_QUEUES, - .rx = &rt2800usb_queue_rx, - .tx = &rt2800usb_queue_tx, - .bcn = &rt2800usb_queue_bcn, - .lib = &rt2800usb_rt2x00_ops, - .hw = &rt2800_mac80211_ops, + .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 8, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, + .rx = &rt2800usb_queue_rx, + .tx = &rt2800usb_queue_tx, + .bcn = &rt2800usb_queue_bcn, + .lib = &rt2800usb_rt2x00_ops, + .hw = &rt2800_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS - .debugfs = &rt2800_rt2x00debug, + .debugfs = &rt2800_rt2x00debug, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index bf04605896c7..4cb9afeed9d7 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2788,19 +2788,19 @@ static const struct data_queue_desc rt61pci_queue_bcn = { }; static const struct rt2x00_ops rt61pci_ops = { - .name = KBUILD_MODNAME, - .max_sta_intf = 1, - .max_ap_intf = 4, - .eeprom_size = EEPROM_SIZE, - .rf_size = RF_SIZE, - .tx_queues = NUM_TX_QUEUES, - .rx = &rt61pci_queue_rx, - .tx = &rt61pci_queue_tx, - .bcn = &rt61pci_queue_bcn, - .lib = &rt61pci_rt2x00_ops, - .hw = &rt61pci_mac80211_ops, + .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 4, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, + .rx = &rt61pci_queue_rx, + .tx = &rt61pci_queue_tx, + .bcn = &rt61pci_queue_bcn, + .lib = &rt61pci_rt2x00_ops, + .hw = &rt61pci_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS - .debugfs = &rt61pci_rt2x00debug, + .debugfs = &rt61pci_rt2x00debug, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 5bbcf6626f7d..d13a051b39af 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2306,19 +2306,19 @@ static const struct data_queue_desc rt73usb_queue_bcn = { }; static const struct rt2x00_ops rt73usb_ops = { - .name = KBUILD_MODNAME, - .max_sta_intf = 1, - .max_ap_intf = 4, - .eeprom_size = EEPROM_SIZE, - .rf_size = RF_SIZE, - .tx_queues = NUM_TX_QUEUES, - .rx = &rt73usb_queue_rx, - .tx = &rt73usb_queue_tx, - .bcn = &rt73usb_queue_bcn, - .lib = &rt73usb_rt2x00_ops, - .hw = &rt73usb_mac80211_ops, + .name = KBUILD_MODNAME, + .max_sta_intf = 1, + .max_ap_intf = 4, + .eeprom_size = EEPROM_SIZE, + .rf_size = RF_SIZE, + .tx_queues = NUM_TX_QUEUES, + .rx = &rt73usb_queue_rx, + .tx = &rt73usb_queue_tx, + .bcn = &rt73usb_queue_bcn, + .lib = &rt73usb_rt2x00_ops, + .hw = &rt73usb_mac80211_ops, #ifdef CONFIG_RT2X00_LIB_DEBUGFS - .debugfs = &rt73usb_rt2x00debug, + .debugfs = &rt73usb_rt2x00debug, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; -- cgit v1.2.3 From e6218cc47bd54710dc523e8c983ceddba625e3ae Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Mon, 23 Nov 2009 22:44:52 +0100 Subject: rt2x00: Centralize setting of extra TX headroom requested by rt2x00. Set the value of extra_tx_headroom in a central place, rather than in each of the drivers. This is preparatory for taking alignment space into account in the TX headroom requested by rt2x00. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500pci.c | 3 +-- drivers/net/wireless/rt2x00/rt2500usb.c | 3 +-- drivers/net/wireless/rt2x00/rt2800lib.c | 6 ------ drivers/net/wireless/rt2x00/rt2800pci.c | 7 ++++--- drivers/net/wireless/rt2x00/rt2800usb.c | 1 + drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00dev.c | 5 +++++ drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 7f900be39e5a..e7f46405a418 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1432,7 +1432,6 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK; - rt2x00dev->hw->extra_tx_headroom = 0; SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -1629,6 +1628,7 @@ static const struct rt2x00_ops rt2400pci_ops = { .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .tx_queues = NUM_TX_QUEUES, + .extra_tx_headroom = 0, .rx = &rt2400pci_queue_rx, .tx = &rt2400pci_queue_tx, .bcn = &rt2400pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 30960fd8a449..408fcfc120f5 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1733,8 +1733,6 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK; - rt2x00dev->hw->extra_tx_headroom = 0; - SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, rt2x00_eeprom_addr(rt2x00dev, @@ -1928,6 +1926,7 @@ static const struct rt2x00_ops rt2500pci_ops = { .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .tx_queues = NUM_TX_QUEUES, + .extra_tx_headroom = 0, .rx = &rt2500pci_queue_rx, .tx = &rt2500pci_queue_tx, .bcn = &rt2500pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 02290f68113e..83f2592c59de 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1656,8 +1656,6 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK; - rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; - SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, rt2x00_eeprom_addr(rt2x00dev, @@ -1829,6 +1827,7 @@ static const struct rt2x00_ops rt2500usb_ops = { .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .tx_queues = NUM_TX_QUEUES, + .extra_tx_headroom = TXD_DESC_SIZE, .rx = &rt2500usb_queue_rx, .tx = &rt2500usb_queue_tx, .bcn = &rt2500usb_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 02ffcf54bf09..eb1e1d00bec3 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2030,12 +2030,6 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK; - if (rt2x00_intf_is_usb(rt2x00dev)) - rt2x00dev->hw->extra_tx_headroom = - TXINFO_DESC_SIZE + TXWI_DESC_SIZE; - else if (rt2x00_intf_is_pci(rt2x00dev)) - rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE; - SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, rt2x00_eeprom_addr(rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 029a45f0cb99..dfc886fcb44d 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -652,7 +652,7 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); __le32 *txd = skbdesc->desc; - __le32 *txwi = (__le32 *)(skb->data - rt2x00dev->hw->extra_tx_headroom); + __le32 *txwi = (__le32 *)(skb->data - rt2x00dev->ops->extra_tx_headroom); u32 word; /* @@ -725,14 +725,14 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W1_BURST, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W1_SD_LEN0, - rt2x00dev->hw->extra_tx_headroom); + rt2x00dev->ops->extra_tx_headroom); rt2x00_set_field32(&word, TXD_W1_LAST_SEC0, 0); rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0); rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); rt2x00_set_field32(&word, TXD_W2_SD_PTR1, - skbdesc->skb_dma + rt2x00dev->hw->extra_tx_headroom); + skbdesc->skb_dma + rt2x00dev->ops->extra_tx_headroom); rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 3, &word); @@ -1207,6 +1207,7 @@ static const struct rt2x00_ops rt2800pci_ops = { .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .tx_queues = NUM_TX_QUEUES, + .extra_tx_headroom = TXWI_DESC_SIZE, .rx = &rt2800pci_queue_rx, .tx = &rt2800pci_queue_tx, .bcn = &rt2800pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 208316af6d99..af85d18cdbe7 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -796,6 +796,7 @@ static const struct rt2x00_ops rt2800usb_ops = { .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .tx_queues = NUM_TX_QUEUES, + .extra_tx_headroom = TXINFO_DESC_SIZE + TXWI_DESC_SIZE, .rx = &rt2800usb_queue_rx, .tx = &rt2800usb_queue_tx, .bcn = &rt2800usb_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 1cbb7ac2f32f..4d841c07c970 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -588,6 +588,7 @@ struct rt2x00_ops { const unsigned int eeprom_size; const unsigned int rf_size; const unsigned int tx_queues; + const unsigned int extra_tx_headroom; const struct data_queue_desc *rx; const struct data_queue_desc *tx; const struct data_queue_desc *bcn; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 4a4b7e42fe6e..06c43ca39bf8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -683,6 +683,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->queues = rt2x00dev->ops->tx_queues; + /* + * Initialize extra TX headroom required. + */ + rt2x00dev->hw->extra_tx_headroom = rt2x00dev->ops->extra_tx_headroom; + /* * Register HW. */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 4cb9afeed9d7..687e17dc2e9f 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2546,7 +2546,6 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK; - rt2x00dev->hw->extra_tx_headroom = 0; SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -2794,6 +2793,7 @@ static const struct rt2x00_ops rt61pci_ops = { .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .tx_queues = NUM_TX_QUEUES, + .extra_tx_headroom = 0, .rx = &rt61pci_queue_rx, .tx = &rt61pci_queue_tx, .bcn = &rt61pci_queue_bcn, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index d13a051b39af..ced3b6ab5e16 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2069,7 +2069,6 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK; - rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev); SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, @@ -2312,6 +2311,7 @@ static const struct rt2x00_ops rt73usb_ops = { .eeprom_size = EEPROM_SIZE, .rf_size = RF_SIZE, .tx_queues = NUM_TX_QUEUES, + .extra_tx_headroom = TXD_DESC_SIZE, .rx = &rt73usb_queue_rx, .tx = &rt73usb_queue_tx, .bcn = &rt73usb_queue_bcn, -- cgit v1.2.3 From 902b6667d3d17ac53ec62c036cd2bcf713c29d86 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 24 Nov 2009 11:33:27 +0800 Subject: iwmc3200wifi: Parse HT channels EEPROM entries The fat channels eeprom entries let us know if 11n is enabled or not. We update our wiphy supported bands based on that. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/eeprom.c | 30 ++++++++++++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/eeprom.h | 28 ++++++++++++++++++++-------- drivers/net/wireless/iwmc3200wifi/main.c | 6 ++++++ 3 files changed, 56 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c index 365910fbe01e..c574f58dfb20 100644 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.c +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c @@ -66,6 +66,10 @@ static struct iwm_eeprom_entry eeprom_map[] = { [IWM_EEPROM_SKU_CAP] = {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN}, + [IWM_EEPROM_FAT_CHANNELS_CAP] = + {"HT channels capabilities", IWM_EEPROM_FAT_CHANNELS_CAP_OFF, + IWM_EEPROM_FAT_CHANNELS_CAP_LEN}, + [IWM_EEPROM_CALIB_RXIQ_OFFSET] = {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN}, @@ -146,6 +150,32 @@ u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id) return iwm->eeprom + eeprom_map[eeprom_id].offset; } +int iwm_eeprom_fat_channels(struct iwm_priv *iwm) +{ + struct wiphy *wiphy = iwm_to_wiphy(iwm); + struct ieee80211_supported_band *band; + u16 *channels, i; + + channels = (u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_FAT_CHANNELS_CAP); + if (IS_ERR(channels)) + return PTR_ERR(channels); + + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + band->ht_cap.ht_supported = true; + + for (i = 0; i < IWM_EEPROM_FAT_CHANNELS_24; i++) + if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED)) + band->ht_cap.ht_supported = false; + + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + band->ht_cap.ht_supported = true; + for (i = IWM_EEPROM_FAT_CHANNELS_24; i < IWM_EEPROM_FAT_CHANNELS; i++) + if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED)) + band->ht_cap.ht_supported = false; + + return 0; +} + int iwm_eeprom_init(struct iwm_priv *iwm) { int i, ret = 0; diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.h b/drivers/net/wireless/iwmc3200wifi/eeprom.h index cdb31a6a1f5f..0f7f226916cf 100644 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.h +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.h @@ -48,6 +48,7 @@ enum { IWM_EEPROM_CARD_ID, IWM_EEPROM_RADIO_CONF, IWM_EEPROM_SKU_CAP, + IWM_EEPROM_FAT_CHANNELS_CAP, IWM_EEPROM_INDIRECT_OFFSET, IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET, @@ -58,14 +59,15 @@ enum { IWM_EEPROM_LAST, }; -#define IWM_EEPROM_SIG_OFF 0x00 -#define IWM_EEPROM_VERSION_OFF (0x54 << 1) -#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1) -#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1) -#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1) -#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1) -#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1) -#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1) +#define IWM_EEPROM_SIG_OFF 0x00 +#define IWM_EEPROM_VERSION_OFF (0x54 << 1) +#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1) +#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1) +#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1) +#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1) +#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1) +#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1) +#define IWM_EEPROM_FAT_CHANNELS_CAP_OFF (0xde << 1) #define IWM_EEPROM_SIG_LEN 4 #define IWM_EEPROM_VERSION_LEN 2 @@ -74,6 +76,7 @@ enum { #define IWM_EEPROM_CARD_ID_LEN 2 #define IWM_EEPROM_RADIO_CONF_LEN 2 #define IWM_EEPROM_SKU_CAP_LEN 2 +#define IWM_EEPROM_FAT_CHANNELS_CAP_LEN 40 #define IWM_EEPROM_INDIRECT_LEN 2 #define IWM_MAX_EEPROM_DATA_LEN 240 @@ -87,6 +90,14 @@ enum { #define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5) #define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6) +#define IWM_EEPROM_FAT_CHANNELS 20 +/* 2.4 gHz FAT primary channels: 1, 2, 3, 4, 5, 6, 7, 8, 9 */ +#define IWM_EEPROM_FAT_CHANNELS_24 9 +/* 5.2 gHz FAT primary channels: 36,44,52,60,100,108,116,124,132,149,157 */ +#define IWM_EEPROM_FAT_CHANNELS_52 11 + +#define IWM_EEPROM_FAT_CHANNEL_ENABLED (1 << 0) + enum { IWM_EEPROM_CALIB_CAL_HDR, IWM_EEPROM_CALIB_TX_POWER, @@ -110,5 +121,6 @@ struct iwm_eeprom_entry { int iwm_eeprom_init(struct iwm_priv *iwm); void iwm_eeprom_exit(struct iwm_priv *iwm); u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id); +int iwm_eeprom_fat_channels(struct iwm_priv *iwm); #endif diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 75f105a59543..365f3fc37d25 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -691,6 +691,12 @@ static int __iwm_up(struct iwm_priv *iwm) goto err_disable; } + ret = iwm_eeprom_fat_channels(iwm); + if (ret) { + IWM_ERR(iwm, "Couldnt read HT channels EEPROM entries\n"); + goto err_fw; + } + snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s", iwm->lmac_version, iwm->umac_version); -- cgit v1.2.3 From fe19176ea46db572f0dc2df8bfe1dc5d8751ab9e Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 24 Nov 2009 11:33:28 +0800 Subject: iwmc3200wifi: Dont set the UMAC power limit when interface is down When we're down, we shouldnt try to set the UMAC power limit. We just return 0 instead, and cfg80211 toggles the soft rfkill state. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 2e00a4b389e6..7cfc2c0a1fbc 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -678,6 +678,9 @@ static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, case TX_POWER_AUTOMATIC: return 0; case TX_POWER_FIXED: + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return 0; + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, CFG_TX_PWR_LIMIT_USR, dbm * 2); if (ret < 0) @@ -685,6 +688,7 @@ static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, return iwm_tx_power_trigger(iwm); default: + IWM_ERR(iwm, "Unsupported power type: %d\n", type); return -EOPNOTSUPP; } -- cgit v1.2.3 From 0bed08de91c41b21447d704995a438d4536586ba Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 24 Nov 2009 11:33:29 +0800 Subject: iwmc3200wifi: Update wireless_mode with eeprom values The iwmc3200wifi eeprom contains information about the available PHYs on the chip. We should update our wireless_mode setting and profile according to it. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/eeprom.c | 20 ++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/eeprom.h | 1 + drivers/net/wireless/iwmc3200wifi/main.c | 19 ++++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c index c574f58dfb20..8091421ee5e5 100644 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.c +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c @@ -176,6 +176,26 @@ int iwm_eeprom_fat_channels(struct iwm_priv *iwm) return 0; } +u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm) +{ + u16 sku_cap; + u32 wireless_mode = 0; + + sku_cap = *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP)); + + if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_24GHZ) + wireless_mode |= WIRELESS_MODE_11G; + + if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_52GHZ) + wireless_mode |= WIRELESS_MODE_11A; + + if (sku_cap & IWM_EEPROM_SKU_CAP_11N_ENABLE) + wireless_mode |= WIRELESS_MODE_11N; + + return wireless_mode; +} + + int iwm_eeprom_init(struct iwm_priv *iwm) { int i, ret = 0; diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.h b/drivers/net/wireless/iwmc3200wifi/eeprom.h index 0f7f226916cf..4e3a3fdab0d3 100644 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.h +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.h @@ -122,5 +122,6 @@ int iwm_eeprom_init(struct iwm_priv *iwm); void iwm_eeprom_exit(struct iwm_priv *iwm); u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id); int iwm_eeprom_fat_channels(struct iwm_priv *iwm); +u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm); #endif diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 365f3fc37d25..e61265af92cd 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -80,7 +80,8 @@ static struct iwm_conf def_iwm_conf = { .assoc_timeout = 2, .roam_timeout = 10, - .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G, + .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G | + WIRELESS_MODE_11N, .coexist_mode = COEX_MODE_CM, /* IBSS */ @@ -630,6 +631,7 @@ static int __iwm_up(struct iwm_priv *iwm) int ret; struct iwm_notif *notif_reboot, *notif_ack = NULL; struct wiphy *wiphy = iwm_to_wiphy(iwm); + u32 wireless_mode; ret = iwm_bus_enable(iwm); if (ret) { @@ -697,6 +699,21 @@ static int __iwm_up(struct iwm_priv *iwm) goto err_fw; } + /* + * Read our SKU capabilities. + * If it's valid, we overwrite the wireless mode conf entry and the + * current profile one. + */ + wireless_mode = iwm_eeprom_wireless_mode(iwm); + if (wireless_mode) { + iwm->conf.wireless_mode = wireless_mode; + if (iwm->umac_profile) + iwm->umac_profile->wireless_mode = + iwm->conf.wireless_mode; + } else + IWM_ERR(iwm, "Wrong SKU capabilities: 0x%x\n", + *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP))); + snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s", iwm->lmac_version, iwm->umac_version); -- cgit v1.2.3 From 2351178c52fedf1846c84b35418f4102487ec00e Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Nov 2009 11:33:30 +0800 Subject: iwmc3200wifi: Set wireless mode correctly Set the wireless mode with regard to both the driver's configuration and the device's EEPROM result. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index e61265af92cd..92e4eaf32ff2 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -701,12 +701,12 @@ static int __iwm_up(struct iwm_priv *iwm) /* * Read our SKU capabilities. - * If it's valid, we overwrite the wireless mode conf entry and the - * current profile one. + * If it's valid, we AND the configured wireless mode with the + * device EEPROM value as the current profile wireless mode. */ wireless_mode = iwm_eeprom_wireless_mode(iwm); if (wireless_mode) { - iwm->conf.wireless_mode = wireless_mode; + iwm->conf.wireless_mode &= wireless_mode; if (iwm->umac_profile) iwm->umac_profile->wireless_mode = iwm->conf.wireless_mode; -- cgit v1.2.3 From a7af530d45969a63e20708417b70c547596ce3a9 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 24 Nov 2009 11:33:31 +0800 Subject: iwmc3200wifi: 802.11n Tx aggregation support To support 802.11n Tx aggregation support with iwmc3200 wifi, we have to handle the UMAC_CMD_OPCODE_STOP_RESUME_STA_TX notification from the UMAC. Before sending an AddBA, the UMAC synchronizes with the host in order to know what is the last Tx frame it's supposed to receive before it will be able to start the actual aggregation session. We thus have to keep track of the last sequence number that is scheduled for transmission on a particular RAxTID, send an answer to the UMAC with this sequence number. The UMAC then does the BA negociation and once it's done with it sends a new UMAC_CMD_OPCODE_STOP_RESUME_STA_TX notification to let us know that we can resume the Tx flow on the specified RAxTID. Signed-off-by: Samuel Ortiz Reviewed-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 31 +++++++++++++ drivers/net/wireless/iwmc3200wifi/commands.h | 10 +++++ drivers/net/wireless/iwmc3200wifi/iwm.h | 10 +++++ drivers/net/wireless/iwmc3200wifi/main.c | 11 ++++- drivers/net/wireless/iwmc3200wifi/netdev.c | 8 ++++ drivers/net/wireless/iwmc3200wifi/rx.c | 66 ++++++++++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/tx.c | 57 +++++++++++++++++++++--- drivers/net/wireless/iwmc3200wifi/umac.h | 34 +++++++++++++- 8 files changed, 217 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 7e12438551ba..46ca7c58f5ac 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -929,3 +929,34 @@ int iwm_target_reset(struct iwm_priv *iwm) return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); } + +int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, + struct iwm_umac_notif_stop_resume_tx *ntf) +{ + struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; + struct iwm_umac_cmd umac_cmd; + struct iwm_umac_cmd_stop_resume_tx stp_res_cmd; + struct iwm_sta_info *sta_info; + u8 sta_id = STA_ID_N_COLOR_ID(ntf->sta_id); + int i; + + sta_info = &iwm->sta_table[sta_id]; + if (!sta_info->valid) { + IWM_ERR(iwm, "Invalid STA: %d\n", sta_id); + return -EINVAL; + } + + umac_cmd.id = UMAC_CMD_OPCODE_STOP_RESUME_STA_TX; + umac_cmd.resp = 0; + + stp_res_cmd.flags = ntf->flags; + stp_res_cmd.sta_id = ntf->sta_id; + stp_res_cmd.stop_resume_tid_msk = ntf->stop_resume_tid_msk; + for (i = 0; i < IWM_UMAC_TID_NR; i++) + stp_res_cmd.last_seq_num[i] = + sta_info->tid_info[i].last_seq_num; + + return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stp_res_cmd, + sizeof(struct iwm_umac_cmd_stop_resume_tx)); + +} diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index b36be2b23a3c..95cdf941b222 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -450,6 +450,14 @@ struct iwm_umac_cmd_stats_req { __le32 flags; } __attribute__ ((packed)); +struct iwm_umac_cmd_stop_resume_tx { + u8 flags; + u8 sta_id; + __le16 stop_resume_tid_msk; + __le16 last_seq_num[IWM_UMAC_TID_NR]; + u16 reserved; +} __attribute__ ((packed)); + /* LMAC commands */ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); int iwm_send_prio_table(struct iwm_priv *iwm); @@ -478,6 +486,8 @@ int iwm_send_umac_channel_list(struct iwm_priv *iwm); int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, int ssid_num); int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); +int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, + struct iwm_umac_notif_stop_resume_tx *ntf); /* UDMA commands */ int iwm_target_reset(struct iwm_priv *iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index a9bf6bc97bea..8d091f918f33 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -131,11 +131,18 @@ struct iwm_notif { unsigned long buf_size; }; +struct iwm_tid_info { + __le16 last_seq_num; + bool stopped; + struct mutex mutex; +}; + struct iwm_sta_info { u8 addr[ETH_ALEN]; bool valid; bool qos; u8 color; + struct iwm_tid_info tid_info[IWM_UMAC_TID_NR]; }; struct iwm_tx_info { @@ -185,6 +192,8 @@ struct iwm_key { struct iwm_tx_queue { int id; struct sk_buff_head queue; + struct sk_buff_head stopped_queue; + spinlock_t lock; struct workqueue_struct *wq; struct work_struct worker; u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE]; @@ -341,6 +350,7 @@ int iwm_up(struct iwm_priv *iwm); int iwm_down(struct iwm_priv *iwm); /* TX API */ +u16 iwm_tid_to_queue(u16 tid); void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); void iwm_tx_worker(struct work_struct *work); int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 92e4eaf32ff2..087f04355c1b 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -248,7 +248,7 @@ static void iwm_watchdog(unsigned long data) int iwm_priv_init(struct iwm_priv *iwm) { - int i; + int i, j; char name[32]; iwm->status = 0; @@ -292,6 +292,8 @@ int iwm_priv_init(struct iwm_priv *iwm) return -EAGAIN; skb_queue_head_init(&iwm->txq[i].queue); + skb_queue_head_init(&iwm->txq[i].stopped_queue); + spin_lock_init(&iwm->txq[i].lock); } for (i = 0; i < IWM_NUM_KEYS; i++) @@ -299,6 +301,12 @@ int iwm_priv_init(struct iwm_priv *iwm) iwm->default_key = -1; + for (i = 0; i < IWM_STA_TABLE_NUM; i++) + for (j = 0; j < IWM_UMAC_TID_NR; j++) { + mutex_init(&iwm->sta_table[i].tid_info[j].mutex); + iwm->sta_table[i].tid_info[j].stopped = false; + } + init_timer(&iwm->watchdog); iwm->watchdog.function = iwm_watchdog; iwm->watchdog.data = (unsigned long)iwm; @@ -572,6 +580,7 @@ void iwm_link_off(struct iwm_priv *iwm) for (i = 0; i < IWM_TX_QUEUES; i++) { skb_queue_purge(&iwm->txq[i].queue); + skb_queue_purge(&iwm->txq[i].stopped_queue); iwm->txq[i].concat_count = 0; iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf; diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index 4f8dbdd7b917..e4f0f8705f65 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -76,6 +76,14 @@ static int iwm_stop(struct net_device *ndev) */ static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; +u16 iwm_tid_to_queue(u16 tid) +{ + if (tid > IWM_UMAC_TID_NR - 2) + return -EINVAL; + + return iwm_1d_to_queue[tid]; +} + static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) { skb->priority = cfg80211_classify8021d(skb); diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index bdb1d7e7979d..72c27a3e5528 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -1087,6 +1087,71 @@ static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf, return 0; } +static int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf, + unsigned long buf_size, + struct iwm_wifi_cmd *cmd) +{ + struct iwm_umac_notif_stop_resume_tx *stp_res_tx = + (struct iwm_umac_notif_stop_resume_tx *)buf; + struct iwm_sta_info *sta_info; + struct iwm_tid_info *tid_info; + u8 sta_id = STA_ID_N_COLOR_ID(stp_res_tx->sta_id); + u16 tid_msk = le16_to_cpu(stp_res_tx->stop_resume_tid_msk); + int bit, ret = 0; + bool stop = false; + + IWM_DBG_NTF(iwm, DBG, "stop/resume notification:\n" + "\tflags: 0x%x\n" + "\tSTA id: %d\n" + "\tTID bitmask: 0x%x\n", + stp_res_tx->flags, stp_res_tx->sta_id, + stp_res_tx->stop_resume_tid_msk); + + if (stp_res_tx->flags & UMAC_STOP_TX_FLAG) + stop = true; + + sta_info = &iwm->sta_table[sta_id]; + if (!sta_info->valid) { + IWM_ERR(iwm, "Stoping an invalid STA: %d %d\n", + sta_id, stp_res_tx->sta_id); + return -EINVAL; + } + + for_each_bit(bit, (unsigned long *)&tid_msk, IWM_UMAC_TID_NR) { + tid_info = &sta_info->tid_info[bit]; + + mutex_lock(&tid_info->mutex); + tid_info->stopped = stop; + mutex_unlock(&tid_info->mutex); + + if (!stop) { + struct iwm_tx_queue *txq; + u16 queue = iwm_tid_to_queue(bit); + + if (queue < 0) + continue; + + txq = &iwm->txq[queue]; + /* + * If we resume, we have to move our SKBs + * back to the tx queue and queue some work. + */ + spin_lock_bh(&txq->lock); + skb_queue_splice_init(&txq->queue, &txq->stopped_queue); + spin_unlock_bh(&txq->lock); + + queue_work(txq->wq, &txq->worker); + } + + } + + /* We send an ACK only for the stop case */ + if (stop) + ret = iwm_send_umac_stop_resume_tx(iwm, stp_res_tx); + + return ret; +} + static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) @@ -1371,6 +1436,7 @@ static const iwm_handler iwm_umac_handlers[] = [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics, [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy, [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list, + [UMAC_CMD_OPCODE_STOP_RESUME_STA_TX] = iwm_ntf_stop_resume_tx, [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper, }; diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c index e3b4f7902daf..01cc2101e682 100644 --- a/drivers/net/wireless/iwmc3200wifi/tx.c +++ b/drivers/net/wireless/iwmc3200wifi/tx.c @@ -329,7 +329,7 @@ static int iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb, memcpy(buf + sizeof(*hdr), skb->data, skb->len); - return 0; + return umac_cmd.seq_num; } static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, @@ -361,9 +361,10 @@ void iwm_tx_worker(struct work_struct *work) struct iwm_priv *iwm; struct iwm_tx_info *tx_info = NULL; struct sk_buff *skb; - int cmdlen, ret; struct iwm_tx_queue *txq; - int pool_id; + struct iwm_sta_info *sta_info; + struct iwm_tid_info *tid_info; + int cmdlen, ret, pool_id; txq = container_of(work, struct iwm_tx_queue, worker); iwm = container_of(txq, struct iwm_priv, txq[txq->id]); @@ -373,8 +374,40 @@ void iwm_tx_worker(struct work_struct *work) while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) && !skb_queue_empty(&txq->queue)) { + spin_lock_bh(&txq->lock); skb = skb_dequeue(&txq->queue); + spin_unlock_bh(&txq->lock); + tx_info = skb_to_tx_info(skb); + sta_info = &iwm->sta_table[tx_info->sta]; + if (!sta_info->valid) { + IWM_ERR(iwm, "Trying to send a frame to unknown STA\n"); + kfree_skb(skb); + continue; + } + + tid_info = &sta_info->tid_info[tx_info->tid]; + + mutex_lock(&tid_info->mutex); + + /* + * If the RAxTID is stopped, we queue the skb to the stopped + * queue. + * Whenever we'll get a UMAC notification to resume the tx flow + * for this RAxTID, we'll merge back the stopped queue into the + * regular queue. See iwm_ntf_stop_resume_tx() from rx.c. + */ + if (tid_info->stopped) { + IWM_DBG_TX(iwm, DBG, "%dx%d stopped\n", + tx_info->sta, tx_info->tid); + spin_lock_bh(&txq->lock); + skb_queue_tail(&txq->stopped_queue, skb); + spin_unlock_bh(&txq->lock); + + mutex_unlock(&tid_info->mutex); + continue; + } + cmdlen = IWM_UDMA_HDR_LEN + skb->len; IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: " @@ -393,13 +426,20 @@ void iwm_tx_worker(struct work_struct *work) if (ret) { IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue " "%d, Tx worker stopped\n", txq->id); + spin_lock_bh(&txq->lock); skb_queue_head(&txq->queue, skb); + spin_unlock_bh(&txq->lock); + + mutex_unlock(&tid_info->mutex); break; } txq->concat_ptr = txq->concat_buf + txq->concat_count; - iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); + tid_info->last_seq_num = + iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); txq->concat_count += ALIGN(cmdlen, 16); + + mutex_unlock(&tid_info->mutex); #endif kfree_skb(skb); } @@ -419,14 +459,14 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct iwm_priv *iwm = ndev_to_iwm(netdev); struct net_device *ndev = iwm_to_ndev(iwm); struct wireless_dev *wdev = iwm_to_wdev(iwm); - u8 *dst_addr; struct iwm_tx_info *tx_info; struct iwm_tx_queue *txq; struct iwm_sta_info *sta_info; - u8 sta_id; + u8 *dst_addr, sta_id; u16 queue; int ret; + if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: " "not associated\n"); @@ -440,7 +480,8 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev) txq = &iwm->txq[queue]; /* No free space for Tx, tx_worker is too slow */ - if (skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) { + if ((skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) || + (skb_queue_len(&txq->stopped_queue) > IWM_TX_LIST_SIZE)) { IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue); netif_stop_subqueue(netdev, queue); return NETDEV_TX_BUSY; @@ -477,7 +518,9 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev) else tx_info->tid = IWM_UMAC_MGMT_TID; + spin_lock_bh(&iwm->txq[queue].lock); skb_queue_tail(&iwm->txq[queue].queue, skb); + spin_unlock_bh(&iwm->txq[queue].lock); queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h index be903543bb47..70094bfe7c91 100644 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -83,6 +83,20 @@ struct iwm_udma_out_wifi_hdr { ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) +/* STA ID and color */ +#define STA_ID_SEED (0x0f) +#define STA_ID_POS (0) +#define STA_ID_MSK (STA_ID_SEED << STA_ID_POS) + +#define STA_COLOR_SEED (0x7) +#define STA_COLOR_POS (4) +#define STA_COLOR_MSK (STA_COLOR_SEED << STA_COLOR_POS) + +#define STA_ID_N_COLOR_COLOR(id_n_color) \ + (((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS) +#define STA_ID_N_COLOR_ID(id_n_color) \ + (((id_n_color) & STA_ID_MSK) >> STA_ID_POS) + /* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */ #define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0 #define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF @@ -260,6 +274,9 @@ struct iwm_udma_out_wifi_hdr { #define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16 #define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17 #define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18 +#define UMAC_CMD_OPCODE_STOP_RESUME_STA_TX 0x19 +#define UMAC_CMD_OPCODE_TEST_BLOCK_ACK 0x1A + #define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA #define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB #define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC @@ -691,13 +708,13 @@ struct iwm_umac_notif_rx_ticket { #define UMAC_PHY_NUM_CHAINS 3 #define IWM_UMAC_MGMT_TID 8 -#define IWM_UMAC_TID_NR 8 +#define IWM_UMAC_TID_NR 9 /* 8 TIDs + MGMT */ struct iwm_umac_notif_stats { struct iwm_umac_wifi_in_hdr hdr; __le32 flags; __le32 timestamp; - __le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */ + __le16 tid_load[IWM_UMAC_TID_NR + 1]; /* 1 non-QoS + 1 dword align */ __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; __le32 chain_energy[UMAC_PHY_NUM_CHAINS]; @@ -742,6 +759,19 @@ struct iwm_umac_notif_stats { __le32 roam_ap_loadblance; } __attribute__ ((packed)); +#define UMAC_STOP_TX_FLAG 0x1 +#define UMAC_RESUME_TX_FLAG 0x2 + +#define LAST_SEQ_NUM_INVALID 0xFFFF + +struct iwm_umac_notif_stop_resume_tx { + struct iwm_umac_wifi_in_hdr hdr; + u8 flags; /* UMAC_*_TX_FLAG_* */ + u8 sta_id; + __le16 stop_resume_tid_msk; /* tid bitmask */ +} __attribute__ ((packed)); + + /* WiFi interface wrapper header */ struct iwm_umac_wifi_if { u8 oid; -- cgit v1.2.3 From b136b3a2c1867172cd3de6e7286c600b04543b30 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 24 Nov 2009 11:33:32 +0800 Subject: iwmc3200wifi: Add stopped queue to debugfs We add the stopped queue count and display to the tx queue debugfs entry. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/debugfs.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c index 1465379f900a..be992ca41cf1 100644 --- a/drivers/net/wireless/iwmc3200wifi/debugfs.c +++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c @@ -158,6 +158,29 @@ static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer, } spin_unlock_irqrestore(&txq->queue.lock, flags); + + spin_lock_irqsave(&txq->stopped_queue.lock, flags); + + len += snprintf(buf + len, buf_len - len, + "\tStopped Queue len: %d\n", + skb_queue_len(&txq->stopped_queue)); + for (j = 0; j < skb_queue_len(&txq->stopped_queue); j++) { + struct iwm_tx_info *tx_info; + + skb = skb->next; + tx_info = skb_to_tx_info(skb); + + len += snprintf(buf + len, buf_len - len, + "\tSKB #%d\n", j); + len += snprintf(buf + len, buf_len - len, + "\t\tsta: %d\n", tx_info->sta); + len += snprintf(buf + len, buf_len - len, + "\t\tcolor: %d\n", tx_info->color); + len += snprintf(buf + len, buf_len - len, + "\t\ttid: %d\n", tx_info->tid); + } + + spin_unlock_irqrestore(&txq->stopped_queue.lock, flags); } ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); -- cgit v1.2.3 From 6b65b6ad016f048547127946d1afe4ba41c74296 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 24 Nov 2009 11:33:33 +0800 Subject: iwmc3200wifi: Remove tx concatenation option The tx concatenation option works fine now, we no longer need the debugging option of disabling concatenation. Signed-off-by: Samuel Ortiz Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/tx.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c index 01cc2101e682..55905f02309c 100644 --- a/drivers/net/wireless/iwmc3200wifi/tx.c +++ b/drivers/net/wireless/iwmc3200wifi/tx.c @@ -354,8 +354,6 @@ static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, return ret; } -#define CONFIG_IWM_TX_CONCATENATED 1 - void iwm_tx_worker(struct work_struct *work) { struct iwm_priv *iwm; @@ -414,11 +412,6 @@ void iwm_tx_worker(struct work_struct *work) "%d, color: %d\n", txq->id, skb, tx_info->sta, tx_info->color); -#if !CONFIG_IWM_TX_CONCATENATED - /* temporarily keep this to comparing the performance */ - ret = iwm_send_packet(iwm, skb, pool_id); -#else - if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE) iwm_tx_send_concat_packets(iwm, txq); @@ -440,7 +433,7 @@ void iwm_tx_worker(struct work_struct *work) txq->concat_count += ALIGN(cmdlen, 16); mutex_unlock(&tid_info->mutex); -#endif + kfree_skb(skb); } -- cgit v1.2.3 From e7824a50662f7f79b1a739f705b4d906c31cf221 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 24 Nov 2009 02:53:25 -0500 Subject: ath9k: fix processing of TX PS null data frames When mac80211 was telling us to go into Powersave we listened and immediately turned RX off. This meant hardware would not see the ACKs from the AP we're associated with and hardware we'd end up retransmiting the null data frame in a loop helplessly. Fix this by keeping track of the transmitted nullfunc frames and only when we are sure the AP has sent back an ACK do we go ahead and shut RX off. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Vivek Natarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 ++ drivers/net/wireless/ath/ath9k/common.h | 1 + drivers/net/wireless/ath/ath9k/mac.c | 9 +++++++++ drivers/net/wireless/ath/ath9k/mac.h | 6 ++++++ drivers/net/wireless/ath/ath9k/main.c | 20 ++++++++++++++++++-- drivers/net/wireless/ath/ath9k/reg.h | 15 ++++++++++++--- drivers/net/wireless/ath/ath9k/xmit.c | 21 +++++++++++++++++++++ 7 files changed, 69 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9ff53c9c4119..3eb9677b2dfe 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -420,6 +420,8 @@ struct ath_led { #define SC_OP_WAIT_FOR_TX_ACK BIT(18) #define SC_OP_BEACON_SYNC BIT(19) #define SC_OP_BT_PRIORITY_DETECTED BIT(21) +#define SC_OP_NULLFUNC_COMPLETED BIT(22) +#define SC_OP_PS_ENABLED BIT(23) struct ath_wiphy; struct ath_rate_table; diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 4e1176029356..b230bb15279e 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -78,6 +78,7 @@ struct ath_buf { dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_buf_addr; /* physical addr of data buffer */ bool bf_stale; + bool bf_isnullfunc; u16 bf_flags; struct ath_buf_state bf_state; dma_addr_t bf_dmacontext; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 46466ffebcb0..09ed441eb6ba 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -231,6 +231,8 @@ int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds) ds->ds_txstat.ts_status = 0; ds->ds_txstat.ts_flags = 0; + if (ads->ds_txstatus1 & AR_FrmXmitOK) + ds->ds_txstat.ts_status |= ATH9K_TX_ACKED; if (ads->ds_txstatus1 & AR_ExcessiveRetries) ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; if (ads->ds_txstatus1 & AR_Filtered) @@ -926,6 +928,13 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, } EXPORT_SYMBOL(ath9k_hw_setuprxdesc); +/* + * This can stop or re-enables RX. + * + * If bool is set this will kill any frame which is currently being + * transferred between the MAC and baseband and also prevent any new + * frames from getting started. + */ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) { u32 reg; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 29dfe14751a7..6cc04951a051 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -76,6 +76,7 @@ #define ATH9K_TXERR_FIFO 0x04 #define ATH9K_TXERR_XTXOP 0x08 #define ATH9K_TXERR_TIMER_EXPIRED 0x10 +#define ATH9K_TX_ACKED 0x20 #define ATH9K_TX_BA 0x01 #define ATH9K_TX_PWRMGMT 0x02 @@ -380,6 +381,11 @@ struct ar5416_desc { #define AR_TxBaStatus 0x40000000 #define AR_TxStatusRsvd01 0x80000000 +/* + * AR_FrmXmitOK - Frame transmission success flag. If set, the frame was + * transmitted successfully. If clear, no ACK or BA was received to indicate + * successful transmission when we were expecting an ACK or BA. + */ #define AR_FrmXmitOK 0x00000001 #define AR_ExcessiveRetries 0x00000002 #define AR_FIFOUnderrun 0x00000004 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index bd1e2de3a1f9..55c669648bd6 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2701,8 +2701,15 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } } + /* + * We just prepare to enable PS. We have to wait until our AP has + * ACK'd our null data frame to disable RX otherwise we'll ignore + * those ACKs and end up retransmitting the same null data frames. + * IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode. + */ if (changed & IEEE80211_CONF_CHANGE_PS) { if (conf->flags & IEEE80211_CONF_PS) { + sc->sc_flags |= SC_OP_PS_ENABLED; if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { @@ -2710,11 +2717,20 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); } - ath9k_hw_setrxabort(sc->sc_ah, 1); } - sc->ps_enabled = true; + /* + * At this point we know hardware has received an ACK + * of a previously sent null data frame. + */ + if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) { + sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; + sc->ps_enabled = true; + ath9k_hw_setrxabort(sc->sc_ah, 1); + } } else { sc->ps_enabled = false; + sc->sc_flags &= ~(SC_OP_PS_ENABLED | + SC_OP_NULLFUNC_COMPLETED); ath9k_setpower(sc, ATH9K_PM_AWAKE); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 49ec25f020f0..8e653fb937a1 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -1332,13 +1332,22 @@ enum { #define AR_MCAST_FIL0 0x8040 #define AR_MCAST_FIL1 0x8044 +/* + * AR_DIAG_SW - Register which can be used for diagnostics and testing purposes. + * + * The force RX abort (AR_DIAG_RX_ABORT, bit 25) can be used in conjunction with + * RX block (AR_DIAG_RX_DIS, bit 5) to help fast channel change to shut down + * receive. The force RX abort bit will kill any frame which is currently being + * transferred between the MAC and baseband. The RX block bit (AR_DIAG_RX_DIS) + * will prevent any new frames from getting started. + */ #define AR_DIAG_SW 0x8048 #define AR_DIAG_CACHE_ACK 0x00000001 #define AR_DIAG_ACK_DIS 0x00000002 #define AR_DIAG_CTS_DIS 0x00000004 #define AR_DIAG_ENCRYPT_DIS 0x00000008 #define AR_DIAG_DECRYPT_DIS 0x00000010 -#define AR_DIAG_RX_DIS 0x00000020 +#define AR_DIAG_RX_DIS 0x00000020 /* RX block */ #define AR_DIAG_LOOP_BACK 0x00000040 #define AR_DIAG_CORR_FCS 0x00000080 #define AR_DIAG_CHAN_INFO 0x00000100 @@ -1347,12 +1356,12 @@ enum { #define AR_DIAG_FRAME_NV0 0x00020000 #define AR_DIAG_OBS_PT_SEL1 0x000C0000 #define AR_DIAG_OBS_PT_SEL1_S 18 -#define AR_DIAG_FORCE_RX_CLEAR 0x00100000 +#define AR_DIAG_FORCE_RX_CLEAR 0x00100000 /* force rx_clear high */ #define AR_DIAG_IGNORE_VIRT_CS 0x00200000 #define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000 #define AR_DIAG_EIFS_CTRL_ENA 0x00800000 #define AR_DIAG_DUAL_CHAIN_INFO 0x01000000 -#define AR_DIAG_RX_ABORT 0x02000000 +#define AR_DIAG_RX_ABORT 0x02000000 /* Force RX abort */ #define AR_DIAG_SATURATE_CYCLE_CNT 0x04000000 #define AR_DIAG_OBS_PT_SEL2 0x08000000 #define AR_DIAG_RX_CLEAR_CTL_LOW 0x10000000 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2bb8c91bf4f9..6f91a8ae616f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1644,6 +1644,14 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, } bf->bf_buf_addr = bf->bf_dmacontext; + + /* tag if this is a nullfunc frame to enable PS when AP acks it */ + if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) { + bf->bf_isnullfunc = true; + sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; + } else + bf->bf_isnullfunc = false; + return 0; } @@ -2038,6 +2046,19 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) break; } + /* + * We now know the nullfunc frame has been ACKed so we + * can disable RX. + */ + if (bf->bf_isnullfunc && + (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { + if ((sc->sc_flags & SC_OP_PS_ENABLED)) { + sc->ps_enabled = true; + ath9k_hw_setrxabort(sc->sc_ah, 1); + } else + sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED; + } + /* * Remove ath_buf's of the same transmit unit from txq, * however leave the last descriptor back as the holding -- cgit v1.2.3 From 1bc1488067ee2c295b933ef6decd6035230f1a1c Mon Sep 17 00:00:00 2001 From: Benoit Papillault Date: Tue, 24 Nov 2009 15:49:18 +0100 Subject: ath9k: Proper padding/unpadding for the TX/RX path. Software padding is done on the TX path and software unpadding is done on the RX path. This patch corrects the position where the padding occurs. A specific function computes the pad position and this function is used in the TX and RX path. This patch has been tested by generating every possible 802.11 frames with every possible frame_control field and a varying length. This patch is useful for analyzing non standard 802.11 frames going over the air Signed-off-by: Benoit Papillault Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common.c | 24 +++++++++++++++--------- drivers/net/wireless/ath/ath9k/common.h | 2 ++ drivers/net/wireless/ath/ath9k/main.c | 14 ++++++-------- drivers/net/wireless/ath/ath9k/xmit.c | 9 ++++++++- 4 files changed, 31 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index d96751ccee96..4d775ae141db 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -236,16 +236,8 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, /* see if any padding is done by the hw and remove it */ hdr = (struct ieee80211_hdr *) skb->data; hdrlen = ieee80211_get_hdrlen_from_skb(skb); - padpos = 24; fc = hdr->frame_control; - if ((fc & cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) == - cpu_to_le16(IEEE80211_FCTL_FROMDS|IEEE80211_FCTL_TODS)) { - padpos += 6; /* ETH_ALEN */ - } - if ((fc & cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FCTL_FTYPE)) == - cpu_to_le16(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) { - padpos += 2; - } + padpos = ath9k_cmn_padpos(hdr->frame_control); /* The MAC header is padded to have 32-bit boundary if the * packet payload is non-zero. The general calculation for @@ -280,6 +272,20 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, } EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess); +int ath9k_cmn_padpos(__le16 frame_control) +{ + int padpos = 24; + if (ieee80211_has_a4(frame_control)) { + padpos += ETH_ALEN; + } + if (ieee80211_is_data_qos(frame_control)) { + padpos += IEEE80211_QOS_CTL_LEN; + } + + return padpos; +} +EXPORT_SYMBOL(ath9k_cmn_padpos); + static int __init ath9k_cmn_init(void) { return 0; diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index b230bb15279e..042999c2fe9c 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -123,3 +123,5 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, struct ath_rx_status *rx_stats, struct ieee80211_rx_status *rxs, bool decrypt_error); + +int ath9k_cmn_padpos(__le16 frame_control); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 55c669648bd6..cfe710b01d85 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2364,7 +2364,8 @@ static int ath9k_tx(struct ieee80211_hw *hw, struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_tx_control txctl; - int hdrlen, padsize; + int padpos, padsize; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) { ath_print(common, ATH_DBG_XMIT, @@ -2374,7 +2375,6 @@ static int ath9k_tx(struct ieee80211_hw *hw, } if (sc->ps_enabled) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; /* * mac80211 does not set PM field for normal data frames, so we * need to update that based on the current PS mode. @@ -2394,7 +2394,6 @@ static int ath9k_tx(struct ieee80211_hw *hw, * power save mode. Need to wake up hardware for the TX to be * completed and if needed, also for RX of buffered frames. */ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; ath9k_ps_wakeup(sc); ath9k_hw_setrxabort(sc->sc_ah, 0); if (ieee80211_is_pspoll(hdr->frame_control)) { @@ -2422,7 +2421,6 @@ static int ath9k_tx(struct ieee80211_hw *hw, * BSSes. */ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); @@ -2430,13 +2428,13 @@ static int ath9k_tx(struct ieee80211_hw *hw, } /* Add the padding after the header if this is not already done */ - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - if (hdrlen & 3) { - padsize = hdrlen % 4; + padpos = ath9k_cmn_padpos(hdr->frame_control); + padsize = padpos & 3; + if (padsize && skb->len>padpos) { if (skb_headroom(skb) < padsize) return -1; skb_push(skb, padsize); - memmove(skb->data, skb->data + padsize, hdrlen); + memmove(skb->data, skb->data + padsize, padpos); } /* Check if a tx queue is available */ diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 6f91a8ae616f..564c6cb1c2b4 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1596,6 +1596,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; int hdrlen; __le16 fc; + int padpos, padsize; tx_info->pad[0] = 0; switch (txctl->frame_type) { @@ -1614,7 +1615,13 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, ATH_TXBUF_RESET(bf); bf->aphy = aphy; - bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); + bf->bf_frmlen = skb->len + FCS_LEN; + /* Remove the padding size from bf_frmlen, if any */ + padpos = ath9k_cmn_padpos(hdr->frame_control); + padsize = padpos & 3; + if (padsize && skb->len>padpos+padsize) { + bf->bf_frmlen -= padsize; + } if (conf_is_ht(&hw->conf) && !is_pae(skb)) bf->bf_state.bf_type |= BUF_HT; -- cgit v1.2.3 From f4709fdf683e1ed37b321c258b614ebe39752bf3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 24 Nov 2009 21:37:57 -0500 Subject: ath9k: Fix maximum tx fifo settings for single stream devices Atheros single stream AR9285 and AR9271 have half the PCU TX FIFO buffer size of that of dual stream devices. Dual stream devices have a max PCU TX FIFO size of 8 KB while single stream devices have 4 KB. Single stream devices have an issue though and require hardware only to use half of the amount of its capable PCU TX FIFO size, 2 KB and this requires a change in software. Technically a change would not have been required (except for frame burst considerations of 128 bytes) if these devices would have been able to use the full 4 KB of the PCU TX FIFO size but our systems engineers recommend 2 KB to be used only. We enforce this through software by reducing the max frame triggger level to 2 KB. Fixing the max frame trigger level should then have a few benefits: * The PER will now be adjusted as designed for underruns when the max trigger level is reached. This should help alleviate the bus as the rate control algorithm chooses a slower rate which should ensure frames are transmitted properly under high system bus load. * The poll we use on our TX queues should now trigger and work as designed for single stream devices. The hardware passes data from each TX queue on the PCU TX FIFO queue respecting each queue's priority. The new trigger level ensures this seeding of the PCU TX FIFO queue occurs as designed which could mean avoiding false resets and actually reseting hw correctly when a TX queue is indeed stuck. * Some undocumented / unsupported behaviour could have been triggered when the max trigger level level was being set to 4 KB on single stream devices. Its not clear what this issue was to me yet. Cc: Kyungwan Nam Cc: Bennyam Malavazi Cc: Stephen Chen Cc: Shan Palanisamy Cc: Paul Shaw Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 11 ++++++++++- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/mac.c | 29 +++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath9k/mac.h | 8 +++++++- drivers/net/wireless/ath/ath9k/rc.c | 12 ++++++++---- 5 files changed, 53 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 63d84613dc96..493160c8c754 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -918,6 +918,11 @@ int ath9k_hw_init(struct ath_hw *ah) ath_print(common, ATH_DBG_RESET, "serialize_regmode is %d\n", ah->config.serialize_regmode); + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1; + else + ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD; + if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { ath_print(common, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " @@ -3224,7 +3229,11 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->keycache_size = AR_KEYTABLE_SIZE; pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; + + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1; + else + pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; if (AR_SREV_9285_10_OR_LATER(ah)) pCap->num_gpio_pins = AR9285_NUM_GPIO; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index b12634262d97..46e1572dc945 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -226,6 +226,7 @@ struct ath9k_ops_config { #define AR_SPUR_FEEQ_BOUND_HT20 10 int spurmode; u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; + u8 max_txtrig_level; }; enum ath9k_int { diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 09ed441eb6ba..71b84d91dcff 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -70,12 +70,37 @@ u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) } EXPORT_SYMBOL(ath9k_hw_numtxpending); +/** + * ath9k_hw_updatetxtriglevel - adjusts the frame trigger level + * + * @ah: atheros hardware struct + * @bIncTrigLevel: whether or not the frame trigger level should be updated + * + * The frame trigger level specifies the minimum number of bytes, + * in units of 64 bytes, that must be DMA'ed into the PCU TX FIFO + * before the PCU will initiate sending the frame on the air. This can + * mean we initiate transmit before a full frame is on the PCU TX FIFO. + * Resets to 0x1 (meaning 64 bytes or a full frame, whichever occurs + * first) + * + * Caution must be taken to ensure to set the frame trigger level based + * on the DMA request size. For example if the DMA request size is set to + * 128 bytes the trigger level cannot exceed 6 * 64 = 384. This is because + * there need to be enough space in the tx FIFO for the requested transfer + * size. Hence the tx FIFO will stop with 512 - 128 = 384 bytes. If we set + * the threshold to a value beyond 6, then the transmit will hang. + * + * Current dual stream devices have a PCU TX FIFO size of 8 KB. + * Current single stream devices have a PCU TX FIFO size of 4 KB, however, + * there is a hardware issue which forces us to use 2 KB instead so the + * frame trigger level must not exceed 2 KB for these chipsets. + */ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) { u32 txcfg, curLevel, newLevel; enum ath9k_int omask; - if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD) + if (ah->tx_trig_level >= ah->config.max_txtrig_level) return false; omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL); @@ -84,7 +109,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) curLevel = MS(txcfg, AR_FTRIG); newLevel = curLevel; if (bIncTrigLevel) { - if (curLevel < MAX_TX_FIFO_THRESHOLD) + if (curLevel < ah->config.max_txtrig_level) newLevel++; } else if (curLevel > MIN_TX_FIFO_THRESHOLD) newLevel--; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 6cc04951a051..0c87771383f0 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -86,9 +86,15 @@ #define ATH9K_TX_SW_ABORTED 0x40 #define ATH9K_TX_SW_FILTERED 0x80 +/* 64 bytes */ #define MIN_TX_FIFO_THRESHOLD 0x1 + +/* + * Single stream device AR9285 and AR9271 require 2 KB + * to work around a hardware issue, all other devices + * have can use the max 4 KB limit. + */ #define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1) -#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD struct ath_tx_status { u32 ts_tstamp; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index e697bd934904..c915954d4d5b 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1235,10 +1235,14 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, return; /* - * If underrun error is seen assume it as an excessive retry only - * if prefetch trigger level have reached the max (0x3f for 5416) - * Adjust the long retry as if the frame was tried hw->max_rate_tries - * times. This affects how ratectrl updates PER for the failed rate. + * If an underrun error is seen assume it as an excessive retry only + * if max frame trigger level has been reached (2 KB for singel stream, + * and 4 KB for dual stream). Adjust the long retry as if the frame was + * tried hw->max_rate_tries times to affect how ratectrl updates PER for + * the failed rate. In case of congestion on the bus penalizing these + * type of underruns should help hardware actually transmit new frames + * successfully by eventually preferring slower rates. This itself + * should also alleviate congestion on the bus. */ if ((tx_info->pad[0] & ATH_TX_INFO_UNDERRUN) && (sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) { -- cgit v1.2.3 From 94db29368a658b13a088db87c7b0bf59b1a7492d Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Wed, 25 Nov 2009 12:01:54 +0530 Subject: ath9k: Ensure a fair beacon distribution in IBSS mode. Update the beacon queue parameters with best effort queue parameters for IBSS mode. This reduces the number of beacons generated by ath9k and ensures a fair beacon distribution when there are multiple IBSS stations. Also CWmin is quadrupled to achieve the expected percentage of distribution. Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 + drivers/net/wireless/ath/ath9k/beacon.c | 14 +++++++++----- drivers/net/wireless/ath/ath9k/main.c | 4 ++++ 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3eb9677b2dfe..42f79caa870b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -329,6 +329,7 @@ void ath_beacon_tasklet(unsigned long data); void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif); void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); +int ath_beaconq_config(struct ath_softc *sc); /*******/ /* ANI */ diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index cb774cc828a3..1660ef17aaf5 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -23,11 +23,12 @@ * the operating mode of the station (AP or AdHoc). Parameters are AIFS * settings and channel width min/max */ -static int ath_beaconq_config(struct ath_softc *sc) +int ath_beaconq_config(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_tx_queue_info qi; + struct ath9k_tx_queue_info qi, qi_be; + int qnum; ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { @@ -37,9 +38,12 @@ static int ath_beaconq_config(struct ath_softc *sc) qi.tqi_cwmax = 0; } else { /* Adhoc mode; important thing is to use 2x cwmin. */ - qi.tqi_aifs = sc->beacon.beacon_qi.tqi_aifs; - qi.tqi_cwmin = 2*sc->beacon.beacon_qi.tqi_cwmin; - qi.tqi_cwmax = sc->beacon.beacon_qi.tqi_cwmax; + qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, + ATH9K_WME_AC_BE); + ath9k_hw_get_txq_props(ah, qnum, &qi_be); + qi.tqi_aifs = qi_be.tqi_aifs; + qi.tqi_cwmin = 4*qi_be.tqi_cwmin; + qi.tqi_cwmax = qi_be.tqi_cwmax; } if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cfe710b01d85..b9598148767b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2882,6 +2882,10 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, if (ret) ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n"); + if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) + if ((qnum == sc->tx.hwq_map[ATH9K_WME_AC_BE]) && !ret) + ath_beaconq_config(sc); + mutex_unlock(&sc->mutex); return ret; -- cgit v1.2.3 From 83daee06adeed7b294802c998d5e03ea7d856aa1 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 25 Nov 2009 10:12:20 +0300 Subject: ray_cs: convert to proc_fops Signed-off-by: Alexey Dobriyan Signed-off-by: John W. Linville --- drivers/net/wireless/ray_cs.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 5ee9d2a19360..0366f5aeb914 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -2865,18 +2865,8 @@ static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) /*===========================================================================*/ #ifdef CONFIG_PROC_FS -static void raycs_write(const char *name, write_proc_t *w, void *data) -{ - struct proc_dir_entry *entry = - create_proc_entry(name, S_IFREG | S_IWUSR, NULL); - if (entry) { - entry->write_proc = w; - entry->data = data; - } -} - -static int write_essid(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static ssize_t ray_cs_essid_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *pos) { static char proc_essid[33]; unsigned int len = count; @@ -2890,8 +2880,13 @@ static int write_essid(struct file *file, const char __user *buffer, return count; } -static int write_int(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static const struct file_operations ray_cs_essid_proc_fops = { + .owner = THIS_MODULE, + .write = ray_cs_essid_proc_write, +}; + +static ssize_t int_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) { static char proc_number[10]; char *p; @@ -2914,9 +2909,14 @@ static int write_int(struct file *file, const char __user *buffer, nr = nr * 10 + c; p++; } while (--len); - *(int *)data = nr; + *(int *)PDE(file->f_path.dentry->d_inode)->data = nr; return count; } + +static const struct file_operations int_proc_fops = { + .owner = THIS_MODULE, + .write = int_proc_write, +}; #endif static struct pcmcia_device_id ray_ids[] = { @@ -2951,9 +2951,9 @@ static int __init init_ray_cs(void) proc_mkdir("driver/ray_cs", NULL); proc_create("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_fops); - raycs_write("driver/ray_cs/essid", write_essid, NULL); - raycs_write("driver/ray_cs/net_type", write_int, &net_type); - raycs_write("driver/ray_cs/translate", write_int, &translate); + proc_create("driver/ray_cs/essid", S_IWUSR, NULL, &ray_cs_essid_proc_fops); + proc_create_data("driver/ray_cs/net_type", S_IWUSR, NULL, &int_proc_fops, &net_type); + proc_create_data("driver/ray_cs/translate", S_IWUSR, NULL, &int_proc_fops, &translate); #endif if (translate != 0) translate = 1; -- cgit v1.2.3 From b8d83392980b65ea548cbf2b1c7c542b51961166 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 25 Nov 2009 10:14:12 +0300 Subject: ipw2x00: convert to seq_file Signed-off-by: Alexey Dobriyan Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/libipw_module.c | 33 ++++++++++++++++++---------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index e8a1ac5f8e11..bf21eb383dbd 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -248,17 +248,22 @@ u32 libipw_debug_level = 0; EXPORT_SYMBOL_GPL(libipw_debug_level); static struct proc_dir_entry *libipw_proc = NULL; -static int show_debug_level(char *page, char **start, off_t offset, - int count, int *eof, void *data) +static int debug_level_proc_show(struct seq_file *m, void *v) { - return snprintf(page, count, "0x%08X\n", libipw_debug_level); + seq_printf(m, "0x%08X\n", libipw_debug_level); + return 0; } -static int store_debug_level(struct file *file, const char __user * buffer, - unsigned long count, void *data) +static int debug_level_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, debug_level_proc_show, NULL); +} + +static ssize_t debug_level_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *pos) { char buf[] = "0x00000000\n"; - unsigned long len = min((unsigned long)sizeof(buf) - 1, count); + size_t len = min(sizeof(buf) - 1, count); unsigned long val; if (copy_from_user(buf, buffer, len)) @@ -272,6 +277,15 @@ static int store_debug_level(struct file *file, const char __user * buffer, return strnlen(buf, len); } + +static const struct file_operations debug_level_proc_fops = { + .owner = THIS_MODULE, + .open = debug_level_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = debug_level_proc_write, +}; #endif /* CONFIG_LIBIPW_DEBUG */ static int __init libipw_init(void) @@ -286,16 +300,13 @@ static int __init libipw_init(void) " proc directory\n"); return -EIO; } - e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, - libipw_proc); + e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc, + &debug_level_proc_fops); if (!e) { remove_proc_entry(DRV_NAME, init_net.proc_net); libipw_proc = NULL; return -EIO; } - e->read_proc = show_debug_level; - e->write_proc = store_debug_level; - e->data = NULL; #endif /* CONFIG_LIBIPW_DEBUG */ printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); -- cgit v1.2.3 From 76bae570899be34317510d8006d490572152bdfb Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 25 Nov 2009 13:08:55 +0100 Subject: libertas: rename persistcfg.c -> mesh.c mesh.c will be the file where we concentrate all mesh-related code. This allows us to either add a KConfig entry for mesh and makes matters easier for the cfg80211 transition. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/Makefile | 2 +- drivers/net/wireless/libertas/mesh.c | 453 +++++++++++++++++++++++++++++ drivers/net/wireless/libertas/persistcfg.c | 453 ----------------------------- 3 files changed, 454 insertions(+), 454 deletions(-) create mode 100644 drivers/net/wireless/libertas/mesh.c delete mode 100644 drivers/net/wireless/libertas/persistcfg.c (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index fa37039e0eae..b188cd97a053 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -5,7 +5,7 @@ libertas-y += cmdresp.o libertas-y += debugfs.o libertas-y += ethtool.o libertas-y += main.o -libertas-y += persistcfg.o +libertas-y += mesh.o libertas-y += rx.o libertas-y += scan.o libertas-y += tx.o diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c new file mode 100644 index 000000000000..871f914a75fc --- /dev/null +++ b/drivers/net/wireless/libertas/mesh.c @@ -0,0 +1,453 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "host.h" +#include "decl.h" +#include "dev.h" +#include "wext.h" +#include "debugfs.h" +#include "scan.h" +#include "assoc.h" +#include "cmd.h" + +static int mesh_get_default_parameters(struct device *dev, + struct mrvl_mesh_defaults *defs) +{ + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + struct cmd_ds_mesh_config cmd; + int ret; + + memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET, + CMD_TYPE_MESH_GET_DEFAULTS); + + if (ret) + return -EOPNOTSUPP; + + memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults)); + + return 0; +} + +/** + * @brief Get function for sysfs attribute bootflag + */ +static ssize_t bootflag_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag)); +} + +/** + * @brief Set function for sysfs attribute bootflag + */ +static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + struct cmd_ds_mesh_config cmd; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%d", &datum); + if ((ret != 1) || (datum > 1)) + return -EINVAL; + + *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum); + cmd.length = cpu_to_le16(sizeof(uint32_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_BOOTFLAG); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute boottime + */ +static ssize_t boottime_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "%d\n", defs.boottime); +} + +/** + * @brief Set function for sysfs attribute boottime + */ +static ssize_t boottime_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + struct cmd_ds_mesh_config cmd; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%d", &datum); + if ((ret != 1) || (datum > 255)) + return -EINVAL; + + /* A too small boot time will result in the device booting into + * standalone (no-host) mode before the host can take control of it, + * so the change will be hard to revert. This may be a desired + * feature (e.g to configure a very fast boot time for devices that + * will not be attached to a host), but dangerous. So I'm enforcing a + * lower limit of 20 seconds: remove and recompile the driver if this + * does not work for you. + */ + datum = (datum < 20) ? 20 : datum; + cmd.data[0] = datum; + cmd.length = cpu_to_le16(sizeof(uint8_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_BOOTTIME); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute channel + */ +static ssize_t channel_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel)); +} + +/** + * @brief Set function for sysfs attribute channel + */ +static ssize_t channel_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + struct cmd_ds_mesh_config cmd; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%d", &datum); + if (ret != 1 || datum < 1 || datum > 11) + return -EINVAL; + + *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum); + cmd.length = cpu_to_le16(sizeof(uint16_t)); + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_DEF_CHANNEL); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute mesh_id + */ +static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct mrvl_mesh_defaults defs; + int maxlen; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) { + lbs_pr_err("inconsistent mesh ID length"); + defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN; + } + + /* SSID not null terminated: reserve room for \0 + \n */ + maxlen = defs.meshie.val.mesh_id_len + 2; + maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE; + + defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0'; + + return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id); +} + +/** + * @brief Set function for sysfs attribute mesh_id + */ +static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + int len; + int ret; + + if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1) + return -EINVAL; + + memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); + ie = (struct mrvl_meshie *) &cmd.data[0]; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + + len = count - 1; + memcpy(ie->val.mesh_id, buf, len); + /* SSID len */ + ie->val.mesh_id_len = len; + /* IE len */ + ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute protocol_id + */ +static ssize_t protocol_id_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id); +} + +/** + * @brief Set function for sysfs attribute protocol_id + */ +static ssize_t protocol_id_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%d", &datum); + if ((ret != 1) || (datum > 255)) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update protocol id */ + ie->val.active_protocol_id = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute metric_id + */ +static ssize_t metric_id_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id); +} + +/** + * @brief Set function for sysfs attribute metric_id + */ +static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%d", &datum); + if ((ret != 1) || (datum > 255)) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update metric id */ + ie->val.active_metric_id = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute capability + */ +static ssize_t capability_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mrvl_mesh_defaults defs; + int ret; + + ret = mesh_get_default_parameters(dev, &defs); + + if (ret) + return ret; + + return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability); +} + +/** + * @brief Set function for sysfs attribute capability + */ +static ssize_t capability_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_mesh_defaults defs; + struct mrvl_meshie *ie; + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + uint32_t datum; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + ret = sscanf(buf, "%d", &datum); + if ((ret != 1) || (datum > 255)) + return -EINVAL; + + /* fetch all other Information Element parameters */ + ret = mesh_get_default_parameters(dev, &defs); + + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); + + /* transfer IE elements */ + ie = (struct mrvl_meshie *) &cmd.data[0]; + memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); + /* update value */ + ie->val.mesh_capability = datum; + + ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, + CMD_TYPE_MESH_SET_MESH_IE); + if (ret) + return ret; + + return strlen(buf); +} + + +static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set); +static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set); +static DEVICE_ATTR(channel, 0644, channel_get, channel_set); +static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set); +static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set); +static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set); +static DEVICE_ATTR(capability, 0644, capability_get, capability_set); + +static struct attribute *boot_opts_attrs[] = { + &dev_attr_bootflag.attr, + &dev_attr_boottime.attr, + &dev_attr_channel.attr, + NULL +}; + +static struct attribute_group boot_opts_group = { + .name = "boot_options", + .attrs = boot_opts_attrs, +}; + +static struct attribute *mesh_ie_attrs[] = { + &dev_attr_mesh_id.attr, + &dev_attr_protocol_id.attr, + &dev_attr_metric_id.attr, + &dev_attr_capability.attr, + NULL +}; + +static struct attribute_group mesh_ie_group = { + .name = "mesh_ie", + .attrs = mesh_ie_attrs, +}; + +void lbs_persist_config_init(struct net_device *dev) +{ + int ret; + ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group); + ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group); +} + +void lbs_persist_config_remove(struct net_device *dev) +{ + sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group); + sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group); +} diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c deleted file mode 100644 index 871f914a75fc..000000000000 --- a/drivers/net/wireless/libertas/persistcfg.c +++ /dev/null @@ -1,453 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "host.h" -#include "decl.h" -#include "dev.h" -#include "wext.h" -#include "debugfs.h" -#include "scan.h" -#include "assoc.h" -#include "cmd.h" - -static int mesh_get_default_parameters(struct device *dev, - struct mrvl_mesh_defaults *defs) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - struct cmd_ds_mesh_config cmd; - int ret; - - memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); - ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET, - CMD_TYPE_MESH_GET_DEFAULTS); - - if (ret) - return -EOPNOTSUPP; - - memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults)); - - return 0; -} - -/** - * @brief Get function for sysfs attribute bootflag - */ -static ssize_t bootflag_get(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mrvl_mesh_defaults defs; - int ret; - - ret = mesh_get_default_parameters(dev, &defs); - - if (ret) - return ret; - - return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag)); -} - -/** - * @brief Set function for sysfs attribute bootflag - */ -static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - struct cmd_ds_mesh_config cmd; - uint32_t datum; - int ret; - - memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%d", &datum); - if ((ret != 1) || (datum > 1)) - return -EINVAL; - - *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum); - cmd.length = cpu_to_le16(sizeof(uint32_t)); - ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, - CMD_TYPE_MESH_SET_BOOTFLAG); - if (ret) - return ret; - - return strlen(buf); -} - -/** - * @brief Get function for sysfs attribute boottime - */ -static ssize_t boottime_get(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mrvl_mesh_defaults defs; - int ret; - - ret = mesh_get_default_parameters(dev, &defs); - - if (ret) - return ret; - - return snprintf(buf, 12, "%d\n", defs.boottime); -} - -/** - * @brief Set function for sysfs attribute boottime - */ -static ssize_t boottime_set(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - struct cmd_ds_mesh_config cmd; - uint32_t datum; - int ret; - - memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%d", &datum); - if ((ret != 1) || (datum > 255)) - return -EINVAL; - - /* A too small boot time will result in the device booting into - * standalone (no-host) mode before the host can take control of it, - * so the change will be hard to revert. This may be a desired - * feature (e.g to configure a very fast boot time for devices that - * will not be attached to a host), but dangerous. So I'm enforcing a - * lower limit of 20 seconds: remove and recompile the driver if this - * does not work for you. - */ - datum = (datum < 20) ? 20 : datum; - cmd.data[0] = datum; - cmd.length = cpu_to_le16(sizeof(uint8_t)); - ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, - CMD_TYPE_MESH_SET_BOOTTIME); - if (ret) - return ret; - - return strlen(buf); -} - -/** - * @brief Get function for sysfs attribute channel - */ -static ssize_t channel_get(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mrvl_mesh_defaults defs; - int ret; - - ret = mesh_get_default_parameters(dev, &defs); - - if (ret) - return ret; - - return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel)); -} - -/** - * @brief Set function for sysfs attribute channel - */ -static ssize_t channel_set(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - struct cmd_ds_mesh_config cmd; - uint32_t datum; - int ret; - - memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%d", &datum); - if (ret != 1 || datum < 1 || datum > 11) - return -EINVAL; - - *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum); - cmd.length = cpu_to_le16(sizeof(uint16_t)); - ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, - CMD_TYPE_MESH_SET_DEF_CHANNEL); - if (ret) - return ret; - - return strlen(buf); -} - -/** - * @brief Get function for sysfs attribute mesh_id - */ -static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct mrvl_mesh_defaults defs; - int maxlen; - int ret; - - ret = mesh_get_default_parameters(dev, &defs); - - if (ret) - return ret; - - if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) { - lbs_pr_err("inconsistent mesh ID length"); - defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN; - } - - /* SSID not null terminated: reserve room for \0 + \n */ - maxlen = defs.meshie.val.mesh_id_len + 2; - maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE; - - defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0'; - - return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id); -} - -/** - * @brief Set function for sysfs attribute mesh_id - */ -static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct cmd_ds_mesh_config cmd; - struct mrvl_mesh_defaults defs; - struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - int len; - int ret; - - if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1) - return -EINVAL; - - memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); - ie = (struct mrvl_meshie *) &cmd.data[0]; - - /* fetch all other Information Element parameters */ - ret = mesh_get_default_parameters(dev, &defs); - - cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); - - /* transfer IE elements */ - memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); - - len = count - 1; - memcpy(ie->val.mesh_id, buf, len); - /* SSID len */ - ie->val.mesh_id_len = len; - /* IE len */ - ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len; - - ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, - CMD_TYPE_MESH_SET_MESH_IE); - if (ret) - return ret; - - return strlen(buf); -} - -/** - * @brief Get function for sysfs attribute protocol_id - */ -static ssize_t protocol_id_get(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mrvl_mesh_defaults defs; - int ret; - - ret = mesh_get_default_parameters(dev, &defs); - - if (ret) - return ret; - - return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id); -} - -/** - * @brief Set function for sysfs attribute protocol_id - */ -static ssize_t protocol_id_set(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct cmd_ds_mesh_config cmd; - struct mrvl_mesh_defaults defs; - struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - uint32_t datum; - int ret; - - memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%d", &datum); - if ((ret != 1) || (datum > 255)) - return -EINVAL; - - /* fetch all other Information Element parameters */ - ret = mesh_get_default_parameters(dev, &defs); - - cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); - - /* transfer IE elements */ - ie = (struct mrvl_meshie *) &cmd.data[0]; - memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); - /* update protocol id */ - ie->val.active_protocol_id = datum; - - ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, - CMD_TYPE_MESH_SET_MESH_IE); - if (ret) - return ret; - - return strlen(buf); -} - -/** - * @brief Get function for sysfs attribute metric_id - */ -static ssize_t metric_id_get(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mrvl_mesh_defaults defs; - int ret; - - ret = mesh_get_default_parameters(dev, &defs); - - if (ret) - return ret; - - return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id); -} - -/** - * @brief Set function for sysfs attribute metric_id - */ -static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct cmd_ds_mesh_config cmd; - struct mrvl_mesh_defaults defs; - struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - uint32_t datum; - int ret; - - memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%d", &datum); - if ((ret != 1) || (datum > 255)) - return -EINVAL; - - /* fetch all other Information Element parameters */ - ret = mesh_get_default_parameters(dev, &defs); - - cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); - - /* transfer IE elements */ - ie = (struct mrvl_meshie *) &cmd.data[0]; - memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); - /* update metric id */ - ie->val.active_metric_id = datum; - - ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, - CMD_TYPE_MESH_SET_MESH_IE); - if (ret) - return ret; - - return strlen(buf); -} - -/** - * @brief Get function for sysfs attribute capability - */ -static ssize_t capability_get(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mrvl_mesh_defaults defs; - int ret; - - ret = mesh_get_default_parameters(dev, &defs); - - if (ret) - return ret; - - return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability); -} - -/** - * @brief Set function for sysfs attribute capability - */ -static ssize_t capability_set(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct cmd_ds_mesh_config cmd; - struct mrvl_mesh_defaults defs; - struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - uint32_t datum; - int ret; - - memset(&cmd, 0, sizeof(cmd)); - ret = sscanf(buf, "%d", &datum); - if ((ret != 1) || (datum > 255)) - return -EINVAL; - - /* fetch all other Information Element parameters */ - ret = mesh_get_default_parameters(dev, &defs); - - cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); - - /* transfer IE elements */ - ie = (struct mrvl_meshie *) &cmd.data[0]; - memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); - /* update value */ - ie->val.mesh_capability = datum; - - ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, - CMD_TYPE_MESH_SET_MESH_IE); - if (ret) - return ret; - - return strlen(buf); -} - - -static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set); -static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set); -static DEVICE_ATTR(channel, 0644, channel_get, channel_set); -static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set); -static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set); -static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set); -static DEVICE_ATTR(capability, 0644, capability_get, capability_set); - -static struct attribute *boot_opts_attrs[] = { - &dev_attr_bootflag.attr, - &dev_attr_boottime.attr, - &dev_attr_channel.attr, - NULL -}; - -static struct attribute_group boot_opts_group = { - .name = "boot_options", - .attrs = boot_opts_attrs, -}; - -static struct attribute *mesh_ie_attrs[] = { - &dev_attr_mesh_id.attr, - &dev_attr_protocol_id.attr, - &dev_attr_metric_id.attr, - &dev_attr_capability.attr, - NULL -}; - -static struct attribute_group mesh_ie_group = { - .name = "mesh_ie", - .attrs = mesh_ie_attrs, -}; - -void lbs_persist_config_init(struct net_device *dev) -{ - int ret; - ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group); - ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group); -} - -void lbs_persist_config_remove(struct net_device *dev) -{ - sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group); - sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group); -} -- cgit v1.2.3 From 5e8e8b5759566b76bdf36046ae015796676a423c Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 25 Nov 2009 13:09:32 +0100 Subject: libertas: introduce mesh.h Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/decl.h | 5 ----- drivers/net/wireless/libertas/dev.h | 12 +----------- drivers/net/wireless/libertas/mesh.h | 32 ++++++++++++++++++++++++++++++++ drivers/net/wireless/libertas/wext.h | 5 ++--- 4 files changed, 35 insertions(+), 19 deletions(-) create mode 100644 drivers/net/wireless/libertas/mesh.h (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 678f7c9f7503..cf3196a7343d 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -27,11 +27,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *); -/* persistcfg.c */ -void lbs_persist_config_init(struct net_device *net); -void lbs_persist_config_remove(struct net_device *net); - - /* main.c */ struct lbs_private *lbs_add_card(void *card, struct device *dmdev); void lbs_remove_card(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 1a675111300d..6a8d2b291d8c 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -6,6 +6,7 @@ #ifndef _LBS_DEV_H_ #define _LBS_DEV_H_ +#include "mesh.h" #include "scan.h" #include "assoc.h" @@ -21,17 +22,6 @@ struct sleep_params { uint16_t sp_reserved; }; -/* Mesh statistics */ -struct lbs_mesh_stats { - u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ - u32 fwd_unicast_cnt; /* Fwd: Unicast counter */ - u32 fwd_drop_ttl; /* Fwd: TTL zero */ - u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */ - u32 fwd_drop_noroute; /* Fwd: No route to Destination */ - u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */ - u32 drop_blind; /* Rx: Dropped by blinding table */ - u32 tx_failed_cnt; /* Tx: Failed transmissions */ -}; /** Private structure for the MV device */ struct lbs_private { diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h new file mode 100644 index 000000000000..3708b6b386cb --- /dev/null +++ b/drivers/net/wireless/libertas/mesh.h @@ -0,0 +1,32 @@ +/** + * Contains all definitions needed for the Libertas' MESH implementation. + */ +#ifndef _LBS_MESH_H_ +#define _LBS_MESH_H_ + + +#include + + +/* Mesh statistics */ +struct lbs_mesh_stats { + u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ + u32 fwd_unicast_cnt; /* Fwd: Unicast counter */ + u32 fwd_drop_ttl; /* Fwd: TTL zero */ + u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */ + u32 fwd_drop_noroute; /* Fwd: No route to Destination */ + u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */ + u32 drop_blind; /* Rx: Dropped by blinding table */ + u32 tx_failed_cnt; /* Tx: Failed transmissions */ +}; + + +struct net_device; + +void lbs_persist_config_init(struct net_device *net); +void lbs_persist_config_remove(struct net_device *net); + +extern struct iw_handler_def mesh_handler_def; + + +#endif diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index 7863baf7d234..f3f19fe8c6c6 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -7,12 +7,11 @@ void lbs_send_disconnect_notification(struct lbs_private *priv); void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); -extern struct iw_handler_def lbs_handler_def; -extern struct iw_handler_def mesh_handler_def; - struct chan_freq_power *lbs_find_cfp_by_band_and_channel( struct lbs_private *priv, u8 band, u16 channel); +extern struct iw_handler_def lbs_handler_def; + #endif -- cgit v1.2.3 From e0e42da3a4df6f487b59dad608db56e25001bcdb Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 25 Nov 2009 13:10:15 +0100 Subject: libertas: moveing mesh-related functions into mesh.c This moves mesh initialization, start/stop and rx/tx handling from into mesh.c. Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/decl.h | 3 + drivers/net/wireless/libertas/main.c | 357 ++-------------------------- drivers/net/wireless/libertas/mesh.c | 441 ++++++++++++++++++++++++++++++++++- drivers/net/wireless/libertas/mesh.h | 24 ++ drivers/net/wireless/libertas/rx.c | 11 +- drivers/net/wireless/libertas/tx.c | 7 +- 6 files changed, 480 insertions(+), 363 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index cf3196a7343d..709ffcad22ad 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -34,6 +34,9 @@ int lbs_start_card(struct lbs_private *priv); void lbs_stop_card(struct lbs_private *priv); void lbs_host_to_card_done(struct lbs_private *priv); +int lbs_set_mac_address(struct net_device *dev, void *addr); +void lbs_set_multicast_list(struct net_device *dev); + int lbs_suspend(struct lbs_private *priv); void lbs_resume(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 01f46cf288d7..db38a5a719fa 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -94,107 +94,9 @@ u8 lbs_data_rate_to_fw_index(u32 rate) return 0; } -/** - * Attributes exported through sysfs - */ - -/** - * @brief Get function for sysfs attribute anycast_mask - */ -static ssize_t lbs_anycast_get(struct device *dev, - struct device_attribute *attr, char * buf) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - struct cmd_ds_mesh_access mesh_access; - int ret; - - memset(&mesh_access, 0, sizeof(mesh_access)); - - ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access); - if (ret) - return ret; - - return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0])); -} - -/** - * @brief Set function for sysfs attribute anycast_mask - */ -static ssize_t lbs_anycast_set(struct device *dev, - struct device_attribute *attr, const char * buf, size_t count) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - struct cmd_ds_mesh_access mesh_access; - uint32_t datum; - int ret; - - memset(&mesh_access, 0, sizeof(mesh_access)); - sscanf(buf, "%x", &datum); - mesh_access.data[0] = cpu_to_le32(datum); - - ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access); - if (ret) - return ret; - - return strlen(buf); -} - -/** - * @brief Get function for sysfs attribute prb_rsp_limit - */ -static ssize_t lbs_prb_rsp_limit_get(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - struct cmd_ds_mesh_access mesh_access; - int ret; - u32 retry_limit; - - memset(&mesh_access, 0, sizeof(mesh_access)); - mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET); - - ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, - &mesh_access); - if (ret) - return ret; - - retry_limit = le32_to_cpu(mesh_access.data[1]); - return snprintf(buf, 10, "%d\n", retry_limit); -} - -/** - * @brief Set function for sysfs attribute prb_rsp_limit - */ -static ssize_t lbs_prb_rsp_limit_set(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - struct cmd_ds_mesh_access mesh_access; - int ret; - unsigned long retry_limit; - - memset(&mesh_access, 0, sizeof(mesh_access)); - mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET); - - if (!strict_strtoul(buf, 10, &retry_limit)) - return -ENOTSUPP; - if (retry_limit > 15) - return -ENOTSUPP; - - mesh_access.data[1] = cpu_to_le32(retry_limit); - - ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, - &mesh_access); - if (ret) - return ret; - - return strlen(buf); -} static int lbs_add_rtap(struct lbs_private *priv); static void lbs_remove_rtap(struct lbs_private *priv); -static int lbs_add_mesh(struct lbs_private *priv); -static void lbs_remove_mesh(struct lbs_private *priv); /** @@ -260,74 +162,7 @@ static ssize_t lbs_rtap_set(struct device *dev, static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set ); /** - * Get function for sysfs attribute mesh - */ -static ssize_t lbs_mesh_get(struct device *dev, - struct device_attribute *attr, char * buf) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev); -} - -/** - * Set function for sysfs attribute mesh - */ -static ssize_t lbs_mesh_set(struct device *dev, - struct device_attribute *attr, const char * buf, size_t count) -{ - struct lbs_private *priv = to_net_dev(dev)->ml_priv; - int enable; - int ret, action = CMD_ACT_MESH_CONFIG_STOP; - - sscanf(buf, "%x", &enable); - enable = !!enable; - if (enable == !!priv->mesh_dev) - return count; - if (enable) - action = CMD_ACT_MESH_CONFIG_START; - ret = lbs_mesh_config(priv, action, priv->channel); - if (ret) - return ret; - - if (enable) - lbs_add_mesh(priv); - else - lbs_remove_mesh(priv); - - return count; -} - -/** - * lbs_mesh attribute to be exported per ethX interface - * through sysfs (/sys/class/net/ethX/lbs_mesh) - */ -static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); - -/** - * anycast_mask attribute to be exported per mshX interface - * through sysfs (/sys/class/net/mshX/anycast_mask) - */ -static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); - -/** - * prb_rsp_limit attribute to be exported per mshX interface - * through sysfs (/sys/class/net/mshX/prb_rsp_limit) - */ -static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get, - lbs_prb_rsp_limit_set); - -static struct attribute *lbs_mesh_sysfs_entries[] = { - &dev_attr_anycast_mask.attr, - &dev_attr_prb_rsp_limit.attr, - NULL, -}; - -static struct attribute_group lbs_mesh_attr_group = { - .attrs = lbs_mesh_sysfs_entries, -}; - -/** - * @brief This function opens the ethX or mshX interface + * @brief This function opens the ethX interface * * @param dev A pointer to net_device structure * @return 0 or -EBUSY if monitor mode active @@ -346,18 +181,12 @@ static int lbs_dev_open(struct net_device *dev) goto out; } - if (dev == priv->mesh_dev) { - priv->mesh_open = 1; - priv->mesh_connect_status = LBS_CONNECTED; - netif_carrier_on(dev); - } else { - priv->infra_open = 1; + priv->infra_open = 1; - if (priv->connect_status == LBS_CONNECTED) - netif_carrier_on(dev); - else - netif_carrier_off(dev); - } + if (priv->connect_status == LBS_CONNECTED) + netif_carrier_on(dev); + else + netif_carrier_off(dev); if (!priv->tx_pending_len) netif_wake_queue(dev); @@ -368,33 +197,6 @@ static int lbs_dev_open(struct net_device *dev) return ret; } -/** - * @brief This function closes the mshX interface - * - * @param dev A pointer to net_device structure - * @return 0 - */ -static int lbs_mesh_stop(struct net_device *dev) -{ - struct lbs_private *priv = dev->ml_priv; - - lbs_deb_enter(LBS_DEB_MESH); - spin_lock_irq(&priv->driver_lock); - - priv->mesh_open = 0; - priv->mesh_connect_status = LBS_DISCONNECTED; - - netif_stop_queue(dev); - netif_carrier_off(dev); - - spin_unlock_irq(&priv->driver_lock); - - schedule_work(&priv->mcast_work); - - lbs_deb_leave(LBS_DEB_MESH); - return 0; -} - /** * @brief This function closes the ethX interface * @@ -466,7 +268,7 @@ void lbs_host_to_card_done(struct lbs_private *priv) } EXPORT_SYMBOL_GPL(lbs_host_to_card_done); -static int lbs_set_mac_address(struct net_device *dev, void *addr) +int lbs_set_mac_address(struct net_device *dev, void *addr) { int ret = 0; struct lbs_private *priv = dev->ml_priv; @@ -600,7 +402,7 @@ static void lbs_set_mcast_worker(struct work_struct *work) lbs_deb_leave(LBS_DEB_NET); } -static void lbs_set_multicast_list(struct net_device *dev) +void lbs_set_multicast_list(struct net_device *dev) { struct lbs_private *priv = dev->ml_priv; @@ -1177,7 +979,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) priv->card = card; - priv->mesh_open = 0; priv->infra_open = 0; @@ -1198,6 +999,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); + priv->mesh_open = 0; sprintf(priv->mesh_ssid, "mesh"); priv->mesh_ssid_len = 4; @@ -1292,50 +1094,12 @@ int lbs_start_card(struct lbs_private *priv) lbs_update_channel(priv); - /* Check mesh FW version and appropriately send the mesh start - * command + /* + * While rtap isn't related to mesh, only mesh-enabled + * firmware implements the rtap functionality via + * CMD_802_11_MONITOR_MODE. */ - if (priv->mesh_fw_ver == MESH_FW_OLD) { - /* Enable mesh, if supported, and work out which TLV it uses. - 0x100 + 291 is an unofficial value used in 5.110.20.pXX - 0x100 + 37 is the official value used in 5.110.21.pXX - but we check them in that order because 20.pXX doesn't - give an error -- it just silently fails. */ - - /* 5.110.20.pXX firmware will fail the command if the channel - doesn't match the existing channel. But only if the TLV - is correct. If the channel is wrong, _BOTH_ versions will - give an error to 0x100+291, and allow 0x100+37 to succeed. - It's just that 5.110.20.pXX will not have done anything - useful */ - - priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; - if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, - priv->channel)) { - priv->mesh_tlv = TLV_TYPE_MESH_ID; - if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, - priv->channel)) - priv->mesh_tlv = 0; - } - } else if (priv->mesh_fw_ver == MESH_FW_NEW) { - /* 10.0.0.pXX new firmwares should succeed with TLV - * 0x100+37; Do not invoke command with old TLV. - */ - priv->mesh_tlv = TLV_TYPE_MESH_ID; - if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, - priv->channel)) - priv->mesh_tlv = 0; - } - if (priv->mesh_tlv) { - lbs_add_mesh(priv); - - if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) - lbs_pr_err("cannot register lbs_mesh attribute\n"); - - /* While rtap isn't related to mesh, only mesh-enabled - * firmware implements the rtap functionality via - * CMD_802_11_MONITOR_MODE. - */ + if (lbs_init_mesh(priv)) { if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) lbs_pr_err("cannot register lbs_rtap attribute\n"); } @@ -1369,10 +1133,8 @@ void lbs_stop_card(struct lbs_private *priv) netif_carrier_off(dev); lbs_debugfs_remove_one(priv); - if (priv->mesh_tlv) { - device_remove_file(&dev->dev, &dev_attr_lbs_mesh); + if (lbs_deinit_mesh(priv)) device_remove_file(&dev->dev, &dev_attr_lbs_rtap); - } /* Delete the timeout of the currently processing command */ del_timer_sync(&priv->command_timer); @@ -1405,95 +1167,6 @@ out: EXPORT_SYMBOL_GPL(lbs_stop_card); -static const struct net_device_ops mesh_netdev_ops = { - .ndo_open = lbs_dev_open, - .ndo_stop = lbs_mesh_stop, - .ndo_start_xmit = lbs_hard_start_xmit, - .ndo_set_mac_address = lbs_set_mac_address, - .ndo_set_multicast_list = lbs_set_multicast_list, -}; - -/** - * @brief This function adds mshX interface - * - * @param priv A pointer to the struct lbs_private structure - * @return 0 if successful, -X otherwise - */ -static int lbs_add_mesh(struct lbs_private *priv) -{ - struct net_device *mesh_dev = NULL; - int ret = 0; - - lbs_deb_enter(LBS_DEB_MESH); - - /* Allocate a virtual mesh device */ - if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) { - lbs_deb_mesh("init mshX device failed\n"); - ret = -ENOMEM; - goto done; - } - mesh_dev->ml_priv = priv; - priv->mesh_dev = mesh_dev; - - mesh_dev->netdev_ops = &mesh_netdev_ops; - mesh_dev->ethtool_ops = &lbs_ethtool_ops; - memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, - sizeof(priv->dev->dev_addr)); - - SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent); - -#ifdef WIRELESS_EXT - mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def; -#endif - mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST; - /* Register virtual mesh interface */ - ret = register_netdev(mesh_dev); - if (ret) { - lbs_pr_err("cannot register mshX virtual interface\n"); - goto err_free; - } - - ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); - if (ret) - goto err_unregister; - - lbs_persist_config_init(mesh_dev); - - /* Everything successful */ - ret = 0; - goto done; - -err_unregister: - unregister_netdev(mesh_dev); - -err_free: - free_netdev(mesh_dev); - -done: - lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); - return ret; -} - -static void lbs_remove_mesh(struct lbs_private *priv) -{ - struct net_device *mesh_dev; - - - mesh_dev = priv->mesh_dev; - if (!mesh_dev) - return; - - lbs_deb_enter(LBS_DEB_MESH); - netif_stop_queue(mesh_dev); - netif_carrier_off(mesh_dev); - sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); - lbs_persist_config_remove(mesh_dev); - unregister_netdev(mesh_dev); - priv->mesh_dev = NULL; - free_netdev(mesh_dev); - lbs_deb_leave(LBS_DEB_MESH); -} - void lbs_queue_event(struct lbs_private *priv, u32 event) { unsigned long flags; diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 871f914a75fc..80c2c7a31c8e 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -6,15 +6,444 @@ #include #include -#include "host.h" +#include "mesh.h" #include "decl.h" -#include "dev.h" -#include "wext.h" -#include "debugfs.h" -#include "scan.h" -#include "assoc.h" #include "cmd.h" + +/*************************************************************************** + * Mesh sysfs support + */ + +/** + * Attributes exported through sysfs + */ + +/** + * @brief Get function for sysfs attribute anycast_mask + */ +static ssize_t lbs_anycast_get(struct device *dev, + struct device_attribute *attr, char * buf) +{ + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + struct cmd_ds_mesh_access mesh_access; + int ret; + + memset(&mesh_access, 0, sizeof(mesh_access)); + + ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access); + if (ret) + return ret; + + return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0])); +} + +/** + * @brief Set function for sysfs attribute anycast_mask + */ +static ssize_t lbs_anycast_set(struct device *dev, + struct device_attribute *attr, const char * buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + struct cmd_ds_mesh_access mesh_access; + uint32_t datum; + int ret; + + memset(&mesh_access, 0, sizeof(mesh_access)); + sscanf(buf, "%x", &datum); + mesh_access.data[0] = cpu_to_le32(datum); + + ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * @brief Get function for sysfs attribute prb_rsp_limit + */ +static ssize_t lbs_prb_rsp_limit_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + struct cmd_ds_mesh_access mesh_access; + int ret; + u32 retry_limit; + + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET); + + ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, + &mesh_access); + if (ret) + return ret; + + retry_limit = le32_to_cpu(mesh_access.data[1]); + return snprintf(buf, 10, "%d\n", retry_limit); +} + +/** + * @brief Set function for sysfs attribute prb_rsp_limit + */ +static ssize_t lbs_prb_rsp_limit_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + struct cmd_ds_mesh_access mesh_access; + int ret; + unsigned long retry_limit; + + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET); + + if (!strict_strtoul(buf, 10, &retry_limit)) + return -ENOTSUPP; + if (retry_limit > 15) + return -ENOTSUPP; + + mesh_access.data[1] = cpu_to_le32(retry_limit); + + ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, + &mesh_access); + if (ret) + return ret; + + return strlen(buf); +} + +/** + * Get function for sysfs attribute mesh + */ +static ssize_t lbs_mesh_get(struct device *dev, + struct device_attribute *attr, char * buf) +{ + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev); +} + +/** + * Set function for sysfs attribute mesh + */ +static ssize_t lbs_mesh_set(struct device *dev, + struct device_attribute *attr, const char * buf, size_t count) +{ + struct lbs_private *priv = to_net_dev(dev)->ml_priv; + int enable; + int ret, action = CMD_ACT_MESH_CONFIG_STOP; + + sscanf(buf, "%x", &enable); + enable = !!enable; + if (enable == !!priv->mesh_dev) + return count; + if (enable) + action = CMD_ACT_MESH_CONFIG_START; + ret = lbs_mesh_config(priv, action, priv->channel); + if (ret) + return ret; + + if (enable) + lbs_add_mesh(priv); + else + lbs_remove_mesh(priv); + + return count; +} + +/** + * lbs_mesh attribute to be exported per ethX interface + * through sysfs (/sys/class/net/ethX/lbs_mesh) + */ +static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); + +/** + * anycast_mask attribute to be exported per mshX interface + * through sysfs (/sys/class/net/mshX/anycast_mask) + */ +static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); + +/** + * prb_rsp_limit attribute to be exported per mshX interface + * through sysfs (/sys/class/net/mshX/prb_rsp_limit) + */ +static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get, + lbs_prb_rsp_limit_set); + +static struct attribute *lbs_mesh_sysfs_entries[] = { + &dev_attr_anycast_mask.attr, + &dev_attr_prb_rsp_limit.attr, + NULL, +}; + +static struct attribute_group lbs_mesh_attr_group = { + .attrs = lbs_mesh_sysfs_entries, +}; + + + +/*************************************************************************** + * Initializing and starting, stopping mesh + */ + +/* + * Check mesh FW version and appropriately send the mesh start + * command + */ +int lbs_init_mesh(struct lbs_private *priv) +{ + struct net_device *dev = priv->dev; + int ret = 0; + + lbs_deb_enter(LBS_DEB_MESH); + + if (priv->mesh_fw_ver == MESH_FW_OLD) { + /* Enable mesh, if supported, and work out which TLV it uses. + 0x100 + 291 is an unofficial value used in 5.110.20.pXX + 0x100 + 37 is the official value used in 5.110.21.pXX + but we check them in that order because 20.pXX doesn't + give an error -- it just silently fails. */ + + /* 5.110.20.pXX firmware will fail the command if the channel + doesn't match the existing channel. But only if the TLV + is correct. If the channel is wrong, _BOTH_ versions will + give an error to 0x100+291, and allow 0x100+37 to succeed. + It's just that 5.110.20.pXX will not have done anything + useful */ + + priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->channel)) { + priv->mesh_tlv = TLV_TYPE_MESH_ID; + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->channel)) + priv->mesh_tlv = 0; + } + } else if (priv->mesh_fw_ver == MESH_FW_NEW) { + /* 10.0.0.pXX new firmwares should succeed with TLV + * 0x100+37; Do not invoke command with old TLV. + */ + priv->mesh_tlv = TLV_TYPE_MESH_ID; + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + priv->channel)) + priv->mesh_tlv = 0; + } + if (priv->mesh_tlv) { + lbs_add_mesh(priv); + + if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) + lbs_pr_err("cannot register lbs_mesh attribute\n"); + + ret = 1; + } + + lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); + return ret; +} + + +int lbs_deinit_mesh(struct lbs_private *priv) +{ + struct net_device *dev = priv->dev; + int ret = 0; + + lbs_deb_enter(LBS_DEB_MESH); + + if (priv->mesh_tlv) { + device_remove_file(&dev->dev, &dev_attr_lbs_mesh); + ret = 1; + } + + lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); + return ret; +} + + +/** + * @brief This function closes the mshX interface + * + * @param dev A pointer to net_device structure + * @return 0 + */ +static int lbs_mesh_stop(struct net_device *dev) +{ + struct lbs_private *priv = dev->ml_priv; + + lbs_deb_enter(LBS_DEB_MESH); + spin_lock_irq(&priv->driver_lock); + + priv->mesh_open = 0; + priv->mesh_connect_status = LBS_DISCONNECTED; + + netif_stop_queue(dev); + netif_carrier_off(dev); + + spin_unlock_irq(&priv->driver_lock); + + schedule_work(&priv->mcast_work); + + lbs_deb_leave(LBS_DEB_MESH); + return 0; +} + +/** + * @brief This function opens the mshX interface + * + * @param dev A pointer to net_device structure + * @return 0 or -EBUSY if monitor mode active + */ +static int lbs_mesh_dev_open(struct net_device *dev) +{ + struct lbs_private *priv = dev->ml_priv; + int ret = 0; + + lbs_deb_enter(LBS_DEB_NET); + + spin_lock_irq(&priv->driver_lock); + + if (priv->monitormode) { + ret = -EBUSY; + goto out; + } + + priv->mesh_open = 1; + priv->mesh_connect_status = LBS_CONNECTED; + netif_carrier_on(dev); + + if (!priv->tx_pending_len) + netif_wake_queue(dev); + out: + + spin_unlock_irq(&priv->driver_lock); + lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); + return ret; +} + +static const struct net_device_ops mesh_netdev_ops = { + .ndo_open = lbs_mesh_dev_open, + .ndo_stop = lbs_mesh_stop, + .ndo_start_xmit = lbs_hard_start_xmit, + .ndo_set_mac_address = lbs_set_mac_address, + .ndo_set_multicast_list = lbs_set_multicast_list, +}; + +/** + * @brief This function adds mshX interface + * + * @param priv A pointer to the struct lbs_private structure + * @return 0 if successful, -X otherwise + */ +int lbs_add_mesh(struct lbs_private *priv) +{ + struct net_device *mesh_dev = NULL; + int ret = 0; + + lbs_deb_enter(LBS_DEB_MESH); + + /* Allocate a virtual mesh device */ + mesh_dev = alloc_netdev(0, "msh%d", ether_setup); + if (!mesh_dev) { + lbs_deb_mesh("init mshX device failed\n"); + ret = -ENOMEM; + goto done; + } + mesh_dev->ml_priv = priv; + priv->mesh_dev = mesh_dev; + + mesh_dev->netdev_ops = &mesh_netdev_ops; + mesh_dev->ethtool_ops = &lbs_ethtool_ops; + memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, + sizeof(priv->dev->dev_addr)); + + SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent); + +#ifdef WIRELESS_EXT + mesh_dev->wireless_handlers = &mesh_handler_def; +#endif + mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + /* Register virtual mesh interface */ + ret = register_netdev(mesh_dev); + if (ret) { + lbs_pr_err("cannot register mshX virtual interface\n"); + goto err_free; + } + + ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); + if (ret) + goto err_unregister; + + lbs_persist_config_init(mesh_dev); + + /* Everything successful */ + ret = 0; + goto done; + +err_unregister: + unregister_netdev(mesh_dev); + +err_free: + free_netdev(mesh_dev); + +done: + lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); + return ret; +} + +void lbs_remove_mesh(struct lbs_private *priv) +{ + struct net_device *mesh_dev; + + mesh_dev = priv->mesh_dev; + if (!mesh_dev) + return; + + lbs_deb_enter(LBS_DEB_MESH); + netif_stop_queue(mesh_dev); + netif_carrier_off(mesh_dev); + sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); + lbs_persist_config_remove(mesh_dev); + unregister_netdev(mesh_dev); + priv->mesh_dev = NULL; + free_netdev(mesh_dev); + lbs_deb_leave(LBS_DEB_MESH); +} + + + +/*************************************************************************** + * Sending and receiving + */ +struct net_device *lbs_mesh_set_dev(struct lbs_private *priv, + struct net_device *dev, struct rxpd *rxpd) +{ + if (priv->mesh_dev) { + if (priv->mesh_fw_ver == MESH_FW_OLD) { + if (rxpd->rx_control & RxPD_MESH_FRAME) + dev = priv->mesh_dev; + } else if (priv->mesh_fw_ver == MESH_FW_NEW) { + if (rxpd->u.bss.bss_num == MESH_IFACE_ID) + dev = priv->mesh_dev; + } + } + return dev; +} + + +void lbs_mesh_set_txpd(struct lbs_private *priv, + struct net_device *dev, struct txpd *txpd) +{ + if (dev == priv->mesh_dev) { + if (priv->mesh_fw_ver == MESH_FW_OLD) + txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); + else if (priv->mesh_fw_ver == MESH_FW_NEW) + txpd->u.bss.bss_num = MESH_IFACE_ID; + } +} + + +/*************************************************************************** + * Persistent configuration support + */ + static int mesh_get_default_parameters(struct device *dev, struct mrvl_mesh_defaults *defs) { diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index 3708b6b386cb..d683c6eef83c 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h @@ -22,10 +22,34 @@ struct lbs_mesh_stats { struct net_device; +struct lbs_private; + +int lbs_init_mesh(struct lbs_private *priv); +int lbs_deinit_mesh(struct lbs_private *priv); + +int lbs_add_mesh(struct lbs_private *priv); +void lbs_remove_mesh(struct lbs_private *priv); + + +/* Sending / Receiving */ + +struct rxpd; +struct txpd; + +struct net_device *lbs_mesh_set_dev(struct lbs_private *priv, + struct net_device *dev, struct rxpd *rxpd); +void lbs_mesh_set_txpd(struct lbs_private *priv, + struct net_device *dev, struct txpd *txpd); + + +/* Persistent configuration */ void lbs_persist_config_init(struct net_device *net); void lbs_persist_config_remove(struct net_device *net); + +/* WEXT handler */ + extern struct iw_handler_def mesh_handler_def; diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 9f18a19cc49d..2daf8ffdb7e1 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -160,15 +160,8 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) p_rx_pd = (struct rxpd *) skb->data; p_rx_pkt = (struct rxpackethdr *) ((u8 *)p_rx_pd + le32_to_cpu(p_rx_pd->pkt_ptr)); - if (priv->mesh_dev) { - if (priv->mesh_fw_ver == MESH_FW_OLD) { - if (p_rx_pd->rx_control & RxPD_MESH_FRAME) - dev = priv->mesh_dev; - } else if (priv->mesh_fw_ver == MESH_FW_NEW) { - if (p_rx_pd->u.bss.bss_num == MESH_IFACE_ID) - dev = priv->mesh_dev; - } - } + + dev = lbs_mesh_set_dev(priv, dev, p_rx_pd); lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min_t(unsigned int, skb->len, 100)); diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index eb856adbf8ea..315d1ce286ca 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -131,12 +131,7 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) txpd->tx_packet_length = cpu_to_le16(pkt_len); txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); - if (dev == priv->mesh_dev) { - if (priv->mesh_fw_ver == MESH_FW_OLD) - txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); - else if (priv->mesh_fw_ver == MESH_FW_NEW) - txpd->u.bss.bss_num = MESH_IFACE_ID; - } + lbs_mesh_set_txpd(priv, dev, txpd); lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd)); -- cgit v1.2.3 From c7fe64cf4a08561a9e8f57e6018a504881236e34 Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 25 Nov 2009 13:10:49 +0100 Subject: libertas: move mesh-only ethtool operations into mesh.c Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/ethtool.c | 84 ++------------------------------- drivers/net/wireless/libertas/mesh.c | 84 +++++++++++++++++++++++++++++++++ drivers/net/wireless/libertas/mesh.h | 11 +++++ 3 files changed, 99 insertions(+), 80 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 53d56ab83c03..63d020374c2b 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -8,17 +8,8 @@ #include "dev.h" #include "wext.h" #include "cmd.h" +#include "mesh.h" -static const char * mesh_stat_strings[]= { - "drop_duplicate_bcast", - "drop_ttl_zero", - "drop_no_fwd_route", - "drop_no_buffers", - "fwded_unicast_cnt", - "fwded_bcast_cnt", - "drop_blind_table", - "tx_failed_cnt" -}; static void lbs_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -73,73 +64,6 @@ out: return ret; } -static void lbs_ethtool_get_stats(struct net_device *dev, - struct ethtool_stats *stats, uint64_t *data) -{ - struct lbs_private *priv = dev->ml_priv; - struct cmd_ds_mesh_access mesh_access; - int ret; - - lbs_deb_enter(LBS_DEB_ETHTOOL); - - /* Get Mesh Statistics */ - ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access); - - if (ret) { - memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t))); - return; - } - - priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]); - priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]); - priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]); - priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]); - priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]); - priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]); - priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]); - priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]); - - data[0] = priv->mstats.fwd_drop_rbt; - data[1] = priv->mstats.fwd_drop_ttl; - data[2] = priv->mstats.fwd_drop_noroute; - data[3] = priv->mstats.fwd_drop_nobuf; - data[4] = priv->mstats.fwd_unicast_cnt; - data[5] = priv->mstats.fwd_bcast_cnt; - data[6] = priv->mstats.drop_blind; - data[7] = priv->mstats.tx_failed_cnt; - - lbs_deb_enter(LBS_DEB_ETHTOOL); -} - -static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset) -{ - struct lbs_private *priv = dev->ml_priv; - - if (sset == ETH_SS_STATS && dev == priv->mesh_dev) - return MESH_STATS_NUM; - - return -EOPNOTSUPP; -} - -static void lbs_ethtool_get_strings(struct net_device *dev, - uint32_t stringset, uint8_t *s) -{ - int i; - - lbs_deb_enter(LBS_DEB_ETHTOOL); - - switch (stringset) { - case ETH_SS_STATS: - for (i=0; i < MESH_STATS_NUM; i++) { - memcpy(s + i * ETH_GSTRING_LEN, - mesh_stat_strings[i], - ETH_GSTRING_LEN); - } - break; - } - lbs_deb_enter(LBS_DEB_ETHTOOL); -} - static void lbs_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { @@ -190,9 +114,9 @@ const struct ethtool_ops lbs_ethtool_ops = { .get_drvinfo = lbs_ethtool_get_drvinfo, .get_eeprom = lbs_ethtool_get_eeprom, .get_eeprom_len = lbs_ethtool_get_eeprom_len, - .get_sset_count = lbs_ethtool_get_sset_count, - .get_ethtool_stats = lbs_ethtool_get_stats, - .get_strings = lbs_ethtool_get_strings, + .get_sset_count = lbs_mesh_ethtool_get_sset_count, + .get_ethtool_stats = lbs_mesh_ethtool_get_stats, + .get_strings = lbs_mesh_ethtool_get_strings, .get_wol = lbs_ethtool_get_wol, .set_wol = lbs_ethtool_set_wol, }; diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 80c2c7a31c8e..3e12060a6470 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -880,3 +880,87 @@ void lbs_persist_config_remove(struct net_device *dev) sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group); sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group); } + + + +/*************************************************************************** + * Ethtool related + */ + +static const char *mesh_stat_strings[] = { + "drop_duplicate_bcast", + "drop_ttl_zero", + "drop_no_fwd_route", + "drop_no_buffers", + "fwded_unicast_cnt", + "fwded_bcast_cnt", + "drop_blind_table", + "tx_failed_cnt" +}; + +void lbs_mesh_ethtool_get_stats(struct net_device *dev, + struct ethtool_stats *stats, uint64_t *data) +{ + struct lbs_private *priv = dev->ml_priv; + struct cmd_ds_mesh_access mesh_access; + int ret; + + lbs_deb_enter(LBS_DEB_ETHTOOL); + + /* Get Mesh Statistics */ + ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access); + + if (ret) { + memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t))); + return; + } + + priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]); + priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]); + priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]); + priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]); + priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]); + priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]); + priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]); + priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]); + + data[0] = priv->mstats.fwd_drop_rbt; + data[1] = priv->mstats.fwd_drop_ttl; + data[2] = priv->mstats.fwd_drop_noroute; + data[3] = priv->mstats.fwd_drop_nobuf; + data[4] = priv->mstats.fwd_unicast_cnt; + data[5] = priv->mstats.fwd_bcast_cnt; + data[6] = priv->mstats.drop_blind; + data[7] = priv->mstats.tx_failed_cnt; + + lbs_deb_enter(LBS_DEB_ETHTOOL); +} + +int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset) +{ + struct lbs_private *priv = dev->ml_priv; + + if (sset == ETH_SS_STATS && dev == priv->mesh_dev) + return MESH_STATS_NUM; + + return -EOPNOTSUPP; +} + +void lbs_mesh_ethtool_get_strings(struct net_device *dev, + uint32_t stringset, uint8_t *s) +{ + int i; + + lbs_deb_enter(LBS_DEB_ETHTOOL); + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < MESH_STATS_NUM; i++) { + memcpy(s + i * ETH_GSTRING_LEN, + mesh_stat_strings[i], + ETH_GSTRING_LEN); + } + break; + } + lbs_deb_enter(LBS_DEB_ETHTOOL); +} diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index d683c6eef83c..23b38ba26cd0 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h @@ -53,4 +53,15 @@ void lbs_persist_config_remove(struct net_device *net); extern struct iw_handler_def mesh_handler_def; +/* Ethtool statistics */ + +struct ethtool_stats; + +void lbs_mesh_ethtool_get_stats(struct net_device *dev, + struct ethtool_stats *stats, uint64_t *data); +int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset); +void lbs_mesh_ethtool_get_strings(struct net_device *dev, + uint32_t stringset, uint8_t *s); + + #endif -- cgit v1.2.3 From ece1e3c61e59ba184150e5aff57bbc6355613e3e Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 25 Nov 2009 13:11:16 +0100 Subject: libertas: move mesh command handling into mesh.c Signed-off-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 168 --------------------------------- drivers/net/wireless/libertas/mesh.c | 175 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/libertas/mesh.h | 11 +++ 3 files changed, 186 insertions(+), 168 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 1065ce29cd08..b9b371bfa30f 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -3,7 +3,6 @@ * It prepares command and sends it to firmware when it is ready. */ -#include #include #include @@ -697,173 +696,6 @@ static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr, return 0; } -static int lbs_cmd_bt_access(struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) -{ - struct cmd_ds_bt_access *bt_access = &cmd->params.bt; - lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); - - cmd->command = cpu_to_le16(CMD_BT_ACCESS); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + - sizeof(struct cmd_header)); - cmd->result = 0; - bt_access->action = cpu_to_le16(cmd_action); - - switch (cmd_action) { - case CMD_ACT_BT_ACCESS_ADD: - memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN); - lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6); - break; - case CMD_ACT_BT_ACCESS_DEL: - memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN); - lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6); - break; - case CMD_ACT_BT_ACCESS_LIST: - bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); - break; - case CMD_ACT_BT_ACCESS_RESET: - break; - case CMD_ACT_BT_ACCESS_SET_INVERT: - bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); - break; - case CMD_ACT_BT_ACCESS_GET_INVERT: - break; - default: - break; - } - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - -static int lbs_cmd_fwt_access(struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) -{ - struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt; - lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); - - cmd->command = cpu_to_le16(CMD_FWT_ACCESS); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + - sizeof(struct cmd_header)); - cmd->result = 0; - - if (pdata_buf) - memcpy(fwt_access, pdata_buf, sizeof(*fwt_access)); - else - memset(fwt_access, 0, sizeof(*fwt_access)); - - fwt_access->action = cpu_to_le16(cmd_action); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - -int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, - struct cmd_ds_mesh_access *cmd) -{ - int ret; - - lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); - - cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS); - cmd->hdr.size = cpu_to_le16(sizeof(*cmd)); - cmd->hdr.result = 0; - - cmd->action = cpu_to_le16(cmd_action); - - ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd); - - lbs_deb_leave(LBS_DEB_CMD); - return ret; -} - -static int __lbs_mesh_config_send(struct lbs_private *priv, - struct cmd_ds_mesh_config *cmd, - uint16_t action, uint16_t type) -{ - int ret; - u16 command = CMD_MESH_CONFIG_OLD; - - lbs_deb_enter(LBS_DEB_CMD); - - /* - * Command id is 0xac for v10 FW along with mesh interface - * id in bits 14-13-12. - */ - if (priv->mesh_fw_ver == MESH_FW_NEW) - command = CMD_MESH_CONFIG | - (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET); - - cmd->hdr.command = cpu_to_le16(command); - cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config)); - cmd->hdr.result = 0; - - cmd->type = cpu_to_le16(type); - cmd->action = cpu_to_le16(action); - - ret = lbs_cmd_with_response(priv, command, cmd); - - lbs_deb_leave(LBS_DEB_CMD); - return ret; -} - -int lbs_mesh_config_send(struct lbs_private *priv, - struct cmd_ds_mesh_config *cmd, - uint16_t action, uint16_t type) -{ - int ret; - - if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG)) - return -EOPNOTSUPP; - - ret = __lbs_mesh_config_send(priv, cmd, action, type); - return ret; -} - -/* This function is the CMD_MESH_CONFIG legacy function. It only handles the - * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG - * are all handled by preparing a struct cmd_ds_mesh_config and passing it to - * lbs_mesh_config_send. - */ -int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) -{ - struct cmd_ds_mesh_config cmd; - struct mrvl_meshie *ie; - DECLARE_SSID_BUF(ssid); - - memset(&cmd, 0, sizeof(cmd)); - cmd.channel = cpu_to_le16(chan); - ie = (struct mrvl_meshie *)cmd.data; - - switch (action) { - case CMD_ACT_MESH_CONFIG_START: - ie->id = WLAN_EID_GENERIC; - ie->val.oui[0] = 0x00; - ie->val.oui[1] = 0x50; - ie->val.oui[2] = 0x43; - ie->val.type = MARVELL_MESH_IE_TYPE; - ie->val.subtype = MARVELL_MESH_IE_SUBTYPE; - ie->val.version = MARVELL_MESH_IE_VERSION; - ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP; - ie->val.active_metric_id = MARVELL_MESH_METRIC_ID; - ie->val.mesh_capability = MARVELL_MESH_CAPABILITY; - ie->val.mesh_id_len = priv->mesh_ssid_len; - memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len); - ie->len = sizeof(struct mrvl_meshie_val) - - IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len; - cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val)); - break; - case CMD_ACT_MESH_CONFIG_STOP: - break; - default: - return -1; - } - lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n", - action, priv->mesh_tlv, chan, - print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len)); - - return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); -} - static void lbs_queue_cmd(struct lbs_private *priv, struct cmd_ctrl_node *cmdnode) { diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 3e12060a6470..2f91c9b808af 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -440,6 +440,181 @@ void lbs_mesh_set_txpd(struct lbs_private *priv, } +/*************************************************************************** + * Mesh command handling + */ + +int lbs_cmd_bt_access(struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct cmd_ds_bt_access *bt_access = &cmd->params.bt; + lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); + + cmd->command = cpu_to_le16(CMD_BT_ACCESS); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + + sizeof(struct cmd_header)); + cmd->result = 0; + bt_access->action = cpu_to_le16(cmd_action); + + switch (cmd_action) { + case CMD_ACT_BT_ACCESS_ADD: + memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN); + lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", + bt_access->addr1, 6); + break; + case CMD_ACT_BT_ACCESS_DEL: + memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN); + lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", + bt_access->addr1, 6); + break; + case CMD_ACT_BT_ACCESS_LIST: + bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); + break; + case CMD_ACT_BT_ACCESS_RESET: + break; + case CMD_ACT_BT_ACCESS_SET_INVERT: + bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); + break; + case CMD_ACT_BT_ACCESS_GET_INVERT: + break; + default: + break; + } + lbs_deb_leave(LBS_DEB_CMD); + return 0; +} + +int lbs_cmd_fwt_access(struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt; + lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); + + cmd->command = cpu_to_le16(CMD_FWT_ACCESS); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + + sizeof(struct cmd_header)); + cmd->result = 0; + + if (pdata_buf) + memcpy(fwt_access, pdata_buf, sizeof(*fwt_access)); + else + memset(fwt_access, 0, sizeof(*fwt_access)); + + fwt_access->action = cpu_to_le16(cmd_action); + + lbs_deb_leave(LBS_DEB_CMD); + return 0; +} + +int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, + struct cmd_ds_mesh_access *cmd) +{ + int ret; + + lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); + + cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS); + cmd->hdr.size = cpu_to_le16(sizeof(*cmd)); + cmd->hdr.result = 0; + + cmd->action = cpu_to_le16(cmd_action); + + ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd); + + lbs_deb_leave(LBS_DEB_CMD); + return ret; +} + +static int __lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type) +{ + int ret; + u16 command = CMD_MESH_CONFIG_OLD; + + lbs_deb_enter(LBS_DEB_CMD); + + /* + * Command id is 0xac for v10 FW along with mesh interface + * id in bits 14-13-12. + */ + if (priv->mesh_fw_ver == MESH_FW_NEW) + command = CMD_MESH_CONFIG | + (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET); + + cmd->hdr.command = cpu_to_le16(command); + cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config)); + cmd->hdr.result = 0; + + cmd->type = cpu_to_le16(type); + cmd->action = cpu_to_le16(action); + + ret = lbs_cmd_with_response(priv, command, cmd); + + lbs_deb_leave(LBS_DEB_CMD); + return ret; +} + +int lbs_mesh_config_send(struct lbs_private *priv, + struct cmd_ds_mesh_config *cmd, + uint16_t action, uint16_t type) +{ + int ret; + + if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG)) + return -EOPNOTSUPP; + + ret = __lbs_mesh_config_send(priv, cmd, action, type); + return ret; +} + +/* This function is the CMD_MESH_CONFIG legacy function. It only handles the + * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG + * are all handled by preparing a struct cmd_ds_mesh_config and passing it to + * lbs_mesh_config_send. + */ +int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) +{ + struct cmd_ds_mesh_config cmd; + struct mrvl_meshie *ie; + DECLARE_SSID_BUF(ssid); + + memset(&cmd, 0, sizeof(cmd)); + cmd.channel = cpu_to_le16(chan); + ie = (struct mrvl_meshie *)cmd.data; + + switch (action) { + case CMD_ACT_MESH_CONFIG_START: + ie->id = WLAN_EID_GENERIC; + ie->val.oui[0] = 0x00; + ie->val.oui[1] = 0x50; + ie->val.oui[2] = 0x43; + ie->val.type = MARVELL_MESH_IE_TYPE; + ie->val.subtype = MARVELL_MESH_IE_SUBTYPE; + ie->val.version = MARVELL_MESH_IE_VERSION; + ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP; + ie->val.active_metric_id = MARVELL_MESH_METRIC_ID; + ie->val.mesh_capability = MARVELL_MESH_CAPABILITY; + ie->val.mesh_id_len = priv->mesh_ssid_len; + memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len); + ie->len = sizeof(struct mrvl_meshie_val) - + IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len; + cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val)); + break; + case CMD_ACT_MESH_CONFIG_STOP: + break; + default: + return -1; + } + lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n", + action, priv->mesh_tlv, chan, + print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len)); + + return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); +} + + + /*************************************************************************** * Persistent configuration support */ diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index 23b38ba26cd0..fea9b5d005fc 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h @@ -6,6 +6,7 @@ #include +#include /* Mesh statistics */ @@ -42,6 +43,16 @@ void lbs_mesh_set_txpd(struct lbs_private *priv, struct net_device *dev, struct txpd *txpd); +/* Command handling */ + +struct cmd_ds_command; + +int lbs_cmd_bt_access(struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf); +int lbs_cmd_fwt_access(struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf); + + /* Persistent configuration */ void lbs_persist_config_init(struct net_device *net); -- cgit v1.2.3 From a830df0714117574fd0d5fe98477059b3e9fd5bf Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 23 Nov 2009 22:33:27 +0100 Subject: ath9k: separate debugfs support from CONFIG_ATH_DEBUG In my setups, ath9k's debugfs files are most of the time much more useful than the messages generated by enabling CONFIG_ATH_DEBUG along with the right debug flags. Since CONFIG_ATH_DEBUG comes with a noticeable overhead on embedded systems, this patch makes it possible to use the debugfs files without that option. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/Kconfig | 13 ++++--------- drivers/net/wireless/ath/ath9k/Makefile | 2 +- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/debug.c | 6 ++++++ drivers/net/wireless/ath/ath9k/debug.h | 6 +++--- 5 files changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 006364f76bb4..03a1106ad725 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -23,17 +23,12 @@ config ATH9K If you choose to build a module, it'll be called ath9k. -if ATH_DEBUG - -config ATH9K_DEBUG +config ATH9K_DEBUGFS bool "Atheros ath9k debugging" depends on ATH9K ---help--- - Say Y, if you need ath9k to display debug messages. - Pass the debug mask as a module parameter: - - modprobe ath9k debug=0x00000200 + Say Y, if you need access to ath9k's statistics for + interrupts, rate control, etc. - Look in ath9k/debug.h for possible debug masks + Also required for changing debug message flags at run time. -endif # ATH_DEBUG diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index e53f9680a385..4985b2b1b0a9 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -7,7 +7,7 @@ ath9k-y += beacon.o \ ath9k-$(CONFIG_PCI) += pci.o ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o -ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o +ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 42f79caa870b..e2cef2ff5d8f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -486,7 +486,7 @@ struct ath_softc { int beacon_interval; -#ifdef CONFIG_ATH9K_DEBUG +#ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; #endif struct ath_beacon_config cur_beacon_conf; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 608fa06e531c..b66f72dbf7b9 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -31,6 +31,8 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file) return 0; } +#ifdef CONFIG_ATH_DEBUG + static ssize_t read_file_debug(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -71,6 +73,8 @@ static const struct file_operations fops_debug = { .owner = THIS_MODULE }; +#endif + static ssize_t read_file_dma(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -563,10 +567,12 @@ int ath9k_init_debug(struct ath_hw *ah) if (!sc->debug.debugfs_phy) goto err; +#ifdef CONFIG_ATH_DEBUG sc->debug.debugfs_debug = debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); if (!sc->debug.debugfs_debug) goto err; +#endif sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_dma); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index f282eeef669b..536663e3ee11 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -23,13 +23,13 @@ struct ath_txq; struct ath_buf; -#ifdef CONFIG_ATH9K_DEBUG +#ifdef CONFIG_ATH9K_DEBUGFS #define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ #else #define TX_STAT_INC(q, c) do { } while (0) #endif -#ifdef CONFIG_ATH9K_DEBUG +#ifdef CONFIG_ATH9K_DEBUGFS /** * struct ath_interrupt_stats - Contains statistics about interrupts @@ -186,6 +186,6 @@ static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, { } -#endif /* CONFIG_ATH9K_DEBUG */ +#endif /* CONFIG_ATH9K_DEBUGFS */ #endif /* DEBUG_H */ -- cgit v1.2.3 From 9bf22f2c4607dbb68beb26153d83fa52b82e2d2f Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 25 Nov 2009 00:02:26 +0100 Subject: iwmc3200wifi: Implement cfg80211 PMKSA API We need to implement the PMKSA API for proper WPA2 pre-auth and fast re-association. Our fullmac device generates all (re-)assoc IEs, and thus it needs the right PMKIDs. With this implementation we now get them from wpa_supplicant. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/cfg80211.c | 31 ++++++++++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/commands.c | 22 ++++++++++++++++++++ drivers/net/wireless/iwmc3200wifi/commands.h | 13 ++++++++++++ drivers/net/wireless/iwmc3200wifi/umac.h | 2 ++ 4 files changed, 68 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 7cfc2c0a1fbc..7c4f44a9c3e6 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -725,6 +725,33 @@ static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy, CFG_POWER_INDEX, iwm->conf.power_index); } +int iwm_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_ADD); +} + +int iwm_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_DEL); +} + +int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + struct cfg80211_pmksa pmksa; + + memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); + + return iwm_send_pmkid_update(iwm, &pmksa, IWM_CMD_PMKID_FLUSH); +} + + static struct cfg80211_ops iwm_cfg80211_ops = { .change_virtual_intf = iwm_cfg80211_change_iface, .add_key = iwm_cfg80211_add_key, @@ -741,6 +768,9 @@ static struct cfg80211_ops iwm_cfg80211_ops = { .set_tx_power = iwm_cfg80211_set_txpower, .get_tx_power = iwm_cfg80211_get_txpower, .set_power_mgmt = iwm_cfg80211_set_power_mgmt, + .set_pmksa = iwm_cfg80211_set_pmksa, + .del_pmksa = iwm_cfg80211_del_pmksa, + .flush_pmksa = iwm_cfg80211_flush_pmksa, }; static const u32 cipher_suites[] = { @@ -786,6 +816,7 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) set_wiphy_dev(wdev->wiphy, dev); wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX; + wdev->wiphy->max_num_pmkids = UMAC_MAX_NUM_PMKIDS; wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz; diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 46ca7c58f5ac..bd0630755b32 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -960,3 +960,25 @@ int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, sizeof(struct iwm_umac_cmd_stop_resume_tx)); } + +int iwm_send_pmkid_update(struct iwm_priv *iwm, + struct cfg80211_pmksa *pmksa, u32 command) +{ + struct iwm_umac_pmkid_update update; + int ret; + + memset(&update, 0, sizeof(struct iwm_umac_pmkid_update)); + + update.command = cpu_to_le32(command); + memcpy(&update.bssid, pmksa->bssid, ETH_ALEN); + memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN); + + ret = iwm_send_wifi_if_cmd(iwm, &update, + sizeof(struct iwm_umac_pmkid_update), 0); + if (ret) { + IWM_ERR(iwm, "PMKID update command failed\n"); + return ret; + } + + return 0; +} diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index 95cdf941b222..06af0552cd75 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -458,6 +458,17 @@ struct iwm_umac_cmd_stop_resume_tx { u16 reserved; } __attribute__ ((packed)); +#define IWM_CMD_PMKID_ADD 1 +#define IWM_CMD_PMKID_DEL 2 +#define IWM_CMD_PMKID_FLUSH 3 + +struct iwm_umac_pmkid_update { + __le32 command; + u8 bssid[ETH_ALEN]; + __le16 reserved; + u8 pmkid[WLAN_PMKID_LEN]; +} __attribute__ ((packed)); + /* LMAC commands */ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); int iwm_send_prio_table(struct iwm_priv *iwm); @@ -488,6 +499,8 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, struct iwm_umac_notif_stop_resume_tx *ntf); +int iwm_send_pmkid_update(struct iwm_priv *iwm, + struct cfg80211_pmksa *pmksa, u32 command); /* UDMA commands */ int iwm_target_reset(struct iwm_priv *iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h index 70094bfe7c91..7f54a145ca65 100644 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -298,6 +298,7 @@ struct iwm_udma_out_wifi_hdr { #define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID 0x1B #define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE 0x1C #define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS 0x1E +#define UMAC_WIFI_IF_CMD_PMKID_UPDATE 0x1F #define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER 0x20 /* UMAC WiFi interface ports */ @@ -771,6 +772,7 @@ struct iwm_umac_notif_stop_resume_tx { __le16 stop_resume_tid_msk; /* tid bitmask */ } __attribute__ ((packed)); +#define UMAC_MAX_NUM_PMKIDS 4 /* WiFi interface wrapper header */ struct iwm_umac_wifi_if { -- cgit v1.2.3 From c2ff581acab16c6af56d9e8c1a579bf041ec00b1 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 23 Nov 2009 18:40:45 -0600 Subject: b43: avoid PPC fault during resume The routine b43_is_hw_radio_enabled() has long been a problem. For PPC architecture with PHY Revision < 3, a read of the register B43_MMIO_HWENABLED_LO will cause a CPU fault unless b43_status() returns a value of 2 (B43_STAT_STARTED) (BUG 14181). Fixing that results in Bug 14538 in which the driver is unable to reassociate after resuming from hibernation because b43_status() returns 0. The correct fix would be to determine why the status is 0; however, I have not yet found why that happens. The correct value is found for my device, which has PHY revision >= 3. Returning TRUE when the PHY revision < 3 and b43_status() returns 0 fixes the regression for 2.6.32. This patch fixes the problem in Red Hat Bugzilla #538523. Signed-off-by: Larry Finger Tested-by: Christian Casteyde Signed-off-by: John W. Linville --- drivers/net/wireless/b43/rfkill.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index ffdce6f3c909..78016ae21c50 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -33,8 +33,14 @@ bool b43_is_hw_radio_enabled(struct b43_wldev *dev) & B43_MMIO_RADIO_HWENABLED_HI_MASK)) return 1; } else { - if (b43_status(dev) >= B43_STAT_STARTED && - b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) + /* To prevent CPU fault on PPC, do not read a register + * unless the interface is started; however, on resume + * for hibernation, this routine is entered early. When + * that happens, unconditionally return TRUE. + */ + if (b43_status(dev) < B43_STAT_STARTED) + return 1; + if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) & B43_MMIO_RADIO_HWENABLED_LO_MASK) return 1; } -- cgit v1.2.3 From 316a4d966cae3c2dec83ebb1ee1a3515f97b30ff Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 23 Nov 2009 18:42:36 -0600 Subject: b43legacy: avoid PPC fault during resume For PPC architecture with PHY Revision < 3, a read of the register B43_MMIO_HWENABLED_LO will cause a CPU fault unless b43legacy_status() returns a value of 2 (B43legacy_STAT_STARTED); however, one finds that the driver is unable to associate after resuming from hibernation unless this routine returns 1. To satisfy both conditions, the routine is rewritten to return TRUE whenever b43legacy_status() returns a value < 2. This patch fixes the second problem listed in the postings for Red Hat Bugzilla #538523. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/rfkill.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index 8783022db11e..d579df72b783 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -34,6 +34,13 @@ bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) return 1; } else { + /* To prevent CPU fault on PPC, do not read a register + * unless the interface is started; however, on resume + * for hibernation, this routine is entered early. When + * that happens, unconditionally return TRUE. + */ + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) + return 1; if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) return 1; -- cgit v1.2.3 From a5186e997524578b4ba91390ad947c767450dac8 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Tue, 24 Nov 2009 23:11:32 +0100 Subject: rt2x00: Fix padding bug on L2PAD devices. While reviewing the l2pad function to align both the header and the payload on a DMA-capable boundary a bug was discovered where the payload would not be properly aligned. The header_align value was used where the payload_align value should have been used. Signed-off-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 32d4aeabfd4d..239afc7a9c0b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -214,7 +214,7 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length) skb_push(skb, header_align); memmove(skb->data, skb->data + header_align, header_length); memmove(skb->data + header_length + l2pad, - skb->data + header_length + l2pad + header_align, + skb->data + header_length + l2pad + payload_align, frame_length - header_length); skbdesc->flags |= SKBDESC_L2_PADDED; } -- cgit v1.2.3 From 1f351e3840dcf25aaddec2d908c3ab06ae105ee6 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 25 Nov 2009 22:55:11 +0100 Subject: airo: Fix integer overflow warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On BigEndian gcc complains: drivers/net/wireless/airo.c: In function ‘sniffing_mode’: drivers/net/wireless/airo.c:4809: warning: integer overflow in expression Fix this by doing the bitwise AND on the host-endian value. Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 4eec87c3be2b..4331d675fcc6 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -4806,7 +4806,7 @@ static int airo_config_commit(struct net_device *dev, static inline int sniffing_mode(struct airo_info *ai) { - return le16_to_cpu(ai->config.rmode & RXMODE_MASK) >= + return (le16_to_cpu(ai->config.rmode) & le16_to_cpu(RXMODE_MASK)) >= le16_to_cpu(RXMODE_RFMON); } -- cgit v1.2.3 From a9a29ce674ac62e7bfcb6c1404ca86cda4782988 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 27 Nov 2009 12:01:35 +0100 Subject: ath9k: enable 2GHz band only if the device supports it Currently, the 2GHz band is enabled unconditionally, even if the device does not support it. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 15 +++++++++++++-- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 28 +++++++++++++++++----------- 3 files changed, 31 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 493160c8c754..2ec61f08cfdb 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -976,7 +976,10 @@ int ath9k_hw_init(struct ath_hw *ah) return r; ath9k_hw_init_mode_gain_regs(ah); - ath9k_hw_fill_cap_info(ah); + r = ath9k_hw_fill_cap_info(ah); + if (r) + return r; + ath9k_hw_init_11a_eeprom_fix(ah); r = ath9k_hw_init_macaddr(ah); @@ -3112,7 +3115,7 @@ EXPORT_SYMBOL(ath9k_hw_set_sta_beacon_timers); /* HW Capabilities */ /*******************/ -void ath9k_hw_fill_cap_info(struct ath_hw *ah) +int ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); @@ -3143,6 +3146,12 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) } eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE); + if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) { + ath_print(common, ATH_DBG_FATAL, + "no band has been marked as supported in EEPROM.\n"); + return -EINVAL; + } + bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); if (eeval & AR5416_OPFLAGS_11A) { @@ -3306,6 +3315,8 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) } else { btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE; } + + return 0; } bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 46e1572dc945..e2b0c73a616f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -620,7 +620,7 @@ void ath9k_hw_detach(struct ath_hw *ah); int ath9k_hw_init(struct ath_hw *ah); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange); -void ath9k_hw_fill_cap_info(struct ath_hw *ah); +int ath9k_hw_fill_cap_info(struct ath_hw *ah); bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 *result); bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b9598148767b..c48743452515 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1793,13 +1793,15 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, /* setup channels and rates */ - sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - sc->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_chantable); - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { + sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; + sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + sc->sbands[IEEE80211_BAND_2GHZ].n_channels = + ARRAY_SIZE(ath9k_2ghz_chantable); + sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; + sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates); + } if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; @@ -1876,8 +1878,9 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->rate_control_algorithm = "ath9k_rate_control"; - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &sc->sbands[IEEE80211_BAND_2GHZ]; if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &sc->sbands[IEEE80211_BAND_5GHZ]; @@ -1916,9 +1919,12 @@ int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, reg = &common->regulatory; if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (test_bit(ATH9K_MODE_11G, ah->caps.wireless_modes)) + setup_ht_cap(sc, + &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); + setup_ht_cap(sc, + &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); } /* initialize tx/rx engine */ -- cgit v1.2.3 From 6646a664e3b60bf3e5db676e0626e6ccd71b3363 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 1 Dec 2009 11:48:50 +0800 Subject: iwmc3200wifi: fix NULL pointer dereference in pmkid update When handling IWM_CMD_PMKID_FLUSH command, the bssid and pmkid in pmksa are all NULL. Check it before memcpy. Signed-off-by: Zhu Yi Acked-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index bd0630755b32..89b33fa8d4ef 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -970,8 +970,10 @@ int iwm_send_pmkid_update(struct iwm_priv *iwm, memset(&update, 0, sizeof(struct iwm_umac_pmkid_update)); update.command = cpu_to_le32(command); - memcpy(&update.bssid, pmksa->bssid, ETH_ALEN); - memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN); + if (pmksa->bssid) + memcpy(&update.bssid, pmksa->bssid, ETH_ALEN); + if (pmksa->pmkid) + memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN); ret = iwm_send_wifi_if_cmd(iwm, &update, sizeof(struct iwm_umac_pmkid_update), 0); -- cgit v1.2.3 From 52ce3e9a7db754b78cf2cbabc87013f921b25b28 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 2 Dec 2009 14:24:37 +0800 Subject: ipw2100: fix rebooting hang with driver loaded Add PCI .shutdown method so that we can disable the device during shutdown or reboot. Without this, the reboot doesn't work well on some platforms. This fixes http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2124 Tested-by: pablo Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 6c836c892e43..17a9cb3528fc 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -6573,6 +6573,16 @@ static int ipw2100_resume(struct pci_dev *pci_dev) } #endif +static void ipw2100_shutdown(struct pci_dev *pci_dev) +{ + struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); + + /* Take down the device; powers it off, etc. */ + ipw2100_down(priv); + + pci_disable_device(pci_dev); +} + #define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x } static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = { @@ -6636,6 +6646,7 @@ static struct pci_driver ipw2100_pci_driver = { .suspend = ipw2100_suspend, .resume = ipw2100_resume, #endif + .shutdown = ipw2100_shutdown, }; /** -- cgit v1.2.3 From df98a4967002d0df88d92f89662261e3a7867cf7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 2 Dec 2009 11:20:36 +0100 Subject: b43: fix two warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My gcc appears to be able to see past the function boundary and notices that the variable 'behaviour' could be used uninitialised: drivers/net/wireless/b43/leds.c: In function ‘b43_leds_register’: drivers/net/wireless/b43/leds.c:339: warning: ‘behaviour’ may be used uninitialized in this function drivers/net/wireless/b43/leds.c: In function ‘b43_leds_init’: drivers/net/wireless/b43/leds.c:262: warning: ‘behaviour’ may be used uninitialized in this function because b43_led_get_sprominfo() didn't initialise it in all cases. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/b43/leds.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 1e8dba488004..c587115dd2b9 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -246,6 +246,7 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev, *behaviour = B43_LED_OFF; break; default: + *behaviour = B43_LED_OFF; B43_WARN_ON(1); return; } -- cgit v1.2.3 From bd3709b546f0113b41f0ecceaf3452a073739bbc Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 2 Dec 2009 12:52:59 -0800 Subject: iwl3945: remove duplicated event logging code In the process of improving uCode event logging capability, the new implementation was introduced without removing the existing implementation. The event log will be dumped to dmesg twice. Remove the old implementation to only log the event once upon sys assert or request by user. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0db9b79a69a6..a63bd5ee53a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1701,15 +1701,6 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log) IWL_ERR(priv, "Start IWL Event Log Dump: display last %d count\n", size); - /* if uCode has wrapped back to top of log, start at the oldest entry, - * i.e the next one that uCode would fill. */ - if (num_wraps) - iwl3945_print_event_log(priv, next_entry, - capacity - next_entry, mode); - - /* (then/else) start at top of log */ - iwl3945_print_event_log(priv, 0, next_entry, mode); - #ifdef CONFIG_IWLWIFI_DEBUG if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { /* if uCode has wrapped back to top of log, -- cgit v1.2.3 From 212fb57519a65c8e15bd3f5db87c3328fcde88de Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 2 Dec 2009 12:53:00 -0800 Subject: iwlwifi: indicate uCode type when fail dump error/event log error_event_table_ptr is only set upon receipt of REPLY_ALIVE. Until then both event log and error log will fail. Add information to indicate which uCode encounter the failure case. Signed-off-by: Wey-Yi Guy Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c96513bddb10..b8377efb3ba7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1662,7 +1662,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) base = le32_to_cpu(priv->card_alive.error_event_table_ptr); if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); + IWL_ERR(priv, + "Not valid error log pointer 0x%08X for %s uCode\n", + base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); return; } @@ -1807,7 +1809,9 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log) base = le32_to_cpu(priv->card_alive.log_event_table_ptr); if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { - IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); + IWL_ERR(priv, + "Invalid event log pointer 0x%08X for %s uCode\n", + base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); return; } -- cgit v1.2.3 From 250cce26d5d03337aec4ff8405121f026adb4a89 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Wed, 2 Dec 2009 12:53:01 -0800 Subject: iwlwifi: driver version track kernel version The driver version number is a remnant from when there was an out-of-tree iwlwifi driver. Now that the driver forms part of kernel source we do not need a separate driver version. Instead, we now use the kernel version as driver version. We maintain the previous tags used to indicate which components the driver has been compiled with. Signed-off-by: Reinette Chatre Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.h | 4 +++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index cf7d3df0744e..675b7df632fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -63,6 +63,8 @@ #ifndef __iwl_core_h__ #define __iwl_core_h__ +#include + /************************ * forward declarations * ************************/ @@ -70,7 +72,7 @@ struct iwl_host_cmd; struct iwl_cmd; -#define IWLWIFI_VERSION "1.3.27k" +#define IWLWIFI_VERSION UTS_RELEASE "-k" #define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation" #define DRV_AUTHOR "" diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a63bd5ee53a7..2a28a1f8b1fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -76,11 +76,9 @@ #define VS #endif -#define IWL39_VERSION "1.2.26k" VD VS +#define DRV_VERSION IWLWIFI_VERSION VD VS #define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation" #define DRV_AUTHOR "" -#define DRV_VERSION IWL39_VERSION - MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); -- cgit v1.2.3 From f330d4f9dfd50c1870a3c4b4b3f855e78eb9ceaa Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 3 Dec 2009 11:40:15 +0100 Subject: iwmc3200wifi: Update wiwi priority table This update follows the firmware engineers recommendations. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 89b33fa8d4ef..63d20e0952e7 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -122,18 +122,18 @@ static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = { {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS}, - {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, + {4, 4, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, - {5, 5, 0, COEX_CALIBRATION_FLAGS}, + {6, 6, 0, COEX_CALIBRATION_FLAGS}, {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, - {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS}, + {6, 5, 0, COEX_CONNECTION_ESTAB_FLAGS}, {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, {1, 1, 0, COEX_RF_ON_FLAGS}, {1, 1, 0, COEX_RF_OFF_FLAGS}, - {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, + {7, 7, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, {1, 1, 0, COEX_RSRVD1_FLAGS}, {1, 1, 0, COEX_RSRVD2_FLAGS} -- cgit v1.2.3 From 1ee9d426ff8ae8312137fc9407eff23ca81cef26 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 3 Dec 2009 11:40:16 +0100 Subject: iwmc3200wifi: Coex table command does not expect a response When sending the wiwi coexistence priority table, we should not tell the LMAC that we want a response. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index 63d20e0952e7..f9dc4b58c499 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -192,7 +192,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm) return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD, &coex_table_cmd, - sizeof(struct iwm_coex_prio_table_cmd), 1); + sizeof(struct iwm_coex_prio_table_cmd), 0); } int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) -- cgit v1.2.3 From 43b5ffe1162a7fbaa89f1c392a28ac54c2e932f7 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 3 Dec 2009 11:40:17 +0100 Subject: iwmc3200wifi: Add wifi-wimax coexistence mode as a module parameter Wifi and wimax coexistence mode is set by wifi at boot time. There can be several modes, defined by priority tables. User space components can decide which one to select by writing to /sys/module/iwmc3200wifi/parameters/wiwi with this patch, before bringing the interface up. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/commands.c | 12 ++++++++---- drivers/net/wireless/iwmc3200wifi/iwm.h | 1 - drivers/net/wireless/iwmc3200wifi/main.c | 1 - 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index f9dc4b58c499..777584d76a88 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -99,6 +99,10 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, return ret; } +static int modparam_wiwi = COEX_MODE_CM; +module_param_named(wiwi, modparam_wiwi, int, 0644); +MODULE_PARM_DESC(wiwi, "Wifi-WiMAX coexistence: 1=SA, 2=XOR, 3=CM (default)"); + static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = { {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS}, @@ -148,7 +152,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm) coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK; - switch (iwm->conf.coexist_mode) { + switch (modparam_wiwi) { case COEX_MODE_XOR: case COEX_MODE_CM: coex_enabled = 1; @@ -173,7 +177,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm) COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK | COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK; - switch (iwm->conf.coexist_mode) { + switch (modparam_wiwi) { case COEX_MODE_XOR: memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl, sizeof(iwm_sta_xor_prio_tbl)); @@ -184,7 +188,7 @@ int iwm_send_prio_table(struct iwm_priv *iwm) break; default: IWM_ERR(iwm, "Invalid coex_mode 0x%x\n", - iwm->conf.coexist_mode); + modparam_wiwi); break; } } else @@ -396,7 +400,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags) return ret; ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_COEX_MODE, iwm->conf.coexist_mode); + CFG_COEX_MODE, modparam_wiwi); if (ret < 0) return ret; diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 8d091f918f33..5a26bb05a33a 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -81,7 +81,6 @@ struct iwm_conf { u32 assoc_timeout; u32 roam_timeout; u32 wireless_mode; - u32 coexist_mode; u8 ibss_band; u8 ibss_channel; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 087f04355c1b..0ffb04111a42 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -82,7 +82,6 @@ static struct iwm_conf def_iwm_conf = { .roam_timeout = 10, .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G | WIRELESS_MODE_11N, - .coexist_mode = COEX_MODE_CM, /* IBSS */ .ibss_band = UMAC_BAND_2GHZ, -- cgit v1.2.3 From 159bcfeb9123c91f0dc885a42b6387a98192f896 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 3 Dec 2009 11:40:18 +0100 Subject: iwmc3200wifi: Enable wimax core through module parameter When debugging the wifi firmware, we need to disable the wimax core to gain some memory space. The default value will keep the wimax core enabled. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/net/wireless/iwmc3200wifi/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless') diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 0ffb04111a42..7f34d6dd3c41 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -68,7 +68,6 @@ static struct iwm_conf def_iwm_conf = { .ct_kill_exit = 110, .reset_on_fatal_err = 1, .auto_connect = 1, - .wimax_not_present = 0, .enable_qos = 1, .mode = UMAC_MODE_BSS, @@ -94,6 +93,10 @@ static int modparam_reset; module_param_named(reset, modparam_reset, bool, 0644); MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])"); +static int modparam_wimax_enable = 1; +module_param_named(wimax_enable, modparam_wimax_enable, bool, 0644); +MODULE_PARM_DESC(wimax_enable, "Enable wimax core (default 1 [wimax enabled])"); + int iwm_mode_to_nl80211_iftype(int mode) { switch (mode) { @@ -486,7 +489,7 @@ static int iwm_config_boot_params(struct iwm_priv *iwm) int ret; /* check Wimax is off and config debug monitor */ - if (iwm->conf.wimax_not_present) { + if (!modparam_wimax_enable) { u32 data1 = 0x1f; u32 addr1 = 0x606BE258; -- cgit v1.2.3