Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller 2008-12-21 19:57:10 -08:00
commit c2da953a46
50 changed files with 1166 additions and 651 deletions

View File

@ -1350,4 +1350,9 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
return retval; return retval;
} }
static inline int ath5k_pad_size(int hdrlen)
{
return (hdrlen < 24) ? 0 : hdrlen & 3;
}
#endif #endif

View File

@ -1668,7 +1668,7 @@ ath5k_tasklet_rx(unsigned long data)
struct ath5k_desc *ds; struct ath5k_desc *ds;
int ret; int ret;
int hdrlen; int hdrlen;
int pad; int padsize;
spin_lock(&sc->rxbuflock); spin_lock(&sc->rxbuflock);
if (list_empty(&sc->rxbuf)) { if (list_empty(&sc->rxbuf)) {
@ -1753,16 +1753,19 @@ accept:
skb_put(skb, rs.rs_datalen); skb_put(skb, rs.rs_datalen);
/* /* The MAC header is padded to have 32-bit boundary if the
* the hardware adds a padding to 4 byte boundaries between * packet payload is non-zero. The general calculation for
* the header and the payload data if the header length is * padsize would take into account odd header lengths:
* not multiples of 4 - remove it * padsize = (4 - hdrlen % 4) % 4; However, since only
*/ * even-length headers are used, padding can only be 0 or 2
* bytes and we can optimize this a bit. In addition, we must
* not try to remove padding from short control frames that do
* not have payload. */
hdrlen = ieee80211_get_hdrlen_from_skb(skb); hdrlen = ieee80211_get_hdrlen_from_skb(skb);
if (hdrlen & 3) { padsize = ath5k_pad_size(hdrlen);
pad = hdrlen % 4; if (padsize) {
memmove(skb->data + pad, skb->data, hdrlen); memmove(skb->data + padsize, skb->data, hdrlen);
skb_pull(skb, pad); skb_pull(skb, padsize);
} }
/* /*
@ -2623,7 +2626,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ath5k_buf *bf; struct ath5k_buf *bf;
unsigned long flags; unsigned long flags;
int hdrlen; int hdrlen;
int pad; int padsize;
ath5k_debug_dump_skb(sc, skb, "TX ", 1); ath5k_debug_dump_skb(sc, skb, "TX ", 1);
@ -2635,15 +2638,16 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* if this is not the case we add the padding after the header * if this is not the case we add the padding after the header
*/ */
hdrlen = ieee80211_get_hdrlen_from_skb(skb); hdrlen = ieee80211_get_hdrlen_from_skb(skb);
if (hdrlen & 3) { padsize = ath5k_pad_size(hdrlen);
pad = hdrlen % 4; if (padsize) {
if (skb_headroom(skb) < pad) {
if (skb_headroom(skb) < padsize) {
ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
" headroom to pad %d\n", hdrlen, pad); " headroom to pad %d\n", hdrlen, padsize);
return -1; return -1;
} }
skb_push(skb, pad); skb_push(skb, padsize);
memmove(skb->data, skb->data+pad, hdrlen); memmove(skb->data, skb->data+padsize, hdrlen);
} }
spin_lock_irqsave(&sc->txbuflock, flags); spin_lock_irqsave(&sc->txbuflock, flags);

View File

@ -71,7 +71,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
/* Verify and set frame length */ /* Verify and set frame length */
/* remove padding we might have added before */ /* remove padding we might have added before */
frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN;
if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL; return -EINVAL;
@ -202,7 +202,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
/* Verify and set frame length */ /* Verify and set frame length */
/* remove padding we might have added before */ /* remove padding we might have added before */
frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN;
if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL; return -EINVAL;

View File

