提交 45ea4ea2 编写于 作者: D David S. Miller
......@@ -145,7 +145,6 @@ usage should require reading the full document.
interface in STA mode at first!
</para>
!Finclude/net/mac80211.h ieee80211_if_init_conf
!Finclude/net/mac80211.h ieee80211_if_conf
</chapter>
<chapter id="rx-tx">
......
......@@ -501,5 +501,6 @@ source "drivers/net/wireless/zd1211rw/Kconfig"
source "drivers/net/wireless/rt2x00/Kconfig"
source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/wl12xx/Kconfig"
source "drivers/net/wireless/iwmc3200wifi/Kconfig"
endmenu
......@@ -60,3 +60,5 @@ obj-$(CONFIG_ATH_COMMON) += ath/
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_WL12XX) += wl12xx/
obj-$(CONFIG_IWM) += iwmc3200wifi/
......@@ -1555,7 +1555,7 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
switch (key->alg) {
case ALG_WEP:
if (key->keylen == LEN_WEP40)
if (key->keylen == WLAN_KEY_LEN_WEP40)
ktype = AR9170_ENC_ALG_WEP64;
else
ktype = AR9170_ENC_ALG_WEP128;
......
......@@ -242,8 +242,8 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf);
static void ath5k_reset_tsf(struct ieee80211_hw *hw);
static int ath5k_beacon_update(struct ath5k_softc *sc,
struct sk_buff *skb);
static int ath5k_beacon_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
......@@ -2127,8 +2127,10 @@ ath5k_beacon_send(struct ath5k_softc *sc)
/* NB: hw still stops DMA, so proceed */
}
/* Note: Beacon buffer is updated on beacon_update when mac80211
* calls config_interface */
/* refresh the beacon for AP mode */
if (sc->opmode == NL80211_IFTYPE_AP)
ath5k_beacon_update(sc->hw, sc->vif);
ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
ath5k_hw_start_tx_dma(ah, sc->bhalq);
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
......@@ -3047,28 +3049,55 @@ ath5k_reset_tsf(struct ieee80211_hw *hw)
ath5k_hw_reset_tsf(sc->ah);
}
/*
* Updates the beacon that is sent by ath5k_beacon_send. For adhoc,
* this is called only once at config_bss time, for AP we do it every
* SWBA interrupt so that the TIM will reflect buffered frames.
*
* Called with the beacon lock.
*/
static int
ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb)
ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
unsigned long flags;
int ret;
struct ath5k_softc *sc = hw->priv;
struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
if (!skb) {
ret = -ENOMEM;
goto out;
}
ath5k_debug_dump_skb(sc, skb, "BC ", 1);
spin_lock_irqsave(&sc->block, flags);
ath5k_txbuf_free(sc, sc->bbuf);
sc->bbuf->skb = skb;
ret = ath5k_beacon_setup(sc, sc->bbuf);
if (ret)
sc->bbuf->skb = NULL;
out:
return ret;
}
/*
* Update the beacon and reconfigure the beacon queues.
*/
static void
ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
int ret;
unsigned long flags;
struct ath5k_softc *sc = hw->priv;
spin_lock_irqsave(&sc->block, flags);
ret = ath5k_beacon_update(hw, vif);
spin_unlock_irqrestore(&sc->block, flags);
if (!ret) {
if (ret == 0) {
ath5k_beacon_config(sc);
mmiowb();
}
return ret;
}
static void
set_beacon_filter(struct ieee80211_hw *hw, bool enable)
{
......@@ -3118,10 +3147,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
(vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_MESH_POINT ||
vif->type == NL80211_IFTYPE_AP)) {
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
if (beacon)
ath5k_beacon_update(sc, beacon);
ath5k_beacon_reconfig(hw, vif);
}
unlock:
......
......@@ -1038,9 +1038,9 @@ int ath5k_keycache_type(const struct ieee80211_key_conf *key)
case ALG_CCMP:
return AR5K_KEYTABLE_TYPE_CCM;
case ALG_WEP:
if (key->keylen == LEN_WEP40)
if (key->keylen == WLAN_KEY_LEN_WEP40)
return AR5K_KEYTABLE_TYPE_40;
else if (key->keylen == LEN_WEP104)
else if (key->keylen == WLAN_KEY_LEN_WEP104)
return AR5K_KEYTABLE_TYPE_104;
return -EINVAL;
default:
......
......@@ -1897,6 +1897,9 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
s16 min_pwrL, min_pwrR;
s16 pwr_i;
if (WARN_ON(stepL[0] == stepL[1] || stepR[0] == stepR[1]))
return 0;
if (pwrL[0] == pwrL[1])
min_pwrL = pwrL[0];
else {
......
......@@ -515,6 +515,10 @@ struct ath_rfkill {
#define SC_OP_LED_ON BIT(13)
#define SC_OP_SCANNING BIT(14)
#define SC_OP_TSF_RESET BIT(15)
#define SC_OP_WAIT_FOR_CAB BIT(16)
#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)
struct ath_bus_ops {
void (*read_cachesize)(struct ath_softc *sc, int *csz);
......@@ -599,6 +603,7 @@ struct ath_softc {
struct ath9k_debug debug;
#endif
struct ath_bus_ops *bus_ops;
struct ath_beacon_config cur_beacon_conf;
};
struct ath_wiphy {
......@@ -676,7 +681,9 @@ static inline void ath9k_ps_restore(struct ath_softc *sc)
{
if (atomic_dec_and_test(&sc->ps_usecount))
if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
!(sc->sc_flags & SC_OP_WAIT_FOR_BEACON))
!(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
SC_OP_WAIT_FOR_PSPOLL_DATA |
SC_OP_WAIT_FOR_TX_ACK)))
ath9k_hw_setpower(sc->sc_ah,
sc->sc_ah->restore_mode);
}
......
......@@ -507,8 +507,7 @@ void ath_beacon_tasklet(unsigned long data)
* slot. Slots that are not occupied will generate nothing.
*/
static void ath_beacon_config_ap(struct ath_softc *sc,
struct ath_beacon_config *conf,
struct ath_vif *avp)
struct ath_beacon_config *conf)
{
u32 nexttbtt, intval;
......@@ -553,14 +552,14 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
* we've associated with.
*/
static void ath_beacon_config_sta(struct ath_softc *sc,
struct ath_beacon_config *conf,
struct ath_vif *avp)
struct ath_beacon_config *conf)
{
struct ath9k_beacon_state bs;
int dtimperiod, dtimcount, sleepduration;
int cfpperiod, cfpcount;
u32 nexttbtt = 0, intval, tsftu;
u64 tsf;
int num_beacons, offset, dtim_dec_count, cfp_dec_count;
memset(&bs, 0, sizeof(bs));
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
......@@ -588,14 +587,27 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
*/
tsf = ath9k_hw_gettsf64(sc->sc_ah);
tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
do {
num_beacons = tsftu / intval + 1;
offset = tsftu % intval;
nexttbtt = tsftu - offset;
if (offset)
nexttbtt += intval;
if (--dtimcount < 0) {
dtimcount = dtimperiod - 1;
if (--cfpcount < 0)
cfpcount = cfpperiod - 1;
}
} while (nexttbtt < tsftu);
/* DTIM Beacon every dtimperiod Beacon */
dtim_dec_count = num_beacons % dtimperiod;
/* CFP every cfpperiod DTIM Beacon */
cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod;
if (dtim_dec_count)
cfp_dec_count++;
dtimcount -= dtim_dec_count;
if (dtimcount < 0)
dtimcount += dtimperiod;
cfpcount -= cfp_dec_count;
if (cfpcount < 0)
cfpcount += cfpperiod;
bs.bs_intval = intval;
bs.bs_nexttbtt = nexttbtt;
......@@ -654,7 +666,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
static void ath_beacon_config_adhoc(struct ath_softc *sc,
struct ath_beacon_config *conf,
struct ath_vif *avp,
struct ieee80211_vif *vif)
{
u64 tsf;
......@@ -698,43 +709,50 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
/* FIXME: Handle properly when vif is NULL */
if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
ath_beacon_start_adhoc(sc, vif);
}
void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
{
struct ath_beacon_config conf;
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
enum nl80211_iftype iftype;
/* Setup the beacon configuration parameters */
memset(&conf, 0, sizeof(struct ath_beacon_config));
conf.beacon_interval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL;
conf.listen_interval = 1;
conf.dtim_period = conf.beacon_interval;
conf.dtim_count = 1;
conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
if (vif) {
struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
switch(avp->av_opmode) {
case NL80211_IFTYPE_AP:
ath_beacon_config_ap(sc, &conf, avp);
break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
ath_beacon_config_adhoc(sc, &conf, avp, vif);
break;
case NL80211_IFTYPE_STATION:
ath_beacon_config_sta(sc, &conf, avp);
break;
default:
DPRINTF(sc, ATH_DBG_CONFIG,
"Unsupported beaconing mode\n");
return;
}
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
iftype = vif->type;
cur_conf->beacon_interval = bss_conf->beacon_int;
cur_conf->dtim_period = bss_conf->dtim_period;
cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1;
cur_conf->bmiss_timeout =
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
} else {
iftype = sc->sc_ah->opmode;
}
sc->sc_flags |= SC_OP_BEACONS;
switch (iftype) {
case NL80211_IFTYPE_AP:
ath_beacon_config_ap(sc, cur_conf);
break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
ath_beacon_config_adhoc(sc, cur_conf, vif);
break;
case NL80211_IFTYPE_STATION:
ath_beacon_config_sta(sc, cur_conf);
break;
default:
DPRINTF(sc, ATH_DBG_CONFIG,
"Unsupported beaconing mode\n");
return;
}
sc->sc_flags |= SC_OP_BEACONS;
}
......@@ -29,6 +29,7 @@ enum ATH_DEBUG {
ATH_DBG_BEACON = 0x00000100,
ATH_DBG_CONFIG = 0x00000200,
ATH_DBG_FATAL = 0x00000400,
ATH_DBG_PS = 0x00000800,
ATH_DBG_ANY = 0xffffffff
};
......
......@@ -2472,14 +2472,14 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
}
break;
case ATH9K_CIPHER_WEP:
if (k->kv_len < LEN_WEP40) {
if (k->kv_len < WLAN_KEY_LEN_WEP40) {
DPRINTF(ah->ah_sc, ATH_DBG_ANY,
"WEP key length %u too small\n", k->kv_len);
return false;
}
if (k->kv_len <= LEN_WEP40)
if (k->kv_len <= WLAN_KEY_LEN_WEP40)
keyType = AR_KEYTABLE_TYPE_40;
else if (k->kv_len <= LEN_WEP104)
else if (k->kv_len <= WLAN_KEY_LEN_WEP104)
keyType = AR_KEYTABLE_TYPE_104;
else
keyType = AR_KEYTABLE_TYPE_128;
......@@ -2498,7 +2498,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
key2 = get_unaligned_le32(k->kv_val + 6);
key3 = get_unaligned_le16(k->kv_val + 10);
key4 = get_unaligned_le32(k->kv_val + 12);
if (k->kv_len <= LEN_WEP104)
if (k->kv_len <= WLAN_KEY_LEN_WEP104)
key4 &= 0xff;
/*
......
......@@ -35,14 +35,14 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
#define CHAN2G(_freq, _idx) { \
.center_freq = (_freq), \
.hw_value = (_idx), \
.max_power = 30, \
.max_power = 20, \
}
#define CHAN5G(_freq, _idx) { \
.band = IEEE80211_BAND_5GHZ, \
.center_freq = (_freq), \
.hw_value = (_idx), \
.max_power = 30, \
.max_power = 20, \
}
/* Some 2 GHz radios are actually tunable on 2312-2732
......@@ -280,7 +280,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
if (r) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to reset channel (%u Mhz) "
"reset status %u\n",
"reset status %d\n",
channel->center_freq, r);
spin_unlock_bh(&sc->sc_resetlock);
return r;
......@@ -329,6 +329,12 @@ static void ath_ani_calibrate(unsigned long data)
if (sc->sc_flags & SC_OP_SCANNING)
goto set_timer;
/* Only calibrate if awake */
if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
goto set_timer;
ath9k_ps_wakeup(sc);
/* Long calibration runs independently of short calibration. */
if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
longcal = true;
......@@ -380,6 +386,8 @@ static void ath_ani_calibrate(unsigned long data)
}
}
ath9k_ps_restore(sc);
set_timer:
/*
* Set timer interval based on previous results.
......@@ -455,8 +463,11 @@ static void ath9k_tasklet(unsigned long data)
struct ath_softc *sc = (struct ath_softc *)data;
u32 status = sc->intrstatus;
ath9k_ps_wakeup(sc);
if (status & ATH9K_INT_FATAL) {
ath_reset(sc, false);
ath9k_ps_restore(sc);
return;
}
......@@ -469,8 +480,19 @@ static void ath9k_tasklet(unsigned long data)
if (status & ATH9K_INT_TX)
ath_tx_tasklet(sc);
if ((status & ATH9K_INT_TSFOOR) &&
(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
/*
* 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");
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC;
}
/* re-enable hardware interrupt */
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
ath9k_ps_restore(sc);
}
irqreturn_t ath_isr(int irq, void *dev)
......@@ -498,14 +520,11 @@ irqreturn_t ath_isr(int irq, void *dev)
if (sc->sc_flags & SC_OP_INVALID)
return IRQ_NONE;
ath9k_ps_wakeup(sc);
/* shared irq, not for us */
if (!ath9k_hw_intrpend(ah)) {
ath9k_ps_restore(sc);
if (!ath9k_hw_intrpend(ah))
return IRQ_NONE;
}
/*
* Figure out the reason(s) for the interrupt. Note
......@@ -520,10 +539,8 @@ irqreturn_t ath_isr(int irq, void *dev)
* If there are no status bits set, then this interrupt was not
* for me (should have been caught above).
*/
if (!status) {
ath9k_ps_restore(sc);
if (!status)
return IRQ_NONE;
}
/* Cache the status */
sc->intrstatus = status;
......@@ -560,20 +577,17 @@ irqreturn_t ath_isr(int irq, void *dev)
ath9k_hw_set_interrupts(ah, sc->imask);
}
if (status & ATH9K_INT_TIM_TIMER) {
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
if (status & ATH9K_INT_TIM_TIMER) {
/* Clear RxAbort bit so that we can
* receive frames */
ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
ath9k_hw_setrxabort(ah, 0);
sched = true;
ath9k_hw_setrxabort(sc->sc_ah, 0);
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
}
}
chip_reset:
ath9k_ps_restore(sc);
ath_debug_stat_interrupt(sc, status);
if (sched) {
......@@ -900,6 +914,13 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
if (avp->av_opmode == NL80211_IFTYPE_STATION) {
sc->curaid = bss_conf->aid;
ath9k_hw_write_associd(sc);
/*
* Request a re-configuration of Beacon related timers
* on the receipt of the first Beacon frame (i.e.,
* after time sync with the AP).
*/
sc->sc_flags |= SC_OP_BEACON_SYNC;
}
/* Configure the beacon */
......@@ -1094,7 +1115,7 @@ void ath_radio_enable(struct ath_softc *sc)
if (r) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to reset channel %u (%uMhz) ",
"reset status %u\n",
"reset status %d\n",
channel->center_freq, r);
}
spin_unlock_bh(&sc->sc_resetlock);
......@@ -1146,7 +1167,7 @@ void ath_radio_disable(struct ath_softc *sc)
if (r) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to reset channel %u (%uMhz) "
"reset status %u\n",
"reset status %d\n",
channel->center_freq, r);
}
spin_unlock_bh(&sc->sc_resetlock);
......@@ -1416,8 +1437,6 @@ static int ath_init(u16 devid, struct ath_softc *sc)
for (i = 0; i < sc->keymax; i++)
ath9k_hw_keyreset(ah, (u16) i);
error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy,
ath9k_reg_notifier);
if (error)
goto bad;
......@@ -1630,14 +1649,19 @@ int ath_attach(u16 devid, struct ath_softc *sc)
if (error != 0)
return error;
reg = &sc->sc_ah->regulatory;
/* get mac address from hardware and set in mac80211 */
SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr);
ath_set_hw_capab(sc, hw);
error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy,
ath9k_reg_notifier);
if (error)
return error;
reg = &sc->sc_ah->regulatory;
if (sc->sc_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))
......@@ -1709,7 +1733,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
if (r)
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to reset hardware; reset status %u\n", r);
"Unable to reset hardware; reset status %d\n", r);
spin_unlock_bh(&sc->sc_resetlock);
if (ath_startrecv(sc) != 0)
......@@ -2001,7 +2025,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
r = ath9k_hw_reset(sc->sc_ah, init_channel, false);
if (r) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to reset hardware; reset status %u "
"Unable to reset hardware; reset status %d "
"(freq %u MHz)\n", r,
curchan->center_freq);
spin_unlock_bh(&sc->sc_resetlock);
......@@ -2074,6 +2098,46 @@ static int ath9k_tx(struct ieee80211_hw *hw,
goto exit;
}
if (sc->hw->conf.flags & IEEE80211_CONF_PS) {
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.
*/
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 "
"while in PS mode\n");
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
}
}
if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) {
/*
* We are using PS-Poll and mac80211 can request TX while in
* 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)) {
DPRINTF(sc, 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");
sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK;
}
/*
* The actual restore operation will happen only after
* the sc_flags bit is cleared. We are just dropping
* the ps_usecount here.
*/
ath9k_ps_restore(sc);
}
memset(&txctl, 0, sizeof(struct ath_tx_control));
/*
......@@ -2311,7 +2375,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
ath9k_hw_setrxabort(sc->sc_ah, 0);
sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
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);
if (sc->imask & ATH9K_INT_TIM_TIMER) {
sc->imask &= ~ATH9K_INT_TIM_TIMER;
ath9k_hw_set_interrupts(sc->sc_ah,
......@@ -2386,8 +2453,10 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
*total_flags &= SUPPORTED_FILTERS;
sc->rx.rxfilter = *total_flags;
ath9k_ps_wakeup(sc);
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
ath9k_ps_restore(sc);
DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter);
}
......
......@@ -473,6 +473,159 @@ void ath_flushrecv(struct ath_softc *sc)
spin_unlock_bh(&sc->rx.rxflushlock);
}
static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
{
/* Check whether the Beacon frame has DTIM indicating buffered bc/mc */
struct ieee80211_mgmt *mgmt;
u8 *pos, *end, id, elen;
struct ieee80211_tim_ie *tim;
mgmt = (struct ieee80211_mgmt *)skb->data;
pos = mgmt->u.beacon.variable;
end = skb->data + skb->len;
while (pos + 2 < end) {
id = *pos++;
elen = *pos++;
if (pos + elen > end)
break;
if (id == WLAN_EID_TIM) {
if (elen < sizeof(*tim))
break;
tim = (struct ieee80211_tim_ie *) pos;
if (tim->dtim_count != 0)
break;
return tim->bitmap_ctrl & 0x01;
}
pos += elen;
}
return false;
}
static void ath_rx_ps_back_to_sleep(struct ath_softc *sc)
{
sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
}
static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt;
if (skb->len < 24 + 8 + 2 + 2)
return;
mgmt = (struct ieee80211_mgmt *)skb->data;
if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0)
return; /* not from our current AP */
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 "
"timestamp from the AP\n");
ath_beacon_config(sc, NULL);
}
if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
/* We are not in PS mode anymore; remain awake */
DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain "
"awake\n");
sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
return;
}
if (ath_beacon_dtim_pending_cab(skb)) {
/*
* Remain awake waiting for buffered broadcast/multicast
* frames.
*/
DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating "
"buffered broadcast/multicast frame(s)\n");
sc->sc_flags |= SC_OP_WAIT_FOR_CAB;
return;
}
if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) {
/*
* This can happen if a broadcast frame is dropped or the AP
* fails to send a frame indicating that all CAB frames have
* been delivered.
*/
DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n");
}
/* No more broadcast/multicast frames to be received at this point. */
ath_rx_ps_back_to_sleep(sc);
}
static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
hdr = (struct ieee80211_hdr *)skb->data;
/* Process Beacon and CAB receive in PS state */
if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) &&
ieee80211_is_beacon(hdr->frame_control))
ath_rx_ps_beacon(sc, skb);
else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) &&
(ieee80211_is_data(hdr->frame_control) ||
ieee80211_is_action(hdr->frame_control)) &&
is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_moredata(hdr->frame_control)) {
DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
"sleep\n");
/*
* No more broadcast/multicast frames to be received at this
* point.
*/
ath_rx_ps_back_to_sleep(sc);
} 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 "
"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 |
SC_OP_WAIT_FOR_TX_ACK));
}
}
static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status)
{
struct ieee80211_hdr *hdr;
hdr = (struct ieee80211_hdr *)skb->data;
/* Send the frame to mac80211 */
if (is_multicast_ether_addr(hdr->addr1)) {
int i;
/*
* Deliver broadcast/multicast frames to all suitable
* virtual wiphys.
*/
/* TODO: filter based on channel configuration */
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
struct sk_buff *nskb;
if (aphy == NULL)
continue;
nskb = skb_copy(skb, GFP_ATOMIC);
if (nskb)
__ieee80211_rx(aphy->hw, nskb, rx_status);
}
__ieee80211_rx(sc->hw, skb, rx_status);
} else {
/* Deliver unicast frames based on receiver address */
__ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status);
}
}
int ath_rx_tasklet(struct ath_softc *sc, int flush)
{
#define PA2DESC(_sc, _pa) \
......@@ -622,7 +775,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
rx_status.flag |= RX_FLAG_DECRYPTED;
} else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
} else if (ieee80211_has_protected(fc)
&& !decrypt_error && skb->len >= hdrlen + 4) {
keyix = skb->data[hdrlen + 3] >> 6;
......@@ -631,36 +784,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
}
if (ah->sw_mgmt_crypto &&
(rx_status.flag & RX_FLAG_DECRYPTED) &&
ieee80211_is_mgmt(hdr->frame_control)) {
ieee80211_is_mgmt(fc)) {
/* Use software decrypt for management frames. */
rx_status.flag &= ~RX_FLAG_DECRYPTED;
}
/* Send the frame to mac80211 */
if (hdr->addr1[5] & 0x01) {
int i;
/*
* Deliver broadcast/multicast frames to all suitable
* virtual wiphys.
*/
/* TODO: filter based on channel configuration */
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
struct sk_buff *nskb;
if (aphy == NULL)
continue;
nskb = skb_copy(skb, GFP_ATOMIC);
if (nskb)
__ieee80211_rx(aphy->hw, nskb,
&rx_status);
}
__ieee80211_rx(sc->hw, skb, &rx_status);
} else {
/* Deliver unicast frames based on receiver address */
__ieee80211_rx(ath_get_virt_hw(sc, hdr), skb,
&rx_status);
}
/* 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,
......@@ -672,6 +800,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
bf->bf_mpdu = NULL;
DPRINTF(sc, ATH_DBG_FATAL,
"dma_mapping_error() on RX\n");
ath_rx_send_to_mac80211(sc, skb, &rx_status);
break;
}
bf->bf_dmacontext = bf->bf_buf_addr;
......@@ -687,11 +816,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
sc->rx.rxotherant = 0;
}
if (ieee80211_is_beacon(fc) &&
(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) {
sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
}
if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
SC_OP_WAIT_FOR_PSPOLL_DATA)))
ath_rx_ps(sc, skb);
ath_rx_send_to_mac80211(sc, skb, &rx_status);
requeue:
list_move_tail(&bf->list, &sc->rx.rxbuf);
ath_rx_buf_link(sc, bf);
......
......@@ -1070,7 +1070,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true);
if (r)
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to reset hardware; reset status %u\n",
"Unable to reset hardware; reset status %d\n",
r);
spin_unlock_bh(&sc->sc_resetlock);
}
......@@ -1790,6 +1790,16 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
skb_pull(skb, padsize);
}
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 "
"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 |
SC_OP_WAIT_FOR_TX_ACK));
}
if (frame_type == ATH9K_NOT_INTERNAL)
ieee80211_tx_status(hw, skb);
else
......
......@@ -200,8 +200,10 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
r = freq_reg_info(wiphy, ch->center_freq,
&bandwidth, &reg_rule);
r = freq_reg_info(wiphy,
ch->center_freq,
bandwidth,
&reg_rule);
if (r)
continue;
/*
......@@ -265,7 +267,7 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
*/
ch = &sband->channels[11]; /* CH 12 */
r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, &reg_rule);
r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
if (!r) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
......@@ -273,7 +275,7 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
}
ch = &sband->channels[12]; /* CH 13 */
r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, &reg_rule);
r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
if (!r) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
......
......@@ -3553,27 +3553,25 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
B43_WARN_ON(wl->vif != vif);
spin_lock_irqsave(&wl->irq_lock, flags);
if (changed & BSS_CHANGED_BSSID) {
spin_lock_irqsave(&wl->irq_lock, flags);
if (conf->bssid)
memcpy(wl->bssid, conf->bssid, ETH_ALEN);
else
memset(wl->bssid, 0, ETH_ALEN);
}
if (b43_status(dev) >= B43_STAT_INITIALIZED) {
if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) {
B43_WARN_ON(vif->type != wl->if_type);
if (changed & BSS_CHANGED_BEACON)
b43_update_templates(wl);
} else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
if (changed & BSS_CHANGED_BEACON)
b43_update_templates(wl);
}
if (b43_status(dev) >= B43_STAT_INITIALIZED) {
if (changed & BSS_CHANGED_BEACON &&
(b43_is_mode(wl, NL80211_IFTYPE_AP) ||
b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) ||
b43_is_mode(wl, NL80211_IFTYPE_ADHOC)))
b43_update_templates(wl);
if (changed & BSS_CHANGED_BSSID)
b43_write_mac_bssid_templates(dev);
}
spin_unlock_irqrestore(&wl->irq_lock, flags);
}
spin_unlock_irqrestore(&wl->irq_lock, flags);
b43_mac_suspend(dev);
......@@ -3639,7 +3637,7 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
err = -EINVAL;
switch (key->alg) {
case ALG_WEP:
if (key->keylen == LEN_WEP40)
if (key->keylen == WLAN_KEY_LEN_WEP40)
algorithm = B43_SEC_ALGO_WEP40;
else
algorithm = B43_SEC_ALGO_WEP104;
......
......@@ -694,8 +694,8 @@ struct b43legacy_wldev {
/* Reason code of the last interrupt. */
u32 irq_reason;
u32 dma_reason[6];
/* saved irq enable/disable state bitfield. */
u32 irq_savedstate;
/* The currently active generic-interrupt mask. */
u32 irq_mask;
/* Link Quality calculation context. */
struct b43legacy_noise_calculation noisecalc;
/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
......
......@@ -583,35 +583,6 @@ static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev)
b43legacy_set_slot_time(dev, 20);
}
/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
* Returns the _previously_ enabled IRQ mask.
*/
static inline u32 b43legacy_interrupt_enable(struct b43legacy_wldev *dev,
u32 mask)
{
u32 old_mask;
old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask |
mask);
return old_mask;
}
/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
* Returns the _previously_ enabled IRQ mask.
*/
static inline u32 b43legacy_interrupt_disable(struct b43legacy_wldev *dev,
u32 mask)
{
u32 old_mask;
old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
return old_mask;
}
/* Synchronize IRQ top- and bottom-half.
* IRQs must be masked before calling this.
* This must not be called with the irq_lock held.
......@@ -1200,7 +1171,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev)
/* This is the bottom half of the asynchronous beacon update. */
/* Ignore interrupt in the future. */
dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
dev->irq_mask &= ~B43legacy_IRQ_BEACON;
cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID);
......@@ -1209,7 +1180,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev)
/* Schedule interrupt manually, if busy. */
if (beacon0_valid && beacon1_valid) {
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, B43legacy_IRQ_BEACON);
dev->irq_savedstate |= B43legacy_IRQ_BEACON;
dev->irq_mask |= B43legacy_IRQ_BEACON;
return;
}
......@@ -1247,12 +1218,11 @@ static void b43legacy_beacon_update_trigger_work(struct work_struct *work)
dev = wl->current_dev;
if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) {
spin_lock_irq(&wl->irq_lock);
/* update beacon right away or defer to irq */
dev->irq_savedstate = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
/* Update beacon right away or defer to IRQ. */
handle_irq_beacon(dev);
/* The handler might have updated the IRQ mask. */
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK,
dev->irq_savedstate);
dev->irq_mask);
mmiowb();
spin_unlock_irq(&wl->irq_lock);
}
......@@ -1398,7 +1368,7 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
if (reason & B43legacy_IRQ_TX_OK)
handle_irq_transmit_status(dev);
b43legacy_interrupt_enable(dev, dev->irq_savedstate);
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask);
mmiowb();
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
}
......@@ -1450,18 +1420,18 @@ static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id)
struct b43legacy_wldev *dev = dev_id;
u32 reason;
if (!dev)
return IRQ_NONE;
B43legacy_WARN_ON(!dev);
spin_lock(&dev->wl->irq_lock);
if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED))
/* This can only happen on shared IRQ lines. */
goto out;
reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) /* shared IRQ */
goto out;
ret = IRQ_HANDLED;
reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
reason &= dev->irq_mask;
if (!reason)
goto out;
......@@ -1485,10 +1455,9 @@ static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id)
& 0x0000DC00;
b43legacy_interrupt_ack(dev, reason);
/* disable all IRQs. They are enabled again in the bottom half. */
dev->irq_savedstate = b43legacy_interrupt_disable(dev,
B43legacy_IRQ_ALL);
/* save the reason code and call our bottom half. */
/* Disable all IRQs. They are enabled again in the bottom half. */
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0);
/* Save the reason code and call our bottom half. */
dev->irq_reason = reason;
tasklet_schedule(&dev->isr_tasklet);
out:
......@@ -1948,7 +1917,8 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev)
/* Re-enable IRQs. */
spin_lock_irq(&dev->wl->irq_lock);
b43legacy_interrupt_enable(dev, dev->irq_savedstate);
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK,
dev->irq_mask);
spin_unlock_irq(&dev->wl->irq_lock);
}
}
......@@ -1967,10 +1937,9 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev)
/* Mask IRQs before suspending MAC. Otherwise
* the MAC stays busy and won't suspend. */
spin_lock_irq(&dev->wl->irq_lock);
tmp = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0);
spin_unlock_irq(&dev->wl->irq_lock);
b43legacy_synchronize_irq(dev);
dev->irq_savedstate = tmp;
b43legacy_power_saving_ctl_bits(dev, -1, 1);
b43legacy_write32(dev, B43legacy_MMIO_MACCTL,
......@@ -2659,7 +2628,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
int antenna_tx;
int antenna_rx;
int err = 0;
u32 savedirqs;
antenna_tx = B43legacy_ANTENNA_DEFAULT;
antenna_rx = B43legacy_ANTENNA_DEFAULT;
......@@ -2699,7 +2667,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
spin_unlock_irqrestore(&wl->irq_lock, flags);
goto out_unlock_mutex;
}
savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0);
spin_unlock_irqrestore(&wl->irq_lock, flags);
b43legacy_synchronize_irq(dev);
......@@ -2738,7 +2706,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
}
spin_lock_irqsave(&wl->irq_lock, flags);
b43legacy_interrupt_enable(dev, savedirqs);
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask);
mmiowb();
spin_unlock_irqrestore(&wl->irq_lock, flags);
out_unlock_mutex:
......@@ -2801,7 +2769,6 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw,
struct b43legacy_wldev *dev;
struct b43legacy_phy *phy;
unsigned long flags;
u32 savedirqs;
mutex_lock(&wl->mutex);
B43legacy_WARN_ON(wl->vif != vif);
......@@ -2817,30 +2784,27 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw,
spin_unlock_irqrestore(&wl->irq_lock, flags);
goto out_unlock_mutex;
}
savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0);
if (changed & BSS_CHANGED_BSSID) {
spin_unlock_irqrestore(&wl->irq_lock, flags);
b43legacy_synchronize_irq(dev);
if (conf->bssid)
memcpy(wl->bssid, conf->bssid, ETH_ALEN);
else
memset(wl->bssid, 0, ETH_ALEN);
}
if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
if (changed & BSS_CHANGED_BEACON &&
(b43legacy_is_mode(wl, NL80211_IFTYPE_AP) ||
b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)))
b43legacy_update_templates(wl);
if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) {
B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP);
if (changed & BSS_CHANGED_BEACON)
b43legacy_update_templates(wl);
} else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
if (changed & BSS_CHANGED_BEACON)
b43legacy_update_templates(wl);
}
if (changed & BSS_CHANGED_BSSID)
b43legacy_write_mac_bssid_templates(dev);
}
spin_unlock_irqrestore(&wl->irq_lock, flags);
}
spin_unlock_irqrestore(&wl->irq_lock, flags);
b43legacy_mac_suspend(dev);
......@@ -2862,7 +2826,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw,
b43legacy_mac_enable(dev);
spin_lock_irqsave(&wl->irq_lock, flags);
b43legacy_interrupt_enable(dev, savedirqs);
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask);
/* XXX: why? */
mmiowb();
spin_unlock_irqrestore(&wl->irq_lock, flags);
......@@ -2922,8 +2886,7 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
* setting the status to INITIALIZED, as the interrupt handler
* won't care about IRQs then. */
spin_lock_irqsave(&wl->irq_lock, flags);
dev->irq_savedstate = b43legacy_interrupt_disable(dev,
B43legacy_IRQ_ALL);
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0);
b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */
spin_unlock_irqrestore(&wl->irq_lock, flags);
b43legacy_synchronize_irq(dev);
......@@ -2963,7 +2926,7 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev)
/* Start data flow (TX/RX) */
b43legacy_mac_enable(dev);
b43legacy_interrupt_enable(dev, dev->irq_savedstate);
b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask);
/* Start maintenance work */
b43legacy_periodic_tasks_setup(dev);
......@@ -3126,7 +3089,7 @@ static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev)
/* IRQ related flags */
dev->irq_reason = 0;
memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
dev->irq_savedstate = B43legacy_IRQ_MASKTEMPLATE;
dev->irq_mask = B43legacy_IRQ_MASKTEMPLATE;
dev->mac_suspended = 1;
......
......@@ -443,7 +443,7 @@ int b43legacy_pio_init(struct b43legacy_wldev *dev)
pio->queue3 = queue;
if (dev->dev->id.revision < 3)
dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND;
dev->irq_mask |= B43legacy_IRQ_PIO_WORKAROUND;
b43legacydbg(dev->wl, "PIO initialized\n");
err = 0;
......
......@@ -44,6 +44,15 @@
#include "iwl-core.h"
#include "iwl-dev.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;
......@@ -61,7 +70,7 @@ static const struct {
{10, 110, 110},
{5, 130, 130},
{0, 167, 167},
/*SOLID_ON*/
/* SOLID_ON */
{-1, IWL_LED_SOLID, 0}
};
......@@ -142,6 +151,30 @@ static int iwl3945_led_off(struct iwl_priv *priv, int led_id)
return iwl_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;
if (iwl_is_rfkill(priv))
iwl3945_led_off(priv, led_id);
else
iwl3945_led_on(priv, led_id);
return 0;
}
/*
* brightness call back function for Tx/Rx LED
*/
......@@ -165,26 +198,21 @@ 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_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->type == IWL_LED_TRG_ASSOC) {
priv->allow_blinking = 1;
IWL_DEBUG_LED(priv, "MAC is associated\n");
}
if (led->led_on)
led->led_on(priv, IWL_LED_LINK);
break;
case LED_OFF:
if (led->type == IWL_LED_TRG_ASSOC) {
priv->allow_blinking = 0;
IWL_DEBUG_LED(priv, "MAC is disassociated\n");
}
if (led->led_off)
led->led_off(priv, IWL_LED_LINK);
break;
......@@ -197,8 +225,6 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev,
}
}
/*
* Register led class with the system
*/
......@@ -237,12 +263,12 @@ static int iwl3945_led_register_led(struct iwl_priv *priv,
static inline u8 get_blink_rate(struct iwl_priv *priv)
{
int index;
u64 current_tpt = priv->rxtxpackets;
s64 tpt = current_tpt - priv->led_tpt;
s64 tpt = priv->rxtxpackets;
if (tpt < 0)
tpt = -tpt;
priv->led_tpt = current_tpt;
IWL_DEBUG_LED(priv, "tpt %lld \n", (long long)tpt);
if (!priv->allow_blinking)
index = IWL_MAX_BLINK_TBL;
......@@ -250,13 +276,9 @@ static inline u8 get_blink_rate(struct iwl_priv *priv)
for (index = 0; index < IWL_MAX_BLINK_TBL; index++)
if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE))
break;
return index;
}
static inline int is_rf_kill(struct iwl_priv *priv)
{
return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
test_bit(STATUS_RF_KILL_SW, &priv->status);
IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", index);
return index;
}
/*
......@@ -272,7 +294,7 @@ void iwl3945_led_background(struct iwl_priv *priv)
priv->last_blink_time = 0;
return;
}
if (is_rf_kill(priv)) {
if (iwl_is_rfkill(priv)) {
priv->last_blink_time = 0;
return;
}
......@@ -341,8 +363,8 @@ int iwl3945_led_register(struct iwl_priv *priv)
IWL_LED_TRG_ASSOC, 0, trigger);
/* for assoc always turn led on */
priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on;
priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_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)
......
......@@ -98,7 +98,6 @@ const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945] = {
* ... and set IWL_EVT_DISABLE to 1. */
void iwl3945_disable_events(struct iwl_priv *priv)
{
int ret;
int i;
u32 base; /* SRAM address of event log header */
u32 disable_ptr; /* SRAM address of event-disable bitmap array */
......@@ -159,26 +158,17 @@ void iwl3945_disable_events(struct iwl_priv *priv)
return;
}
ret = iwl_grab_nic_access(priv);
if (ret) {
IWL_WARN(priv, "Can not read from adapter at this time.\n");
return;
}
disable_ptr = iwl_read_targ_mem(priv, base + (4 * sizeof(u32)));
array_size = iwl_read_targ_mem(priv, base + (5 * sizeof(u32)));
iwl_release_nic_access(priv);
if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) {
IWL_DEBUG_INFO(priv, "Disabling selected uCode log events at 0x%x\n",
disable_ptr);
ret = iwl_grab_nic_access(priv);
for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++)
iwl_write_targ_mem(priv,
disable_ptr + (i * sizeof(u32)),
evt_disable[i]);
iwl_release_nic_access(priv);
} else {
IWL_DEBUG_INFO(priv, "Selected uCode log events may be disabled\n");
IWL_DEBUG_INFO(priv, " by writing \"1\"s into disable bitmap\n");
......@@ -908,55 +898,30 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
if (src == IWL_PWR_SRC_VAUX) {
if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) {
iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
~APMG_PS_CTRL_MSK_PWR_SRC);
iwl_release_nic_access(priv);
iwl_poll_bit(priv, CSR_GPIO_IN,
CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
CSR_GPIO_IN_BIT_AUX_POWER, 5000);
} else {
iwl_release_nic_access(priv);
}
} else {
iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
~APMG_PS_CTRL_MSK_PWR_SRC);
iwl_release_nic_access(priv);
iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */
}
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
return 0;
}
static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
int rc;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
rc = iwl_grab_nic_access(priv);
if (rc) {
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
}
iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->dma_addr);
iwl_write_direct32(priv, FH39_RCSR_RPTR_ADDR(0), rxq->rb_stts_dma);
iwl_write_direct32(priv, FH39_RCSR_WPTR(0), 0);
......@@ -973,23 +938,11 @@ static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
/* fake read to flush all prev I/O */
iwl_read_direct32(priv, FH39_RSSR_CTRL);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static int iwl3945_tx_reset(struct iwl_priv *priv)
{
int rc;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
rc = iwl_grab_nic_access(priv);
if (rc) {
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
}
/* bypass mode */
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0x2);
......@@ -1017,8 +970,6 @@ static int iwl3945_tx_reset(struct iwl_priv *priv)
FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH |
FH39_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
......@@ -1061,7 +1012,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
static int iwl3945_apm_init(struct iwl_priv *priv)
{
int ret = 0;
int ret;
iwl_power_initialize(priv);
......@@ -1083,10 +1034,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv)
goto out;
}
ret = iwl_grab_nic_access(priv);
if (ret)
goto out;
/* enable DMA */
iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
APMG_CLK_VAL_BSM_CLK_RQT);
......@@ -1097,7 +1044,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv)
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
iwl_release_nic_access(priv);
out:
return ret;
}
......@@ -1196,22 +1142,13 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv)
iwl3945_rx_init(priv, rxq);
spin_lock_irqsave(&priv->lock, flags);
/* Look at using this instead:
rxq->need_update = 1;
iwl_rx_queue_update_write_ptr(priv, rxq);
*/
rc = iwl_grab_nic_access(priv);
if (rc) {
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
}
iwl_write_direct32(priv, FH39_RCSR_WPTR(0), rxq->write & ~7);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
rc = iwl3945_txq_ctx_reset(priv);
if (rc)
......@@ -1243,14 +1180,6 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
{
int txq_id;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
if (iwl_grab_nic_access(priv)) {
spin_unlock_irqrestore(&priv->lock, flags);
iwl3945_hw_txq_ctx_free(priv);
return;
}
/* stop SCD */
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
......@@ -1263,9 +1192,6 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
1000);
}
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
iwl3945_hw_txq_ctx_free(priv);
}
......@@ -1310,12 +1236,8 @@ static void iwl3945_apm_stop(struct iwl_priv *priv)
static int iwl3945_apm_reset(struct iwl_priv *priv)
{
int rc;
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);
......@@ -1325,36 +1247,31 @@ static int iwl3945_apm_reset(struct iwl_priv *priv)
iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
rc = iwl_grab_nic_access(priv);
if (!rc) {
iwl_write_prph(priv, APMG_CLK_CTRL_REG,
APMG_CLK_VAL_BSM_CLK_RQT);
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,
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);
/* 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,
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,
udelay(5);
iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ);
iwl_release_nic_access(priv);
}
/* Clear the 'host command active' bit... */
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
return 0;
}
/**
......@@ -2500,14 +2417,6 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
int iwl3945_hw_rxq_stop(struct iwl_priv *priv)
{
int rc;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
rc = iwl_grab_nic_access(priv);
if (rc) {
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
}
iwl_write_direct32(priv, FH39_RCSR_CONFIG(0), 0);
rc = iwl_poll_direct_bit(priv, FH39_RSSR_STATUS,
......@@ -2515,28 +2424,17 @@ int iwl3945_hw_rxq_stop(struct iwl_priv *priv)
if (rc < 0)
IWL_ERR(priv, "Can't stop Rx DMA.\n");
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
{
int rc;
unsigned long flags;
int txq_id = txq->q.id;
struct iwl3945_shared *shared_data = priv->shared_virt;
shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr);
spin_lock_irqsave(&priv->lock, flags);
rc = iwl_grab_nic_access(priv);
if (rc) {
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
}
iwl_write_direct32(priv, FH39_CBCC_CTRL(txq_id), 0);
iwl_write_direct32(priv, FH39_CBCC_BASE(txq_id), 0);
......@@ -2546,11 +2444,9 @@ int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD |
FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL |
FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE);
iwl_release_nic_access(priv);
/* fake read to flush all prev. writes */
iwl_read32(priv, FH39_TSSR_CBB_BASE);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
......@@ -2858,10 +2754,6 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
inst_len = priv->ucode_init.len;
data_len = priv->ucode_init_data.len;
rc = iwl_grab_nic_access(priv);
if (rc)
return rc;
iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
......@@ -2875,10 +2767,8 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
le32_to_cpu(*image));
rc = iwl3945_verify_bsm(priv);
if (rc) {
iwl_release_nic_access(priv);
if (rc)
return rc;
}
/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
......@@ -2910,8 +2800,6 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
iwl_write_prph(priv, BSM_WR_CTRL_REG,
BSM_WR_CTRL_REG_BIT_START_EN);
iwl_release_nic_access(priv);
return 0;
}
......@@ -2950,6 +2838,7 @@ static struct iwl_lib_ops iwl3945_lib = {
.send_tx_power = iwl3945_send_tx_power,
.is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr,
.post_associate = iwl3945_post_associate,
.isr = iwl_isr_legacy,
.config_ap = iwl3945_config_ap,
};
......@@ -2983,7 +2872,8 @@ static struct iwl_cfg iwl3945_bg_cfg = {
.eeprom_size = IWL3945_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
.ops = &iwl3945_ops,
.mod_params = &iwl3945_mod_params
.mod_params = &iwl3945_mod_params,
.use_isr_legacy = true
};
static struct iwl_cfg iwl3945_abg_cfg = {
......@@ -2995,7 +2885,8 @@ static struct iwl_cfg iwl3945_abg_cfg = {
.eeprom_size = IWL3945_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_3945_EEPROM_VERSION,
.ops = &iwl3945_ops,
.mod_params = &iwl3945_mod_params
.mod_params = &iwl3945_mod_params,
.use_isr_legacy = true
};
struct pci_device_id iwl3945_hw_card_ids[] = {
......
......@@ -163,10 +163,6 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
inst_len = priv->ucode_init.len;
data_len = priv->ucode_init_data.len;
ret = iwl_grab_nic_access(priv);
if (ret)
return ret;
iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
......@@ -179,10 +175,8 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
_iwl_write_prph(priv, reg_offset, le32_to_cpu(*image));
ret = iwl4965_verify_bsm(priv);
if (ret) {
iwl_release_nic_access(priv);
if (ret)
return ret;
}
/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
......@@ -211,7 +205,6 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
* (e.g. when powering back up after power-save shutdown) */
iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN);
iwl_release_nic_access(priv);
return 0;
}
......@@ -229,20 +222,12 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
{
dma_addr_t pinst;
dma_addr_t pdata;
unsigned long flags;
int ret = 0;
/* bits 35:4 for 4965 */
pinst = priv->ucode_code.p_addr >> 4;
pdata = priv->ucode_data_backup.p_addr >> 4;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
/* Tell bootstrap uCode where to find image to load */
iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
......@@ -253,10 +238,6 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
* that all new ptr/size info is in place */
iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
priv->ucode_code.len | BSM_DRAM_INST_LOAD);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n");
return ret;
......@@ -312,10 +293,12 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv)
queue_work(priv->workqueue, &priv->restart);
}
static int is_fat_channel(__le32 rxon_flags)
static bool is_fat_channel(__le32 rxon_flags)
{
return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
(rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK);
int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK)
>> RXON_FLG_CHANNEL_MODE_POS;
return ((chan_mod == CHANNEL_MODE_PURE_40) ||
(chan_mod == CHANNEL_MODE_MIXED));
}
/*
......@@ -358,10 +341,6 @@ static int iwl4965_apm_init(struct iwl_priv *priv)
goto out;
}
ret = iwl_grab_nic_access(priv);
if (ret)
goto out;
/* enable DMA */
iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
APMG_CLK_VAL_BSM_CLK_RQT);
......@@ -372,7 +351,6 @@ static int iwl4965_apm_init(struct iwl_priv *priv)
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
iwl_release_nic_access(priv);
out:
return ret;
}
......@@ -454,11 +432,9 @@ static void iwl4965_apm_stop(struct iwl_priv *priv)
static int iwl4965_apm_reset(struct iwl_priv *priv)
{
int ret = 0;
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);
......@@ -475,9 +451,6 @@ static int iwl4965_apm_reset(struct iwl_priv *priv)
udelay(10);
ret = iwl_grab_nic_access(priv);
if (ret)
goto out;
/* 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);
......@@ -488,14 +461,10 @@ static int iwl4965_apm_reset(struct iwl_priv *priv)
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
iwl_release_nic_access(priv);
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
out:
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
......@@ -681,18 +650,11 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
{
u32 a;
unsigned long flags;
int ret;
int i, chan;
u32 reg_val;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
/* Clear 4965's internal Tx Scheduler data base */
priv->scd_base_addr = iwl_read_prph(priv, IWL49_SCD_SRAM_BASE_ADDR);
a = priv->scd_base_addr + IWL49_SCD_CONTEXT_DATA_OFFSET;
......@@ -759,10 +721,9 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
}
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
return 0;
}
static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
......@@ -788,6 +749,12 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
.nrg_th_ofdm = 100,
};
static void iwl4965_set_ct_threshold(struct iwl_priv *priv)
{
/* want Kelvin */
priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
}
/**
* iwl4965_hw_set_hw_params
*
......@@ -822,7 +789,8 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
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.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
priv->hw_params.sens = &iwl4965_sensitivity;
......@@ -1524,7 +1492,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv)
struct iwl4965_txpowertable_cmd cmd = { 0 };
int ret;
u8 band = 0;
u8 is_fat = 0;
bool is_fat = false;
u8 ctrl_chan_high = 0;
if (test_bit(STATUS_SCANNING, &priv->status)) {
......@@ -1602,7 +1570,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
{
int rc;
u8 band = 0;
u8 is_fat = 0;
bool is_fat = false;
u8 ctrl_chan_high = 0;
struct iwl4965_channel_switch_cmd cmd = { 0 };
const struct iwl_channel_info *ch_info;
......@@ -1833,8 +1801,6 @@ static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv,
static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo)
{
int ret = 0;
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
(IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
IWL_WARN(priv,
......@@ -1844,10 +1810,6 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
return -EINVAL;
}
ret = iwl_grab_nic_access(priv);
if (ret)
return ret;
iwl4965_tx_queue_stop_scheduler(priv, txq_id);
iwl_clear_bits_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id));
......@@ -1861,8 +1823,6 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
iwl_txq_ctx_deactivate(priv, txq_id);
iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
iwl_release_nic_access(priv);
return 0;
}
......@@ -1904,7 +1864,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
int tx_fifo, int sta_id, int tid, u16 ssn_idx)
{
unsigned long flags;
int ret;
u16 ra_tid;
if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
......@@ -1922,11 +1881,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
/* Stop this Tx queue before configuring it */
iwl4965_tx_queue_stop_scheduler(priv, txq_id);
......@@ -1959,7 +1913,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
......@@ -2331,9 +2284,13 @@ static struct iwl_lib_ops iwl4965_lib = {
},
.send_tx_power = iwl4965_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
.temperature = iwl4965_temperature_calib,
.post_associate = iwl_post_associate,
.config_ap = iwl_config_ap,
.isr = iwl_isr_legacy,
.temp_ops = {
.temperature = iwl4965_temperature_calib,
.set_ct_kill = iwl4965_set_ct_threshold,
},
};
static struct iwl_ops iwl4965_ops = {
......@@ -2354,6 +2311,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
.eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION,
.ops = &iwl4965_ops,
.mod_params = &iwl4965_mod_params,
.use_isr_legacy = true
};
/* Module firmware */
......
......@@ -87,6 +87,18 @@
#define IWL50_NUM_AMPDU_QUEUES 10
#define IWL50_FIRST_AMPDU_QUEUE 10
/* 5150 only */
#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5)
static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
{
u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv,
EEPROM_5000_TEMPERATURE);
/* offset = temperature - voltage / coef */
s32 offset = (s32)(temp_calib[0] - temp_calib[1] / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
return offset;
}
/* Fixed (non-configurable) rx data from phy */
/**
......
......@@ -124,10 +124,6 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
return ret;
}
ret = iwl_grab_nic_access(priv);
if (ret)
return ret;
/* enable DMA */
iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
......@@ -137,8 +133,6 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
iwl_release_nic_access(priv);
return ret;
}
......@@ -165,12 +159,9 @@ static void iwl5000_apm_stop(struct iwl_priv *priv)
static int iwl5000_apm_reset(struct iwl_priv *priv)
{
int ret = 0;
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);
......@@ -193,10 +184,6 @@ static int iwl5000_apm_reset(struct iwl_priv *priv)
goto out;
}
ret = iwl_grab_nic_access(priv);
if (ret)
goto out;
/* enable DMA */
iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
......@@ -205,11 +192,7 @@ static int iwl5000_apm_reset(struct iwl_priv *priv)
/* disable L1-Active */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
iwl_release_nic_access(priv);
out:
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
......@@ -252,11 +235,9 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
* (PCIe power is lost before PERST# is asserted),
* causing ME FW to lose ownership and not being able to obtain it back.
*/
iwl_grab_nic_access(priv);
iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
}
......@@ -434,15 +415,19 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
return &priv->eeprom[address];
}
static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv)
static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
{
const s32 volt2temp_coef = -5;
u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv,
EEPROM_5000_TEMPERATURE);
/* offset = temperate - voltage / coef */
s32 offset = temp_calib[0] - temp_calib[1] / volt2temp_coef;
s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - offset;
return threshold * volt2temp_coef;
const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) -
iwl_temp_calib_to_offset(priv);
priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef;
}
static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
{
/* want Celsius */
priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
}
/*
......@@ -533,19 +518,9 @@ static int iwl5000_load_section(struct iwl_priv *priv,
struct fw_desc *image,
u32 dst_addr)
{
int ret = 0;
unsigned long flags;
dma_addr_t phy_addr = image->p_addr;
u32 byte_cnt = image->len;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
iwl_write_direct32(priv,
FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
......@@ -574,8 +549,6 @@ static int iwl5000_load_section(struct iwl_priv *priv,
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
......@@ -736,18 +709,11 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
{
u32 a;
unsigned long flags;
int ret;
int i, chan;
u32 reg_val;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR);
a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET;
for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET;
......@@ -815,7 +781,6 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
iwl_txq_ctx_activate(priv, 8);
iwl_txq_ctx_activate(priv, 9);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
......@@ -868,17 +833,8 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
case CSR_HW_REV_TYPE_5150:
/* 5150 wants in Kelvin */
priv->hw_params.ct_kill_threshold =
iwl5150_get_ct_threshold(priv);
break;
default:
/* all others want Celsius */
priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
break;
}
if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
/* Set initial calibration set */
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
......@@ -900,7 +856,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
break;
}
return 0;
}
......@@ -1006,7 +961,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
int tx_fifo, int sta_id, int tid, u16 ssn_idx)
{
unsigned long flags;
int ret;
u16 ra_tid;
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
......@@ -1024,11 +978,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
/* Stop this Tx queue before configuring it */
iwl5000_tx_queue_stop_scheduler(priv, txq_id);
......@@ -1064,7 +1013,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
......@@ -1073,8 +1021,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo)
{
int ret;
if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
(IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
IWL_ERR(priv,
......@@ -1084,10 +1030,6 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
return -EINVAL;
}
ret = iwl_grab_nic_access(priv);
if (ret)
return ret;
iwl5000_tx_queue_stop_scheduler(priv, txq_id);
iwl_clear_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1 << txq_id));
......@@ -1101,8 +1043,6 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
iwl_txq_ctx_deactivate(priv, txq_id);
iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
iwl_release_nic_access(priv);
return 0;
}
......@@ -1434,6 +1374,17 @@ static void iwl5000_temperature(struct iwl_priv *priv)
priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
}
static void iwl5150_temperature(struct iwl_priv *priv)
{
u32 vt = 0;
s32 offset = iwl_temp_calib_to_offset(priv);
vt = le32_to_cpu(priv->statistics.general.temperature);
vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
/* now vt hold the temperature in Kelvin */
priv->temperature = KELVIN_TO_CELSIUS(vt);
}
/* Calc max signal level (dBm) among 3 possible receivers */
int iwl5000_calc_rssi(struct iwl_priv *priv,
struct iwl_rx_phy_res *rx_resp)
......@@ -1511,7 +1462,6 @@ struct iwl_lib_ops iwl5000_lib = {
.init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.temperature = iwl5000_temperature,
.update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
.init = iwl5000_apm_init,
......@@ -1537,7 +1487,62 @@ struct iwl_lib_ops iwl5000_lib = {
.query_addr = iwl5000_eeprom_query_addr,
},
.post_associate = iwl_post_associate,
.isr = iwl_isr_ict,
.config_ap = iwl_config_ap,
.temp_ops = {
.temperature = iwl5000_temperature,
.set_ct_kill = iwl5000_set_ct_threshold,
},
};
static struct iwl_lib_ops iwl5150_lib = {
.set_hw_params = iwl5000_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,
.txq_agg_enable = iwl5000_txq_agg_enable,
.txq_agg_disable = iwl5000_txq_agg_disable,
.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl_hw_txq_free_tfd,
.txq_init = iwl_hw_tx_queue_init,
.rx_handler_setup = iwl5000_rx_handler_setup,
.setup_deferred_work = iwl5000_setup_deferred_work,
.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
.load_ucode = iwl5000_load_ucode,
.init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
.init = iwl5000_apm_init,
.reset = iwl5000_apm_reset,
.stop = iwl5000_apm_stop,
.config = iwl5000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
.eeprom_ops = {
.regulatory_bands = {
EEPROM_5000_REG_BAND_1_CHANNELS,
EEPROM_5000_REG_BAND_2_CHANNELS,
EEPROM_5000_REG_BAND_3_CHANNELS,
EEPROM_5000_REG_BAND_4_CHANNELS,
EEPROM_5000_REG_BAND_5_CHANNELS,
EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
EEPROM_5000_REG_BAND_52_FAT_CHANNELS
},
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
.calib_version = iwl5000_eeprom_calib_version,
.query_addr = iwl5000_eeprom_query_addr,
},
.post_associate = iwl_post_associate,
.isr = iwl_isr_ict,
.config_ap = iwl_config_ap,
.temp_ops = {
.temperature = iwl5150_temperature,
.set_ct_kill = iwl5150_set_ct_threshold,
},
};
struct iwl_ops iwl5000_ops = {
......@@ -1547,6 +1552,13 @@ struct iwl_ops iwl5000_ops = {
.smgmt = &iwl5000_station_mgmt,
};
static struct iwl_ops iwl5150_ops = {
.lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
.smgmt = &iwl5000_station_mgmt,
};
struct iwl_mod_params iwl50_mod_params = {
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
......@@ -1642,7 +1654,7 @@ struct iwl_cfg iwl5150_agn_cfg = {
.ucode_api_max = IWL5150_UCODE_API_MAX,
.ucode_api_min = IWL5150_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl5000_ops,
.ops = &iwl5150_ops,
.eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
......
......@@ -270,6 +270,8 @@ const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
{"60", "64QAM 5/6"}
};
#define MCS_INDEX_PER_STREAM (8)
static inline u8 rs_extract_rate(u32 rate_n_flags)
{
return (u8)(rate_n_flags & 0xFF);
......@@ -652,19 +654,19 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
return 1;
}
/* FIXME:RS: in 4965 we don't use greenfield at all */
/* FIXME:RS: don't use greenfield for now in TX */
#if 0
static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf)
{
return (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
priv->current_ht_config.is_green_field &&
!priv->current_ht_config.non_GF_STA_present;
}
#endif
static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf)
/* in 4965 we don't use greenfield at all */
static inline u8 rs_use_green(struct iwl_priv *priv,
struct ieee80211_conf *conf)
{
return 0;
u8 is_green;
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
is_green = 0;
else
is_green = (conf_is_ht(conf) &&
priv->current_ht_config.is_green_field &&
!priv->current_ht_config.non_GF_STA_present);
return is_green;
}
/**
......@@ -2061,6 +2063,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
active_tbl = 1 - lq_sta->active_tbl;
tbl = &(lq_sta->lq_info[active_tbl]);
if (is_legacy(tbl->lq_type))
lq_sta->is_green = 0;
else
lq_sta->is_green = rs_use_green(priv, conf);
is_green = lq_sta->is_green;
/* current tx rate */
......@@ -2514,12 +2520,33 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
}
}
if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT)
rate_idx = rate_lowest_index(sband, sta);
else if (sband->band == IEEE80211_BAND_5GHZ)
if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) {
rate_idx -= IWL_FIRST_OFDM_RATE;
/* 6M and 9M shared same MCS index */
rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0;
if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
IWL_RATE_MIMO3_6M_PLCP)
rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM);
else if (rs_extract_rate(lq_sta->last_rate_n_flags) >=
IWL_RATE_MIMO2_6M_PLCP)
rate_idx = rate_idx + MCS_INDEX_PER_STREAM;
info->control.rates[0].flags = IEEE80211_TX_RC_MCS;
if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK)
info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI;
if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK)
info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA;
if (lq_sta->last_rate_n_flags & RATE_MCS_FAT_MSK)
info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK)
info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD;
} else {
if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT)
rate_idx = rate_lowest_index(sband, sta);
else if (sband->band == IEEE80211_BAND_5GHZ)
rate_idx -= IWL_FIRST_OFDM_RATE;
}
info->control.rates[0].idx = rate_idx;
}
static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
......@@ -2896,7 +2923,8 @@ 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_fat) ? "40MHz" : "20MHz");
desc += sprintf(buff+desc, " %s\n", (tbl->is_SGI) ? "SGI" : "");
desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "",
(lq_sta->is_green) ? "GF enabled" : "");
}
desc += sprintf(buff+desc, "last tx rate=0x%X\n",
lq_sta->last_rate_n_flags);
......@@ -2959,13 +2987,14 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
return -ENOMEM;
for (i = 0; i < LQ_SIZE; i++) {
desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n"
"rate=0x%X\n",
lq_sta->active_tbl == i ? "*" : "x",
lq_sta->lq_info[i].lq_type,
lq_sta->lq_info[i].is_SGI,
lq_sta->lq_info[i].is_fat,
lq_sta->lq_info[i].is_dup,
lq_sta->is_green,
lq_sta->lq_info[i].current_rate);
for (j = 0; j < IWL_RATE_COUNT; j++) {
desc += sprintf(buff+desc,
......
......@@ -503,24 +503,12 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
int iwl_hw_tx_queue_init(struct iwl_priv *priv,
struct iwl_tx_queue *txq)
{
int ret;
unsigned long flags;
int txq_id = txq->q.id;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
/* Circular buffer (TFD queue in DRAM) physical base address */
iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
txq->q.dma_addr >> 8);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
......@@ -709,6 +697,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
unsigned long reg_flags;
IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
(flags & HW_CARD_DISABLED) ? "Kill" : "On",
......@@ -720,32 +709,25 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
if (!iwl_grab_nic_access(priv)) {
iwl_write_direct32(
priv, HBUS_TARG_MBX_C,
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
iwl_release_nic_access(priv);
}
iwl_write_direct32(priv, HBUS_TARG_MBX_C,
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
if (!(flags & RXON_CARD_DISABLED)) {
iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
if (!iwl_grab_nic_access(priv)) {
iwl_write_direct32(
priv, HBUS_TARG_MBX_C,
iwl_write_direct32(priv, HBUS_TARG_MBX_C,
HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
iwl_release_nic_access(priv);
}
}
if (flags & RF_CARD_DISABLED) {
iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
iwl_read32(priv, CSR_UCODE_DRV_GP1);
spin_lock_irqsave(&priv->reg_lock, reg_flags);
if (!iwl_grab_nic_access(priv))
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
}
......@@ -774,14 +756,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret)
goto err;
if (src == IWL_PWR_SRC_VAUX) {
if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
......@@ -793,10 +767,7 @@ int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
~APMG_PS_CTRL_MSK_PWR_SRC);
}
iwl_release_nic_access(priv);
err:
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
return 0;
}
/**
......@@ -860,6 +831,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
unsigned long flags;
u8 fill_rx = 0;
u32 count = 8;
int total_empty;
/* uCode's read index (stored in shared DRAM) indicates the last Rx
* buffer that the driver may process (last buffer filled by ucode). */
......@@ -870,7 +842,12 @@ void iwl_rx_handle(struct iwl_priv *priv)
if (i == r)
IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i);
if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
/* calculate total frames need to be restock after handling RX */
total_empty = r - priv->rxq.write_actual;
if (total_empty < 0)
total_empty += RX_QUEUE_SIZE;
if (total_empty > (RX_QUEUE_SIZE / 2))
fill_rx = 1;
while (i != r) {
......@@ -947,7 +924,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
count++;
if (count >= 8) {
priv->rxq.read = i;
iwl_rx_queue_restock(priv);
iwl_rx_replenish_now(priv);
count = 0;
}
}
......@@ -955,7 +932,10 @@ void iwl_rx_handle(struct iwl_priv *priv)
/* Backtrack one entry */
priv->rxq.read = i;
iwl_rx_queue_restock(priv);
if (fill_rx)
iwl_rx_replenish_now(priv);
else
iwl_rx_queue_restock(priv);
}
/* call this function to flush any scheduled tasklet */
......@@ -966,7 +946,7 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv)
tasklet_kill(&priv->irq_tasklet);
}
static void iwl_irq_tasklet(struct iwl_priv *priv)
static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
{
u32 inta, handled = 0;
u32 inta_fh;
......@@ -1127,9 +1107,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
priv->isr_stats.unhandled++;
}
if (inta & ~CSR_INI_SET_MASK) {
if (inta & ~(priv->inta_mask)) {
IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
inta & ~CSR_INI_SET_MASK);
inta & ~priv->inta_mask);
IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh);
}
......@@ -1150,6 +1130,199 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
}
/* tasklet for iwlagn interrupt */
static void iwl_irq_tasklet(struct iwl_priv *priv)
{
u32 inta = 0;
u32 handled = 0;
unsigned long flags;
#ifdef CONFIG_IWLWIFI_DEBUG
u32 inta_mask;
#endif
spin_lock_irqsave(&priv->lock, flags);
/* Ack/clear/reset pending uCode interrupts.
* Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
*/
iwl_write32(priv, CSR_INT, priv->inta);
inta = priv->inta;
#ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ",
inta, inta_mask);
}
#endif
/* saved interrupt in inta variable now we can reset priv->inta */
priv->inta = 0;
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
priv->isr_stats.hw++;
iwl_irq_handle_error(priv);
handled |= CSR_INT_BIT_HW_ERR;
spin_unlock_irqrestore(&priv->lock, flags);
return;
}
#ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
"the frame/frames.\n");
priv->isr_stats.sch++;
}
/* Alive notification via Rx interrupt will do the real work */
if (inta & CSR_INT_BIT_ALIVE) {
IWL_DEBUG_ISR(priv, "Alive interrupt\n");
priv->isr_stats.alive++;
}
}
#endif
/* Safely ignore these bits for debug checks below */
inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
/* HW RF KILL switch toggled */
if (inta & CSR_INT_BIT_RF_KILL) {
int hw_rf_kill = 0;
if (!(iwl_read32(priv, CSR_GP_CNTRL) &
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1;
IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio");
priv->isr_stats.rfkill++;
/* driver only loads ucode once setting the interface up.
* the driver allows loading the ucode even if the radio
* is killed. Hence update the killswitch state here. The
* rfkill handler will care about restarting if needed.
*/
if (!test_bit(STATUS_ALIVE, &priv->status)) {
if (hw_rf_kill)
set_bit(STATUS_RF_KILL_HW, &priv->status);
else
clear_bit(STATUS_RF_KILL_HW, &priv->status);
queue_work(priv->workqueue, &priv->rf_kill);
}
handled |= CSR_INT_BIT_RF_KILL;
}
/* Chip got too hot and stopped itself */
if (inta & CSR_INT_BIT_CT_KILL) {
IWL_ERR(priv, "Microcode CT kill error detected.\n");
priv->isr_stats.ctkill++;
handled |= CSR_INT_BIT_CT_KILL;
}
/* Error detected by uCode */
if (inta & CSR_INT_BIT_SW_ERR) {
IWL_ERR(priv, "Microcode SW error detected. "
" Restarting 0x%X.\n", inta);
priv->isr_stats.sw++;
priv->isr_stats.sw_err = inta;
iwl_irq_handle_error(priv);
handled |= CSR_INT_BIT_SW_ERR;
}
/* uCode wakes up after power-down sleep */
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]);
priv->isr_stats.wakeup++;
handled |= CSR_INT_BIT_WAKEUP;
}
/* All uCode command responses, including Tx command responses,
* Rx "responses" (frame-received notification), and other
* notifications from uCode come through here*/
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX |
CSR_INT_BIT_RX_PERIODIC)) {
IWL_DEBUG_ISR(priv, "Rx interrupt\n");
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
iwl_write32(priv, CSR_FH_INT_STATUS,
CSR49_FH_INT_RX_MASK);
}
if (inta & CSR_INT_BIT_RX_PERIODIC) {
handled |= CSR_INT_BIT_RX_PERIODIC;
iwl_write32(priv, CSR_INT, CSR_INT_BIT_RX_PERIODIC);
}
/* Sending RX interrupt require many steps to be done in the
* the device:
* 1- write interrupt to current index in ICT table.
* 2- dma RX frame.
* 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
*/
iwl_write32(priv, CSR_INT_PERIODIC_REG,
CSR_INT_PERIODIC_DIS);
iwl_rx_handle(priv);
/* Only set RX periodic if real RX is received. */
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX))
iwl_write32(priv, CSR_INT_PERIODIC_REG,
CSR_INT_PERIODIC_ENA);
priv->isr_stats.rx++;
}
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");
priv->isr_stats.tx++;
handled |= CSR_INT_BIT_FH_TX;
/* FH finished to write, send event */
priv->ucode_write_complete = 1;
wake_up_interruptible(&priv->wait_command_queue);
}
if (inta & ~handled) {
IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
priv->isr_stats.unhandled++;
}
if (inta & ~(priv->inta_mask)) {
IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
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);
}
/******************************************************************************
*
......@@ -1579,6 +1752,8 @@ static void __iwl_down(struct iwl_priv *priv)
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
STATUS_EXIT_PENDING;
/* 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);
......@@ -1587,13 +1762,8 @@ static void __iwl_down(struct iwl_priv *priv)
iwl_txq_ctx_stop(priv);
iwl_rxq_stop(priv);
spin_lock_irqsave(&priv->lock, flags);
if (!iwl_grab_nic_access(priv)) {
iwl_write_prph(priv, APMG_CLK_DIS_REG,
APMG_CLK_VAL_DMA_CLK_RQT);
iwl_release_nic_access(priv);
}
spin_unlock_irqrestore(&priv->lock, flags);
iwl_write_prph(priv, APMG_CLK_DIS_REG,
APMG_CLK_VAL_DMA_CLK_RQT);
udelay(5);
......@@ -1622,6 +1792,49 @@ static void iwl_down(struct iwl_priv *priv)
iwl_cancel_deferred_work(priv);
}
#define HW_READY_TIMEOUT (50)
static int iwl_set_hw_ready(struct iwl_priv *priv)
{
int ret = 0;
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
/* See if we got it */
ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
HW_READY_TIMEOUT);
if (ret != -ETIMEDOUT)
priv->hw_ready = true;
else
priv->hw_ready = false;
IWL_DEBUG_INFO(priv, "hardware %s\n",
(priv->hw_ready == 1) ? "ready" : "not ready");
return ret;
}
static int iwl_prepare_card_hw(struct iwl_priv *priv)
{
int ret = 0;
IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n");
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PREPARE);
ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
if (ret != -ETIMEDOUT)
iwl_set_hw_ready(priv);
return ret;
}
#define MAX_HW_RESTARTS 5
static int __iwl_up(struct iwl_priv *priv)
......@@ -1639,6 +1852,13 @@ static int __iwl_up(struct iwl_priv *priv)
return -EIO;
}
iwl_prepare_card_hw(priv);
if (!priv->hw_ready) {
IWL_WARN(priv, "Exit HW not ready\n");
return -EIO;
}
/* If platform's RF_KILL switch is NOT set to KILL */
if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
clear_bit(STATUS_RF_KILL_HW, &priv->status);
......@@ -1667,6 +1887,8 @@ static int __iwl_up(struct iwl_priv *priv)
/* clear (again), then enable host interrupts */
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
/* enable dram interrupt */
iwl_reset_ict(priv);
iwl_enable_interrupts(priv);
/* really make sure rfkill handshake bits are cleared */
......@@ -2298,8 +2520,10 @@ static ssize_t show_version(struct device *d,
if (priv->eeprom) {
eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
pos += sprintf(buf + pos, "EEPROM version: 0x%x\n",
eeprom_ver);
pos += sprintf(buf + pos, "NVM Type: %s, version: 0x%x\n",
(priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
? "OTP" : "EEPROM", eeprom_ver);
} else {
pos += sprintf(buf + pos, "EEPROM not initialzed\n");
}
......@@ -2478,7 +2702,7 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
static ssize_t show_qos(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
struct iwl_priv *priv = dev_get_drvdata(d);
char *p = buf;
int q;
......@@ -2565,8 +2789,12 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
priv->statistics_periodic.data = (unsigned long)priv;
priv->statistics_periodic.function = iwl_bg_statistics_periodic;
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
iwl_irq_tasklet, (unsigned long)priv);
if (!priv->cfg->use_isr_legacy)
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
iwl_irq_tasklet, (unsigned long)priv);
else
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
iwl_irq_tasklet_legacy, (unsigned long)priv);
}
static void iwl_cancel_deferred_work(struct iwl_priv *priv)
......@@ -2655,6 +2883,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
priv->cfg = cfg;
priv->pci_dev = pdev;
priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG
priv->debug_level = priv->cfg->mod_params->debug;
......@@ -2705,6 +2934,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
(unsigned long long) pci_resource_len(pdev, 0));
IWL_DEBUG_INFO(priv, "pci_resource_base = %p\n", priv->hw_base);
/* this spin lock will be used in apm_ops.init and EEPROM access
* we should init now
*/
spin_lock_init(&priv->reg_lock);
iwl_hw_detect(priv);
IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n",
priv->cfg->name, priv->hw_rev);
......@@ -2713,6 +2946,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* PCI Tx retries from interfering with C3 CPU state */
pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
iwl_prepare_card_hw(priv);
if (!priv->hw_ready) {
IWL_WARN(priv, "Failed, HW not ready\n");
goto out_iounmap;
}
/* amp init */
err = priv->cfg->ops->lib->apm_ops.init(priv);
if (err < 0) {
......@@ -2763,8 +3002,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_enable_msi(priv->pci_dev);
err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED,
DRV_NAME, priv);
iwl_alloc_isr_ict(priv);
err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr,
IRQF_SHARED, DRV_NAME, priv);
if (err) {
IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
goto out_disable_msi;
......@@ -2821,6 +3061,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
out_free_irq:
free_irq(priv->pci_dev->irq, priv);
iwl_free_isr_ict(priv);
out_disable_msi:
pci_disable_msi(priv->pci_dev);
iwl_uninit_drv(priv);
......@@ -2902,6 +3143,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_uninit_drv(priv);
iwl_free_isr_ict(priv);
if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
......
......@@ -614,8 +614,18 @@ enum {
#define RXON_FLG_CHANNEL_MODE_POS (25)
#define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25)
#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK cpu_to_le32(0x1 << 25)
#define RXON_FLG_CHANNEL_MODE_MIXED_MSK cpu_to_le32(0x2 << 25)
/* channel mode */
enum {
CHANNEL_MODE_LEGACY = 0,
CHANNEL_MODE_PURE_40 = 1,
CHANNEL_MODE_MIXED = 2,
CHANNEL_MODE_RESERVED = 3,
};
#define RXON_FLG_CHANNEL_MODE_LEGACY cpu_to_le32(CHANNEL_MODE_LEGACY << RXON_FLG_CHANNEL_MODE_POS)
#define RXON_FLG_CHANNEL_MODE_PURE_40 cpu_to_le32(CHANNEL_MODE_PURE_40 << RXON_FLG_CHANNEL_MODE_POS)
#define RXON_FLG_CHANNEL_MODE_MIXED cpu_to_le32(CHANNEL_MODE_MIXED << RXON_FLG_CHANNEL_MODE_POS)
/* CTS to self (if spec allows) flag */
#define RXON_FLG_SELF_CTS_EN cpu_to_le32(0x1<<30)
......
......@@ -39,6 +39,7 @@
#include "iwl-rfkill.h"
#include "iwl-power.h"
#include "iwl-sta.h"
#include "iwl-helpers.h"
MODULE_DESCRIPTION("iwl core");
......@@ -59,6 +60,8 @@ MODULE_LICENSE("GPL");
IWL_RATE_##pp##M_INDEX, \
IWL_RATE_##np##M_INDEX }
static irqreturn_t iwl_isr(int irq, void *data);
/*
* Parameter order:
* rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
......@@ -603,10 +606,10 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv,
if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
return !(ch_info->fat_extension_channel &
IEEE80211_CHAN_NO_FAT_ABOVE);
IEEE80211_CHAN_NO_HT40PLUS);
else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
return !(ch_info->fat_extension_channel &
IEEE80211_CHAN_NO_FAT_BELOW);
IEEE80211_CHAN_NO_HT40MINUS);
return 0;
}
......@@ -617,19 +620,23 @@ u8 iwl_is_fat_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) ||
(iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE))
(iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ))
return 0;
/* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40
* the bit will not set if it is pure 40MHz case
*/
if (sta_ht_inf) {
if ((!sta_ht_inf->ht_supported) ||
(!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)))
if (!sta_ht_inf->ht_supported)
return 0;
}
return iwl_is_channel_extension(priv, priv->band,
le16_to_cpu(priv->staging_rxon.channel),
iwl_ht_conf->extension_chan_offset);
if (iwl_ht_conf->ht_protection & IEEE80211_HT_OP_MODE_PROTECTION_20MHZ)
return 1;
else
return iwl_is_channel_extension(priv, priv->band,
le16_to_cpu(priv->staging_rxon.channel),
iwl_ht_conf->extension_chan_offset);
}
EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
......@@ -799,42 +806,51 @@ EXPORT_SYMBOL(iwl_rate_get_lowest_plcp);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
{
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
u32 val;
if (!ht_info->is_ht) {
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
RXON_FLG_CHANNEL_MODE_PURE_40_MSK |
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
RXON_FLG_FAT_PROT_MSK |
RXON_FLG_HT_PROT_MSK);
return;
}
/* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */
if (iwl_is_fat_tx_allowed(priv, NULL))
rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
else
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
/* Note: control channel is opposite of extension channel */
switch (ht_info->extension_chan_offset) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
break;
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
default:
rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
break;
/* 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);
/* Set up channel bandwidth:
* 20 MHz only, 20/40 mixed or pure 40 if fat ok */
/* clear the HT channel mode before set the mode */
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK |
RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
if (iwl_is_fat_tx_allowed(priv, NULL)) {
/* pure 40 fat */
if (rxon->flags & RXON_FLG_FAT_PROT_MSK)
rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40;
else {
/* Note: control channel is opposite of extension channel */
switch (ht_info->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;
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED;
break;
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
default:
/* channel location only valid if in Mixed mode */
IWL_ERR(priv, "invalid extension channel offset\n");
break;
}
}
} else {
rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY;
}
val = ht_info->ht_protection;
rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
......@@ -1122,8 +1138,9 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
priv->staging_rxon.cck_basic_rates =
(IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
/* clear both MIX and PURE40 mode flag */
priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
RXON_FLG_CHANNEL_MODE_PURE_40);
memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
......@@ -1483,11 +1500,272 @@ void iwl_enable_interrupts(struct iwl_priv *priv)
{
IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
set_bit(STATUS_INT_ENABLED, &priv->status);
iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
}
EXPORT_SYMBOL(iwl_enable_interrupts);
irqreturn_t iwl_isr(int irq, void *data)
#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
/* Free dram table */
void iwl_free_isr_ict(struct iwl_priv *priv)
{
if (priv->ict_tbl_vir) {
pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) +
PAGE_SIZE, priv->ict_tbl_vir,
priv->ict_tbl_dma);
priv->ict_tbl_vir = NULL;
}
}
EXPORT_SYMBOL(iwl_free_isr_ict);
/* allocate dram shared table it is a PAGE_SIZE aligned
* also reset all data related to ICT table interrupt.
*/
int iwl_alloc_isr_ict(struct iwl_priv *priv)
{
if (priv->cfg->use_isr_legacy)
return 0;
/* allocate shrared data table */
priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) *
ICT_COUNT) + PAGE_SIZE,
&priv->ict_tbl_dma);
if (!priv->ict_tbl_vir)
return -ENOMEM;
/* align table to PAGE_SIZE boundry */
priv->aligned_ict_tbl_dma = ALIGN(priv->ict_tbl_dma, PAGE_SIZE);
IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n",
(unsigned long long)priv->ict_tbl_dma,
(unsigned long long)priv->aligned_ict_tbl_dma,
(int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma));
priv->ict_tbl = priv->ict_tbl_vir +
(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma);
IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n",
priv->ict_tbl, priv->ict_tbl_vir,
(int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma));
/* reset table and index to all 0 */
memset(priv->ict_tbl_vir,0, (sizeof(u32) * ICT_COUNT) + PAGE_SIZE);
priv->ict_index = 0;
/* add periodic RX interrupt */
priv->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
return 0;
}
EXPORT_SYMBOL(iwl_alloc_isr_ict);
/* Device is going up inform it about using ICT interrupt table,
* also we need to tell the driver to start using ICT interrupt.
*/
int iwl_reset_ict(struct iwl_priv *priv)
{
u32 val;
unsigned long flags;
if (!priv->ict_tbl_vir)
return 0;
spin_lock_irqsave(&priv->lock, flags);
iwl_disable_interrupts(priv);
memset(&priv->ict_tbl[0],0, sizeof(u32) * ICT_COUNT);
val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT;
val |= CSR_DRAM_INT_TBL_ENABLE;
val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X "
"aligned dma address %Lx\n",
val, (unsigned long long)priv->aligned_ict_tbl_dma);
iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val);
priv->use_ict = true;
priv->ict_index = 0;
iwl_write32(priv, CSR_INT, priv->inta_mask);
iwl_enable_interrupts(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
EXPORT_SYMBOL(iwl_reset_ict);
/* Device is going down disable ict interrupt usage */
void iwl_disable_ict(struct iwl_priv *priv)
{
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
priv->use_ict = false;
spin_unlock_irqrestore(&priv->lock, flags);
}
EXPORT_SYMBOL(iwl_disable_ict);
/* interrupt handler using ict table, with this interrupt driver will
* stop using INTA register to get device's interrupt, reading this register
* is expensive, device will write interrupts in ICT dram table, increment
* index then will fire interrupt to driver, driver will OR all ICT table
* entries from current index up to table entry with 0 value. the result is
* the interrupt we need to service, driver will set the entries back to 0 and
* set index.
*/
irqreturn_t iwl_isr_ict(int irq, void *data)
{
struct iwl_priv *priv = data;
u32 inta, inta_mask;
u32 val = 0;
if (!priv)
return IRQ_NONE;
/* dram interrupt table not set yet,
* use legacy interrupt.
*/
if (!priv->use_ict)
return iwl_isr(irq, data);
spin_lock(&priv->lock);
/* Disable (but don't clear!) interrupts here to avoid
* back-to-back ISRs and sporadic interrupts from our NIC.
* If we have something to service, the tasklet will re-enable ints.
* If we *don't* have something, we'll re-enable before leaving here.
*/
inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
iwl_write32(priv, CSR_INT_MASK, 0x00000000);
/* Ignore interrupt if there's nothing in NIC to service.
* This may be due to IRQ shared with another device,
* or due to sporadic interrupts thrown from our NIC. */
if (!priv->ict_tbl[priv->ict_index]) {
IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
goto none;
}
/* read all entries that not 0 start with ict_index */
while (priv->ict_tbl[priv->ict_index]) {
val |= priv->ict_tbl[priv->ict_index];
IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n",
priv->ict_index,
priv->ict_tbl[priv->ict_index]);
priv->ict_tbl[priv->ict_index] = 0;
priv->ict_index = iwl_queue_inc_wrap(priv->ict_index,
ICT_COUNT);
}
/* We should not get this value, just ignore it. */
if (val == 0xffffffff)
val = 0;
inta = (0xff & val) | ((0xff00 & val) << 16);
IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
inta, inta_mask, val);
inta &= priv->inta_mask;
priv->inta |= inta;
/* iwl_irq_tasklet() will service interrupts and re-enable them */
if (likely(inta))
tasklet_schedule(&priv->irq_tasklet);
else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) {
/* Allow interrupt if was disabled by this handler and
* no tasklet was schedules, We should not enable interrupt,
* tasklet will enable it.
*/
iwl_enable_interrupts(priv);
}
spin_unlock(&priv->lock);
return IRQ_HANDLED;
none:
/* re-enable interrupts here since we don't have anything to service.
* only Re-enable if disabled by irq.
*/
if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
iwl_enable_interrupts(priv);
spin_unlock(&priv->lock);
return IRQ_NONE;
}
EXPORT_SYMBOL(iwl_isr_ict);
static irqreturn_t iwl_isr(int irq, void *data)
{
struct iwl_priv *priv = data;
u32 inta, inta_mask;
u32 inta_fh;
if (!priv)
return IRQ_NONE;
spin_lock(&priv->lock);
/* Disable (but don't clear!) interrupts here to avoid
* back-to-back ISRs and sporadic interrupts from our NIC.
* If we have something to service, the tasklet will re-enable ints.
* If we *don't* have something, we'll re-enable before leaving here. */
inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
iwl_write32(priv, CSR_INT_MASK, 0x00000000);
/* Discover which interrupts are active/pending */
inta = iwl_read32(priv, CSR_INT);
/* Ignore interrupt if there's nothing in NIC to service.
* This may be due to IRQ shared with another device,
* or due to sporadic interrupts thrown from our NIC. */
if (!inta) {
IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
goto none;
}
if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
/* Hardware disappeared. It might have already raised
* an interrupt */
IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
goto unplugged;
}
#ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & (IWL_DL_ISR)) {
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
"fh 0x%08x\n", inta, inta_mask, inta_fh);
}
#endif
priv->inta |= inta;
/* iwl_irq_tasklet() will service interrupts and re-enable them */
if (likely(inta))
tasklet_schedule(&priv->irq_tasklet);
else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
iwl_enable_interrupts(priv);
unplugged:
spin_unlock(&priv->lock);
return IRQ_HANDLED;
none:
/* re-enable interrupts here since we don't have anything to service. */
/* only Re-enable if diabled by irq and no schedules tasklet. */
if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
iwl_enable_interrupts(priv);
spin_unlock(&priv->lock);
return IRQ_NONE;
}
irqreturn_t iwl_isr_legacy(int irq, void *data)
{
struct iwl_priv *priv = data;
u32 inta, inta_mask;
......@@ -1544,7 +1822,7 @@ irqreturn_t iwl_isr(int irq, void *data)
spin_unlock(&priv->lock);
return IRQ_NONE;
}
EXPORT_SYMBOL(iwl_isr);
EXPORT_SYMBOL(iwl_isr_legacy);
int iwl_send_bt_config(struct iwl_priv *priv)
{
......@@ -1588,10 +1866,6 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32
IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
ret = iwl_grab_nic_access(priv);
if (ret)
return ret;
for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
/* read data comes through single port, auto-incr addr */
/* NOTE: Use the debugless read so we don't flood kernel log
......@@ -1607,8 +1881,6 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32
}
}
iwl_release_nic_access(priv);
return ret;
}
......@@ -1626,10 +1898,6 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
ret = iwl_grab_nic_access(priv);
if (ret)
return ret;
iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
IWL49_RTC_INST_LOWER_BOUND);
......@@ -1650,8 +1918,6 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
}
}
iwl_release_nic_access(priv);
if (!errcnt)
IWL_DEBUG_INFO(priv,
"ucode image in INSTRUCTION memory is good\n");
......@@ -1760,7 +2026,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
u32 data2, line;
u32 desc, time, count, base, data1;
u32 blink1, blink2, ilink1, ilink2;
int ret;
if (priv->ucode_type == UCODE_INIT)
base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
......@@ -1772,12 +2037,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
return;
}
ret = iwl_grab_nic_access(priv);
if (ret) {
IWL_WARN(priv, "Can not read from adapter at this time.\n");
return;
}
count = iwl_read_targ_mem(priv, base);
if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
......@@ -1804,7 +2063,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
ilink1, ilink2);
iwl_release_nic_access(priv);
}
EXPORT_SYMBOL(iwl_dump_nic_error_log);
......@@ -1813,7 +2071,6 @@ EXPORT_SYMBOL(iwl_dump_nic_error_log);
/**
* iwl_print_event_log - Dump error event log to syslog
*
* NOTE: Must be called with iwl_grab_nic_access() already obtained!
*/
static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
u32 num_events, u32 mode)
......@@ -1859,7 +2116,6 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
void iwl_dump_nic_event_log(struct iwl_priv *priv)
{
int ret;
u32 base; /* SRAM byte address of event log header */
u32 capacity; /* event log capacity in # entries */
u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
......@@ -1877,12 +2133,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
return;
}
ret = iwl_grab_nic_access(priv);
if (ret) {
IWL_WARN(priv, "Can not read from adapter at this time.\n");
return;
}
/* event log header */
capacity = iwl_read_targ_mem(priv, base);
mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
......@@ -1894,7 +2144,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
/* bail out if nothing in log */
if (size == 0) {
IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
iwl_release_nic_access(priv);
return;
}
......@@ -1909,7 +2158,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
/* (then/else) start at top of log */
iwl_print_event_log(priv, 0, next_entry, mode);
iwl_release_nic_access(priv);
}
EXPORT_SYMBOL(iwl_dump_nic_event_log);
......@@ -2016,11 +2264,11 @@ int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv)
/* wake up ucode */
msleep(10);
spin_lock_irqsave(&priv->lock, flags);
iwl_read32(priv, CSR_UCODE_DRV_GP1);
spin_lock_irqsave(&priv->reg_lock, flags);
if (!iwl_grab_nic_access(priv))
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
spin_unlock_irqrestore(&priv->reg_lock, flags);
if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - "
......
......@@ -112,6 +112,19 @@ struct iwl_hcmd_utils_ops {
struct iwl_rx_phy_res *rx_resp);
};
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);
};
struct iwl_temp_ops {
void (*temperature)(struct iwl_priv *priv);
void (*set_ct_kill)(struct iwl_priv *priv);
};
struct iwl_lib_ops {
/* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv);
......@@ -149,23 +162,21 @@ struct iwl_lib_ops {
int (*is_valid_rtc_data_addr)(u32 addr);
/* 1st ucode load */
int (*load_ucode)(struct iwl_priv *priv);
/* power management */
struct {
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);
} apm_ops;
/* power management */
struct iwl_apm_ops apm_ops;
/* power */
int (*send_tx_power) (struct iwl_priv *priv);
void (*update_chain_flags)(struct iwl_priv *priv);
void (*temperature) (struct iwl_priv *priv);
void (*post_associate) (struct iwl_priv *priv);
void (*config_ap) (struct iwl_priv *priv);
irqreturn_t (*isr) (int irq, void *data);
/* eeprom operations (as defined in iwl-eeprom.h) */
struct iwl_eeprom_ops eeprom_ops;
/* temperature */
struct iwl_temp_ops temp_ops;
};
struct iwl_ops {
......@@ -229,6 +240,7 @@ struct iwl_cfg {
u8 valid_tx_ant;
u8 valid_rx_ant;
bool need_pll_cfg;
bool use_isr_legacy;
};
/***************************
......@@ -306,10 +318,11 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl_rx_queue *q);
void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
void iwl_rx_replenish(struct iwl_priv *priv);
void iwl_rx_replenish_now(struct iwl_priv *priv);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
int iwl_rx_queue_restock(struct iwl_priv *priv);
int iwl_rx_queue_space(const struct iwl_rx_queue *q);
void iwl_rx_allocate(struct iwl_priv *priv);
void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority);
void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
/* Handlers */
......@@ -456,7 +469,13 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
*****************************************************/
void iwl_disable_interrupts(struct iwl_priv *priv);
void iwl_enable_interrupts(struct iwl_priv *priv);
irqreturn_t iwl_isr(int irq, void *data);
irqreturn_t iwl_isr_legacy(int irq, void *data);
int iwl_reset_ict(struct iwl_priv *priv);
void iwl_disable_ict(struct iwl_priv *priv);
int iwl_alloc_isr_ict(struct iwl_priv *priv);
void iwl_free_isr_ict(struct iwl_priv *priv);
irqreturn_t iwl_isr_ict(int irq, void *data);
static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
{
int pos;
......
......@@ -89,6 +89,7 @@
/* EEPROM reads */
#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 (CSR_BASE+0x044)
#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
......@@ -96,8 +97,10 @@
#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)
#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)
/*
......@@ -123,16 +126,18 @@
#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_PCI_OWN_SEM (0x00400000)
#define CSR_HW_IF_CONFIG_REG_BIT_ME_OWN (0x02000000)
#define CSR_HW_IF_CONFIG_REG_BIT_WAKE_ME (0x08000000)
#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_INT_PERIODIC_DIS (0x00)
#define CSR_INT_PERIODIC_ENA (0xFF)
/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
* acknowledged (reset) by host writing "1" to flagged bits. */
#define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */
#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */
#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */
#define CSR_INT_BIT_RX_PERIODIC (1 << 28) /* Rx periodic */
#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */
#define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */
#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */
......@@ -226,6 +231,10 @@
#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 */
/* CSR GIO */
#define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002)
......@@ -251,6 +260,11 @@
/* HPET MEM debug */
#define CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000)
/* DRAM INT TABLE */
#define CSR_DRAM_INT_TBL_ENABLE (1 << 31)
#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27)
/*=== HBUS (Host-side Bus) ===*/
#define HBUS_BASE (0x400)
/*
......
......@@ -68,7 +68,7 @@ struct iwl_debugfs {
struct dentry *dir_rf;
struct dir_data_files {
struct dentry *file_sram;
struct dentry *file_eeprom;
struct dentry *file_nvm;
struct dentry *file_stations;
struct dentry *file_rx_statistics;
struct dentry *file_tx_statistics;
......
......@@ -172,7 +172,6 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
const size_t bufsz = sizeof(buf);
iwl_grab_nic_access(priv);
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);
......@@ -192,7 +191,6 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
}
pos += scnprintf(buf + pos, bufsz - pos, "\n");
iwl_release_nic_access(priv);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
return ret;
......@@ -292,7 +290,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
return ret;
}
static ssize_t iwl_dbgfs_eeprom_read(struct file *file,
static ssize_t iwl_dbgfs_nvm_read(struct file *file,
char __user *user_buf,
size_t count,
loff_t *ppos)
......@@ -306,7 +304,7 @@ static ssize_t iwl_dbgfs_eeprom_read(struct file *file,
buf_size = 4 * eeprom_len + 256;
if (eeprom_len % 16) {
IWL_ERR(priv, "EEPROM size is not multiple of 16.\n");
IWL_ERR(priv, "NVM size is not multiple of 16.\n");
return -ENODATA;
}
......@@ -318,6 +316,13 @@ static ssize_t iwl_dbgfs_eeprom_read(struct file *file,
}
ptr = priv->eeprom;
if (!ptr) {
IWL_ERR(priv, "Invalid EEPROM/OTP memory\n");
return -ENOMEM;
}
pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n",
(priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
? "OTP" : "EEPROM");
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,
......@@ -375,51 +380,53 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
}
supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
channels = supp_band->channels;
if (supp_band) {
channels = supp_band->channels;
pos += scnprintf(buf + pos, bufsz - pos,
"Displaying %d channels in 2.4GHz band 802.11bg):\n",
supp_band->n_channels);
for (i = 0; i < supp_band->n_channels; i++)
pos += scnprintf(buf + pos, bufsz - pos,
"%d: %ddBm: BSS%s%s, %s.\n",
ieee80211_frequency_to_channel(
channels[i].center_freq),
channels[i].max_power,
channels[i].flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
|| (channels[i].flags &
IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].flags &
IEEE80211_CHAN_PASSIVE_SCAN ?
"passive only" : "active/passive");
"Displaying %d channels in 2.4GHz band 802.11bg):\n",
supp_band->n_channels);
for (i = 0; i < supp_band->n_channels; i++)
pos += scnprintf(buf + pos, bufsz - pos,
"%d: %ddBm: BSS%s%s, %s.\n",
ieee80211_frequency_to_channel(
channels[i].center_freq),
channels[i].max_power,
channels[i].flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
|| (channels[i].flags &
IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].flags &
IEEE80211_CHAN_PASSIVE_SCAN ?
"passive only" : "active/passive");
}
supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
channels = supp_band->channels;
pos += scnprintf(buf + pos, bufsz - pos,
"Displaying %d channels in 5.2GHz band (802.11a)\n",
supp_band->n_channels);
if (supp_band) {
channels = supp_band->channels;
for (i = 0; i < supp_band->n_channels; i++)
pos += scnprintf(buf + pos, bufsz - pos,
"%d: %ddBm: BSS%s%s, %s.\n",
ieee80211_frequency_to_channel(
channels[i].center_freq),
channels[i].max_power,
channels[i].flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
|| (channels[i].flags &
IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].flags &
IEEE80211_CHAN_PASSIVE_SCAN ?
"passive only" : "active/passive");
"Displaying %d channels in 5.2GHz band (802.11a)\n",
supp_band->n_channels);
for (i = 0; i < supp_band->n_channels; i++)
pos += scnprintf(buf + pos, bufsz - pos,
"%d: %ddBm: BSS%s%s, %s.\n",
ieee80211_frequency_to_channel(
channels[i].center_freq),
channels[i].max_power,
channels[i].flags & IEEE80211_CHAN_RADAR ?
" (IEEE 802.11h required)" : "",
((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
|| (channels[i].flags &
IEEE80211_CHAN_RADAR)) ? "" :
", IBSS",
channels[i].flags &
IEEE80211_CHAN_PASSIVE_SCAN ?
"passive only" : "active/passive");
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
return ret;
......@@ -564,7 +571,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_WRITE_FILE_OPS(log_event);
DEBUGFS_READ_FILE_OPS(eeprom);
DEBUGFS_READ_FILE_OPS(nvm);
DEBUGFS_READ_FILE_OPS(stations);
DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
......@@ -598,7 +605,7 @@ 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_FILE(eeprom, data);
DEBUGFS_ADD_FILE(nvm, data);
DEBUGFS_ADD_FILE(sram, data);
DEBUGFS_ADD_FILE(log_event, data);
DEBUGFS_ADD_FILE(stations, data);
......@@ -629,7 +636,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
if (!priv->dbgfs)
return;
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_eeprom);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
......
......@@ -382,6 +382,7 @@ struct iwl_rx_queue {
u32 read;
u32 write;
u32 free_count;
u32 write_actual;
struct list_head rx_free;
struct list_head rx_used;
int need_update;
......@@ -499,22 +500,13 @@ struct iwl_qos_info {
#define STA_PS_STATUS_WAKE 0
#define STA_PS_STATUS_SLEEP 1
struct iwl3945_tid_data {
u16 seq_number;
};
struct iwl3945_hw_key {
enum ieee80211_key_alg alg;
int keylen;
u8 key[32];
};
struct iwl3945_station_entry {
struct iwl3945_addsta_cmd sta;
struct iwl3945_tid_data tid[MAX_TID_COUNT];
struct iwl_tid_data tid[MAX_TID_COUNT];
u8 used;
u8 ps_status;
struct iwl3945_hw_key keyinfo;
struct iwl_hw_key keyinfo;
};
struct iwl_station_entry {
......@@ -823,6 +815,11 @@ enum {
MEASUREMENT_ACTIVE = (1 << 1),
};
enum iwl_nvm_type {
NVM_DEVICE_TYPE_EEPROM = 0,
NVM_DEVICE_TYPE_OTP,
};
/* interrupt statistics */
struct isr_statistics {
u32 hw;
......@@ -900,6 +897,7 @@ struct iwl_priv {
/* spinlock */
spinlock_t lock; /* protect general shared data */
spinlock_t hcmd_lock; /* protect hcmd */
spinlock_t reg_lock; /* protect hw register access */
struct mutex mutex;
/* basic pci-network driver stuff */
......@@ -1033,6 +1031,7 @@ struct iwl_priv {
/* eeprom */
u8 *eeprom;
int nvm_device_type;
struct iwl_eeprom_calib_info *calib_info;
enum nl80211_iftype iw_mode;
......@@ -1050,7 +1049,16 @@ struct iwl_priv {
/*End*/
struct iwl_hw_params hw_params;
/* INT ICT Table */
u32 *ict_tbl;
dma_addr_t ict_tbl_dma;
dma_addr_t aligned_ict_tbl_dma;
int ict_index;
void *ict_tbl_vir;
u32 inta;
bool use_ict;
u32 inta_mask;
/* Current association information needed to configure the
* hardware */
u16 assoc_id;
......@@ -1105,7 +1113,7 @@ struct iwl_priv {
u32 disable_tx_power_cal;
struct work_struct run_time_calib_work;
struct timer_list statistics_periodic;
bool hw_ready;
/*For 3945*/
#define IWL_DEFAULT_TX_POWER 0x0F
......
......@@ -152,6 +152,32 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
static int iwlcore_get_nvm_type(struct iwl_priv *priv)
{
u32 otpgp;
int nvm_type;
/* OTP only valid for CP/PP and after */
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
case CSR_HW_REV_TYPE_3945:
case CSR_HW_REV_TYPE_4965:
case CSR_HW_REV_TYPE_5300:
case CSR_HW_REV_TYPE_5350:
case CSR_HW_REV_TYPE_5100:
case CSR_HW_REV_TYPE_5150:
nvm_type = NVM_DEVICE_TYPE_EEPROM;
break;
default:
otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
nvm_type = NVM_DEVICE_TYPE_OTP;
else
nvm_type = NVM_DEVICE_TYPE_EEPROM;
break;
}
return nvm_type;
}
/*
* The device's EEPROM semaphore prevents conflicts between driver and uCode
* when accessing the EEPROM; each access is a series of pulses to/from the
......@@ -198,6 +224,33 @@ const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
}
EXPORT_SYMBOL(iwlcore_eeprom_query_addr);
static int iwl_init_otp_access(struct iwl_priv *priv)
{
int ret;
/* Enable 40MHz radio clock */
_iwl_write32(priv, CSR_GP_CNTRL,
_iwl_read32(priv, CSR_GP_CNTRL) |
CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock to be ready */
ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
25000);
if (ret < 0)
IWL_ERR(priv, "Time out access OTP\n");
else {
if (!ret) {
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);
}
}
return ret;
}
/**
* iwl_eeprom_init - read EEPROM contents
*
......@@ -209,11 +262,18 @@ int iwl_eeprom_init(struct iwl_priv *priv)
{
u16 *e;
u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
int sz = priv->cfg->eeprom_size;
int sz;
int ret;
u16 addr;
u32 otpgp;
priv->nvm_device_type = iwlcore_get_nvm_type(priv);
/* allocate eeprom */
if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
priv->cfg->eeprom_size =
OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL;
sz = priv->cfg->eeprom_size;
priv->eeprom = kzalloc(sz, GFP_KERNEL);
if (!priv->eeprom) {
ret = -ENOMEM;
......@@ -235,30 +295,77 @@ int iwl_eeprom_init(struct iwl_priv *priv)
ret = -ENOENT;
goto err;
}
/* eeprom is an array of 16bit values */
for (addr = 0; addr < sz; addr += sizeof(u16)) {
u32 r;
_iwl_write32(priv, CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
if (ret < 0) {
IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr);
goto done;
if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
ret = iwl_init_otp_access(priv);
if (ret) {
IWL_ERR(priv, "Failed to initialize OTP access.\n");
ret = -ENOENT;
goto err;
}
_iwl_write32(priv, CSR_EEPROM_GP,
iwl_read32(priv, CSR_EEPROM_GP) &
~CSR_EEPROM_GP_IF_OWNER_MSK);
/* clear */
_iwl_write32(priv, CSR_OTP_GP_REG,
iwl_read32(priv, CSR_OTP_GP_REG) |
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
for (addr = 0; addr < sz; addr += sizeof(u16)) {
u32 r;
_iwl_write32(priv, CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
if (ret < 0) {
IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
goto done;
}
r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
/* check for ECC errors: */
otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
/* stop in this case */
IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n");
goto done;
}
if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
/* continue in this case */
_iwl_write32(priv, CSR_OTP_GP_REG,
iwl_read32(priv, CSR_OTP_GP_REG) |
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
}
e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
}
} else {
/* eeprom is an array of 16bit values */
for (addr = 0; addr < sz; addr += sizeof(u16)) {
u32 r;
_iwl_write32(priv, CSR_EEPROM_REG,
CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
CSR_EEPROM_REG_READ_VALID_MSK,
IWL_EEPROM_ACCESS_TIMEOUT);
if (ret < 0) {
IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr);
goto done;
}
r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
}
r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
}
ret = 0;
done:
priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv);
err:
if (ret)
kfree(priv->eeprom);
iwl_eeprom_free(priv);
alloc_err:
return ret;
}
......@@ -301,6 +408,8 @@ EXPORT_SYMBOL(iwl_eeprom_query_addr);
u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
{
if (!priv->eeprom)
return 0;
return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
}
EXPORT_SYMBOL(iwl_eeprom_query16);
......@@ -481,8 +590,8 @@ int iwl_init_channel_map(struct iwl_priv *priv)
/* First write that fat is not enabled, and then enable
* one by one */
ch_info->fat_extension_channel =
(IEEE80211_CHAN_NO_FAT_ABOVE |
IEEE80211_CHAN_NO_FAT_BELOW);
(IEEE80211_CHAN_NO_HT40PLUS |
IEEE80211_CHAN_NO_HT40MINUS);
if (!(is_channel_valid(ch_info))) {
IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - "
......@@ -561,7 +670,7 @@ int iwl_init_channel_map(struct iwl_priv *priv)
fat_extension_chan = 0;
else
fat_extension_chan =
IEEE80211_CHAN_NO_FAT_BELOW;
IEEE80211_CHAN_NO_HT40MINUS;
/* Set up driver's info for lower half */
iwl_set_fat_chan_info(priv, ieeeband,
......@@ -573,7 +682,7 @@ int iwl_init_channel_map(struct iwl_priv *priv)
iwl_set_fat_chan_info(priv, ieeeband,
(eeprom_ch_index[ch] + 4),
&(eeprom_ch_info[ch]),
IEEE80211_CHAN_NO_FAT_ABOVE);
IEEE80211_CHAN_NO_HT40PLUS);
}
}
......
......@@ -179,6 +179,10 @@ struct iwl_eeprom_channel {
#define EEPROM_5050_TX_POWER_VERSION (4)
#define EEPROM_5050_EEPROM_VERSION (0x21E)
/* OTP */
#define OTP_LOWER_BLOCKS_TOTAL (3)
#define OTP_BLOCK_SIZE (0x400)
/* 2.4 GHz */
extern const u8 iwl_eeprom_band_1[14];
......
......@@ -131,9 +131,23 @@ static inline void __iwl_set_bit(const char *f, u32 l,
IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
_iwl_write32(priv, reg, val);
}
#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m)
static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m)
{
unsigned long reg_flags;
spin_lock_irqsave(&p->reg_lock, reg_flags);
__iwl_set_bit(__FILE__, __LINE__, p, r, m);
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
}
#else
#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m)
static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m)
{
unsigned long reg_flags;
spin_lock_irqsave(&p->reg_lock, reg_flags);
_iwl_set_bit(p, r, m);
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
}
#endif
static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
......@@ -148,19 +162,30 @@ static inline void __iwl_clear_bit(const char *f, u32 l,
IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
_iwl_write32(priv, reg, val);
}
#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m)
static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m)
{
unsigned long reg_flags;
spin_lock_irqsave(&p->reg_lock, reg_flags);
__iwl_clear_bit(__FILE__, __LINE__, p, r, m);
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
}
#else
#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m)
static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m)
{
unsigned long reg_flags;
spin_lock_irqsave(&p->reg_lock, reg_flags);
_iwl_clear_bit(p, r, m);
spin_unlock_irqrestore(&p->reg_lock, reg_flags);
}
#endif
static inline int _iwl_grab_nic_access(struct iwl_priv *priv)
{
int ret;
u32 val;
#ifdef CONFIG_IWLWIFI_DEBUG
if (atomic_read(&priv->restrict_refcnt))
return 0;
#endif
/* this bit wakes up the NIC */
_iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
ret = _iwl_poll_bit(priv, CSR_GP_CNTRL,
......@@ -170,12 +195,10 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv)
if (ret < 0) {
val = _iwl_read32(priv, CSR_GP_CNTRL);
IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
_iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
return -EIO;
}
#ifdef CONFIG_IWLWIFI_DEBUG
atomic_inc(&priv->restrict_refcnt);
#endif
return 0;
}
......@@ -183,9 +206,6 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv)
static inline int __iwl_grab_nic_access(const char *f, u32 l,
struct iwl_priv *priv)
{
if (atomic_read(&priv->restrict_refcnt))
IWL_ERR(priv, "Grabbing access while already held %s %d.\n", f, l);
IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l);
return _iwl_grab_nic_access(priv);
}
......@@ -198,18 +218,13 @@ static inline int __iwl_grab_nic_access(const char *f, u32 l,
static inline void _iwl_release_nic_access(struct iwl_priv *priv)
{
#ifdef CONFIG_IWLWIFI_DEBUG
if (atomic_dec_and_test(&priv->restrict_refcnt))
#endif
_iwl_clear_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
_iwl_clear_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
}
#ifdef CONFIG_IWLWIFI_DEBUG
static inline void __iwl_release_nic_access(const char *f, u32 l,
struct iwl_priv *priv)
{
if (atomic_read(&priv->restrict_refcnt) <= 0)
IWL_ERR(priv, "Release unheld nic access at line %s %d.\n", f, l);
IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l);
_iwl_release_nic_access(priv);
......@@ -230,16 +245,37 @@ static inline u32 __iwl_read_direct32(const char *f, u32 l,
struct iwl_priv *priv, u32 reg)
{
u32 value = _iwl_read_direct32(priv, reg);
if (!atomic_read(&priv->restrict_refcnt))
IWL_ERR(priv, "Nic access not held from %s %d\n", f, l);
IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value,
f, l);
return value;
}
#define iwl_read_direct32(priv, reg) \
__iwl_read_direct32(__FILE__, __LINE__, priv, reg)
static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg)
{
u32 value;
unsigned long reg_flags;
spin_lock_irqsave(&priv->reg_lock, reg_flags);
iwl_grab_nic_access(priv);
value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
return value;
}
#else
#define iwl_read_direct32 _iwl_read_direct32
static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg)
{
u32 value;
unsigned long reg_flags;
spin_lock_irqsave(&priv->reg_lock, reg_flags);
iwl_grab_nic_access(priv);
value = _iwl_read_direct32(priv, reg);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
return value;
}
#endif
static inline void _iwl_write_direct32(struct iwl_priv *priv,
......@@ -247,19 +283,17 @@ static inline void _iwl_write_direct32(struct iwl_priv *priv,
{
_iwl_write32(priv, reg, value);
}
#ifdef CONFIG_IWLWIFI_DEBUG
static void __iwl_write_direct32(const char *f , u32 line,
struct iwl_priv *priv, u32 reg, u32 value)
static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value)
{
if (!atomic_read(&priv->restrict_refcnt))
IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line);
_iwl_write_direct32(priv, reg, value);
unsigned long reg_flags;
spin_lock_irqsave(&priv->reg_lock, reg_flags);
if (!iwl_grab_nic_access(priv)) {
_iwl_write_direct32(priv, reg, value);
iwl_release_nic_access(priv);
}
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
#define iwl_write_direct32(priv, reg, value) \
__iwl_write_direct32(__func__, __LINE__, priv, reg, value)
#else
#define iwl_write_direct32 _iwl_write_direct32
#endif
static inline void iwl_write_reg_buf(struct iwl_priv *priv,
u32 reg, u32 len, u32 *values)
......@@ -268,14 +302,23 @@ static inline void iwl_write_reg_buf(struct iwl_priv *priv,
if ((priv != NULL) && (values != NULL)) {
for (; 0 < len; len -= count, reg += count, values++)
_iwl_write_direct32(priv, reg, *values);
iwl_write_direct32(priv, reg, *values);
}
}
static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr,
u32 mask, int timeout)
{
return _iwl_poll_bit(priv, addr, mask, mask, timeout);
int t = 0;
do {
if ((iwl_read_direct32(priv, addr) & mask) == mask)
return t;
udelay(IWL_POLL_INTERVAL);
t += IWL_POLL_INTERVAL;
} while (t < timeout);
return -ETIMEDOUT;
}
#ifdef CONFIG_IWLWIFI_DEBUG
......@@ -305,20 +348,18 @@ static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg)
rmb();
return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
}
#ifdef CONFIG_IWLWIFI_DEBUG
static inline u32 __iwl_read_prph(const char *f, u32 line,
struct iwl_priv *priv, u32 reg)
static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg)
{
if (!atomic_read(&priv->restrict_refcnt))
IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line);
return _iwl_read_prph(priv, reg);
}
unsigned long reg_flags;
u32 val;
#define iwl_read_prph(priv, reg) \
__iwl_read_prph(__func__, __LINE__, priv, reg)
#else
#define iwl_read_prph _iwl_read_prph
#endif
spin_lock_irqsave(&priv->reg_lock, reg_flags);
iwl_grab_nic_access(priv);
val = _iwl_read_prph(priv, reg);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
return val;
}
static inline void _iwl_write_prph(struct iwl_priv *priv,
u32 addr, u32 val)
......@@ -328,83 +369,107 @@ static inline void _iwl_write_prph(struct iwl_priv *priv,
wmb();
_iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
}
#ifdef CONFIG_IWLWIFI_DEBUG
static inline void __iwl_write_prph(const char *f, u32 line,
struct iwl_priv *priv, u32 addr, u32 val)
static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val)
{
if (!atomic_read(&priv->restrict_refcnt))
IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line);
_iwl_write_prph(priv, addr, val);
}
unsigned long reg_flags;
#define iwl_write_prph(priv, addr, val) \
__iwl_write_prph(__func__, __LINE__, priv, addr, val);
#else
#define iwl_write_prph _iwl_write_prph
#endif
spin_lock_irqsave(&priv->reg_lock, reg_flags);
if (!iwl_grab_nic_access(priv)) {
_iwl_write_prph(priv, addr, val);
iwl_release_nic_access(priv);
}
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
#define _iwl_set_bits_prph(priv, reg, mask) \
_iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask))
#ifdef CONFIG_IWLWIFI_DEBUG
static inline void __iwl_set_bits_prph(const char *f, u32 line,
struct iwl_priv *priv,
u32 reg, u32 mask)
static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
{
if (!atomic_read(&priv->restrict_refcnt))
IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line);
unsigned long reg_flags;
spin_lock_irqsave(&priv->reg_lock, reg_flags);
iwl_grab_nic_access(priv);
_iwl_set_bits_prph(priv, reg, mask);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
#define iwl_set_bits_prph(priv, reg, mask) \
__iwl_set_bits_prph(__func__, __LINE__, priv, reg, mask)
#else
#define iwl_set_bits_prph _iwl_set_bits_prph
#endif
#define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \
_iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits))
#ifdef CONFIG_IWLWIFI_DEBUG
static inline void __iwl_set_bits_mask_prph(const char *f, u32 line,
struct iwl_priv *priv, u32 reg, u32 bits, u32 mask)
static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
u32 bits, u32 mask)
{
if (!atomic_read(&priv->restrict_refcnt))
IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line);
unsigned long reg_flags;
spin_lock_irqsave(&priv->reg_lock, reg_flags);
iwl_grab_nic_access(priv);
_iwl_set_bits_mask_prph(priv, reg, bits, mask);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
#define iwl_set_bits_mask_prph(priv, reg, bits, mask) \
__iwl_set_bits_mask_prph(__func__, __LINE__, priv, reg, bits, mask)
#else
#define iwl_set_bits_mask_prph _iwl_set_bits_mask_prph
#endif
static inline void iwl_clear_bits_prph(struct iwl_priv
*priv, u32 reg, u32 mask)
{
u32 val = _iwl_read_prph(priv, reg);
unsigned long reg_flags;
u32 val;
spin_lock_irqsave(&priv->reg_lock, reg_flags);
iwl_grab_nic_access(priv);
val = _iwl_read_prph(priv, reg);
_iwl_write_prph(priv, reg, (val & ~mask));
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
{
iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
unsigned long reg_flags;
u32 value;
spin_lock_irqsave(&priv->reg_lock, reg_flags);
iwl_grab_nic_access(priv);
_iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
rmb();
return iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
return value;
}
static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val)
{
iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
wmb();
iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
unsigned long reg_flags;
spin_lock_irqsave(&priv->reg_lock, reg_flags);
if (!iwl_grab_nic_access(priv)) {
_iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
wmb();
_iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
iwl_release_nic_access(priv);
}
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr,
u32 len, u32 *values)
{
iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
wmb();
for (; 0 < len; len -= sizeof(u32), values++)
iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
unsigned long reg_flags;
spin_lock_irqsave(&priv->reg_lock, reg_flags);
if (!iwl_grab_nic_access(priv)) {
_iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
wmb();
for (; 0 < len; len -= sizeof(u32), values++)
_iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
iwl_release_nic_access(priv);
}
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
#endif
......@@ -145,18 +145,14 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
goto exit_unlock;
}
ret = iwl_grab_nic_access(priv);
if (ret)
goto exit_unlock;
/* Device expects a multiple of 8 */
iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write & ~0x7);
iwl_release_nic_access(priv);
q->write_actual = (q->write & ~0x7);
iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual);
/* Else device is assumed to be awake */
} else {
/* Device expects a multiple of 8 */
iwl_write32(priv, rx_wrt_ptr_reg, q->write & ~0x7);
q->write_actual = (q->write & ~0x7);
iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual);
}
q->need_update = 0;
......@@ -218,7 +214,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
/* If we've added more space for the firmware to place data, tell it.
* Increment device's write pointer in multiples of 8. */
if (write != (rxq->write & ~0x7)) {
if (rxq->write_actual != (rxq->write & ~0x7)) {
spin_lock_irqsave(&rxq->lock, flags);
rxq->need_update = 1;
spin_unlock_irqrestore(&rxq->lock, flags);
......@@ -238,7 +234,7 @@ EXPORT_SYMBOL(iwl_rx_queue_restock);
* Also restock the Rx queue via iwl_rx_queue_restock.
* This is called as a scheduled work item (except for during initialization)
*/
void iwl_rx_allocate(struct iwl_priv *priv)
void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
......@@ -260,7 +256,8 @@ void iwl_rx_allocate(struct iwl_priv *priv)
/* Alloc a new receive buffer */
rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
GFP_KERNEL);
priority);
if (!rxb->skb) {
IWL_CRIT(priv, "Can not allocate SKB buffers\n");
/* We don't reschedule replenish work here -- we will
......@@ -295,7 +292,7 @@ void iwl_rx_replenish(struct iwl_priv *priv)
{
unsigned long flags;
iwl_rx_allocate(priv);
iwl_rx_allocate(priv, GFP_KERNEL);
spin_lock_irqsave(&priv->lock, flags);
iwl_rx_queue_restock(priv);
......@@ -303,6 +300,14 @@ void iwl_rx_replenish(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_rx_replenish);
void iwl_rx_replenish_now(struct iwl_priv *priv)
{
iwl_rx_allocate(priv, GFP_ATOMIC);
iwl_rx_queue_restock(priv);
}
EXPORT_SYMBOL(iwl_rx_replenish_now);
/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
* If an SKB has been detached, the POOL needs to have its SKB set to NULL
......@@ -358,6 +363,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
/* 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->write_actual = 0;
rxq->free_count = 0;
rxq->need_update = 0;
return 0;
......@@ -396,6 +402,7 @@ void iwl_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->write_actual = 0;
rxq->free_count = 0;
spin_unlock_irqrestore(&rxq->lock, flags);
}
......@@ -403,18 +410,12 @@ EXPORT_SYMBOL(iwl_rx_queue_reset);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
int ret;
unsigned long flags;
u32 rb_size;
const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
const u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT why this stalls RX */
u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
if (!priv->cfg->use_isr_legacy)
rb_timeout = RX_RB_TIMEOUT;
if (priv->cfg->mod_params->amsdu_size_8K)
rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
......@@ -452,35 +453,19 @@ 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_release_nic_access(priv);
iwl_write32(priv, CSR_INT_COALESCING, 0x40);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
int iwl_rxq_stop(struct iwl_priv *priv)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (unlikely(ret)) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
/* stop Rx DMA */
iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
EXPORT_SYMBOL(iwl_rxq_stop);
......@@ -582,8 +567,8 @@ void iwl_rx_statistics(struct iwl_priv *priv,
iwl_leds_background(priv);
if (priv->cfg->ops->lib->temperature && change)
priv->cfg->ops->lib->temperature(priv);
if (priv->cfg->ops->lib->temp_ops.temperature && change)
priv->cfg->ops->lib->temp_ops.temperature(priv);
}
EXPORT_SYMBOL(iwl_rx_statistics);
......
......@@ -586,6 +586,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
u8 rx_ant = priv->hw_params.valid_rx_ant;
u8 rate;
bool is_active = false;
int chan_mod;
conf = ieee80211_get_hw_conf(priv->hw);
......@@ -703,7 +704,9 @@ static void iwl_bg_request_scan(struct work_struct *data)
if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
band = IEEE80211_BAND_2GHZ;
scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) {
chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK)
>> RXON_FLG_CHANNEL_MODE_POS;
if (chan_mod == CHANNEL_MODE_PURE_40) {
rate = IWL_RATE_6M_PLCP;
} else {
rate = IWL_RATE_1M_PLCP;
......
......@@ -102,13 +102,8 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
return ret;
}
/* restore this queue's parameters in nic hardware. */
ret = iwl_grab_nic_access(priv);
if (ret)
return ret;
iwl_write_direct32(priv, HBUS_TARG_WRPTR,
txq->q.write_ptr | (txq_id << 8));
iwl_release_nic_access(priv);
/* else not in power-save mode, uCode will never sleep when we're
* trying to tx (during RFKILL, we're not trying to tx). */
......@@ -429,11 +424,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
goto error_kw;
}
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (unlikely(ret)) {
spin_unlock_irqrestore(&priv->lock, flags);
goto error_reset;
}
/* Turn off all Tx DMA fifos */
priv->cfg->ops->lib->txq_set_sched(priv, 0);
......@@ -441,7 +431,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
/* Tell NIC where to find the "keep warm" buffer */
iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
/* Alloc and init all Tx queues, including the command queue (#4) */
......@@ -460,7 +449,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
error:
iwl_hw_txq_ctx_free(priv);
error_reset:
iwl_free_dma_ptr(priv, &priv->kw);
error_kw:
iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
......@@ -478,10 +466,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv)
/* Turn off all Tx DMA fifos */
spin_lock_irqsave(&priv->lock, flags);
if (iwl_grab_nic_access(priv)) {
spin_unlock_irqrestore(&priv->lock, flags);
return;
}
priv->cfg->ops->lib->txq_set_sched(priv, 0);
......@@ -492,7 +476,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv)
FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
1000);
}
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
/* Deallocate memory for all Tx queues */
......
......@@ -340,7 +340,7 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
unsigned long flags;
spin_lock_irqsave(&priv->sta_lock, flags);
memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl3945_hw_key));
memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
memset(&priv->stations_39[sta_id].sta.key, 0,
sizeof(struct iwl4965_keyinfo));
priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
......@@ -578,8 +578,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
int sta_id)
{
struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
struct iwl3945_hw_key *keyinfo =
&priv->stations_39[sta_id].keyinfo;
struct iwl_hw_key *keyinfo = &priv->stations_39[sta_id].keyinfo;
switch (keyinfo->alg) {
case ALG_CCMP:
......@@ -1687,7 +1686,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
u32 i;
u32 desc, time, count, base, data1;
u32 blink1, blink2, ilink1, ilink2;
int rc;
base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
......@@ -1696,11 +1694,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
return;
}
rc = iwl_grab_nic_access(priv);
if (rc) {
IWL_WARN(priv, "Can not read from adapter at this time.\n");
return;
}
count = iwl_read_targ_mem(priv, base);
......@@ -1735,8 +1728,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
ilink1, ilink2, data1);
}
iwl_release_nic_access(priv);
}
#define EVENT_START_OFFSET (6 * sizeof(u32))
......@@ -1744,7 +1735,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv)
/**
* iwl3945_print_event_log - Dump error event log to syslog
*
* NOTE: Must be called with iwl_grab_nic_access() already obtained!
*/
static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
u32 num_events, u32 mode)
......@@ -1787,7 +1777,6 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
static void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
{
int rc;
u32 base; /* SRAM byte address of event log header */
u32 capacity; /* event log capacity in # entries */
u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
......@@ -1801,12 +1790,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
return;
}
rc = iwl_grab_nic_access(priv);
if (rc) {
IWL_WARN(priv, "Can not read from adapter at this time.\n");
return;
}
/* event log header */
capacity = iwl_read_targ_mem(priv, base);
mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
......@@ -1818,7 +1801,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
/* bail out if nothing in log */
if (size == 0) {
IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
iwl_release_nic_access(priv);
return;
}
......@@ -1834,7 +1816,6 @@ static 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);
iwl_release_nic_access(priv);
}
static void iwl3945_irq_tasklet(struct iwl_priv *priv)
......@@ -1953,11 +1934,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
priv->isr_stats.tx++;
iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6));
if (!iwl_grab_nic_access(priv)) {
iwl_write_direct32(priv, FH39_TCSR_CREDIT
(FH39_SRVC_CHNL), 0x0);
iwl_release_nic_access(priv);
}
iwl_write_direct32(priv, FH39_TCSR_CREDIT
(FH39_SRVC_CHNL), 0x0);
handled |= CSR_INT_BIT_FH_TX;
}
......@@ -1966,9 +1944,9 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
priv->isr_stats.unhandled++;
}
if (inta & ~CSR_INI_SET_MASK) {
if (inta & ~priv->inta_mask) {
IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
inta & ~CSR_INI_SET_MASK);
inta & ~priv->inta_mask);
IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh);
}
......@@ -2132,10 +2110,6 @@ static int iwl3945_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 le
IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
rc = iwl_grab_nic_access(priv);
if (rc)
return rc;
iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
IWL39_RTC_INST_LOWER_BOUND);
......@@ -2156,7 +2130,6 @@ static int iwl3945_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 le
}
}
iwl_release_nic_access(priv);
if (!errcnt)
IWL_DEBUG_INFO(priv,
......@@ -2180,10 +2153,6 @@ static int iwl3945_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32
IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
rc = iwl_grab_nic_access(priv);
if (rc)
return rc;
for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
/* read data comes through single port, auto-incr addr */
/* NOTE: Use the debugless read so we don't flood kernel log
......@@ -2204,8 +2173,6 @@ static int iwl3945_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32
}
}
iwl_release_nic_access(priv);
return rc;
}
......@@ -2529,20 +2496,11 @@ static int iwl3945_set_ucode_ptrs(struct iwl_priv *priv)
{
dma_addr_t pinst;
dma_addr_t pdata;
int rc = 0;
unsigned long flags;
/* bits 31:0 for 3945 */
pinst = priv->ucode_code.p_addr;
pdata = priv->ucode_data_backup.p_addr;
spin_lock_irqsave(&priv->lock, flags);
rc = iwl_grab_nic_access(priv);
if (rc) {
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
}
/* Tell bootstrap uCode where to find image to load */
iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
......@@ -2554,13 +2512,9 @@ static int iwl3945_set_ucode_ptrs(struct iwl_priv *priv)
iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
priv->ucode_code.len | BSM_DRAM_INST_LOAD);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n");
return rc;
return 0;
}
/**
......@@ -2613,7 +2567,6 @@ static void iwl3945_init_alive_start(struct iwl_priv *priv)
*/
static void iwl3945_alive_start(struct iwl_priv *priv)
{
int rc = 0;
int thermal_spin = 0;
u32 rfkill;
......@@ -2638,15 +2591,8 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
priv->cfg->ops->smgmt->clear_station_table(priv);
rc = iwl_grab_nic_access(priv);
if (rc) {
IWL_WARN(priv, "Can not read RFKILL status from adapter\n");
return;
}
rfkill = iwl_read_prph(priv, APMG_RFKILL_REG);
IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill);
iwl_release_nic_access(priv);
if (rfkill & 0x1) {
clear_bit(STATUS_RF_KILL_HW, &priv->status);
......@@ -2792,13 +2738,8 @@ static void __iwl3945_down(struct iwl_priv *priv)
iwl3945_hw_txq_ctx_stop(priv);
iwl3945_hw_rxq_stop(priv);
spin_lock_irqsave(&priv->lock, flags);
if (!iwl_grab_nic_access(priv)) {
iwl_write_prph(priv, APMG_CLK_DIS_REG,
APMG_CLK_VAL_DMA_CLK_RQT);
iwl_release_nic_access(priv);
}
spin_unlock_irqrestore(&priv->lock, flags);
iwl_write_prph(priv, APMG_CLK_DIS_REG,
APMG_CLK_VAL_DMA_CLK_RQT);
udelay(5);
......@@ -4243,6 +4184,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
priv->cfg = cfg;
priv->pci_dev = pdev;
priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG
priv->debug_level = iwl3945_mod_params.debug;
......@@ -4289,6 +4231,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
* PCI Tx retries from interfering with C3 CPU state */
pci_write_config_byte(pdev, 0x41, 0x00);
/* this spin lock will be used in apm_ops.init and EEPROM access
* we should init now
*/
spin_lock_init(&priv->reg_lock);
/* amp init */
err = priv->cfg->ops->lib->apm_ops.init(priv);
if (err < 0) {
......@@ -4344,8 +4291,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
pci_enable_msi(priv->pci_dev);
err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED,
DRV_NAME, priv);
err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr,
IRQF_SHARED, DRV_NAME, priv);
if (err) {
IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
goto out_disable_msi;
......
config IWM
tristate "Intel Wireless Multicomm 3200 WiFi driver"
depends on MMC && WLAN_80211 && EXPERIMENTAL
select LIB80211
select FW_LOADER
select RFKILL
config IWM_DEBUG
bool "Enable full debugging output in iwmc3200wifi"
depends on IWM && DEBUG_FS
---help---
This option will enable debug tracing and setting for iwm
You can set the debug level and module through debugfs. By
default all modules are set to the IWL_DL_ERR level.
To see the list of debug modules and levels, see iwm/debug.h
For example, if you want the full MLME debug output:
echo 0xff > /debug/iwm/phyN/debug/mlme
Or, if you want the full debug, for all modules:
echo 0xff > /debug/iwm/phyN/debug/level
echo 0xff > /debug/iwm/phyN/debug/modules
obj-$(CONFIG_IWM) := iwmc3200wifi.o
iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o
iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o rfkill.o
iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o
此差异已折叠。
此差异已折叠。
/*
* Intel Wireless Multicomm 3200 WiFi driver
*
* Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
* Samuel Ortiz <samuel.ortiz@intel.com>
* Zhu Yi <yi.zhu@intel.com>
*
* 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 Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
#ifndef __IWM_CFG80211_H__
#define __IWM_CFG80211_H__
int iwm_cfg80211_inform_bss(struct iwm_priv *iwm);
struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev);
void iwm_wdev_free(struct iwm_priv *iwm);
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册