@ -701,6 +701,7 @@ struct ath_softc {
struct ath_hal *sc_ah; struct ath_hal *sc_ah;
void __iomem *mem; void __iomem *mem;
spinlock_t sc_resetlock; spinlock_t sc_resetlock;
struct mutex mutex;
u8 sc_curbssid[ETH_ALEN]; u8 sc_curbssid[ETH_ALEN];
u8 sc_myaddr[ETH_ALEN]; u8 sc_myaddr[ETH_ALEN];

View File

@ -61,8 +61,7 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz)
static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
{ {
if (!sc->sc_curaid) sc->cur_rate_table = sc->hw_rate_table[mode];
sc->cur_rate_table = sc->hw_rate_table[mode];
/* /*
* All protection frames are transmited at 2Mb/s for * All protection frames are transmited at 2Mb/s for
* 11g, otherwise at 1Mb/s. * 11g, otherwise at 1Mb/s.
@ -623,37 +622,40 @@ static int ath_get_channel(struct ath_softc *sc,
return -1; return -1;
} }
/* ext_chan_offset: (-1, 0, 1) (below, none, above) */
static u32 ath_get_extchanmode(struct ath_softc *sc, static u32 ath_get_extchanmode(struct ath_softc *sc,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
int ext_chan_offset, enum nl80211_channel_type channel_type)
enum ath9k_ht_macmode tx_chan_width)
{ {
u32 chanmode = 0; u32 chanmode = 0;
switch (chan->band) { switch (chan->band) {
case IEEE80211_BAND_2GHZ: case IEEE80211_BAND_2GHZ:
if ((ext_chan_offset == 0) && switch(channel_type) {
(tx_chan_width == ATH9K_HT_MACMODE_20)) case NL80211_CHAN_NO_HT:
case NL80211_CHAN_HT20:
chanmode = CHANNEL_G_HT20; chanmode = CHANNEL_G_HT20;
if ((ext_chan_offset == 1) && break;
(tx_chan_width == ATH9K_HT_MACMODE_2040)) case NL80211_CHAN_HT40PLUS:
chanmode = CHANNEL_G_HT40PLUS; chanmode = CHANNEL_G_HT40PLUS;
if ((ext_chan_offset == -1) && break;
(tx_chan_width == ATH9K_HT_MACMODE_2040)) case NL80211_CHAN_HT40MINUS:
chanmode = CHANNEL_G_HT40MINUS; chanmode = CHANNEL_G_HT40MINUS;
break;
}
break; break;
case IEEE80211_BAND_5GHZ: case IEEE80211_BAND_5GHZ:
if ((ext_chan_offset == 0) && switch(channel_type) {
(tx_chan_width == ATH9K_HT_MACMODE_20)) case NL80211_CHAN_NO_HT:
case NL80211_CHAN_HT20:
chanmode = CHANNEL_A_HT20; chanmode = CHANNEL_A_HT20;
if ((ext_chan_offset == 1) && break;
(tx_chan_width == ATH9K_HT_MACMODE_2040)) case NL80211_CHAN_HT40PLUS:
chanmode = CHANNEL_A_HT40PLUS; chanmode = CHANNEL_A_HT40PLUS;
if ((ext_chan_offset == -1) && break;
(tx_chan_width == ATH9K_HT_MACMODE_2040)) case NL80211_CHAN_HT40MINUS:
chanmode = CHANNEL_A_HT40MINUS; chanmode = CHANNEL_A_HT40MINUS;
break;
}
break; break;
default: default:
break; break;
@ -662,13 +664,6 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
return chanmode; return chanmode;
} }
static void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot)
{
ath9k_hw_keyreset(sc->sc_ah, keyix);
if (freeslot)
clear_bit(keyix, sc->sc_keymap);
}
static int ath_keyset(struct ath_softc *sc, u16 keyix, static int ath_keyset(struct ath_softc *sc, u16 keyix,
struct ath9k_keyval *hk, const u8 mac[ETH_ALEN]) struct ath9k_keyval *hk, const u8 mac[ETH_ALEN])
{ {
@ -680,21 +675,20 @@ static int ath_keyset(struct ath_softc *sc, u16 keyix,
return status != false; return status != false;
} }
static int ath_setkey_tkip(struct ath_softc *sc, static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
struct ieee80211_key_conf *key,
struct ath9k_keyval *hk, struct ath9k_keyval *hk,
const u8 *addr) const u8 *addr)
{ {
u8 *key_rxmic = NULL; const u8 *key_rxmic;
u8 *key_txmic = NULL; const u8 *key_txmic;
key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
if (addr == NULL) { if (addr == NULL) {
/* Group key installation */ /* Group key installation */
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
return ath_keyset(sc, key->keyidx, hk, addr); return ath_keyset(sc, keyix, hk, addr);
} }
if (!sc->sc_splitmic) { if (!sc->sc_splitmic) {
/* /*
@ -703,14 +697,14 @@ static int ath_setkey_tkip(struct ath_softc *sc,
*/ */
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
return ath_keyset(sc, key->keyidx, hk, addr); return ath_keyset(sc, keyix, hk, addr);
} }
/* /*
* TX key goes at first index, RX key at +32. * TX key goes at first index, RX key at +32.
* The hal handles the MIC keys at index+64. * The hal handles the MIC keys at index+64.
*/ */
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
if (!ath_keyset(sc, key->keyidx, hk, NULL)) { if (!ath_keyset(sc, keyix, hk, NULL)) {
/* Txmic entry failed. No need to proceed further */ /* Txmic entry failed. No need to proceed further */
DPRINTF(sc, ATH_DBG_KEYCACHE, DPRINTF(sc, ATH_DBG_KEYCACHE,
"Setting TX MIC Key Failed\n"); "Setting TX MIC Key Failed\n");
@ -719,18 +713,97 @@ static int ath_setkey_tkip(struct ath_softc *sc,
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
/* XXX delete tx key on failure? */ /* XXX delete tx key on failure? */
return ath_keyset(sc, key->keyidx+32, hk, addr); return ath_keyset(sc, keyix + 32, hk, addr);
}
static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc)
{
int i;
for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
if (test_bit(i, sc->sc_keymap) ||
test_bit(i + 64, sc->sc_keymap))
continue; /* At least one part of TKIP key allocated */
if (sc->sc_splitmic &&
(test_bit(i + 32, sc->sc_keymap) ||
test_bit(i + 64 + 32, sc->sc_keymap)))
continue; /* At least one part of TKIP key allocated */
/* Found a free slot for a TKIP key */
return i;
}
return -1;
}
static int ath_reserve_key_cache_slot(struct ath_softc *sc)
{
int i;
/* First, try to find slots that would not be available for TKIP. */
if (sc->sc_splitmic) {
for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 4; i++) {
if (!test_bit(i, sc->sc_keymap) &&
(test_bit(i + 32, sc->sc_keymap) ||
test_bit(i + 64, sc->sc_keymap) ||
test_bit(i + 64 + 32, sc->sc_keymap)))
return i;
if (!test_bit(i + 32, sc->sc_keymap) &&
(test_bit(i, sc->sc_keymap) ||
test_bit(i + 64, sc->sc_keymap) ||
test_bit(i + 64 + 32, sc->sc_keymap)))
return i + 32;
if (!test_bit(i + 64, sc->sc_keymap) &&
(test_bit(i , sc->sc_keymap) ||
test_bit(i + 32, sc->sc_keymap) ||
test_bit(i + 64 + 32, sc->sc_keymap)))
return i + 64;
if (!test_bit(i + 64 + 32, sc->sc_keymap) &&
(test_bit(i, sc->sc_keymap) ||
test_bit(i + 32, sc->sc_keymap) ||
test_bit(i + 64, sc->sc_keymap)))
return i + 64 + 32;
}
} else {
for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
if (!test_bit(i, sc->sc_keymap) &&
test_bit(i + 64, sc->sc_keymap))
return i;
if (test_bit(i, sc->sc_keymap) &&
!test_bit(i + 64, sc->sc_keymap))
return i + 64;
}
}
/* No partially used TKIP slots, pick any available slot */
for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) {
/* Do not allow slots that could be needed for TKIP group keys
* to be used. This limitation could be removed if we know that
* TKIP will not be used. */
if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
continue;
if (sc->sc_splitmic) {
if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
continue;
if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
continue;
}
if (!test_bit(i, sc->sc_keymap))
return i; /* Found a free slot for a key */
}
/* No free slot found */
return -1;
} }
static int ath_key_config(struct ath_softc *sc, static int ath_key_config(struct ath_softc *sc,
const u8 *addr, const u8 *addr,
struct ieee80211_key_conf *key) struct ieee80211_key_conf *key)
{ {
struct ieee80211_vif *vif;
struct ath9k_keyval hk; struct ath9k_keyval hk;
const u8 *mac = NULL; const u8 *mac = NULL;
int ret = 0; int ret = 0;
enum nl80211_iftype opmode; int idx;
memset(&hk, 0, sizeof(hk)); memset(&hk, 0, sizeof(hk));
@ -748,65 +821,69 @@ static int ath_key_config(struct ath_softc *sc,
return -EINVAL; return -EINVAL;
} }
hk.kv_len = key->keylen; hk.kv_len = key->keylen;
memcpy(hk.kv_val, key->key, key->keylen); memcpy(hk.kv_val, key->key, key->keylen);
if (!sc->sc_vaps[0]) if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
return -EIO; /* For now, use the default keys for broadcast keys. This may
* need to change with virtual interfaces. */
idx = key->keyidx;
} else if (key->keyidx) {
struct ieee80211_vif *vif;
vif = sc->sc_vaps[0]; mac = addr;
opmode = vif->type; vif = sc->sc_vaps[0];
if (vif->type != NL80211_IFTYPE_AP) {
/* /* Only keyidx 0 should be used with unicast key, but
* Strategy: * allow this for client mode for now. */
* For STA mc tx, we will not setup a key at idx = key->keyidx;
* all since we never tx mc. } else
* return -EIO;
* For STA mc rx, we will use the keyID.
*
* For ADHOC mc tx, we will use the keyID, and no macaddr.
*
* For ADHOC mc rx, we will alloc a slot and plumb the mac of
* the peer node.
* BUT we will plumb a cleartext key so that we can do
* per-Sta default key table lookup in software.
*/
if (is_broadcast_ether_addr(addr)) {
switch (opmode) {
case NL80211_IFTYPE_STATION:
/* default key: could be group WPA key
* or could be static WEP key */
mac = NULL;
break;
case NL80211_IFTYPE_ADHOC:
break;
case NL80211_IFTYPE_AP:
break;
default:
ASSERT(0);
break;
}
} else { } else {
mac = addr; mac = addr;
if (key->alg == ALG_TKIP)
idx = ath_reserve_key_cache_slot_tkip(sc);
else
idx = ath_reserve_key_cache_slot(sc);
if (idx < 0)
return -EIO; /* no free key cache entries */
} }
if (key->alg == ALG_TKIP) if (key->alg == ALG_TKIP)
ret = ath_setkey_tkip(sc, key, &hk, mac); ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac);
else else
ret = ath_keyset(sc, key->keyidx, &hk, mac); ret = ath_keyset(sc, idx, &hk, mac);
if (!ret) if (!ret)
return -EIO; return -EIO;
return 0; set_bit(idx, sc->sc_keymap);
if (key->alg == ALG_TKIP) {
set_bit(idx + 64, sc->sc_keymap);
if (sc->sc_splitmic) {
set_bit(idx + 32, sc->sc_keymap);
set_bit(idx + 64 + 32, sc->sc_keymap);
}
}
return idx;
} }
static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
{ {
int freeslot; ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx);
if (key->hw_key_idx < IEEE80211_WEP_NKID)
return;
freeslot = (key->keyidx >= 4) ? 1 : 0; clear_bit(key->hw_key_idx, sc->sc_keymap);
ath_key_reset(sc, key->keyidx, freeslot); if (key->alg != ALG_TKIP)
return;
clear_bit(key->hw_key_idx + 64, sc->sc_keymap);
if (sc->sc_splitmic) {
clear_bit(key->hw_key_idx + 32, sc->sc_keymap);
clear_bit(key->hw_key_idx + 64 + 32, sc->sc_keymap);
}
} }
static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info)
@ -829,45 +906,15 @@ static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info)
ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
} }
static void ath9k_ht_conf(struct ath_softc *sc,
struct ieee80211_bss_conf *bss_conf)
{
if (sc->hw->conf.ht.enabled) {
if (bss_conf->ht.width_40_ok)
sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
else
sc->tx_chan_width = ATH9K_HT_MACMODE_20;
ath9k_hw_set11nmac2040(sc->sc_ah, sc->tx_chan_width);
DPRINTF(sc, ATH_DBG_CONFIG,
"BSS Changed HT, chanwidth: %d\n", sc->tx_chan_width);
}
}
static inline int ath_sec_offset(u8 ext_offset)
{
if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)
return 0;
else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
return 1;
else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
return -1;
return 0;
}
static void ath9k_bss_assoc_info(struct ath_softc *sc, static void ath9k_bss_assoc_info(struct ath_softc *sc,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf) struct ieee80211_bss_conf *bss_conf)
{ {
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_channel *curchan = hw->conf.channel;
struct ath_vap *avp = (void *)vif->drv_priv; struct ath_vap *avp = (void *)vif->drv_priv;
int pos;
if (bss_conf->assoc) { if (bss_conf->assoc) {
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d\n", bss_conf->aid); DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
bss_conf->aid, sc->sc_curbssid);
/* New association, store aid */ /* New association, store aid */
if (avp->av_opmode == NL80211_IFTYPE_STATION) { if (avp->av_opmode == NL80211_IFTYPE_STATION) {
@ -886,40 +933,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
/* Update chainmask */
ath_update_chainmask(sc, hw->conf.ht.enabled);
DPRINTF(sc, ATH_DBG_CONFIG,
"bssid %pM aid 0x%x\n",
sc->sc_curbssid, sc->sc_curaid);
pos = ath_get_channel(sc, curchan);
if (pos == -1) {
DPRINTF(sc, ATH_DBG_FATAL,
"Invalid channel: %d\n", curchan->center_freq);
return;
}
if (hw->conf.ht.enabled) {
int offset =
ath_sec_offset(bss_conf->ht.secondary_channel_offset);
sc->tx_chan_width = (bss_conf->ht.width_40_ok) ?
ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
sc->sc_ah->ah_channels[pos].chanmode =
ath_get_extchanmode(sc, curchan,
offset, sc->tx_chan_width);
} else {
sc->sc_ah->ah_channels[pos].chanmode =
(curchan->band == IEEE80211_BAND_2GHZ) ?
CHANNEL_G : CHANNEL_A;
}
/* set h/w channel */
if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel: %d\n",
curchan->center_freq);
/* Start ANI */ /* Start ANI */
mod_timer(&sc->sc_ani.timer, mod_timer(&sc->sc_ani.timer,
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
@ -1291,9 +1304,6 @@ static void ath_detach(struct ath_softc *sc)
ath_deinit_leds(sc); ath_deinit_leds(sc);
ieee80211_unregister_hw(hw); ieee80211_unregister_hw(hw);
ath_rate_control_unregister();
ath_rx_cleanup(sc); ath_rx_cleanup(sc);
ath_tx_cleanup(sc); ath_tx_cleanup(sc);
@ -1326,6 +1336,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
printk(KERN_ERR "Unable to create debugfs files\n"); printk(KERN_ERR "Unable to create debugfs files\n");
spin_lock_init(&sc->sc_resetlock); spin_lock_init(&sc->sc_resetlock);
mutex_init(&sc->mutex);
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
(unsigned long)sc); (unsigned long)sc);
@ -1362,18 +1373,6 @@ static int ath_init(u16 devid, struct ath_softc *sc)
*/ */
for (i = 0; i < sc->sc_keymax; i++) for (i = 0; i < sc->sc_keymax; i++)
ath9k_hw_keyreset(ah, (u16) i); ath9k_hw_keyreset(ah, (u16) i);
/*
* Mark key cache slots associated with global keys
* as in use. If we knew TKIP was not to be used we
* could leave the +32, +64, and +32+64 slots free.
* XXX only for splitmic.
*/
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
set_bit(i, sc->sc_keymap);
set_bit(i + 32, sc->sc_keymap);
set_bit(i + 64, sc->sc_keymap);
set_bit(i + 32 + 64, sc->sc_keymap);
}
/* Collect the channel list using the default country code */ /* Collect the channel list using the default country code */
@ -1574,15 +1573,7 @@ static int ath_attach(u16 devid, struct ath_softc *sc)
hw->sta_data_size = sizeof(struct ath_node); hw->sta_data_size = sizeof(struct ath_node);
hw->vif_data_size = sizeof(struct ath_vap); hw->vif_data_size = sizeof(struct ath_vap);
/* Register rate control */
hw->rate_control_algorithm = "ath9k_rate_control"; hw->rate_control_algorithm = "ath9k_rate_control";
error = ath_rate_control_register();
if (error != 0) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to register rate control algorithm: %d\n", error);
ath_rate_control_unregister();
goto bad;
}
if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
@ -1615,10 +1606,6 @@ static int ath_attach(u16 devid, struct ath_softc *sc)
#endif #endif
error = ieee80211_register_hw(hw); error = ieee80211_register_hw(hw);
if (error != 0) {
ath_rate_control_unregister();
goto bad;
}
/* Initialize LED control */ /* Initialize LED control */
ath_init_leds(sc); ath_init_leds(sc);
@ -1626,7 +1613,6 @@ static int ath_attach(u16 devid, struct ath_softc *sc)
return 0; return 0;
detach: detach:
ath_detach(sc); ath_detach(sc);
bad:
return error; return error;
} }
@ -2146,7 +2132,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
struct ath_softc *sc = hw->priv; struct ath_softc *sc = hw->priv;
struct ieee80211_conf *conf = &hw->conf; struct ieee80211_conf *conf = &hw->conf;
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { mutex_lock(&sc->mutex);
if (changed & (IEEE80211_CONF_CHANGE_CHANNEL |
IEEE80211_CONF_CHANGE_HT)) {
struct ieee80211_channel *curchan = hw->conf.channel; struct ieee80211_channel *curchan = hw->conf.channel;
int pos; int pos;
@ -2157,6 +2145,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
if (pos == -1) { if (pos == -1) {
DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n",
curchan->center_freq); curchan->center_freq);
mutex_unlock(&sc->mutex);
return -EINVAL; return -EINVAL;
} }
@ -2165,29 +2154,29 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
(curchan->band == IEEE80211_BAND_2GHZ) ? (curchan->band == IEEE80211_BAND_2GHZ) ?
CHANNEL_G : CHANNEL_A; CHANNEL_G : CHANNEL_A;
if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) && if (conf->ht.enabled) {
(conf->ht.enabled)) { if (conf->ht.channel_type == NL80211_CHAN_HT40PLUS ||
sc->tx_chan_width = (!!conf->ht.sec_chan_offset) ? conf->ht.channel_type == NL80211_CHAN_HT40MINUS)
ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20; sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
sc->sc_ah->ah_channels[pos].chanmode = sc->sc_ah->ah_channels[pos].chanmode =
ath_get_extchanmode(sc, curchan, ath_get_extchanmode(sc, curchan,
conf->ht.sec_chan_offset, conf->ht.channel_type);
sc->tx_chan_width);
} }
if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) { if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
mutex_unlock(&sc->mutex);
return -EINVAL; return -EINVAL;
} }
}
if (changed & IEEE80211_CONF_CHANGE_HT)
ath_update_chainmask(sc, conf->ht.enabled); ath_update_chainmask(sc, conf->ht.enabled);
}
if (changed & IEEE80211_CONF_CHANGE_POWER) if (changed & IEEE80211_CONF_CHANGE_POWER)
sc->sc_config.txpowlimit = 2 * conf->power_level; sc->sc_config.txpowlimit = 2 * conf->power_level;
mutex_unlock(&sc->mutex);
return 0; return 0;
} }
@ -2371,18 +2360,17 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
switch (cmd) { switch (cmd) {
case SET_KEY: case SET_KEY:
ret = ath_key_config(sc, addr, key); ret = ath_key_config(sc, addr, key);
if (!ret) { if (ret >= 0) {
set_bit(key->keyidx, sc->sc_keymap); key->hw_key_idx = ret;
key->hw_key_idx = key->keyidx;
/* push IV and Michael MIC generation to stack */ /* push IV and Michael MIC generation to stack */
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
if (key->alg == ALG_TKIP) if (key->alg == ALG_TKIP)
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
ret = 0;
} }
break; break;
case DISABLE_KEY: case DISABLE_KEY:
ath_key_delete(sc, key); ath_key_delete(sc, key);
clear_bit(key->keyidx, sc->sc_keymap);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
@ -2417,9 +2405,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
} }
if (changed & BSS_CHANGED_HT)
ath9k_ht_conf(sc, bss_conf);
if (changed & BSS_CHANGED_ASSOC) { if (changed & BSS_CHANGED_ASSOC) {
DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
bss_conf->assoc); bss_conf->assoc);
@ -2780,11 +2765,24 @@ static struct pci_driver ath_pci_driver = {
static int __init init_ath_pci(void) static int __init init_ath_pci(void)
{ {
int error;
printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION); printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION);
/* Register rate control algorithm */
error = ath_rate_control_register();
if (error != 0) {
printk(KERN_ERR
"Unable to register rate control algorithm: %d\n",
error);
ath_rate_control_unregister();
return error;
}
if (pci_register_driver(&ath_pci_driver) < 0) { if (pci_register_driver(&ath_pci_driver) < 0) {
printk(KERN_ERR printk(KERN_ERR
"ath_pci: No devices found, driver not installed.\n"); "ath_pci: No devices found, driver not installed.\n");
ath_rate_control_unregister();
pci_unregister_driver(&ath_pci_driver); pci_unregister_driver(&ath_pci_driver);
return -ENODEV; return -ENODEV;
} }
@ -2795,6 +2793,7 @@ module_init(init_ath_pci);
static void __exit exit_ath_pci(void) static void __exit exit_ath_pci(void)
{ {
ath_rate_control_unregister();
pci_unregister_driver(&ath_pci_driver); pci_unregister_driver(&ath_pci_driver);
printk(KERN_INFO "%s: Driver unloaded\n", dev_info); printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
} }

View File

@ -1498,7 +1498,8 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
__le16 fc = hdr->frame_control; __le16 fc = hdr->frame_control;
/* lowest rate for management and multicast/broadcast frames */ /* lowest rate for management and multicast/broadcast frames */
if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
!sta) {
tx_info->control.rates[0].idx = rate_lowest_index(sband, sta); tx_info->control.rates[0].idx = rate_lowest_index(sband, sta);
tx_info->control.rates[0].count = tx_info->control.rates[0].count =
is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY; is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY;

View File

@ -111,33 +111,6 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len)
return skb; return skb;
} }
static int ath_rate2idx(struct ath_softc *sc, int rate)
{
int i = 0, cur_band, n_rates;
struct ieee80211_hw *hw = sc->hw;
cur_band = hw->conf.channel->band;
n_rates = sc->sbands[cur_band].n_bitrates;
for (i = 0; i < n_rates; i++) {
if (sc->sbands[cur_band].bitrates[i].bitrate == rate)
break;
}
/*
* NB:mac80211 validates rx rate index against the supported legacy rate
* index only (should be done against ht rates also), return the highest
* legacy rate index for rx rate which does not match any one of the
* supported basic and extended rates to make mac80211 happy.
* The following hack will be cleaned up once the issue with
* the rx rate index validation in mac80211 is fixed.
*/
if (i == n_rates)
return n_rates - 1;
return i;
}
/* /*
* For Decrypt or Demic errors, we only mark packet status here and always push * For Decrypt or Demic errors, we only mark packet status here and always push
* up the frame up to let mac80211 handle the actual error case, be it no * up the frame up to let mac80211 handle the actual error case, be it no
@ -147,9 +120,7 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
struct ieee80211_rx_status *rx_status, bool *decrypt_error, struct ieee80211_rx_status *rx_status, bool *decrypt_error,
struct ath_softc *sc) struct ath_softc *sc)
{ {
struct ath_rate_table *rate_table = sc->cur_rate_table;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
int ratekbps, rix;
u8 ratecode; u8 ratecode;
__le16 fc; __le16 fc;
@ -204,15 +175,36 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
} }
ratecode = ds->ds_rxstat.rs_rate; ratecode = ds->ds_rxstat.rs_rate;
rix = rate_table->rateCodeToIndex[ratecode];
ratekbps = rate_table->info[rix].ratekbps;
/* HT rate */
if (ratecode & 0x80) { if (ratecode & 0x80) {
/* HT rate */
rx_status->flag |= RX_FLAG_HT;
if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040)
ratekbps = (ratekbps * 27) / 13; rx_status->flag |= RX_FLAG_40MHZ;
if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
ratekbps = (ratekbps * 10) / 9; rx_status->flag |= RX_FLAG_SHORT_GI;
rx_status->rate_idx = ratecode & 0x7f;
} else {
int i = 0, cur_band, n_rates;
struct ieee80211_hw *hw = sc->hw;
cur_band = hw->conf.channel->band;
n_rates = sc->sbands[cur_band].n_bitrates;
for (i = 0; i < n_rates; i++) {
if (sc->sbands[cur_band].bitrates[i].hw_value ==
ratecode) {
rx_status->rate_idx = i;
break;
}
if (sc->sbands[cur_band].bitrates[i].hw_value_short ==
ratecode) {
rx_status->rate_idx = i;
rx_status->flag |= RX_FLAG_SHORTPRE;
break;
}
}
} }
rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
@ -220,7 +212,6 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
rx_status->freq = sc->hw->conf.channel->center_freq; rx_status->freq = sc->hw->conf.channel->center_freq;
rx_status->noise = sc->sc_ani.sc_noise_floor; rx_status->noise = sc->sc_ani.sc_noise_floor;
rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
rx_status->rate_idx = ath_rate2idx(sc, (ratekbps / 100));
rx_status->antenna = ds->ds_rxstat.rs_antenna; rx_status->antenna = ds->ds_rxstat.rs_antenna;
/* at 45 you will be able to use MCS 15 reliably. A more elaborate /* at 45 you will be able to use MCS 15 reliably. A more elaborate
@ -528,6 +519,15 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
if (!skb) if (!skb)
continue; continue;
/*
* Synchronize the DMA transfer with CPU before
* 1. accessing the frame
* 2. requeueing the same buffer to h/w
*/
pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr,
sc->rx.bufsize,
PCI_DMA_FROMDEVICE);
/* /*
* If we're asked to flush receive queue, directly * If we're asked to flush receive queue, directly
* chain it back at the queue without processing it. * chain it back at the queue without processing it.
@ -556,10 +556,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
if (!requeue_skb) if (!requeue_skb)
goto requeue; goto requeue;
/* Sync and unmap the frame */ /* Unmap the frame */
pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr,
sc->rx.bufsize,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sc->pdev, bf->bf_buf_addr, pci_unmap_single(sc->pdev, bf->bf_buf_addr,
sc->rx.bufsize, sc->rx.bufsize,
PCI_DMA_FROMDEVICE); PCI_DMA_FROMDEVICE);

View File

@ -106,6 +106,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
struct ieee80211_hw *hw = sc->hw; struct ieee80211_hw *hw = sc->hw;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
int hdrlen, padsize;
DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
@ -125,7 +126,26 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
tx_info->flags |= IEEE80211_TX_STAT_ACK; tx_info->flags |= IEEE80211_TX_STAT_ACK;
} }
tx_info->status.rates[0].count = tx_status->retries + 1; tx_info->status.rates[0].count = tx_status->retries;
if (tx_info->status.rates[0].flags & IEEE80211_TX_RC_MCS) {
/* Change idx from internal table index to MCS index */
int idx = tx_info->status.rates[0].idx;
struct ath_rate_table *rate_table = sc->cur_rate_table;
if (idx >= 0 && idx < rate_table->rate_cnt)
tx_info->status.rates[0].idx =
rate_table->info[idx].ratecode & 0x7f;
}
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
padsize = hdrlen & 3;
if (padsize && hdrlen >= 24) {
/*
* Remove MAC header padding before giving the frame back to
* mac80211.
*/
memmove(skb->data + padsize, skb->data, hdrlen);
skb_pull(skb, padsize);
}
ieee80211_tx_status(hw, skb); ieee80211_tx_status(hw, skb);
} }

View File

@ -731,6 +731,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev)
add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0); add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
add_dyn_dbg("debug_lo", B43_DBG_LO, 0); add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0); add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0);
#undef add_dyn_dbg #undef add_dyn_dbg
} }

View File

@ -12,6 +12,7 @@ enum b43_dyndbg { /* Dynamic debugging features */
B43_DBG_PWORK_STOP, B43_DBG_PWORK_STOP,
B43_DBG_LO, B43_DBG_LO,
B43_DBG_FIRMWARE, B43_DBG_FIRMWARE,
B43_DBG_KEYS,
__B43_NR_DYNDBG, __B43_NR_DYNDBG,
}; };

View File

@ -992,6 +992,52 @@ static void b43_clear_keys(struct b43_wldev *dev)
b43_key_clear(dev, i); b43_key_clear(dev, i);
} }
static void b43_dump_keymemory(struct b43_wldev *dev)
{
unsigned int i, index, offset;
DECLARE_MAC_BUF(macbuf);
u8 mac[ETH_ALEN];
u16 algo;
u32 rcmta0;
u16 rcmta1;
u64 hf;
struct b43_key *key;
if (!b43_debug(dev, B43_DBG_KEYS))
return;
hf = b43_hf_read(dev);
b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n",
!!(hf & B43_HF_USEDEFKEYS));
for (index = 0; index < dev->max_nr_keys; index++) {
key = &(dev->key[index]);
printk(KERN_DEBUG "Key slot %02u: %s",
index, (key->keyconf == NULL) ? " " : "*");
offset = dev->ktp + (index * B43_SEC_KEYSIZE);
for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i);
printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF));
}
algo = b43_shm_read16(dev, B43_SHM_SHARED,
B43_SHM_SH_KEYIDXBLOCK + (index * 2));
printk(" Algo: %04X/%02X", algo, key->algorithm);
if (index >= 4) {
rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA,
((index - 4) * 2) + 0);
rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA,
((index - 4) * 2) + 1);
*((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
*((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
printk(" MAC: %s",
print_mac(macbuf, mac));
} else
printk(" DEFAULT KEY");
printk("\n");
}
}
void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
{ {
u32 macctl; u32 macctl;
@ -3324,7 +3370,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
unsigned long flags; unsigned long flags;
int antenna; int antenna;
int err = 0; int err = 0;
u32 savedirqs;
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
@ -3335,24 +3380,14 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
dev = wl->current_dev; dev = wl->current_dev;
phy = &dev->phy; phy = &dev->phy;
b43_mac_suspend(dev);
if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
b43_set_retry_limits(dev, conf->short_frame_max_tx_count, b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
conf->long_frame_max_tx_count); conf->long_frame_max_tx_count);
changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS; changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
if (!changed) if (!changed)
goto out_unlock_mutex; goto out_mac_enable;
/* Disable IRQs while reconfiguring the device.
* This makes it possible to drop the spinlock throughout
* the reconfiguration process. */
spin_lock_irqsave(&wl->irq_lock, flags);
if (b43_status(dev) < B43_STAT_STARTED) {
spin_unlock_irqrestore(&wl->irq_lock, flags);
goto out_unlock_mutex;
}
savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
spin_unlock_irqrestore(&wl->irq_lock, flags);
b43_synchronize_irq(dev);
/* Switch to the requested channel. /* Switch to the requested channel.
* The firmware takes care of races with the TX handler. */ * The firmware takes care of races with the TX handler. */
@ -3399,11 +3434,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
} }
} }
spin_lock_irqsave(&wl->irq_lock, flags); out_mac_enable:
b43_interrupt_enable(dev, savedirqs); b43_mac_enable(dev);
mmiowb(); out_unlock_mutex:
spin_unlock_irqrestore(&wl->irq_lock, flags);
out_unlock_mutex:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
return err; return err;
@ -3461,27 +3494,12 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
{ {
struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev; struct b43_wldev *dev;
struct b43_phy *phy;
unsigned long flags;
u32 savedirqs;
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
dev = wl->current_dev; dev = wl->current_dev;
phy = &dev->phy; if (!dev || b43_status(dev) < B43_STAT_STARTED)
/* Disable IRQs while reconfiguring the device.
* This makes it possible to drop the spinlock throughout
* the reconfiguration process. */
spin_lock_irqsave(&wl->irq_lock, flags);
if (b43_status(dev) < B43_STAT_STARTED) {
spin_unlock_irqrestore(&wl->irq_lock, flags);
goto out_unlock_mutex; goto out_unlock_mutex;
}
savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
spin_unlock_irqrestore(&wl->irq_lock, flags);
b43_synchronize_irq(dev);
b43_mac_suspend(dev); b43_mac_suspend(dev);
if (changed & BSS_CHANGED_BASIC_RATES) if (changed & BSS_CHANGED_BASIC_RATES)
@ -3495,13 +3513,7 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
} }
b43_mac_enable(dev); b43_mac_enable(dev);
out_unlock_mutex:
spin_lock_irqsave(&wl->irq_lock, flags);
b43_interrupt_enable(dev, savedirqs);
/* XXX: why? */
mmiowb();
spin_unlock_irqrestore(&wl->irq_lock, flags);
out_unlock_mutex:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
return; return;
@ -3599,15 +3611,18 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
default: default:
B43_WARN_ON(1); B43_WARN_ON(1);
} }
out_unlock: out_unlock:
spin_unlock_irqrestore(&wl->irq_lock, flags);
mutex_unlock(&wl->mutex);
if (!err) { if (!err) {
b43dbg(wl, "%s hardware based encryption for keyidx: %d, " b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
"mac: %pM\n", "mac: %pM\n",
cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
addr); addr);
b43_dump_keymemory(dev);
} }
spin_unlock_irqrestore(&wl->irq_lock, flags);
mutex_unlock(&wl->mutex);
return err; return err;
} }

View File

@ -178,13 +178,27 @@ void b43_phy_unlock(struct b43_wldev *dev)
b43_power_saving_ctl_bits(dev, 0); b43_power_saving_ctl_bits(dev, 0);
} }
static inline void assert_mac_suspended(struct b43_wldev *dev)
{
if (!B43_DEBUG)
return;
if ((b43_status(dev) >= B43_STAT_INITIALIZED) &&
(dev->mac_suspended <= 0)) {
b43dbg(dev->wl, "PHY/RADIO register access with "
"enabled MAC.\n");
dump_stack();
}
}
u16 b43_radio_read(struct b43_wldev *dev, u16 reg) u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
{ {
assert_mac_suspended(dev);
return dev->phy.ops->radio_read(dev, reg); return dev->phy.ops->radio_read(dev, reg);
} }
void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value) void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
{ {
assert_mac_suspended(dev);
dev->phy.ops->radio_write(dev, reg, value); dev->phy.ops->radio_write(dev, reg, value);
} }
@ -208,11 +222,13 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
u16 b43_phy_read(struct b43_wldev *dev, u16 reg) u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
{ {
assert_mac_suspended(dev);
return dev->phy.ops->phy_read(dev, reg); return dev->phy.ops->phy_read(dev, reg);
} }
void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
{ {
assert_mac_suspended(dev);
dev->phy.ops->phy_write(dev, reg, value); dev->phy.ops->phy_write(dev, reg, value);
} }
@ -280,8 +296,10 @@ void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state)
state = RFKILL_STATE_SOFT_BLOCKED; state = RFKILL_STATE_SOFT_BLOCKED;
} }
b43_mac_suspend(dev);
phy->ops->software_rfkill(dev, state); phy->ops->software_rfkill(dev, state);
phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
b43_mac_enable(dev);
} }
/** /**

View File

@ -3047,6 +3047,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
int rfatt, bbatt; int rfatt, bbatt;
u8 tx_control; u8 tx_control;
b43_mac_suspend(dev);
spin_lock_irq(&dev->wl->irq_lock); spin_lock_irq(&dev->wl->irq_lock);
/* Calculate the new attenuation values. */ /* Calculate the new attenuation values. */
@ -3103,6 +3105,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
gphy->tx_control); gphy->tx_control);
b43_radio_unlock(dev); b43_radio_unlock(dev);
b43_phy_unlock(dev); b43_phy_unlock(dev);
b43_mac_enable(dev);
} }
static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev, static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
@ -3215,9 +3219,9 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)
struct b43_phy *phy = &dev->phy; struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g; struct b43_phy_g *gphy = phy->g;
b43_mac_suspend(dev);
//TODO: update_aci_moving_average //TODO: update_aci_moving_average
if (gphy->aci_enable && gphy->aci_wlan_automatic) { if (gphy->aci_enable && gphy->aci_wlan_automatic) {
b43_mac_suspend(dev);
if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) { if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) {
if (0 /*TODO: bunch of conditions */ ) { if (0 /*TODO: bunch of conditions */ ) {
phy->ops->interf_mitigation(dev, phy->ops->interf_mitigation(dev,
@ -3227,12 +3231,12 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev)
if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev)) if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev))
phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE); phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
} }
b43_mac_enable(dev);
} else if (gphy->interfmode == B43_INTERFMODE_NONWLAN && } else if (gphy->interfmode == B43_INTERFMODE_NONWLAN &&
phy->rev == 1) { phy->rev == 1) {
//TODO: implement rev1 workaround //TODO: implement rev1 workaround
} }
b43_lo_g_maintanance_work(dev); b43_lo_g_maintanance_work(dev);
b43_mac_enable(dev);
} }
static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev) static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)

View File

@ -2482,7 +2482,6 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
frame_size = iwl3945_fill_beacon_frame(priv, frame_size = iwl3945_fill_beacon_frame(priv,
tx_beacon_cmd->frame, tx_beacon_cmd->frame,
iwl3945_broadcast_addr,
sizeof(frame->u) - sizeof(*tx_beacon_cmd)); sizeof(frame->u) - sizeof(*tx_beacon_cmd));
BUG_ON(frame_size > MAX_MPDU_SIZE); BUG_ON(frame_size > MAX_MPDU_SIZE);

View File

@ -405,12 +405,6 @@ struct iwl3945_rx_queue {
#define SCAN_INTERVAL 100 #define SCAN_INTERVAL 100
#define MAX_A_CHANNELS 252
#define MIN_A_CHANNELS 7
#define MAX_B_CHANNELS 14
#define MIN_B_CHANNELS 1
#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ #define STATUS_HCMD_ACTIVE 0 /* host command in progress */
#define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */
#define STATUS_INT_ENABLED 2 #define STATUS_INT_ENABLED 2
@ -590,8 +584,7 @@ extern int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len,
extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv, extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv,
struct iwl3945_host_cmd *cmd); struct iwl3945_host_cmd *cmd);
extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,int left);
const u8 *dest, int left);
extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv,
struct iwl3945_rx_queue *q); struct iwl3945_rx_queue *q);
extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv); extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv);

View File

@ -426,7 +426,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
static int iwl4965_apm_stop_master(struct iwl_priv *priv) static int iwl4965_apm_stop_master(struct iwl_priv *priv)
{ {
int ret = 0;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
@ -434,16 +433,13 @@ static int iwl4965_apm_stop_master(struct iwl_priv *priv)
/* set stop master bit */ /* set stop master bit */
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
ret = iwl_poll_direct_bit(priv, CSR_RESET, iwl_poll_direct_bit(priv, CSR_RESET,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
if (ret < 0)
goto out;
out:
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
IWL_DEBUG_INFO("stop master\n"); IWL_DEBUG_INFO("stop master\n");
return ret; return 0;
} }
static void iwl4965_apm_stop(struct iwl_priv *priv) static void iwl4965_apm_stop(struct iwl_priv *priv)
@ -2354,7 +2350,7 @@ module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
module_param_named(debug, iwl4965_mod_params.debug, int, 0444); module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
MODULE_PARM_DESC(debug, "debug output mask"); MODULE_PARM_DESC(debug, "debug output mask");
module_param_named( module_param_named(
disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444); disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);

View File

@ -73,7 +73,6 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = {
/* FIXME: same implementation as 4965 */ /* FIXME: same implementation as 4965 */
static int iwl5000_apm_stop_master(struct iwl_priv *priv) static int iwl5000_apm_stop_master(struct iwl_priv *priv)
{ {
int ret = 0;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
@ -81,16 +80,13 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv)
/* set stop master bit */ /* set stop master bit */
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
ret = iwl_poll_direct_bit(priv, CSR_RESET, iwl_poll_direct_bit(priv, CSR_RESET,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
if (ret < 0)
goto out;
out:
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
IWL_DEBUG_INFO("stop master\n"); IWL_DEBUG_INFO("stop master\n");
return ret; return 0;
} }
@ -1623,7 +1619,7 @@ MODULE_PARM_DESC(disable50,
module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
MODULE_PARM_DESC(swcrypto50, MODULE_PARM_DESC(swcrypto50,
"using software crypto engine (default 0 [hardware])\n"); "using software crypto engine (default 0 [hardware])\n");
module_param_named(debug50, iwl50_mod_params.debug, int, 0444); module_param_named(debug50, iwl50_mod_params.debug, uint, 0444);
MODULE_PARM_DESC(debug50, "50XX debug output mask"); MODULE_PARM_DESC(debug50, "50XX debug output mask");
module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");

View File

@ -836,6 +836,10 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
(hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) { hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) {
IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
/* the last LQ command could failed so the LQ in ucode not
* the same in driver sync up
*/
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
goto out; goto out;
} }
@ -2167,6 +2171,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_conf *conf = &priv->hw->conf; struct ieee80211_conf *conf = &priv->hw->conf;
struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_lq_sta *lq_sta = priv_sta;
u16 mask_bit = 0;
lq_sta->flush_timer = 0; lq_sta->flush_timer = 0;
lq_sta->supp_rates = sta->supp_rates[sband->band]; lq_sta->supp_rates = sta->supp_rates[sband->band];
@ -2200,16 +2205,6 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
priv->assoc_station_added = 1; priv->assoc_station_added = 1;
} }
/* Find highest tx rate supported by hardware and destination station */
lq_sta->last_txrate_idx = 3;
for (i = 0; i < sband->n_bitrates; i++)
if (sta->supp_rates[sband->band] & BIT(i))
lq_sta->last_txrate_idx = i;
/* For MODE_IEEE80211A, skip over cck rates in global rate table */
if (sband->band == IEEE80211_BAND_5GHZ)
lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
lq_sta->is_dup = 0; lq_sta->is_dup = 0;
lq_sta->is_green = rs_use_green(priv, conf); lq_sta->is_green = rs_use_green(priv, conf);
lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
@ -2248,6 +2243,17 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
lq_sta->drv = priv; lq_sta->drv = priv;
/* Find highest tx rate supported by hardware and destination station */
mask_bit = sta->supp_rates[sband->band] & lq_sta->active_legacy_rate;
lq_sta->last_txrate_idx = 3;
for (i = 0; i < sband->n_bitrates; i++)
if (mask_bit & BIT(i))
lq_sta->last_txrate_idx = i;
/* For MODE_IEEE80211A, skip over cck rates in global rate table */
if (sband->band == IEEE80211_BAND_5GHZ)
lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
rs_initialize_lq(priv, conf, sta, lq_sta); rs_initialize_lq(priv, conf, sta, lq_sta);
} }

View File

@ -371,7 +371,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,
const u8 *dest, int left) int left)
{ {
if (!iwl_is_associated(priv) || !priv->ibss_beacon || if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
((priv->iw_mode != NL80211_IFTYPE_ADHOC) && ((priv->iw_mode != NL80211_IFTYPE_ADHOC) &&
@ -424,7 +424,6 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
iwl_bcast_addr,
sizeof(frame->u) - sizeof(*tx_beacon_cmd)); sizeof(frame->u) - sizeof(*tx_beacon_cmd));
BUG_ON(frame_size > MAX_MPDU_SIZE); BUG_ON(frame_size > MAX_MPDU_SIZE);
@ -515,19 +514,27 @@ static void iwl_ht_conf(struct iwl_priv *priv,
iwl_conf->supported_chan_width = iwl_conf->supported_chan_width =
!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
iwl_conf->extension_chan_offset = bss_conf->ht.secondary_channel_offset; /*
* XXX: The HT configuration needs to be moved into iwl_mac_config()
* to be done there correctly.
*/
iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
if (priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40MINUS)
iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
else if(priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40PLUS)
iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
/* If no above or below channel supplied disable FAT channel */ /* If no above or below channel supplied disable FAT channel */
if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) { iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW)
iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
iwl_conf->supported_chan_width = 0; iwl_conf->supported_chan_width = 0;
}
iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
iwl_conf->tx_chan_width = bss_conf->ht.width_40_ok; iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0;
iwl_conf->ht_protection = iwl_conf->ht_protection =
bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
iwl_conf->non_GF_STA_present = iwl_conf->non_GF_STA_present =
@ -1103,16 +1110,6 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
priv->cfg->ops->lib->rx_handler_setup(priv); priv->cfg->ops->lib->rx_handler_setup(priv);
} }
/*
* this should be called while priv->lock is locked
*/
static void __iwl_rx_replenish(struct iwl_priv *priv)
{
iwl_rx_allocate(priv);
iwl_rx_queue_restock(priv);
}
/** /**
* iwl_rx_handle - Main entry function for receiving responses from uCode * iwl_rx_handle - Main entry function for receiving responses from uCode
* *
@ -1221,7 +1218,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
count++; count++;
if (count >= 8) { if (count >= 8) {
priv->rxq.read = i; priv->rxq.read = i;
__iwl_rx_replenish(priv); iwl_rx_queue_restock(priv);
count = 0; count = 0;
} }
} }
@ -3335,7 +3332,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
/* /*
* The following adds a new attribute to the sysfs representation * The following adds a new attribute to the sysfs representation
* of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
* used for controlling the debug level. * used for controlling the debug level.
* *
* See the level definitions in iwl for details. * See the level definitions in iwl for details.
@ -3421,7 +3418,11 @@ static ssize_t show_tx_power(struct device *d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
if (!iwl_is_ready_rf(priv))
return sprintf(buf, "off\n");
else
return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
} }
static ssize_t store_tx_power(struct device *d, static ssize_t store_tx_power(struct device *d,

View File

@ -70,6 +70,15 @@
* INIT calibrations framework * INIT calibrations framework
*****************************************************************************/ *****************************************************************************/
struct statistics_general_data {
u32 beacon_silence_rssi_a;
u32 beacon_silence_rssi_b;
u32 beacon_silence_rssi_c;
u32 beacon_energy_a;
u32 beacon_energy_b;
u32 beacon_energy_c;
};
int iwl_send_calib_results(struct iwl_priv *priv) int iwl_send_calib_results(struct iwl_priv *priv)
{ {
int ret = 0; int ret = 0;

View File

@ -2418,6 +2418,8 @@ struct statistics_rx_ht_phy {
__le32 reserved2; __le32 reserved2;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1)
struct statistics_rx_non_phy { struct statistics_rx_non_phy {
__le32 bogus_cts; /* CTS received when not expecting CTS */ __le32 bogus_cts; /* CTS received when not expecting CTS */
__le32 bogus_ack; /* ACK received when not expecting ACK */ __le32 bogus_ack; /* ACK received when not expecting ACK */

View File

@ -154,7 +154,7 @@ struct iwl_ops {
struct iwl_mod_params { struct iwl_mod_params {
int disable; /* def: 0 = enable radio */ int disable; /* def: 0 = enable radio */
int sw_crypto; /* def: 0 = using hardware encryption */ int sw_crypto; /* def: 0 = using hardware encryption */
int debug; /* def: 0 = minimal debug log messages */ u32 debug; /* def: 0 = minimal debug log messages */
int disable_hw_scan; /* def: 0 = use h/w scan */ int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */ int num_of_queues; /* def: HW dependent */
int num_of_ampdu_queues;/* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */

View File

@ -96,28 +96,25 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
#endif /* CONFIG_IWLWIFI_DEBUGFS */ #endif /* CONFIG_IWLWIFI_DEBUGFS */
/* /*
* To use the debug system; * To use the debug system:
* *
* If you are defining a new debug classification, simply add it to the #define * If you are defining a new debug classification, simply add it to the #define
* list here in the form of: * list here in the form of
* *
* #define IWL_DL_xxxx VALUE * #define IWL_DL_xxxx VALUE
* *
* shifting value to the left one bit from the previous entry. xxxx should be * where xxxx should be the name of the classification (for example, WEP).
* the name of the classification (for example, WEP)
* *
* You then need to either add a IWL_xxxx_DEBUG() macro definition for your * You then need to either add a IWL_xxxx_DEBUG() macro definition for your
* classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want
* to send output to that classification. * to send output to that classification.
* *
* To add your debug level to the list of levels seen when you perform * The active debug levels can be accessed via files
* *
* % cat /sys/class/net/wlanX/device/debug_level * /sys/module/iwlagn/parameters/debug{50}
* /sys/class/net/wlan0/device/debug_level
* *
* you simply need to add your entry to the iwl_debug_levels array. * when CONFIG_IWLWIFI_DEBUG=y.
*
* If you do not see debug_level in /sys/class/net/wlanX/device/debug_level
* then you do not have CONFIG_IWLWIFI_DEBUG defined in your kernel config file
*/ */
#define IWL_DL_INFO (1 << 0) #define IWL_DL_INFO (1 << 0)

View File

@ -323,14 +323,6 @@ struct iwl_rx_queue {
#define IWL_SUPPORTED_RATES_IE_LEN 8 #define IWL_SUPPORTED_RATES_IE_LEN 8
#define SCAN_INTERVAL 100
#define MAX_A_CHANNELS 252
#define MIN_A_CHANNELS 7
#define MAX_B_CHANNELS 14
#define MIN_B_CHANNELS 1
#define MAX_TID_COUNT 9 #define MAX_TID_COUNT 9
#define IWL_INVALID_RATE 0xFF #define IWL_INVALID_RATE 0xFF
@ -496,8 +488,6 @@ struct iwl_sensitivity_ranges {
}; };
#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ)
#define KELVIN_TO_CELSIUS(x) ((x)-273) #define KELVIN_TO_CELSIUS(x) ((x)-273)
#define CELSIUS_TO_KELVIN(x) ((x)+273) #define CELSIUS_TO_KELVIN(x) ((x)+273)
@ -546,9 +536,6 @@ struct iwl_hw_params {
const struct iwl_sensitivity_ranges *sens; const struct iwl_sensitivity_ranges *sens;
}; };
#define HT_SHORT_GI_20MHZ (1 << 0)
#define HT_SHORT_GI_40MHZ (1 << 1)
/****************************************************************************** /******************************************************************************
* *
@ -590,15 +577,15 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
} }
struct iwl_priv;
struct iwl_dma_ptr { struct iwl_dma_ptr {
dma_addr_t dma; dma_addr_t dma;
void *addr; void *addr;
size_t size; size_t size;
}; };
#define HT_SHORT_GI_20MHZ (1 << 0)
#define HT_SHORT_GI_40MHZ (1 << 1)
#define IWL_CHANNEL_WIDTH_20MHZ 0 #define IWL_CHANNEL_WIDTH_20MHZ 0
#define IWL_CHANNEL_WIDTH_40MHZ 1 #define IWL_CHANNEL_WIDTH_40MHZ 1
@ -613,7 +600,6 @@ struct iwl_dma_ptr {
#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
/* Sensitivity and chain noise calibration */ /* Sensitivity and chain noise calibration */
#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1)
#define INITIALIZATION_VALUE 0xFFFF #define INITIALIZATION_VALUE 0xFFFF
#define CAL_NUM_OF_BEACONS 20 #define CAL_NUM_OF_BEACONS 20
#define MAXIMUM_ALLOWED_PATHLOSS 15 #define MAXIMUM_ALLOWED_PATHLOSS 15
@ -666,15 +652,6 @@ enum iwl4965_calib_enabled_state {
IWL_CALIB_ENABLED = 1, IWL_CALIB_ENABLED = 1,
}; };
struct statistics_general_data {
u32 beacon_silence_rssi_a;
u32 beacon_silence_rssi_b;
u32 beacon_silence_rssi_c;
u32 beacon_energy_a;
u32 beacon_energy_b;
u32 beacon_energy_c;
};
/* /*
* enum iwl_calib * enum iwl_calib

View File

@ -87,17 +87,18 @@ static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs)
#define iwl_read32(p, o) _iwl_read32(p, o) #define iwl_read32(p, o) _iwl_read32(p, o)
#endif #endif
#define IWL_POLL_INTERVAL 10 /* microseconds */
static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
u32 bits, u32 mask, int timeout) u32 bits, u32 mask, int timeout)
{ {
int i = 0; int t = 0;
do { do {
if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
return i; return t;
udelay(10); udelay(IWL_POLL_INTERVAL);
i += 10; t += IWL_POLL_INTERVAL;
} while (i < timeout); } while (t < timeout);
return -ETIMEDOUT; return -ETIMEDOUT;
} }

View File

@ -292,7 +292,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
break; break;
IWL_DEBUG_LED("LED BLINK IDX=%d", i); IWL_DEBUG_LED("LED BLINK IDX=%d\n", i);
return i; return i;
} }

View File

@ -244,25 +244,31 @@ void iwl_rx_allocate(struct iwl_priv *priv)
struct list_head *element; struct list_head *element;
struct iwl_rx_mem_buffer *rxb; struct iwl_rx_mem_buffer *rxb;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&rxq->lock, flags);
while (!list_empty(&rxq->rx_used)) { while (1) {
spin_lock_irqsave(&rxq->lock, flags);
if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags);
return;
}
element = rxq->rx_used.next; element = rxq->rx_used.next;
rxb = list_entry(element, struct iwl_rx_mem_buffer, list); rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
list_del(element);
spin_unlock_irqrestore(&rxq->lock, flags);
/* Alloc a new receive buffer */ /* Alloc a new receive buffer */
rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256, rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
__GFP_NOWARN | GFP_ATOMIC); GFP_KERNEL);
if (!rxb->skb) { if (!rxb->skb) {
if (net_ratelimit()) printk(KERN_CRIT DRV_NAME
printk(KERN_CRIT DRV_NAME "Can not allocate SKB buffers\n");
": Can not allocate SKB buffers\n");
/* We don't reschedule replenish work here -- we will /* We don't reschedule replenish work here -- we will
* call the restock method and if it still needs * call the restock method and if it still needs
* more buffers it will schedule replenish */ * more buffers it will schedule replenish */
break; break;
} }
priv->alloc_rxb_skb++;
list_del(element);
/* Get physical address of RB/SKB */ /* Get physical address of RB/SKB */
rxb->real_dma_addr = pci_map_single( rxb->real_dma_addr = pci_map_single(
@ -276,12 +282,15 @@ void iwl_rx_allocate(struct iwl_priv *priv)
rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256); rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256);
skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr); skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr);
spin_lock_irqsave(&rxq->lock, flags);
list_add_tail(&rxb->list, &rxq->rx_free); list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++; rxq->free_count++;
priv->alloc_rxb_skb++;
spin_unlock_irqrestore(&rxq->lock, flags);
} }
spin_unlock_irqrestore(&rxq->lock, flags);
} }
EXPORT_SYMBOL(iwl_rx_allocate);
void iwl_rx_replenish(struct iwl_priv *priv) void iwl_rx_replenish(struct iwl_priv *priv)
{ {

View File

@ -645,7 +645,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
struct iwl_tx_cmd *tx_cmd, struct iwl_tx_cmd *tx_cmd,
struct ieee80211_tx_info *info, struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,
int is_unicast, u8 std_id) u8 std_id)
{ {
__le16 fc = hdr->frame_control; __le16 fc = hdr->frame_control;
__le32 tx_flags = tx_cmd->tx_flags; __le32 tx_flags = tx_cmd->tx_flags;
@ -834,7 +834,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
u16 len, len_org; u16 len, len_org;
u16 seq_number = 0; u16 seq_number = 0;
__le16 fc; __le16 fc;
u8 hdr_len, unicast; u8 hdr_len;
u8 sta_id; u8 sta_id;
u8 wait_write_ptr = 0; u8 wait_write_ptr = 0;
u8 tid = 0; u8 tid = 0;
@ -854,8 +854,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
goto drop_unlock; goto drop_unlock;
} }
unicast = !is_multicast_ether_addr(hdr->addr1);
fc = hdr->frame_control; fc = hdr->frame_control;
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
@ -994,7 +992,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
len = (u16)skb->len; len = (u16)skb->len;
tx_cmd->len = cpu_to_le16(len); tx_cmd->len = cpu_to_le16(len);
/* TODO need this for burst mode later on */ /* TODO need this for burst mode later on */
iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id); iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
/* set is_hcca to 0; it probably will never be implemented */ /* set is_hcca to 0; it probably will never be implemented */
iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);

View File

@ -65,7 +65,7 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv,
/* module parameters */ /* module parameters */
static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */ static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */
static int iwl3945_param_debug; /* def: 0 = minimal debug log messages */ static u32 iwl3945_param_debug; /* def: 0 = minimal debug log messages */
static int iwl3945_param_disable; /* def: 0 = enable radio */ static int iwl3945_param_disable; /* def: 0 = enable radio */
static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */ static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */
int iwl3945_param_hwcrypto; /* def: 0 = use software encryption */ int iwl3945_param_hwcrypto; /* def: 0 = use software encryption */
@ -1402,7 +1402,7 @@ static void iwl3945_free_frame(struct iwl3945_priv *priv, struct iwl3945_frame *
unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,
const u8 *dest, int left) int left)
{ {
if (!iwl3945_is_associated(priv) || !priv->ibss_beacon || if (!iwl3945_is_associated(priv) || !priv->ibss_beacon ||
@ -8343,7 +8343,7 @@ MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444); module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444);
MODULE_PARM_DESC(hwcrypto, MODULE_PARM_DESC(hwcrypto,
"using hardware crypto engine (default 0 [software])\n"); "using hardware crypto engine (default 0 [software])\n");
module_param_named(debug, iwl3945_param_debug, int, 0444); module_param_named(debug, iwl3945_param_debug, uint, 0444);
MODULE_PARM_DESC(debug, "debug output mask"); MODULE_PARM_DESC(debug, "debug output mask");
module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444); module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");

View File

@ -26,6 +26,7 @@
* if_sdio_card_to_host() to pad the data. * if_sdio_card_to_host() to pad the data.
*/ */
#include <linux/kernel.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
@ -581,7 +582,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
chunk_size, (chunk_size + 31) / 32 * 32); chunk_size, (chunk_size + 31) / 32 * 32);
*/ */
ret = sdio_writesb(card->func, card->ioport, ret = sdio_writesb(card->func, card->ioport,
chunk_buffer, (chunk_size + 31) / 32 * 32); chunk_buffer, roundup(chunk_size, 32));
if (ret) if (ret)
goto release; goto release;

View File

@ -495,11 +495,9 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
} }
if (changed & BSS_CHANGED_HT) { if (changed & BSS_CHANGED_HT) {
printk(KERN_DEBUG " %s: HT: sec_ch_offs=%d width_40_ok=%d " printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n",
"op_mode=%d\n",
wiphy_name(hw->wiphy), wiphy_name(hw->wiphy),
info->ht.secondary_channel_offset, info->ht.operation_mode);
info->ht.width_40_ok, info->ht.operation_mode);
} }
if (changed & BSS_CHANGED_BASIC_RATES) { if (changed & BSS_CHANGED_BASIC_RATES) {

View File

@ -44,6 +44,9 @@ enum p54_control_frame_types {
P54_CONTROL_TYPE_BT_OPTIONS = 35 P54_CONTROL_TYPE_BT_OPTIONS = 35
}; };
#define P54_HDR_FLAG_CONTROL BIT(15)
#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0))
struct p54_hdr { struct p54_hdr {
__le16 flags; __le16 flags;
__le16 len; __le16 len;
@ -54,6 +57,10 @@ struct p54_hdr {
u8 data[0]; u8 data[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
#define FREE_AFTER_TX(skb) \
((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
struct p54_edcf_queue_param { struct p54_edcf_queue_param {
__le16 aifs; __le16 aifs;
__le16 cwmin; __le16 cwmin;
@ -61,6 +68,13 @@ struct p54_edcf_queue_param {
__le16 txop; __le16 txop;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct p54_rssi_linear_approximation {
s16 mul;
s16 add;
s16 longbow_unkn;
s16 longbow_unk2;
};
#define EEPROM_READBACK_LEN 0x3fc #define EEPROM_READBACK_LEN 0x3fc
#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
@ -71,11 +85,11 @@ struct p54_edcf_queue_param {
#define FW_LM20 0x4c4d3230 #define FW_LM20 0x4c4d3230
struct p54_common { struct p54_common {
struct ieee80211_hw *hw;
u32 rx_start; u32 rx_start;
u32 rx_end; u32 rx_end;
struct sk_buff_head tx_queue; struct sk_buff_head tx_queue;
void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb, void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
int free_on_tx);
int (*open)(struct ieee80211_hw *dev); int (*open)(struct ieee80211_hw *dev);
void (*stop)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev);
int mode; int mode;
@ -90,6 +104,7 @@ struct p54_common {
struct pda_channel_output_limit *output_limit; struct pda_channel_output_limit *output_limit;
unsigned int output_limit_len; unsigned int output_limit_len;
struct pda_pa_curve_data *curve_data; struct pda_pa_curve_data *curve_data;
struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
unsigned int filter_flags; unsigned int filter_flags;
bool use_short_slot; bool use_short_slot;
u16 rxhw; u16 rxhw;
@ -106,9 +121,7 @@ struct p54_common {
struct ieee80211_tx_queue_stats tx_stats[8]; struct ieee80211_tx_queue_stats tx_stats[8];
struct p54_edcf_queue_param qos_params[8]; struct p54_edcf_queue_param qos_params[8];
struct ieee80211_low_level_stats stats; struct ieee80211_low_level_stats stats;
struct timer_list stats_timer; struct delayed_work work;
struct completion stats_comp;
struct sk_buff *cached_stats;
struct sk_buff *cached_beacon; struct sk_buff *cached_beacon;
int noise; int noise;
void *eeprom; void *eeprom;

View File

@ -335,6 +335,36 @@ static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2",
"Frisbee", "Xbow", "Longbow", "NULL", "NULL" }; "Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
static int p54_init_xbow_synth(struct ieee80211_hw *dev); static int p54_init_xbow_synth(struct ieee80211_hw *dev);
static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
u16 type)
{
struct p54_common *priv = dev->priv;
int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
int i;
if (len != (entry_size * num_entries)) {
printk(KERN_ERR "%s: unknown rssi calibration data packing "
" type:(%x) len:%d.\n",
wiphy_name(dev->wiphy), type, len);
print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
data, len);
printk(KERN_ERR "%s: please report this issue.\n",
wiphy_name(dev->wiphy));
return;
}
for (i = 0; i < num_entries; i++) {
struct pda_rssi_cal_entry *cal = data +
(offset + i * entry_size);
priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
}
}
static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
{ {
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
@ -434,6 +464,12 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
case PDR_HARDWARE_PLATFORM_COMPONENT_ID: case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
priv->version = *(u8 *)(entry->data + 1); priv->version = *(u8 *)(entry->data + 1);
break; break;
case PDR_RSSI_LINEAR_APPROXIMATION:
case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
p54_parse_rssical(dev, entry->data, data_len,
le16_to_cpu(entry->code));
break;
case PDR_END: case PDR_END:
/* make it overrun */ /* make it overrun */
entry_len = len; entry_len = len;
@ -453,10 +489,7 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
case PDR_DEFAULT_COUNTRY: case PDR_DEFAULT_COUNTRY:
case PDR_ANTENNA_GAIN: case PDR_ANTENNA_GAIN:
case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA: case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
case PDR_RSSI_LINEAR_APPROXIMATION:
case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
case PDR_REGULATORY_POWER_LIMITS: case PDR_REGULATORY_POWER_LIMITS:
case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
case PDR_RADIATED_TRANSMISSION_CORRECTION: case PDR_RADIATED_TRANSMISSION_CORRECTION:
case PDR_PRISM_TX_IQ_CALIBRATION: case PDR_PRISM_TX_IQ_CALIBRATION:
case PDR_BASEBAND_REGISTERS: case PDR_BASEBAND_REGISTERS:
@ -527,8 +560,11 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
{ {
/* TODO: get the rssi_add & rssi_mul data from the eeprom */ struct p54_common *priv = dev->priv;
return ((rssi * 0x83) / 64 - 400) / 4; int band = dev->conf.channel->band;
return ((rssi * priv->rssical_db[band].mul) / 64 +
priv->rssical_db[band].add) / 4;
} }
static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
@ -589,6 +625,9 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
ieee80211_rx_irqsafe(dev, skb, &rx_status); ieee80211_rx_irqsafe(dev, skb, &rx_status);
queue_delayed_work(dev->workqueue, &priv->work,
msecs_to_jiffies(P54_STATISTICS_UPDATE));
return -1; return -1;
} }
@ -644,7 +683,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
freed = priv->rx_end - last_addr; freed = priv->rx_end - last_addr;
__skb_unlink(skb, &priv->tx_queue); __skb_unlink(skb, &priv->tx_queue);
spin_unlock_irqrestore(&priv->tx_queue.lock, flags); spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
kfree_skb(skb); dev_kfree_skb_any(skb);
if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 +
IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
@ -652,6 +691,27 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
} }
EXPORT_SYMBOL_GPL(p54_free_skb); EXPORT_SYMBOL_GPL(p54_free_skb);
static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
__le32 req_id)
{
struct p54_common *priv = dev->priv;
struct sk_buff *entry = priv->tx_queue.next;
unsigned long flags;
spin_lock_irqsave(&priv->tx_queue.lock, flags);
while (entry != (struct sk_buff *)&priv->tx_queue) {
struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
if (hdr->req_id == req_id) {
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
return entry;
}
entry = entry->next;
}
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
return NULL;
}
static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
{ {
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
@ -696,6 +756,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
entry_hdr = (struct p54_hdr *) entry->data; entry_hdr = (struct p54_hdr *) entry->data;
entry_data = (struct p54_tx_data *) entry_hdr->data; entry_data = (struct p54_tx_data *) entry_hdr->data;
priv->tx_stats[entry_data->hw_queue].len--; priv->tx_stats[entry_data->hw_queue].len--;
priv->stats.dot11ACKFailureCount += payload->tries - 1;
if (unlikely(entry == priv->cached_beacon)) { if (unlikely(entry == priv->cached_beacon)) {
kfree_skb(entry); kfree_skb(entry);
@ -775,8 +836,12 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
struct p54_statistics *stats = (struct p54_statistics *) hdr->data; struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
u32 tsf32 = le32_to_cpu(stats->tsf32); u32 tsf32;
if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
return ;
tsf32 = le32_to_cpu(stats->tsf32);
if (tsf32 < priv->tsf_low32) if (tsf32 < priv->tsf_low32)
priv->tsf_high32++; priv->tsf_high32++;
priv->tsf_low32 = tsf32; priv->tsf_low32 = tsf32;
@ -786,9 +851,8 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
complete(&priv->stats_comp);
mod_timer(&priv->stats_timer, jiffies + 5 * HZ); p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id));
} }
static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
@ -897,6 +961,8 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
* have a few spare slots for control frames left. * have a few spare slots for control frames left.
*/ */
ieee80211_stop_queues(dev); ieee80211_stop_queues(dev);
queue_delayed_work(dev->workqueue, &priv->work,
msecs_to_jiffies(P54_TX_TIMEOUT));
if (unlikely(left == 32)) { if (unlikely(left == 32)) {
/* /*
@ -1022,7 +1088,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev)
eeprom_hdr->v2.magic2 = 0xf; eeprom_hdr->v2.magic2 = 0xf;
memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
} }
priv->tx(dev, skb, 0); priv->tx(dev, skb);
if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
printk(KERN_ERR "%s: device does not respond!\n", printk(KERN_ERR "%s: device does not respond!\n",
@ -1063,7 +1129,7 @@ static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
tim->count = 1; tim->count = 1;
tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid); tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
priv->tx(dev, skb, 1); priv->tx(dev, skb);
return 0; return 0;
} }
@ -1081,7 +1147,7 @@ static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
memcpy(sta->addr, addr, ETH_ALEN); memcpy(sta->addr, addr, ETH_ALEN);
priv->tx(dev, skb, 1); priv->tx(dev, skb);
return 0; return 0;
} }
@ -1124,7 +1190,7 @@ static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
hdr = (void *)entry->data; hdr = (void *)entry->data;
cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
cancel->req_id = hdr->req_id; cancel->req_id = hdr->req_id;
priv->tx(dev, skb, 1); priv->tx(dev, skb);
return 0; return 0;
} }
@ -1353,7 +1419,11 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
/* modifies skb->cb and with it info, so must be last! */ /* modifies skb->cb and with it info, so must be last! */
if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
goto err; goto err;
priv->tx(dev, skb, 0); priv->tx(dev, skb);
queue_delayed_work(dev->workqueue, &priv->work,
msecs_to_jiffies(P54_TX_FRAME_LIFETIME));
return 0; return 0;
err: err:
@ -1428,19 +1498,19 @@ static int p54_setup_mac(struct ieee80211_hw *dev)
setup->v2.lpf_bandwidth = cpu_to_le16(65535); setup->v2.lpf_bandwidth = cpu_to_le16(65535);
setup->v2.osc_start_delay = cpu_to_le16(65535); setup->v2.osc_start_delay = cpu_to_le16(65535);
} }
priv->tx(dev, skb, 1); priv->tx(dev, skb);
return 0; return 0;
} }
static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell, static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
u16 frequency)
{ {
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
struct sk_buff *skb; struct sk_buff *skb;
struct p54_scan *chan; struct p54_scan *chan;
unsigned int i; unsigned int i;
void *entry; void *entry;
__le16 freq = cpu_to_le16(frequency); __le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
int band = dev->conf.channel->band;
skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) +
sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN, sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN,
@ -1501,15 +1571,15 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell,
} }
if (priv->fw_var < 0x500) { if (priv->fw_var < 0x500) {
chan->v1.rssical_mul = cpu_to_le16(130); chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
chan->v1.rssical_add = cpu_to_le16(0xfe70); chan->v1_rssi.add = cpu_to_le16(priv->rssical_db[band].add);
} else { } else {
chan->v2.rssical_mul = cpu_to_le16(130); chan->v2.rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
chan->v2.rssical_add = cpu_to_le16(0xfe70); chan->v2.rssi.add = cpu_to_le16(priv->rssical_db[band].add);
chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
memset(chan->v2.rts_rates, 0, 8); memset(chan->v2.rts_rates, 0, 8);
} }
priv->tx(dev, skb, 1); priv->tx(dev, skb);
return 0; return 0;
err: err:
@ -1535,7 +1605,7 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
led->led_permanent = cpu_to_le16(link); led->led_permanent = cpu_to_le16(link);
led->led_temporary = cpu_to_le16(act); led->led_temporary = cpu_to_le16(act);
led->duration = cpu_to_le16(1000); led->duration = cpu_to_le16(1000);
priv->tx(dev, skb, 1); priv->tx(dev, skb);
return 0; return 0;
} }
@ -1575,21 +1645,7 @@ static int p54_set_edcf(struct ieee80211_hw *dev)
edcf->flags = 0; edcf->flags = 0;
memset(edcf->mapping, 0, sizeof(edcf->mapping)); memset(edcf->mapping, 0, sizeof(edcf->mapping));
memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
priv->tx(dev, skb, 1); priv->tx(dev, skb);
return 0;
}
static int p54_init_stats(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
priv->cached_stats = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL,
sizeof(struct p54_hdr) + sizeof(struct p54_statistics),
P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
if (!priv->cached_stats)
return -ENOMEM;
mod_timer(&priv->stats_timer, jiffies + HZ);
return 0; return 0;
} }
@ -1684,9 +1740,6 @@ static int p54_start(struct ieee80211_hw *dev)
P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
err = p54_set_edcf(dev); err = p54_set_edcf(dev);
if (err)
goto out;
err = p54_init_stats(dev);
if (err) if (err)
goto out; goto out;
@ -1698,6 +1751,8 @@ static int p54_start(struct ieee80211_hw *dev)
goto out; goto out;
} }
queue_delayed_work(dev->workqueue, &priv->work, 0);
out: out:
mutex_unlock(&priv->conf_mutex); mutex_unlock(&priv->conf_mutex);
return err; return err;
@ -1710,9 +1765,7 @@ static void p54_stop(struct ieee80211_hw *dev)
mutex_lock(&priv->conf_mutex); mutex_lock(&priv->conf_mutex);
priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->mode = NL80211_IFTYPE_UNSPECIFIED;
del_timer(&priv->stats_timer); cancel_delayed_work_sync(&priv->work);
p54_free_skb(dev, priv->cached_stats);
priv->cached_stats = NULL;
if (priv->cached_beacon) if (priv->cached_beacon)
p54_tx_cancel(dev, priv->cached_beacon); p54_tx_cancel(dev, priv->cached_beacon);
@ -1784,8 +1837,7 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed)
goto out; goto out;
} }
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
ret = p54_scan(dev, P54_SCAN_EXIT, 0, ret = p54_scan(dev, P54_SCAN_EXIT, 0);
conf->channel->center_freq);
if (ret) if (ret)
goto out; goto out;
} }
@ -1811,8 +1863,7 @@ static int p54_config_interface(struct ieee80211_hw *dev,
} }
if (conf->changed & IEEE80211_IFCC_BEACON) { if (conf->changed & IEEE80211_IFCC_BEACON) {
ret = p54_scan(dev, P54_SCAN_EXIT, 0, ret = p54_scan(dev, P54_SCAN_EXIT, 0);
dev->conf.channel->center_freq);
if (ret) if (ret)
goto out; goto out;
ret = p54_setup_mac(dev); ret = p54_setup_mac(dev);
@ -1885,18 +1936,33 @@ static int p54_init_xbow_synth(struct ieee80211_hw *dev)
xbow->magic2 = cpu_to_le16(0x2); xbow->magic2 = cpu_to_le16(0x2);
xbow->freq = cpu_to_le16(5390); xbow->freq = cpu_to_le16(5390);
memset(xbow->padding, 0, sizeof(xbow->padding)); memset(xbow->padding, 0, sizeof(xbow->padding));
priv->tx(dev, skb, 1); priv->tx(dev, skb);
return 0; return 0;
} }
static void p54_statistics_timer(unsigned long data) static void p54_work(struct work_struct *work)
{ {
struct ieee80211_hw *dev = (struct ieee80211_hw *) data; struct p54_common *priv = container_of(work, struct p54_common,
struct p54_common *priv = dev->priv; work.work);
struct ieee80211_hw *dev = priv->hw;
struct sk_buff *skb;
BUG_ON(!priv->cached_stats); if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
return ;
priv->tx(dev, priv->cached_stats, 0); /*
* TODO: walk through tx_queue and do the following tasks
* 1. initiate bursts.
* 2. cancel stuck frames / reset the device if necessary.
*/
skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(struct p54_hdr) +
sizeof(struct p54_statistics),
P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
if (!skb)
return ;
priv->tx(dev, skb);
} }
static int p54_get_stats(struct ieee80211_hw *dev, static int p54_get_stats(struct ieee80211_hw *dev,
@ -1904,17 +1970,7 @@ static int p54_get_stats(struct ieee80211_hw *dev,
{ {
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
del_timer(&priv->stats_timer);
p54_statistics_timer((unsigned long)dev);
if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) {
printk(KERN_ERR "%s: device does not respond!\n",
wiphy_name(dev->wiphy));
return -EBUSY;
}
memcpy(stats, &priv->stats, sizeof(*stats)); memcpy(stats, &priv->stats, sizeof(*stats));
return 0; return 0;
} }
@ -1946,8 +2002,7 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
priv->basic_rate_mask = info->basic_rates; priv->basic_rate_mask = info->basic_rates;
p54_setup_mac(dev); p54_setup_mac(dev);
if (priv->fw_var >= 0x500) if (priv->fw_var >= 0x500)
p54_scan(dev, P54_SCAN_EXIT, 0, p54_scan(dev, P54_SCAN_EXIT, 0);
dev->conf.channel->center_freq);
} }
if (changed & BSS_CHANGED_ASSOC) { if (changed & BSS_CHANGED_ASSOC) {
if (info->assoc) { if (info->assoc) {
@ -2039,7 +2094,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
} }
priv->tx(dev, skb, 1); priv->tx(dev, skb);
mutex_unlock(&priv->conf_mutex); mutex_unlock(&priv->conf_mutex);
return 0; return 0;
} }
@ -2072,6 +2127,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
return NULL; return NULL;
priv = dev->priv; priv = dev->priv;
priv->hw = dev;
priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->mode = NL80211_IFTYPE_UNSPECIFIED;
priv->basic_rate_mask = 0x15f; priv->basic_rate_mask = 0x15f;
skb_queue_head_init(&priv->tx_queue); skb_queue_head_init(&priv->tx_queue);
@ -2107,9 +2163,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
mutex_init(&priv->conf_mutex); mutex_init(&priv->conf_mutex);
init_completion(&priv->eeprom_comp); init_completion(&priv->eeprom_comp);
init_completion(&priv->stats_comp); INIT_DELAYED_WORK(&priv->work, p54_work);
setup_timer(&priv->stats_timer, p54_statistics_timer,
(unsigned long)dev);
return dev; return dev;
} }
@ -2118,8 +2172,6 @@ EXPORT_SYMBOL_GPL(p54_init_common);
void p54_free_common(struct ieee80211_hw *dev) void p54_free_common(struct ieee80211_hw *dev)
{ {
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
del_timer(&priv->stats_timer);
kfree_skb(priv->cached_stats);
kfree(priv->iq_autocal); kfree(priv->iq_autocal);
kfree(priv->output_limit); kfree(priv->output_limit);
kfree(priv->curve_data); kfree(priv->curve_data);

View File

@ -84,9 +84,6 @@ struct bootrec_desc {
#define BR_CODE_END_OF_BRA 0xFF0000FF #define BR_CODE_END_OF_BRA 0xFF0000FF
#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF #define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
#define P54_HDR_FLAG_CONTROL BIT(15)
#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0))
#define P54_HDR_FLAG_DATA_ALIGN BIT(14) #define P54_HDR_FLAG_DATA_ALIGN BIT(14)
#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0) #define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0)
#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1) #define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
@ -178,6 +175,11 @@ struct pda_pa_curve_data {
u8 data[0]; u8 data[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct pda_rssi_cal_entry {
__le16 mul;
__le16 add;
} __attribute__ ((packed));
/* /*
* this defines the PDR codes used to build PDAs as defined in document * this defines the PDR codes used to build PDAs as defined in document
* number 553155. The current implementation mirrors version 1.1 of the * number 553155. The current implementation mirrors version 1.1 of the
@ -355,6 +357,11 @@ struct p54_tx_data {
u8 align[0]; u8 align[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
/* unit is ms */
#define P54_TX_FRAME_LIFETIME 2000
#define P54_TX_TIMEOUT 4000
#define P54_STATISTICS_UPDATE 5000
#define P54_FILTER_TYPE_NONE 0 #define P54_FILTER_TYPE_NONE 0
#define P54_FILTER_TYPE_STATION BIT(0) #define P54_FILTER_TYPE_STATION BIT(0)
#define P54_FILTER_TYPE_IBSS BIT(1) #define P54_FILTER_TYPE_IBSS BIT(1)
@ -424,22 +431,18 @@ struct p54_scan {
u8 dup_16qam; u8 dup_16qam;
u8 dup_64qam; u8 dup_64qam;
union { union {
struct { struct pda_rssi_cal_entry v1_rssi;
__le16 rssical_mul;
__le16 rssical_add;
} v1 __attribute__ ((packed));
struct { struct {
__le32 basic_rate_mask; __le32 basic_rate_mask;
u8 rts_rates[8]; u8 rts_rates[8];
__le16 rssical_mul; struct pda_rssi_cal_entry rssi;
__le16 rssical_add;
} v2 __attribute__ ((packed)); } v2 __attribute__ ((packed));
} __attribute__ ((packed)); } __attribute__ ((packed));
} __attribute__ ((packed)); } __attribute__ ((packed));
#define P54_SCAN_V1_LEN (sizeof(struct p54_scan)-12) #define P54_SCAN_V1_LEN 0x70
#define P54_SCAN_V2_LEN (sizeof(struct p54_scan)) #define P54_SCAN_V2_LEN 0x7c
struct p54_led { struct p54_led {
__le16 mode; __le16 mode;

View File

@ -227,7 +227,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
while (i != idx) { while (i != idx) {
desc = &ring[i]; desc = &ring[i];
p54_free_skb(dev, tx_buf[i]); if (tx_buf[i])
if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i]))
p54_free_skb(dev, tx_buf[i]);
tx_buf[i] = NULL; tx_buf[i] = NULL;
pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
@ -298,8 +300,7 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id)
return reg ? IRQ_HANDLED : IRQ_NONE; return reg ? IRQ_HANDLED : IRQ_NONE;
} }
static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb, static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
int free_on_tx)
{ {
struct p54p_priv *priv = dev->priv; struct p54p_priv *priv = dev->priv;
struct p54p_ring_control *ring_control = priv->ring_control; struct p54p_ring_control *ring_control = priv->ring_control;
@ -314,6 +315,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
idx = le32_to_cpu(ring_control->host_idx[1]); idx = le32_to_cpu(ring_control->host_idx[1]);
i = idx % ARRAY_SIZE(ring_control->tx_data); i = idx % ARRAY_SIZE(ring_control->tx_data);
priv->tx_buf_data[i] = skb;
mapping = pci_map_single(priv->pdev, skb->data, skb->len, mapping = pci_map_single(priv->pdev, skb->data, skb->len,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
desc = &ring_control->tx_data[i]; desc = &ring_control->tx_data[i];
@ -324,10 +326,6 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
wmb(); wmb();
ring_control->host_idx[1] = cpu_to_le32(idx + 1); ring_control->host_idx[1] = cpu_to_le32(idx + 1);
if (free_on_tx)
priv->tx_buf_data[i] = skb;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));

View File

@ -138,22 +138,16 @@ static void p54u_rx_cb(struct urb *urb)
} }
} }
static void p54u_tx_reuse_skb_cb(struct urb *urb) static void p54u_tx_cb(struct urb *urb)
{
struct sk_buff *skb = urb->context;
struct p54u_priv *priv = (struct p54u_priv *)((struct ieee80211_hw *)
usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)))->priv;
skb_pull(skb, priv->common.tx_hdr_len);
}
static void p54u_tx_free_skb_cb(struct urb *urb)
{ {
struct sk_buff *skb = urb->context; struct sk_buff *skb = urb->context;
struct ieee80211_hw *dev = (struct ieee80211_hw *) struct ieee80211_hw *dev = (struct ieee80211_hw *)
usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
struct p54u_priv *priv = dev->priv;
p54_free_skb(dev, skb); skb_pull(skb, priv->common.tx_hdr_len);
if (FREE_AFTER_TX(skb))
p54_free_skb(dev, skb);
} }
static void p54u_tx_dummy_cb(struct urb *urb) { } static void p54u_tx_dummy_cb(struct urb *urb) { }
@ -213,8 +207,7 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
return ret; return ret;
} }
static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb)
int free_on_tx)
{ {
struct p54u_priv *priv = dev->priv; struct p54u_priv *priv = dev->priv;
struct urb *addr_urb, *data_urb; struct urb *addr_urb, *data_urb;
@ -236,9 +229,7 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb,
p54u_tx_dummy_cb, dev); p54u_tx_dummy_cb, dev);
usb_fill_bulk_urb(data_urb, priv->udev, usb_fill_bulk_urb(data_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
skb->data, skb->len, skb->data, skb->len, p54u_tx_cb, skb);
free_on_tx ? p54u_tx_free_skb_cb :
p54u_tx_reuse_skb_cb, skb);
usb_anchor_urb(addr_urb, &priv->submitted); usb_anchor_urb(addr_urb, &priv->submitted);
err = usb_submit_urb(addr_urb, GFP_ATOMIC); err = usb_submit_urb(addr_urb, GFP_ATOMIC);
@ -273,8 +264,7 @@ static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
return cpu_to_le32(chk); return cpu_to_le32(chk);
} }
static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
int free_on_tx)
{ {
struct p54u_priv *priv = dev->priv; struct p54u_priv *priv = dev->priv;
struct urb *data_urb; struct urb *data_urb;
@ -293,9 +283,7 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb,
usb_fill_bulk_urb(data_urb, priv->udev, usb_fill_bulk_urb(data_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
skb->data, skb->len, skb->data, skb->len, p54u_tx_cb, skb);
free_on_tx ? p54u_tx_free_skb_cb :
p54u_tx_reuse_skb_cb, skb);
usb_anchor_urb(data_urb, &priv->submitted); usb_anchor_urb(data_urb, &priv->submitted);
if (usb_submit_urb(data_urb, GFP_ATOMIC)) { if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
@ -306,14 +294,15 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb,
usb_free_urb(data_urb); usb_free_urb(data_urb);
} }
static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
int free_on_tx)
{ {
struct p54u_priv *priv = dev->priv; struct p54u_priv *priv = dev->priv;
struct urb *int_urb, *data_urb; struct urb *int_urb, *data_urb;
struct net2280_tx_hdr *hdr; struct net2280_tx_hdr *hdr;
struct net2280_reg_write *reg; struct net2280_reg_write *reg;
int err = 0; int err = 0;
__le32 addr = ((struct p54_hdr *) skb->data)->req_id;
__le16 len = cpu_to_le16(skb->len);
reg = kmalloc(sizeof(*reg), GFP_ATOMIC); reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
if (!reg) if (!reg)
@ -338,8 +327,8 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb,
hdr = (void *)skb_push(skb, sizeof(*hdr)); hdr = (void *)skb_push(skb, sizeof(*hdr));
memset(hdr, 0, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr));
hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id; hdr->len = len;
hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_hdr)); hdr->device_addr = addr;
usb_fill_bulk_urb(int_urb, priv->udev, usb_fill_bulk_urb(int_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
@ -354,9 +343,7 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb,
usb_fill_bulk_urb(data_urb, priv->udev, usb_fill_bulk_urb(data_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
skb->data, skb->len, skb->data, skb->len, p54u_tx_cb, skb);
free_on_tx ? p54u_tx_free_skb_cb :
p54u_tx_reuse_skb_cb, skb);
usb_anchor_urb(int_urb, &priv->submitted); usb_anchor_urb(int_urb, &priv->submitted);
err = usb_submit_urb(int_urb, GFP_ATOMIC); err = usb_submit_urb(int_urb, GFP_ATOMIC);

View File

@ -213,7 +213,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
urb = usb_alloc_urb(0, GFP_ATOMIC); urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) { if (!urb) {
kfree_skb(skb); kfree_skb(skb);
return 0; return -ENOMEM;
} }
flags = skb->len; flags = skb->len;
@ -281,7 +281,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
} }
usb_free_urb(urb); usb_free_urb(urb);
return 0; return rc;
} }
static void rtl8187_rx_cb(struct urb *urb) static void rtl8187_rx_cb(struct urb *urb)
@ -294,15 +294,16 @@ static void rtl8187_rx_cb(struct urb *urb)
int rate, signal; int rate, signal;
u32 flags; u32 flags;
u32 quality; u32 quality;
unsigned long f;
spin_lock(&priv->rx_queue.lock); spin_lock_irqsave(&priv->rx_queue.lock, f);
if (skb->next) if (skb->next)
__skb_unlink(skb, &priv->rx_queue); __skb_unlink(skb, &priv->rx_queue);
else { else {
spin_unlock(&priv->rx_queue.lock); spin_unlock_irqrestore(&priv->rx_queue.lock, f);
return; return;
} }
spin_unlock(&priv->rx_queue.lock); spin_unlock_irqrestore(&priv->rx_queue.lock, f);
skb_put(skb, urb->actual_length); skb_put(skb, urb->actual_length);
if (unlikely(urb->status)) { if (unlikely(urb->status)) {
@ -942,7 +943,6 @@ static int rtl8187_start(struct ieee80211_hw *dev)
static void rtl8187_stop(struct ieee80211_hw *dev) static void rtl8187_stop(struct ieee80211_hw *dev)
{ {
struct rtl8187_priv *priv = dev->priv; struct rtl8187_priv *priv = dev->priv;
struct rtl8187_rx_info *info;
struct sk_buff *skb; struct sk_buff *skb;
u32 reg; u32 reg;
@ -961,10 +961,6 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
while ((skb = skb_dequeue(&priv->rx_queue))) {
info = (struct rtl8187_rx_info *)skb->cb;
kfree_skb(skb);
}
while ((skb = skb_dequeue(&priv->b_tx_status.queue))) while ((skb = skb_dequeue(&priv->b_tx_status.queue)))
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);

View File

@ -201,13 +201,13 @@ enum nl80211_commands {
* @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
* @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
* @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
* @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
* if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included): * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
* NL80211_SEC_CHAN_NO_HT = HT not allowed (i.e., same as not including * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
* this attribute) * this attribute)
* NL80211_SEC_CHAN_DISABLED = HT20 only * NL80211_CHAN_HT20 = HT20 only
* NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
* NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
* *
* @NL80211_ATTR_IFINDEX: network interface index of the device to operate on * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
* @NL80211_ATTR_IFNAME: network interface name * @NL80211_ATTR_IFNAME: network interface name
@ -344,7 +344,7 @@ enum nl80211_attrs {
NL80211_ATTR_WIPHY_TXQ_PARAMS, NL80211_ATTR_WIPHY_TXQ_PARAMS,
NL80211_ATTR_WIPHY_FREQ, NL80211_ATTR_WIPHY_FREQ,
NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
@ -424,6 +424,32 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
}; };
/**
* enum nl80211_rate_info - bitrate information
*
* These attribute types are used with %NL80211_STA_INFO_TXRATE
* when getting information about the bitrate of a station.
*
* @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
* @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
* @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
* @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
* @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
* @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
__NL80211_RATE_INFO_INVALID,
NL80211_RATE_INFO_BITRATE,
NL80211_RATE_INFO_MCS,
NL80211_RATE_INFO_40_MHZ_WIDTH,
NL80211_RATE_INFO_SHORT_GI,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
};
/** /**
* enum nl80211_sta_info - station information * enum nl80211_sta_info - station information
* *
@ -436,6 +462,9 @@ enum nl80211_sta_flags {
* @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
* @__NL80211_STA_INFO_AFTER_LAST: internal * @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute * @NL80211_STA_INFO_MAX: highest possible station info attribute
* @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
* @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
* containing info as possible, see &enum nl80211_sta_info_txrate.
*/ */
enum nl80211_sta_info { enum nl80211_sta_info {
__NL80211_STA_INFO_INVALID, __NL80211_STA_INFO_INVALID,
@ -445,6 +474,8 @@ enum nl80211_sta_info {
NL80211_STA_INFO_LLID, NL80211_STA_INFO_LLID,
NL80211_STA_INFO_PLID, NL80211_STA_INFO_PLID,
NL80211_STA_INFO_PLINK_STATE, NL80211_STA_INFO_PLINK_STATE,
NL80211_STA_INFO_SIGNAL,
NL80211_STA_INFO_TX_BITRATE,
/* keep last */ /* keep last */
__NL80211_STA_INFO_AFTER_LAST, __NL80211_STA_INFO_AFTER_LAST,
@ -774,10 +805,10 @@ enum nl80211_txq_q {
NL80211_TXQ_Q_BK NL80211_TXQ_Q_BK
}; };
enum nl80211_sec_chan_offset { enum nl80211_channel_type {
NL80211_SEC_CHAN_NO_HT /* No HT */, NL80211_CHAN_NO_HT,
NL80211_SEC_CHAN_DISABLED /* HT20 only */, NL80211_CHAN_HT20,
NL80211_SEC_CHAN_BELOW /* HT40- */, NL80211_CHAN_HT40MINUS,
NL80211_SEC_CHAN_ABOVE /* HT40+ */ NL80211_CHAN_HT40PLUS
}; };
#endif /* __LINUX_NL80211_H */ #endif /* __LINUX_NL80211_H */

View File

@ -169,6 +169,9 @@ struct station_parameters {
* @STATION_INFO_LLID: @llid filled * @STATION_INFO_LLID: @llid filled
* @STATION_INFO_PLID: @plid filled * @STATION_INFO_PLID: @plid filled
* @STATION_INFO_PLINK_STATE: @plink_state filled * @STATION_INFO_PLINK_STATE: @plink_state filled
* @STATION_INFO_SIGNAL: @signal filled
* @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled
* (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
*/ */
enum station_info_flags { enum station_info_flags {
STATION_INFO_INACTIVE_TIME = 1<<0, STATION_INFO_INACTIVE_TIME = 1<<0,
@ -177,6 +180,39 @@ enum station_info_flags {
STATION_INFO_LLID = 1<<3, STATION_INFO_LLID = 1<<3,
STATION_INFO_PLID = 1<<4, STATION_INFO_PLID = 1<<4,
STATION_INFO_PLINK_STATE = 1<<5, STATION_INFO_PLINK_STATE = 1<<5,
STATION_INFO_SIGNAL = 1<<6,
STATION_INFO_TX_BITRATE = 1<<7,
};
/**
* enum station_info_rate_flags - bitrate info flags
*
* Used by the driver to indicate the specific rate transmission
* type for 802.11n transmissions.
*
* @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
* @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
* @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
*/
enum rate_info_flags {
RATE_INFO_FLAGS_MCS = 1<<0,
RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1,
RATE_INFO_FLAGS_SHORT_GI = 1<<2,
};
/**
* struct rate_info - bitrate information
*
* Information about a receiving or transmitting bitrate
*
* @flags: bitflag of flags from &enum rate_info_flags
* @mcs: mcs index if struct describes a 802.11n bitrate
* @legacy: bitrate in 100kbit/s for 802.11abg
*/
struct rate_info {
u8 flags;
u8 mcs;
u16 legacy;
}; };
/** /**
@ -191,6 +227,8 @@ enum station_info_flags {
* @llid: mesh local link id * @llid: mesh local link id
* @plid: mesh peer link id * @plid: mesh peer link id
* @plink_state: mesh peer link state * @plink_state: mesh peer link state
* @signal: signal strength of last received packet in dBm
* @txrate: current unicast bitrate to this station
*/ */
struct station_info { struct station_info {
u32 filled; u32 filled;
@ -200,6 +238,8 @@ struct station_info {
u16 llid; u16 llid;
u16 plid; u16 plid;
u8 plink_state; u8 plink_state;
s8 signal;
struct rate_info txrate;
}; };
/** /**
@ -523,7 +563,7 @@ struct cfg80211_ops {
int (*set_channel)(struct wiphy *wiphy, int (*set_channel)(struct wiphy *wiphy,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_sec_chan_offset); enum nl80211_channel_type channel_type);
}; };
/* temporary wext handlers */ /* temporary wext handlers */

View File

@ -165,14 +165,9 @@ enum ieee80211_bss_change {
/** /**
* struct ieee80211_bss_ht_conf - BSS's changing HT configuration * struct ieee80211_bss_ht_conf - BSS's changing HT configuration
* @secondary_channel_offset: secondary channel offset, uses
* %IEEE80211_HT_PARAM_CHA_SEC_ values
* @width_40_ok: indicates that 40 MHz bandwidth may be used for TX
* @operation_mode: HT operation mode (like in &struct ieee80211_ht_info) * @operation_mode: HT operation mode (like in &struct ieee80211_ht_info)
*/ */
struct ieee80211_bss_ht_conf { struct ieee80211_bss_ht_conf {
u8 secondary_channel_offset;
bool width_40_ok;
u16 operation_mode; u16 operation_mode;
}; };
@ -441,6 +436,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
* is valid. This is useful in monitor mode and necessary for beacon frames * is valid. This is useful in monitor mode and necessary for beacon frames
* to enable IBSS merging. * to enable IBSS merging.
* @RX_FLAG_SHORTPRE: Short preamble was used for this frame * @RX_FLAG_SHORTPRE: Short preamble was used for this frame
* @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
* @RX_FLAG_40MHZ: HT40 (40 MHz) was used
* @RX_FLAG_SHORT_GI: Short guard interval was used
*/ */
enum mac80211_rx_flags { enum mac80211_rx_flags {
RX_FLAG_MMIC_ERROR = 1<<0, RX_FLAG_MMIC_ERROR = 1<<0,
@ -451,7 +449,10 @@ enum mac80211_rx_flags {
RX_FLAG_FAILED_FCS_CRC = 1<<5, RX_FLAG_FAILED_FCS_CRC = 1<<5,
RX_FLAG_FAILED_PLCP_CRC = 1<<6, RX_FLAG_FAILED_PLCP_CRC = 1<<6,
RX_FLAG_TSFT = 1<<7, RX_FLAG_TSFT = 1<<7,
RX_FLAG_SHORTPRE = 1<<8 RX_FLAG_SHORTPRE = 1<<8,
RX_FLAG_HT = 1<<9,
RX_FLAG_40MHZ = 1<<10,
RX_FLAG_SHORT_GI = 1<<11,
}; };
/** /**
@ -471,7 +472,8 @@ enum mac80211_rx_flags {
* @noise: noise when receiving this frame, in dBm. * @noise: noise when receiving this frame, in dBm.
* @qual: overall signal quality indication, in percent (0-100). * @qual: overall signal quality indication, in percent (0-100).
* @antenna: antenna used * @antenna: antenna used
* @rate_idx: index of data rate into band's supported rates * @rate_idx: index of data rate into band's supported rates or MCS index if
* HT rates are use (RX_FLAG_HT)
* @flag: %RX_FLAG_* * @flag: %RX_FLAG_*
*/ */
struct ieee80211_rx_status { struct ieee80211_rx_status {
@ -508,9 +510,7 @@ static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void)
struct ieee80211_ht_conf { struct ieee80211_ht_conf {
bool enabled; bool enabled;
int sec_chan_offset; /* 0 = HT40 disabled; -1 = HT40 enabled, secondary enum nl80211_channel_type channel_type;
* channel below primary; 1 = HT40 enabled,
* secondary channel above primary */
}; };
/** /**
@ -854,6 +854,11 @@ enum ieee80211_tkip_key_type {
* *
* @IEEE80211_HW_AMPDU_AGGREGATION: * @IEEE80211_HW_AMPDU_AGGREGATION:
* Hardware supports 11n A-MPDU aggregation. * Hardware supports 11n A-MPDU aggregation.
*
* @IEEE80211_HW_NO_STACK_DYNAMIC_PS:
* Hardware which has dynamic power save support, meaning
* that power save is enabled in idle periods, and don't need support
* from stack.
*/ */
enum ieee80211_hw_flags { enum ieee80211_hw_flags {
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
@ -866,6 +871,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_NOISE_DBM = 1<<8, IEEE80211_HW_NOISE_DBM = 1<<8,
IEEE80211_HW_SPECTRUM_MGMT = 1<<9, IEEE80211_HW_SPECTRUM_MGMT = 1<<9,
IEEE80211_HW_AMPDU_AGGREGATION = 1<<10, IEEE80211_HW_AMPDU_AGGREGATION = 1<<10,
IEEE80211_HW_NO_STACK_DYNAMIC_PS = 1<<11,
}; };
/** /**

View File

@ -310,12 +310,35 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->filled = STATION_INFO_INACTIVE_TIME | sinfo->filled = STATION_INFO_INACTIVE_TIME |
STATION_INFO_RX_BYTES | STATION_INFO_RX_BYTES |
STATION_INFO_TX_BYTES; STATION_INFO_TX_BYTES |
STATION_INFO_TX_BITRATE;
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
sinfo->rx_bytes = sta->rx_bytes; sinfo->rx_bytes = sta->rx_bytes;
sinfo->tx_bytes = sta->tx_bytes; sinfo->tx_bytes = sta->tx_bytes;
if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
sinfo->filled |= STATION_INFO_SIGNAL;
sinfo->signal = (s8)sta->last_signal;
}
sinfo->txrate.flags = 0;
if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI)
sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) {
struct ieee80211_supported_band *sband;
sband = sta->local->hw.wiphy->bands[
sta->local->hw.conf.channel->band];
sinfo->txrate.legacy =
sband->bitrates[sta->last_tx_rate.idx].bitrate;
} else
sinfo->txrate.mcs = sta->last_tx_rate.idx;
if (ieee80211_vif_is_mesh(&sdata->vif)) { if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH #ifdef CONFIG_MAC80211_MESH
sinfo->filled |= STATION_INFO_LLID | sinfo->filled |= STATION_INFO_LLID |
@ -663,6 +686,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
struct sta_info *sta; struct sta_info *sta;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int err; int err;
int layer2_update;
/* Prevent a race with changing the rate control algorithm */ /* Prevent a race with changing the rate control algorithm */
if (!netif_running(dev)) if (!netif_running(dev))
@ -693,17 +717,25 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
rate_control_rate_init(sta); rate_control_rate_init(sta);
layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
sdata->vif.type == NL80211_IFTYPE_AP;
rcu_read_lock(); rcu_read_lock();
err = sta_info_insert(sta); err = sta_info_insert(sta);
if (err) { if (err) {
/* STA has been freed */ /* STA has been freed */
if (err == -EEXIST && layer2_update) {
/* Need to update layer 2 devices on reassociation */
sta = sta_info_get(local, mac);
if (sta)
ieee80211_send_layer2_update(sta);
}
rcu_read_unlock(); rcu_read_unlock();
return err; return err;
} }
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || if (layer2_update)
sdata->vif.type == NL80211_IFTYPE_AP)
ieee80211_send_layer2_update(sta); ieee80211_send_layer2_update(sta);
rcu_read_unlock(); rcu_read_unlock();
@ -1099,12 +1131,12 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
static int ieee80211_set_channel(struct wiphy *wiphy, static int ieee80211_set_channel(struct wiphy *wiphy,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_sec_chan_offset sec_chan_offset) enum nl80211_channel_type channel_type)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_local *local = wiphy_priv(wiphy);
local->oper_channel = chan; local->oper_channel = chan;
local->oper_sec_chan_offset = sec_chan_offset; local->oper_channel_type = channel_type;
return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
} }

View File

@ -98,6 +98,7 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_ht_conf ht; struct ieee80211_bss_ht_conf ht;
u32 changed = 0; u32 changed = 0;
bool enable_ht = true, ht_changed; bool enable_ht = true, ht_changed;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
@ -112,24 +113,36 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
ieee80211_channel_to_frequency(hti->control_chan)) ieee80211_channel_to_frequency(hti->control_chan))
enable_ht = false; enable_ht = false;
/* if (enable_ht) {
* XXX: This is totally incorrect when there are multiple virtual channel_type = NL80211_CHAN_HT20;
* interfaces, needs to be fixed later.
*/ if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
ht_changed = local->hw.conf.ht.enabled != enable_ht; (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
(hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
channel_type = NL80211_CHAN_HT40PLUS;
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
channel_type = NL80211_CHAN_HT40MINUS;
break;
}
}
}
ht_changed = local->hw.conf.ht.enabled != enable_ht ||
channel_type != local->hw.conf.ht.channel_type;
local->oper_channel_type = channel_type;
local->hw.conf.ht.enabled = enable_ht; local->hw.conf.ht.enabled = enable_ht;
if (ht_changed) if (ht_changed)
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
/* disable HT */ /* disable HT */
if (!enable_ht) if (!enable_ht)
return 0; return 0;
ht.secondary_channel_offset =
hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
ht.width_40_ok =
!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
(sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
(hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY);
ht.operation_mode = le16_to_cpu(hti->operation_mode); ht.operation_mode = le16_to_cpu(hti->operation_mode);
/* if bss configuration changed store the new one */ /* if bss configuration changed store the new one */

View File

@ -538,6 +538,11 @@ enum {
IEEE80211_ADDBA_MSG = 4, IEEE80211_ADDBA_MSG = 4,
}; };
enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_DRIVER,
IEEE80211_QUEUE_STOP_REASON_PS,
};
/* maximum number of hardware queues we support. */ /* maximum number of hardware queues we support. */
#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
@ -554,7 +559,8 @@ struct ieee80211_local {
const struct ieee80211_ops *ops; const struct ieee80211_ops *ops;
unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)];
unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
spinlock_t queue_stop_reason_lock;
struct net_device *mdev; /* wmaster# - "master" 802.11 device */ struct net_device *mdev; /* wmaster# - "master" 802.11 device */
int open_count; int open_count;
int monitors, cooked_mntrs; int monitors, cooked_mntrs;
@ -625,7 +631,7 @@ struct ieee80211_local {
struct delayed_work scan_work; struct delayed_work scan_work;
struct ieee80211_sub_if_data *scan_sdata; struct ieee80211_sub_if_data *scan_sdata;
struct ieee80211_channel *oper_channel, *scan_channel; struct ieee80211_channel *oper_channel, *scan_channel;
enum nl80211_sec_chan_offset oper_sec_chan_offset; enum nl80211_channel_type oper_channel_type;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len; size_t scan_ssid_len;
struct list_head bss_list; struct list_head bss_list;
@ -689,6 +695,12 @@ struct ieee80211_local {
int wifi_wme_noack_test; int wifi_wme_noack_test;
unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
bool powersave;
int dynamic_ps_timeout;
struct work_struct dynamic_ps_enable_work;
struct work_struct dynamic_ps_disable_work;
struct timer_list dynamic_ps_timer;
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
struct local_debugfsdentries { struct local_debugfsdentries {
struct dentry *rcdir; struct dentry *rcdir;
@ -971,6 +983,15 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq);
u64 ieee80211_mandatory_rates(struct ieee80211_local *local, u64 ieee80211_mandatory_rates(struct ieee80211_local *local,
enum ieee80211_band band); enum ieee80211_band band);
void ieee80211_dynamic_ps_enable_work(struct work_struct *work);
void ieee80211_dynamic_ps_disable_work(struct work_struct *work);
void ieee80211_dynamic_ps_timer(unsigned long data);
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason);
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason);
#ifdef CONFIG_MAC80211_NOINLINE #ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline #define debug_noinline noinline
#else #else

View File

@ -195,37 +195,30 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
int ret = 0; int ret = 0;
int power; int power;
enum nl80211_sec_chan_offset sec_chan_offset; enum nl80211_channel_type channel_type;
might_sleep(); might_sleep();
if (local->sw_scanning) { if (local->sw_scanning) {
chan = local->scan_channel; chan = local->scan_channel;
sec_chan_offset = NL80211_SEC_CHAN_NO_HT; channel_type = NL80211_CHAN_NO_HT;
} else { } else {
chan = local->oper_channel; chan = local->oper_channel;
sec_chan_offset = local->oper_sec_chan_offset; channel_type = local->oper_channel_type;
} }
if (chan != local->hw.conf.channel || if (chan != local->hw.conf.channel ||
sec_chan_offset != local->hw.conf.ht.sec_chan_offset) { channel_type != local->hw.conf.ht.channel_type) {
local->hw.conf.channel = chan; local->hw.conf.channel = chan;
switch (sec_chan_offset) { local->hw.conf.ht.channel_type = channel_type;
case NL80211_SEC_CHAN_NO_HT: switch (channel_type) {
case NL80211_CHAN_NO_HT:
local->hw.conf.ht.enabled = false; local->hw.conf.ht.enabled = false;
local->hw.conf.ht.sec_chan_offset = 0;
break; break;
case NL80211_SEC_CHAN_DISABLED: case NL80211_CHAN_HT20:
case NL80211_CHAN_HT40MINUS:
case NL80211_CHAN_HT40PLUS:
local->hw.conf.ht.enabled = true; local->hw.conf.ht.enabled = true;
local->hw.conf.ht.sec_chan_offset = 0;
break;
case NL80211_SEC_CHAN_BELOW:
local->hw.conf.ht.enabled = true;
local->hw.conf.ht.sec_chan_offset = -1;
break;
case NL80211_SEC_CHAN_ABOVE:
local->hw.conf.ht.enabled = true;
local->hw.conf.ht.sec_chan_offset = 1;
break; break;
} }
changed |= IEEE80211_CONF_CHANGE_CHANNEL; changed |= IEEE80211_CONF_CHANGE_CHANNEL;
@ -348,7 +341,8 @@ static void ieee80211_tasklet_handler(unsigned long data)
dev_kfree_skb(skb); dev_kfree_skb(skb);
break ; break ;
default: default:
WARN_ON(1); WARN(1, "mac80211: Packet is of unknown type %d\n",
skb->pkt_type);
dev_kfree_skb(skb); dev_kfree_skb(skb);
break; break;
} }
@ -731,8 +725,17 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
spin_lock_init(&local->key_lock); spin_lock_init(&local->key_lock);
spin_lock_init(&local->queue_stop_reason_lock);
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
INIT_WORK(&local->dynamic_ps_enable_work,
ieee80211_dynamic_ps_enable_work);
INIT_WORK(&local->dynamic_ps_disable_work,
ieee80211_dynamic_ps_disable_work);
setup_timer(&local->dynamic_ps_timer,
ieee80211_dynamic_ps_timer, (unsigned long) local);
sta_info_init(local); sta_info_init(local);
tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,

View File

@ -309,7 +309,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ASSOC_REQ); IEEE80211_STYPE_ASSOC_REQ);
mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
mgmt->u.reassoc_req.listen_interval = mgmt->u.assoc_req.listen_interval =
cpu_to_le16(local->hw.conf.listen_interval); cpu_to_le16(local->hw.conf.listen_interval);
} }
@ -744,6 +744,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
bss_info_changed |= BSS_CHANGED_BASIC_RATES; bss_info_changed |= BSS_CHANGED_BASIC_RATES;
ieee80211_bss_info_change_notify(sdata, bss_info_changed); ieee80211_bss_info_change_notify(sdata, bss_info_changed);
if (local->powersave) {
if (local->dynamic_ps_timeout > 0)
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(local->dynamic_ps_timeout));
else {
conf->flags |= IEEE80211_CONF_PS;
ieee80211_hw_config(local,
IEEE80211_CONF_CHANGE_PS);
}
}
netif_tx_start_all_queues(sdata->dev); netif_tx_start_all_queues(sdata->dev);
netif_carrier_on(sdata->dev); netif_carrier_on(sdata->dev);
@ -812,7 +823,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sta_info *sta; struct sta_info *sta;
u32 changed = 0; u32 changed = 0, config_changed = 0;
rcu_read_lock(); rcu_read_lock();
@ -858,8 +869,18 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock(); rcu_read_unlock();
local->hw.conf.ht.enabled = false; local->hw.conf.ht.enabled = false;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); local->oper_channel_type = NL80211_CHAN_NO_HT;
config_changed |= IEEE80211_CONF_CHANGE_HT;
del_timer_sync(&local->dynamic_ps_timer);
cancel_work_sync(&local->dynamic_ps_enable_work);
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
config_changed |= IEEE80211_CONF_CHANGE_PS;
}
ieee80211_hw_config(local, config_changed);
ieee80211_bss_info_change_notify(sdata, changed); ieee80211_bss_info_change_notify(sdata, changed);
rcu_read_lock(); rcu_read_lock();
@ -1612,8 +1633,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
* e.g: at 1 MBit that means mactime is 192 usec earlier * e.g: at 1 MBit that means mactime is 192 usec earlier
* (=24 bytes * 8 usecs/byte) than the beacon timestamp. * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
*/ */
int rate = local->hw.wiphy->bands[band]-> int rate;
if (rx_status->flag & RX_FLAG_HT) {
rate = 65; /* TODO: HT rates */
} else {
rate = local->hw.wiphy->bands[band]->
bitrates[rx_status->rate_idx].bitrate; bitrates[rx_status->rate_idx].bitrate;
}
rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
} else if (local && local->ops && local->ops->get_tsf) } else if (local && local->ops && local->ops->get_tsf)
/* second best option: get current TSF */ /* second best option: get current TSF */
@ -2576,3 +2602,39 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
ieee80211_restart_sta_timer(sdata); ieee80211_restart_sta_timer(sdata);
rcu_read_unlock(); rcu_read_unlock();
} }
void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
{
struct ieee80211_local *local =
container_of(work, struct ieee80211_local,
dynamic_ps_disable_work);
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}
ieee80211_wake_queues_by_reason(&local->hw,
IEEE80211_QUEUE_STOP_REASON_PS);
}
void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
{
struct ieee80211_local *local =
container_of(work, struct ieee80211_local,
dynamic_ps_enable_work);
if (local->hw.conf.flags & IEEE80211_CONF_PS)
return;
local->hw.conf.flags |= IEEE80211_CONF_PS;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}
void ieee80211_dynamic_ps_timer(unsigned long data)
{
struct ieee80211_local *local = (void *) data;
queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
}

View File

@ -123,7 +123,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
/* radiotap header, set always present flags */ /* radiotap header, set always present flags */
rthdr->it_present = rthdr->it_present =
cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
(1 << IEEE80211_RADIOTAP_RATE) |
(1 << IEEE80211_RADIOTAP_CHANNEL) | (1 << IEEE80211_RADIOTAP_CHANNEL) |
(1 << IEEE80211_RADIOTAP_ANTENNA) | (1 << IEEE80211_RADIOTAP_ANTENNA) |
(1 << IEEE80211_RADIOTAP_RX_FLAGS)); (1 << IEEE80211_RADIOTAP_RX_FLAGS));
@ -149,7 +148,19 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
pos++; pos++;
/* IEEE80211_RADIOTAP_RATE */ /* IEEE80211_RADIOTAP_RATE */
*pos = rate->bitrate / 5; if (status->flag & RX_FLAG_HT) {
/*
* TODO: add following information into radiotap header once
* suitable fields are defined for it:
* - MCS index (status->rate_idx)
* - HT40 (status->flag & RX_FLAG_40MHZ)
* - short-GI (status->flag & RX_FLAG_SHORT_GI)
*/
*pos = 0;
} else {
rthdr->it_present |= (1 << IEEE80211_RADIOTAP_RATE);
*pos = rate->bitrate / 5;
}
pos++; pos++;
/* IEEE80211_RADIOTAP_CHANNEL */ /* IEEE80211_RADIOTAP_CHANNEL */
@ -1849,9 +1860,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
if (!(sdata->dev->flags & IFF_PROMISC)) if (!(sdata->dev->flags & IFF_PROMISC))
return 0; return 0;
rx->flags &= ~IEEE80211_RX_RA_MATCH; rx->flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!rx->sta) } else if (!rx->sta) {
int rate_idx;
if (rx->status->flag & RX_FLAG_HT)
rate_idx = 0; /* TODO: HT rates */
else
rate_idx = rx->status->rate_idx;
rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2, rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2,
BIT(rx->status->rate_idx)); BIT(rate_idx));
}
break; break;
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MESH_POINT:
if (!multicast && if (!multicast &&
@ -2057,7 +2074,13 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
tid_agg_rx->reorder_buf[index]->cb, tid_agg_rx->reorder_buf[index]->cb,
sizeof(status)); sizeof(status));
sband = local->hw.wiphy->bands[status.band]; sband = local->hw.wiphy->bands[status.band];
rate = &sband->bitrates[status.rate_idx]; if (status.flag & RX_FLAG_HT) {
/* TODO: HT rates */
rate = sband->bitrates;
} else {
rate = &sband->bitrates
[status.rate_idx];
}
__ieee80211_rx_handle_packet(hw, __ieee80211_rx_handle_packet(hw,
tid_agg_rx->reorder_buf[index], tid_agg_rx->reorder_buf[index],
&status, rate); &status, rate);
@ -2101,7 +2124,10 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
sizeof(status)); sizeof(status));
sband = local->hw.wiphy->bands[status.band]; sband = local->hw.wiphy->bands[status.band];
rate = &sband->bitrates[status.rate_idx]; if (status.flag & RX_FLAG_HT)
rate = sband->bitrates; /* TODO: HT rates */
else
rate = &sband->bitrates[status.rate_idx];
__ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
&status, rate); &status, rate);
tid_agg_rx->stored_mpdu_num--; tid_agg_rx->stored_mpdu_num--;
@ -2189,15 +2215,26 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
} }
sband = local->hw.wiphy->bands[status->band]; sband = local->hw.wiphy->bands[status->band];
if (!sband) {
if (!sband ||
status->rate_idx < 0 ||
status->rate_idx >= sband->n_bitrates) {
WARN_ON(1); WARN_ON(1);
return; return;
} }
rate = &sband->bitrates[status->rate_idx]; if (status->flag & RX_FLAG_HT) {
/* rate_idx is MCS index */
if (WARN_ON(status->rate_idx < 0 ||
status->rate_idx >= 76))
return;
/* HT rates are not in the table - use the highest legacy rate
* for now since other parts of mac80211 may not yet be fully
* MCS aware. */
rate = &sband->bitrates[sband->n_bitrates - 1];
} else {
if (WARN_ON(status->rate_idx < 0 ||
status->rate_idx >= sband->n_bitrates))
return;
rate = &sband->bitrates[status->rate_idx];
}
/* /*
* key references and virtual interfaces are protected using RCU * key references and virtual interfaces are protected using RCU

View File

@ -1473,6 +1473,19 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
goto fail; goto fail;
} }
if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
local->dynamic_ps_timeout > 0) {
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
ieee80211_stop_queues_by_reason(&local->hw,
IEEE80211_QUEUE_STOP_REASON_PS);
queue_work(local->hw.workqueue,
&local->dynamic_ps_disable_work);
}
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(local->dynamic_ps_timeout));
}
nh_pos = skb_network_header(skb) - skb->data; nh_pos = skb_network_header(skb) - skb->data;
h_pos = skb_transport_header(skb) - skb->data; h_pos = skb_transport_header(skb) - skb->data;

View File

@ -330,10 +330,20 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
} }
EXPORT_SYMBOL(ieee80211_ctstoself_duration); EXPORT_SYMBOL(ieee80211_ctstoself_duration);
void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason)
{ {
struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_local *local = hw_to_local(hw);
/* we don't need to track ampdu queues */
if (queue < ieee80211_num_regular_queues(hw)) {
__clear_bit(reason, &local->queue_stop_reasons[queue]);
if (local->queue_stop_reasons[queue] != 0)
/* someone still has this queue stopped */
return;
}
if (test_bit(queue, local->queues_pending)) { if (test_bit(queue, local->queues_pending)) {
set_bit(queue, local->queues_pending_run); set_bit(queue, local->queues_pending_run);
tasklet_schedule(&local->tx_pending_tasklet); tasklet_schedule(&local->tx_pending_tasklet);
@ -341,22 +351,74 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
netif_wake_subqueue(local->mdev, queue); netif_wake_subqueue(local->mdev, queue);
} }
} }
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason)
{
struct ieee80211_local *local = hw_to_local(hw);
unsigned long flags;
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
__ieee80211_wake_queue(hw, queue, reason);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
{
ieee80211_wake_queue_by_reason(hw, queue,
IEEE80211_QUEUE_STOP_REASON_DRIVER);
}
EXPORT_SYMBOL(ieee80211_wake_queue); EXPORT_SYMBOL(ieee80211_wake_queue);
void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason)
{ {
struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_local *local = hw_to_local(hw);
/* we don't need to track ampdu queues */
if (queue < ieee80211_num_regular_queues(hw))
__set_bit(reason, &local->queue_stop_reasons[queue]);
netif_stop_subqueue(local->mdev, queue); netif_stop_subqueue(local->mdev, queue);
} }
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason)
{
struct ieee80211_local *local = hw_to_local(hw);
unsigned long flags;
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
__ieee80211_stop_queue(hw, queue, reason);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
{
ieee80211_stop_queue_by_reason(hw, queue,
IEEE80211_QUEUE_STOP_REASON_DRIVER);
}
EXPORT_SYMBOL(ieee80211_stop_queue); EXPORT_SYMBOL(ieee80211_stop_queue);
void ieee80211_stop_queues(struct ieee80211_hw *hw) void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason)
{ {
struct ieee80211_local *local = hw_to_local(hw);
unsigned long flags;
int i; int i;
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
for (i = 0; i < ieee80211_num_queues(hw); i++) for (i = 0; i < ieee80211_num_queues(hw); i++)
ieee80211_stop_queue(hw, i); __ieee80211_stop_queue(hw, i, reason);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
void ieee80211_stop_queues(struct ieee80211_hw *hw)
{
ieee80211_stop_queues_by_reason(hw,
IEEE80211_QUEUE_STOP_REASON_DRIVER);
} }
EXPORT_SYMBOL(ieee80211_stop_queues); EXPORT_SYMBOL(ieee80211_stop_queues);
@ -367,12 +429,24 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
} }
EXPORT_SYMBOL(ieee80211_queue_stopped); EXPORT_SYMBOL(ieee80211_queue_stopped);
void ieee80211_wake_queues(struct ieee80211_hw *hw) void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason)
{ {
struct ieee80211_local *local = hw_to_local(hw);
unsigned long flags;
int i; int i;
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
for (i = 0; i < hw->queues + hw->ampdu_queues; i++) for (i = 0; i < hw->queues + hw->ampdu_queues; i++)
ieee80211_wake_queue(hw, i); __ieee80211_wake_queue(hw, i, reason);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}
void ieee80211_wake_queues(struct ieee80211_hw *hw)
{
ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER);
} }
EXPORT_SYMBOL(ieee80211_wake_queues); EXPORT_SYMBOL(ieee80211_wake_queues);
@ -641,7 +715,7 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz)
chan->flags & IEEE80211_CHAN_NO_IBSS) chan->flags & IEEE80211_CHAN_NO_IBSS)
return ret; return ret;
local->oper_channel = chan; local->oper_channel = chan;
local->oper_sec_chan_offset = NL80211_SEC_CHAN_NO_HT; local->oper_channel_type = NL80211_CHAN_NO_HT;
if (local->sw_scanning || local->hw_scanning) if (local->sw_scanning || local->hw_scanning)
ret = 0; ret = 0;

View File

@ -830,25 +830,56 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
struct iw_param *wrq, struct iw_param *wrq,
char *extra) char *extra)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_conf *conf = &local->hw.conf; struct ieee80211_conf *conf = &local->hw.conf;
int ret = 0, timeout = 0;
bool ps;
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return -EINVAL;
if (wrq->disabled) { if (wrq->disabled) {
conf->flags &= ~IEEE80211_CONF_PS; ps = false;
return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); timeout = 0;
goto set;
} }
switch (wrq->flags & IW_POWER_MODE) { switch (wrq->flags & IW_POWER_MODE) {
case IW_POWER_ON: /* If not specified */ case IW_POWER_ON: /* If not specified */
case IW_POWER_MODE: /* If set all mask */ case IW_POWER_MODE: /* If set all mask */
case IW_POWER_ALL_R: /* If explicitely state all */ case IW_POWER_ALL_R: /* If explicitely state all */
conf->flags |= IEEE80211_CONF_PS; ps = true;
break;
default: /* Otherwise we ignore */
break; break;
default: /* Otherwise we don't support it */
return -EINVAL;
} }
return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); if (wrq->flags & IW_POWER_TIMEOUT)
timeout = wrq->value / 1000;
set:
if (ps == local->powersave && timeout == local->dynamic_ps_timeout)
return ret;
local->powersave = ps;
local->dynamic_ps_timeout = timeout;
if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) &&
local->dynamic_ps_timeout > 0)
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(local->dynamic_ps_timeout));
else {
if (local->powersave)
conf->flags |= IEEE80211_CONF_PS;
else
conf->flags &= ~IEEE80211_CONF_PS;
}
ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}
return ret;
} }
static int ieee80211_ioctl_giwpower(struct net_device *dev, static int ieee80211_ioctl_giwpower(struct net_device *dev,
@ -857,9 +888,8 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev,
char *extra) char *extra)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_conf *conf = &local->hw.conf;
wrqu->power.disabled = !(conf->flags & IEEE80211_CONF_PS); wrqu->power.disabled = !local->powersave;
return 0; return 0;
} }

View File

@ -60,7 +60,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
.len = BUS_ID_SIZE-1 }, .len = BUS_ID_SIZE-1 },
[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
[NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
@ -362,8 +362,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
} }
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
enum nl80211_sec_chan_offset sec_chan_offset = enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
NL80211_SEC_CHAN_NO_HT;
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_ht_cap *ht_cap;
u32 freq, sec_freq; u32 freq, sec_freq;
@ -375,13 +374,13 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
result = -EINVAL; result = -EINVAL;
if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) { if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
sec_chan_offset = nla_get_u32(info->attrs[ channel_type = nla_get_u32(info->attrs[
NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]); NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT && if (channel_type != NL80211_CHAN_NO_HT &&
sec_chan_offset != NL80211_SEC_CHAN_DISABLED && channel_type != NL80211_CHAN_HT20 &&
sec_chan_offset != NL80211_SEC_CHAN_BELOW && channel_type != NL80211_CHAN_HT40PLUS &&
sec_chan_offset != NL80211_SEC_CHAN_ABOVE) channel_type != NL80211_CHAN_HT40MINUS)
goto bad_res; goto bad_res;
} }
@ -392,9 +391,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
goto bad_res; goto bad_res;
if (sec_chan_offset == NL80211_SEC_CHAN_BELOW) if (channel_type == NL80211_CHAN_HT40MINUS)
sec_freq = freq - 20; sec_freq = freq - 20;
else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE) else if (channel_type == NL80211_CHAN_HT40PLUS)
sec_freq = freq + 20; sec_freq = freq + 20;
else else
sec_freq = 0; sec_freq = 0;
@ -402,7 +401,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
/* no HT capabilities */ /* no HT capabilities */
if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT && if (channel_type != NL80211_CHAN_NO_HT &&
!ht_cap->ht_supported) !ht_cap->ht_supported)
goto bad_res; goto bad_res;
@ -422,7 +421,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
} }
result = rdev->ops->set_channel(&rdev->wiphy, chan, result = rdev->ops->set_channel(&rdev->wiphy, chan,
sec_chan_offset); channel_type);
if (result) if (result)
goto bad_res; goto bad_res;
} }
@ -1091,12 +1090,46 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags)
return 0; return 0;
} }
static u16 nl80211_calculate_bitrate(struct rate_info *rate)
{
int modulation, streams, bitrate;
if (!(rate->flags & RATE_INFO_FLAGS_MCS))
return rate->legacy;
/* the formula below does only work for MCS values smaller than 32 */
if (rate->mcs >= 32)
return 0;
modulation = rate->mcs & 7;
streams = (rate->mcs >> 3) + 1;
bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ?
13500000 : 6500000;
if (modulation < 4)
bitrate *= (modulation + 1);
else if (modulation == 4)
bitrate *= (modulation + 2);
else
bitrate *= (modulation + 3);
bitrate *= streams;
if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
bitrate = (bitrate / 9) * 10;
/* do NOT round down here */
return (bitrate + 50000) / 100000;
}
static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
int flags, struct net_device *dev, int flags, struct net_device *dev,
u8 *mac_addr, struct station_info *sinfo) u8 *mac_addr, struct station_info *sinfo)
{ {
void *hdr; void *hdr;
struct nlattr *sinfoattr; struct nlattr *sinfoattr, *txrate;
u16 bitrate;
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
if (!hdr) if (!hdr)
@ -1126,7 +1159,29 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
if (sinfo->filled & STATION_INFO_PLINK_STATE) if (sinfo->filled & STATION_INFO_PLINK_STATE)
NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE,
sinfo->plink_state); sinfo->plink_state);
if (sinfo->filled & STATION_INFO_SIGNAL)
NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL,
sinfo->signal);
if (sinfo->filled & STATION_INFO_TX_BITRATE) {
txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE);
if (!txrate)
goto nla_put_failure;
/* nl80211_calculate_bitrate will return 0 for mcs >= 32 */
bitrate = nl80211_calculate_bitrate(&sinfo->txrate);
if (bitrate > 0)
NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS)
NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS,
sinfo->txrate.mcs);
if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI)
NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
nla_nest_end(msg, txrate);
}
nla_nest_end(msg, sinfoattr); nla_nest_end(msg, sinfoattr);
return genlmsg_end(msg, hdr); return genlmsg_end(msg, hdr);