mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-30 07:34:12 +08:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
c2da953a46
@ -1350,4 +1350,9 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline int ath5k_pad_size(int hdrlen)
|
||||
{
|
||||
return (hdrlen < 24) ? 0 : hdrlen & 3;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1668,7 +1668,7 @@ ath5k_tasklet_rx(unsigned long data)
|
||||
struct ath5k_desc *ds;
|
||||
int ret;
|
||||
int hdrlen;
|
||||
int pad;
|
||||
int padsize;
|
||||
|
||||
spin_lock(&sc->rxbuflock);
|
||||
if (list_empty(&sc->rxbuf)) {
|
||||
@ -1753,16 +1753,19 @@ accept:
|
||||
|
||||
skb_put(skb, rs.rs_datalen);
|
||||
|
||||
/*
|
||||
* the hardware adds a padding to 4 byte boundaries between
|
||||
* the header and the payload data if the header length is
|
||||
* not multiples of 4 - remove it
|
||||
*/
|
||||
/* The MAC header is padded to have 32-bit boundary if the
|
||||
* packet payload is non-zero. The general calculation for
|
||||
* padsize would take into account odd header lengths:
|
||||
* padsize = (4 - hdrlen % 4) % 4; However, since only
|
||||
* even-length headers are used, padding can only be 0 or 2
|
||||
* bytes and we can optimize this a bit. In addition, we must
|
||||
* not try to remove padding from short control frames that do
|
||||
* not have payload. */
|
||||
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||
if (hdrlen & 3) {
|
||||
pad = hdrlen % 4;
|
||||
memmove(skb->data + pad, skb->data, hdrlen);
|
||||
skb_pull(skb, pad);
|
||||
padsize = ath5k_pad_size(hdrlen);
|
||||
if (padsize) {
|
||||
memmove(skb->data + padsize, skb->data, hdrlen);
|
||||
skb_pull(skb, padsize);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2623,7 +2626,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
struct ath5k_buf *bf;
|
||||
unsigned long flags;
|
||||
int hdrlen;
|
||||
int pad;
|
||||
int padsize;
|
||||
|
||||
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
|
||||
*/
|
||||
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
|
||||
if (hdrlen & 3) {
|
||||
pad = hdrlen % 4;
|
||||
if (skb_headroom(skb) < pad) {
|
||||
padsize = ath5k_pad_size(hdrlen);
|
||||
if (padsize) {
|
||||
|
||||
if (skb_headroom(skb) < padsize) {
|
||||
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;
|
||||
}
|
||||
skb_push(skb, pad);
|
||||
memmove(skb->data, skb->data+pad, hdrlen);
|
||||
skb_push(skb, padsize);
|
||||
memmove(skb->data, skb->data+padsize, hdrlen);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sc->txbuflock, flags);
|
||||
|
@ -71,7 +71,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
|
||||
/* Verify and set frame length */
|
||||
|
||||
/* 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)
|
||||
return -EINVAL;
|
||||
@ -202,7 +202,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
|
||||
/* Verify and set frame length */
|
||||
|
||||
/* 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)
|
||||
return -EINVAL;
|
||||
|
@ -701,6 +701,7 @@ struct ath_softc {
|
||||
struct ath_hal *sc_ah;
|
||||
void __iomem *mem;
|
||||
spinlock_t sc_resetlock;
|
||||
struct mutex mutex;
|
||||
|
||||
u8 sc_curbssid[ETH_ALEN];
|
||||
u8 sc_myaddr[ETH_ALEN];
|
||||
|
@ -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)
|
||||
{
|
||||
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
|
||||
* 11g, otherwise at 1Mb/s.
|
||||
@ -623,37 +622,40 @@ static int ath_get_channel(struct ath_softc *sc,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ext_chan_offset: (-1, 0, 1) (below, none, above) */
|
||||
|
||||
static u32 ath_get_extchanmode(struct ath_softc *sc,
|
||||
struct ieee80211_channel *chan,
|
||||
int ext_chan_offset,
|
||||
enum ath9k_ht_macmode tx_chan_width)
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
u32 chanmode = 0;
|
||||
|
||||
switch (chan->band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
if ((ext_chan_offset == 0) &&
|
||||
(tx_chan_width == ATH9K_HT_MACMODE_20))
|
||||
switch(channel_type) {
|
||||
case NL80211_CHAN_NO_HT:
|
||||
case NL80211_CHAN_HT20:
|
||||
chanmode = CHANNEL_G_HT20;
|
||||
if ((ext_chan_offset == 1) &&
|
||||
(tx_chan_width == ATH9K_HT_MACMODE_2040))
|
||||
break;
|
||||
case NL80211_CHAN_HT40PLUS:
|
||||
chanmode = CHANNEL_G_HT40PLUS;
|
||||
if ((ext_chan_offset == -1) &&
|
||||
(tx_chan_width == ATH9K_HT_MACMODE_2040))
|
||||
break;
|
||||
case NL80211_CHAN_HT40MINUS:
|
||||
chanmode = CHANNEL_G_HT40MINUS;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
if ((ext_chan_offset == 0) &&
|
||||
(tx_chan_width == ATH9K_HT_MACMODE_20))
|
||||
switch(channel_type) {
|
||||
case NL80211_CHAN_NO_HT:
|
||||
case NL80211_CHAN_HT20:
|
||||
chanmode = CHANNEL_A_HT20;
|
||||
if ((ext_chan_offset == 1) &&
|
||||
(tx_chan_width == ATH9K_HT_MACMODE_2040))
|
||||
break;
|
||||
case NL80211_CHAN_HT40PLUS:
|
||||
chanmode = CHANNEL_A_HT40PLUS;
|
||||
if ((ext_chan_offset == -1) &&
|
||||
(tx_chan_width == ATH9K_HT_MACMODE_2040))
|
||||
break;
|
||||
case NL80211_CHAN_HT40MINUS:
|
||||
chanmode = CHANNEL_A_HT40MINUS;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -662,13 +664,6 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
static int ath_setkey_tkip(struct ath_softc *sc,
|
||||
struct ieee80211_key_conf *key,
|
||||
static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
|
||||
struct ath9k_keyval *hk,
|
||||
const u8 *addr)
|
||||
{
|
||||
u8 *key_rxmic = NULL;
|
||||
u8 *key_txmic = NULL;
|
||||
const u8 *key_rxmic;
|
||||
const u8 *key_txmic;
|
||||
|
||||
key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
|
||||
key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
|
||||
key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
|
||||
key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
|
||||
|
||||
if (addr == NULL) {
|
||||
/* Group key installation */
|
||||
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
|
||||
return ath_keyset(sc, key->keyidx, hk, addr);
|
||||
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
|
||||
return ath_keyset(sc, keyix, hk, addr);
|
||||
}
|
||||
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_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.
|
||||
* The hal handles the MIC keys at index+64.
|
||||
*/
|
||||
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 */
|
||||
DPRINTF(sc, ATH_DBG_KEYCACHE,
|
||||
"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));
|
||||
/* 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,
|
||||
const u8 *addr,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct ieee80211_vif *vif;
|
||||
struct ath9k_keyval hk;
|
||||
const u8 *mac = NULL;
|
||||
int ret = 0;
|
||||
enum nl80211_iftype opmode;
|
||||
int idx;
|
||||
|
||||
memset(&hk, 0, sizeof(hk));
|
||||
|
||||
@ -748,65 +821,69 @@ static int ath_key_config(struct ath_softc *sc,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hk.kv_len = key->keylen;
|
||||
hk.kv_len = key->keylen;
|
||||
memcpy(hk.kv_val, key->key, key->keylen);
|
||||
|
||||
if (!sc->sc_vaps[0])
|
||||
return -EIO;
|
||||
if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
|
||||
/* 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];
|
||||
opmode = vif->type;
|
||||
|
||||
/*
|
||||
* Strategy:
|
||||
* For STA mc tx, we will not setup a key at
|
||||
* all since we never tx mc.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
mac = addr;
|
||||
vif = sc->sc_vaps[0];
|
||||
if (vif->type != NL80211_IFTYPE_AP) {
|
||||
/* Only keyidx 0 should be used with unicast key, but
|
||||
* allow this for client mode for now. */
|
||||
idx = key->keyidx;
|
||||
} else
|
||||
return -EIO;
|
||||
} else {
|
||||
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)
|
||||
ret = ath_setkey_tkip(sc, key, &hk, mac);
|
||||
ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac);
|
||||
else
|
||||
ret = ath_keyset(sc, key->keyidx, &hk, mac);
|
||||
ret = ath_keyset(sc, idx, &hk, mac);
|
||||
|
||||
if (!ret)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
ath_key_reset(sc, key->keyidx, freeslot);
|
||||
clear_bit(key->hw_key_idx, sc->sc_keymap);
|
||||
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)
|
||||
@ -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;
|
||||
}
|
||||
|
||||
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,
|
||||
struct ieee80211_vif *vif,
|
||||
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;
|
||||
int pos;
|
||||
|
||||
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 */
|
||||
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_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 */
|
||||
mod_timer(&sc->sc_ani.timer,
|
||||
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
|
||||
@ -1291,9 +1304,6 @@ static void ath_detach(struct ath_softc *sc)
|
||||
ath_deinit_leds(sc);
|
||||
|
||||
ieee80211_unregister_hw(hw);
|
||||
|
||||
ath_rate_control_unregister();
|
||||
|
||||
ath_rx_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");
|
||||
|
||||
spin_lock_init(&sc->sc_resetlock);
|
||||
mutex_init(&sc->mutex);
|
||||
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
|
||||
tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
|
||||
(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++)
|
||||
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 */
|
||||
|
||||
@ -1574,15 +1573,7 @@ static int ath_attach(u16 devid, struct ath_softc *sc)
|
||||
hw->sta_data_size = sizeof(struct ath_node);
|
||||
hw->vif_data_size = sizeof(struct ath_vap);
|
||||
|
||||
/* Register 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) {
|
||||
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
|
||||
|
||||
error = ieee80211_register_hw(hw);
|
||||
if (error != 0) {
|
||||
ath_rate_control_unregister();
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Initialize LED control */
|
||||
ath_init_leds(sc);
|
||||
@ -1626,7 +1613,6 @@ static int ath_attach(u16 devid, struct ath_softc *sc)
|
||||
return 0;
|
||||
detach:
|
||||
ath_detach(sc);
|
||||
bad:
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -2146,7 +2132,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
struct ath_softc *sc = hw->priv;
|
||||
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;
|
||||
int pos;
|
||||
|
||||
@ -2157,6 +2145,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
if (pos == -1) {
|
||||
DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n",
|
||||
curchan->center_freq);
|
||||
mutex_unlock(&sc->mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -2165,29 +2154,29 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
(curchan->band == IEEE80211_BAND_2GHZ) ?
|
||||
CHANNEL_G : CHANNEL_A;
|
||||
|
||||
if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) &&
|
||||
(conf->ht.enabled)) {
|
||||
sc->tx_chan_width = (!!conf->ht.sec_chan_offset) ?
|
||||
ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
|
||||
if (conf->ht.enabled) {
|
||||
if (conf->ht.channel_type == NL80211_CHAN_HT40PLUS ||
|
||||
conf->ht.channel_type == NL80211_CHAN_HT40MINUS)
|
||||
sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
|
||||
|
||||
sc->sc_ah->ah_channels[pos].chanmode =
|
||||
ath_get_extchanmode(sc, curchan,
|
||||
conf->ht.sec_chan_offset,
|
||||
sc->tx_chan_width);
|
||||
conf->ht.channel_type);
|
||||
}
|
||||
|
||||
if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
|
||||
DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
|
||||
mutex_unlock(&sc->mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_HT)
|
||||
ath_update_chainmask(sc, conf->ht.enabled);
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_POWER)
|
||||
sc->sc_config.txpowlimit = 2 * conf->power_level;
|
||||
|
||||
mutex_unlock(&sc->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2371,18 +2360,17 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
|
||||
switch (cmd) {
|
||||
case SET_KEY:
|
||||
ret = ath_key_config(sc, addr, key);
|
||||
if (!ret) {
|
||||
set_bit(key->keyidx, sc->sc_keymap);
|
||||
key->hw_key_idx = key->keyidx;
|
||||
if (ret >= 0) {
|
||||
key->hw_key_idx = ret;
|
||||
/* push IV and Michael MIC generation to stack */
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
if (key->alg == ALG_TKIP)
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case DISABLE_KEY:
|
||||
ath_key_delete(sc, key);
|
||||
clear_bit(key->keyidx, sc->sc_keymap);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
@ -2417,9 +2405,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
|
||||
sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_HT)
|
||||
ath9k_ht_conf(sc, bss_conf);
|
||||
|
||||
if (changed & BSS_CHANGED_ASSOC) {
|
||||
DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
|
||||
bss_conf->assoc);
|
||||
@ -2780,11 +2765,24 @@ static struct pci_driver ath_pci_driver = {
|
||||
|
||||
static int __init init_ath_pci(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
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) {
|
||||
printk(KERN_ERR
|
||||
"ath_pci: No devices found, driver not installed.\n");
|
||||
ath_rate_control_unregister();
|
||||
pci_unregister_driver(&ath_pci_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -2795,6 +2793,7 @@ module_init(init_ath_pci);
|
||||
|
||||
static void __exit exit_ath_pci(void)
|
||||
{
|
||||
ath_rate_control_unregister();
|
||||
pci_unregister_driver(&ath_pci_driver);
|
||||
printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
|
||||
}
|
||||
|
@ -1498,7 +1498,8 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
||||
__le16 fc = hdr->frame_control;
|
||||
|
||||
/* 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].count =
|
||||
is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY;
|
||||
|
@ -111,33 +111,6 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len)
|
||||
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
|
||||
* 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 ath_softc *sc)
|
||||
{
|
||||
struct ath_rate_table *rate_table = sc->cur_rate_table;
|
||||
struct ieee80211_hdr *hdr;
|
||||
int ratekbps, rix;
|
||||
u8 ratecode;
|
||||
__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;
|
||||
rix = rate_table->rateCodeToIndex[ratecode];
|
||||
ratekbps = rate_table->info[rix].ratekbps;
|
||||
|
||||
/* HT rate */
|
||||
if (ratecode & 0x80) {
|
||||
/* HT rate */
|
||||
rx_status->flag |= RX_FLAG_HT;
|
||||
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)
|
||||
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);
|
||||
@ -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->noise = sc->sc_ani.sc_noise_floor;
|
||||
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;
|
||||
|
||||
/* 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)
|
||||
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
|
||||
* 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)
|
||||
goto requeue;
|
||||
|
||||
/* Sync and unmap the frame */
|
||||
pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr,
|
||||
sc->rx.bufsize,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
/* Unmap the frame */
|
||||
pci_unmap_single(sc->pdev, bf->bf_buf_addr,
|
||||
sc->rx.bufsize,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
|
@ -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_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
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);
|
||||
|
||||
@ -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->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);
|
||||
}
|
||||
|
@ -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_lo", B43_DBG_LO, 0);
|
||||
add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
|
||||
add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0);
|
||||
|
||||
#undef add_dyn_dbg
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ enum b43_dyndbg { /* Dynamic debugging features */
|
||||
B43_DBG_PWORK_STOP,
|
||||
B43_DBG_LO,
|
||||
B43_DBG_FIRMWARE,
|
||||
B43_DBG_KEYS,
|
||||
__B43_NR_DYNDBG,
|
||||
};
|
||||
|
||||
|
@ -992,6 +992,52 @@ static void b43_clear_keys(struct b43_wldev *dev)
|
||||
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)
|
||||
{
|
||||
u32 macctl;
|
||||
@ -3324,7 +3370,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
|
||||
unsigned long flags;
|
||||
int antenna;
|
||||
int err = 0;
|
||||
u32 savedirqs;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
@ -3335,24 +3380,14 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
|
||||
dev = wl->current_dev;
|
||||
phy = &dev->phy;
|
||||
|
||||
b43_mac_suspend(dev);
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
|
||||
b43_set_retry_limits(dev, conf->short_frame_max_tx_count,
|
||||
conf->long_frame_max_tx_count);
|
||||
changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
|
||||
if (!changed)
|
||||
goto out_unlock_mutex;
|
||||
|
||||
/* 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);
|
||||
goto out_mac_enable;
|
||||
|
||||
/* Switch to the requested channel.
|
||||
* 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);
|
||||
b43_interrupt_enable(dev, savedirqs);
|
||||
mmiowb();
|
||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||
out_unlock_mutex:
|
||||
out_mac_enable:
|
||||
b43_mac_enable(dev);
|
||||
out_unlock_mutex:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
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_wldev *dev;
|
||||
struct b43_phy *phy;
|
||||
unsigned long flags;
|
||||
u32 savedirqs;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
dev = wl->current_dev;
|
||||
phy = &dev->phy;
|
||||
|
||||
/* 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);
|
||||
if (!dev || b43_status(dev) < B43_STAT_STARTED)
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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:
|
||||
out_unlock_mutex:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
return;
|
||||
@ -3599,15 +3611,18 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||
mutex_unlock(&wl->mutex);
|
||||
if (!err) {
|
||||
b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
|
||||
"mac: %pM\n",
|
||||
cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
|
||||
addr);
|
||||
b43_dump_keymemory(dev);
|
||||
}
|
||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -178,13 +178,27 @@ void b43_phy_unlock(struct b43_wldev *dev)
|
||||
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)
|
||||
{
|
||||
assert_mac_suspended(dev);
|
||||
return dev->phy.ops->radio_read(dev, reg);
|
||||
}
|
||||
|
||||
void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
|
||||
{
|
||||
assert_mac_suspended(dev);
|
||||
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)
|
||||
{
|
||||
assert_mac_suspended(dev);
|
||||
return dev->phy.ops->phy_read(dev, reg);
|
||||
}
|
||||
|
||||
void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
|
||||
{
|
||||
assert_mac_suspended(dev);
|
||||
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;
|
||||
}
|
||||
|
||||
b43_mac_suspend(dev);
|
||||
phy->ops->software_rfkill(dev, state);
|
||||
phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
|
||||
b43_mac_enable(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3047,6 +3047,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
|
||||
int rfatt, bbatt;
|
||||
u8 tx_control;
|
||||
|
||||
b43_mac_suspend(dev);
|
||||
|
||||
spin_lock_irq(&dev->wl->irq_lock);
|
||||
|
||||
/* Calculate the new attenuation values. */
|
||||
@ -3103,6 +3105,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
|
||||
gphy->tx_control);
|
||||
b43_radio_unlock(dev);
|
||||
b43_phy_unlock(dev);
|
||||
|
||||
b43_mac_enable(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_g *gphy = phy->g;
|
||||
|
||||
b43_mac_suspend(dev);
|
||||
//TODO: update_aci_moving_average
|
||||
if (gphy->aci_enable && gphy->aci_wlan_automatic) {
|
||||
b43_mac_suspend(dev);
|
||||
if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) {
|
||||
if (0 /*TODO: bunch of conditions */ ) {
|
||||
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))
|
||||
phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE);
|
||||
}
|
||||
b43_mac_enable(dev);
|
||||
} else if (gphy->interfmode == B43_INTERFMODE_NONWLAN &&
|
||||
phy->rev == 1) {
|
||||
//TODO: implement rev1 workaround
|
||||
}
|
||||
b43_lo_g_maintanance_work(dev);
|
||||
b43_mac_enable(dev);
|
||||
}
|
||||
|
||||
static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
|
||||
|
@ -2482,7 +2482,6 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
|
||||
|
||||
frame_size = iwl3945_fill_beacon_frame(priv,
|
||||
tx_beacon_cmd->frame,
|
||||
iwl3945_broadcast_addr,
|
||||
sizeof(frame->u) - sizeof(*tx_beacon_cmd));
|
||||
|
||||
BUG_ON(frame_size > MAX_MPDU_SIZE);
|
||||
|
@ -405,12 +405,6 @@ struct iwl3945_rx_queue {
|
||||
|
||||
#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_SYNC_ACTIVE 1 /* sync host command in progress */
|
||||
#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,
|
||||
struct iwl3945_host_cmd *cmd);
|
||||
extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
|
||||
struct ieee80211_hdr *hdr,
|
||||
const u8 *dest, int left);
|
||||
struct ieee80211_hdr *hdr,int left);
|
||||
extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv,
|
||||
struct iwl3945_rx_queue *q);
|
||||
extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv);
|
||||
|
@ -426,7 +426,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
|
||||
|
||||
static int iwl4965_apm_stop_master(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long 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 */
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
IWL_DEBUG_INFO("stop master\n");
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
|
||||
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_param_named(
|
||||
disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
|
||||
|
@ -73,7 +73,6 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = {
|
||||
/* FIXME: same implementation as 4965 */
|
||||
static int iwl5000_apm_stop_master(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long 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 */
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
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_PARM_DESC(swcrypto50,
|
||||
"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_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
|
||||
MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
|
||||
|
@ -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[info->band]->bitrates[info->status.rates[0].idx].bitrate)) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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 ieee80211_conf *conf = &priv->hw->conf;
|
||||
struct iwl_lq_sta *lq_sta = priv_sta;
|
||||
u16 mask_bit = 0;
|
||||
|
||||
lq_sta->flush_timer = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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_green = rs_use_green(priv, conf);
|
||||
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->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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
struct ieee80211_hdr *hdr,
|
||||
const u8 *dest, int left)
|
||||
int left)
|
||||
{
|
||||
if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
|
||||
((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;
|
||||
|
||||
frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
|
||||
iwl_bcast_addr,
|
||||
sizeof(frame->u) - sizeof(*tx_beacon_cmd));
|
||||
|
||||
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 =
|
||||
!!(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 (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_NONE;
|
||||
iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW)
|
||||
iwl_conf->supported_chan_width = 0;
|
||||
}
|
||||
|
||||
iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2);
|
||||
|
||||
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 =
|
||||
bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
@ -1221,7 +1218,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
|
||||
count++;
|
||||
if (count >= 8) {
|
||||
priv->rxq.read = i;
|
||||
__iwl_rx_replenish(priv);
|
||||
iwl_rx_queue_restock(priv);
|
||||
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
|
||||
* 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.
|
||||
*
|
||||
* 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 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,
|
||||
|
@ -70,6 +70,15 @@
|
||||
* 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 ret = 0;
|
||||
|
@ -2418,6 +2418,8 @@ struct statistics_rx_ht_phy {
|
||||
__le32 reserved2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1)
|
||||
|
||||
struct statistics_rx_non_phy {
|
||||
__le32 bogus_cts; /* CTS received when not expecting CTS */
|
||||
__le32 bogus_ack; /* ACK received when not expecting ACK */
|
||||
|
@ -154,7 +154,7 @@ struct iwl_ops {
|
||||
struct iwl_mod_params {
|
||||
int disable; /* def: 0 = enable radio */
|
||||
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 num_of_queues; /* def: HW dependent */
|
||||
int num_of_ampdu_queues;/* def: HW dependent */
|
||||
|
@ -96,28 +96,25 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
|
||||
#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
|
||||
* list here in the form of:
|
||||
* list here in the form of
|
||||
*
|
||||
* #define IWL_DL_xxxx VALUE
|
||||
*
|
||||
* shifting value to the left one bit from the previous entry. xxxx should be
|
||||
* the name of the classification (for example, WEP)
|
||||
* where xxxx should be the name of the classification (for example, WEP).
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* when CONFIG_IWLWIFI_DEBUG=y.
|
||||
*/
|
||||
|
||||
#define IWL_DL_INFO (1 << 0)
|
||||
|
@ -323,14 +323,6 @@ struct iwl_rx_queue {
|
||||
|
||||
#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 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 CELSIUS_TO_KELVIN(x) ((x)+273)
|
||||
|
||||
@ -546,9 +536,6 @@ struct iwl_hw_params {
|
||||
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 {
|
||||
dma_addr_t dma;
|
||||
void *addr;
|
||||
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_40MHZ 1
|
||||
|
||||
@ -613,7 +600,6 @@ struct iwl_dma_ptr {
|
||||
#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
|
||||
|
||||
/* Sensitivity and chain noise calibration */
|
||||
#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1)
|
||||
#define INITIALIZATION_VALUE 0xFFFF
|
||||
#define CAL_NUM_OF_BEACONS 20
|
||||
#define MAXIMUM_ALLOWED_PATHLOSS 15
|
||||
@ -666,15 +652,6 @@ enum iwl4965_calib_enabled_state {
|
||||
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
|
||||
|
@ -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)
|
||||
#endif
|
||||
|
||||
#define IWL_POLL_INTERVAL 10 /* microseconds */
|
||||
static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
|
||||
u32 bits, u32 mask, int timeout)
|
||||
{
|
||||
int i = 0;
|
||||
int t = 0;
|
||||
|
||||
do {
|
||||
if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
|
||||
return i;
|
||||
udelay(10);
|
||||
i += 10;
|
||||
} while (i < timeout);
|
||||
return t;
|
||||
udelay(IWL_POLL_INTERVAL);
|
||||
t += IWL_POLL_INTERVAL;
|
||||
} while (t < timeout);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
|
||||
if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
|
||||
break;
|
||||
|
||||
IWL_DEBUG_LED("LED BLINK IDX=%d", i);
|
||||
IWL_DEBUG_LED("LED BLINK IDX=%d\n", i);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -244,25 +244,31 @@ void iwl_rx_allocate(struct iwl_priv *priv)
|
||||
struct list_head *element;
|
||||
struct iwl_rx_mem_buffer *rxb;
|
||||
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;
|
||||
rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
|
||||
list_del(element);
|
||||
|
||||
spin_unlock_irqrestore(&rxq->lock, flags);
|
||||
|
||||
/* Alloc a new receive buffer */
|
||||
rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
|
||||
__GFP_NOWARN | GFP_ATOMIC);
|
||||
GFP_KERNEL);
|
||||
if (!rxb->skb) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_CRIT DRV_NAME
|
||||
": Can not allocate SKB buffers\n");
|
||||
printk(KERN_CRIT DRV_NAME
|
||||
"Can not allocate SKB buffers\n");
|
||||
/* We don't reschedule replenish work here -- we will
|
||||
* call the restock method and if it still needs
|
||||
* more buffers it will schedule replenish */
|
||||
break;
|
||||
}
|
||||
priv->alloc_rxb_skb++;
|
||||
list_del(element);
|
||||
|
||||
/* Get physical address of RB/SKB */
|
||||
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);
|
||||
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);
|
||||
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)
|
||||
{
|
||||
|
@ -645,7 +645,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
|
||||
struct iwl_tx_cmd *tx_cmd,
|
||||
struct ieee80211_tx_info *info,
|
||||
struct ieee80211_hdr *hdr,
|
||||
int is_unicast, u8 std_id)
|
||||
u8 std_id)
|
||||
{
|
||||
__le16 fc = hdr->frame_control;
|
||||
__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 seq_number = 0;
|
||||
__le16 fc;
|
||||
u8 hdr_len, unicast;
|
||||
u8 hdr_len;
|
||||
u8 sta_id;
|
||||
u8 wait_write_ptr = 0;
|
||||
u8 tid = 0;
|
||||
@ -854,8 +854,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
||||
goto drop_unlock;
|
||||
}
|
||||
|
||||
unicast = !is_multicast_ether_addr(hdr->addr1);
|
||||
|
||||
fc = hdr->frame_control;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
@ -994,7 +992,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
||||
len = (u16)skb->len;
|
||||
tx_cmd->len = cpu_to_le16(len);
|
||||
/* 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 */
|
||||
iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);
|
||||
|
@ -65,7 +65,7 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv,
|
||||
|
||||
/* module parameters */
|
||||
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_antenna; /* def: 0 = both antennas (use diversity) */
|
||||
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,
|
||||
struct ieee80211_hdr *hdr,
|
||||
const u8 *dest, int left)
|
||||
int left)
|
||||
{
|
||||
|
||||
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_PARM_DESC(hwcrypto,
|
||||
"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_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444);
|
||||
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
|
||||
|
@ -26,6 +26,7 @@
|
||||
* if_sdio_card_to_host() to pad the data.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/firmware.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);
|
||||
*/
|
||||
ret = sdio_writesb(card->func, card->ioport,
|
||||
chunk_buffer, (chunk_size + 31) / 32 * 32);
|
||||
chunk_buffer, roundup(chunk_size, 32));
|
||||
if (ret)
|
||||
goto release;
|
||||
|
||||
|
@ -495,11 +495,9 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_HT) {
|
||||
printk(KERN_DEBUG " %s: HT: sec_ch_offs=%d width_40_ok=%d "
|
||||
"op_mode=%d\n",
|
||||
printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n",
|
||||
wiphy_name(hw->wiphy),
|
||||
info->ht.secondary_channel_offset,
|
||||
info->ht.width_40_ok, info->ht.operation_mode);
|
||||
info->ht.operation_mode);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_BASIC_RATES) {
|
||||
|
@ -44,6 +44,9 @@ enum p54_control_frame_types {
|
||||
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 {
|
||||
__le16 flags;
|
||||
__le16 len;
|
||||
@ -54,6 +57,10 @@ struct p54_hdr {
|
||||
u8 data[0];
|
||||
} __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 {
|
||||
__le16 aifs;
|
||||
__le16 cwmin;
|
||||
@ -61,6 +68,13 @@ struct p54_edcf_queue_param {
|
||||
__le16 txop;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct p54_rssi_linear_approximation {
|
||||
s16 mul;
|
||||
s16 add;
|
||||
s16 longbow_unkn;
|
||||
s16 longbow_unk2;
|
||||
};
|
||||
|
||||
#define EEPROM_READBACK_LEN 0x3fc
|
||||
|
||||
#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
|
||||
@ -71,11 +85,11 @@ struct p54_edcf_queue_param {
|
||||
#define FW_LM20 0x4c4d3230
|
||||
|
||||
struct p54_common {
|
||||
struct ieee80211_hw *hw;
|
||||
u32 rx_start;
|
||||
u32 rx_end;
|
||||
struct sk_buff_head tx_queue;
|
||||
void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb,
|
||||
int free_on_tx);
|
||||
void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
|
||||
int (*open)(struct ieee80211_hw *dev);
|
||||
void (*stop)(struct ieee80211_hw *dev);
|
||||
int mode;
|
||||
@ -90,6 +104,7 @@ struct p54_common {
|
||||
struct pda_channel_output_limit *output_limit;
|
||||
unsigned int output_limit_len;
|
||||
struct pda_pa_curve_data *curve_data;
|
||||
struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
|
||||
unsigned int filter_flags;
|
||||
bool use_short_slot;
|
||||
u16 rxhw;
|
||||
@ -106,9 +121,7 @@ struct p54_common {
|
||||
struct ieee80211_tx_queue_stats tx_stats[8];
|
||||
struct p54_edcf_queue_param qos_params[8];
|
||||
struct ieee80211_low_level_stats stats;
|
||||
struct timer_list stats_timer;
|
||||
struct completion stats_comp;
|
||||
struct sk_buff *cached_stats;
|
||||
struct delayed_work work;
|
||||
struct sk_buff *cached_beacon;
|
||||
int noise;
|
||||
void *eeprom;
|
||||
|
@ -335,6 +335,36 @@ static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2",
|
||||
"Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
|
||||
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)
|
||||
{
|
||||
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:
|
||||
priv->version = *(u8 *)(entry->data + 1);
|
||||
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:
|
||||
/* make it overrun */
|
||||
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_ANTENNA_GAIN:
|
||||
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_RSSI_LINEAR_APPROXIMATION_EXTENDED:
|
||||
case PDR_RADIATED_TRANSMISSION_CORRECTION:
|
||||
case PDR_PRISM_TX_IQ_CALIBRATION:
|
||||
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)
|
||||
{
|
||||
/* TODO: get the rssi_add & rssi_mul data from the eeprom */
|
||||
return ((rssi * 0x83) / 64 - 400) / 4;
|
||||
struct p54_common *priv = dev->priv;
|
||||
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)
|
||||
@ -589,6 +625,9 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
|
||||
ieee80211_rx_irqsafe(dev, skb, &rx_status);
|
||||
|
||||
queue_delayed_work(dev->workqueue, &priv->work,
|
||||
msecs_to_jiffies(P54_STATISTICS_UPDATE));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -644,7 +683,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
freed = priv->rx_end - last_addr;
|
||||
__skb_unlink(skb, &priv->tx_queue);
|
||||
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 +
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
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_data = (struct p54_tx_data *) entry_hdr->data;
|
||||
priv->tx_stats[entry_data->hw_queue].len--;
|
||||
priv->stats.dot11ACKFailureCount += payload->tries - 1;
|
||||
|
||||
if (unlikely(entry == priv->cached_beacon)) {
|
||||
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_hdr *hdr = (struct p54_hdr *) skb->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)
|
||||
priv->tsf_high32++;
|
||||
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->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)
|
||||
@ -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.
|
||||
*/
|
||||
ieee80211_stop_queues(dev);
|
||||
queue_delayed_work(dev->workqueue, &priv->work,
|
||||
msecs_to_jiffies(P54_TX_TIMEOUT));
|
||||
|
||||
if (unlikely(left == 32)) {
|
||||
/*
|
||||
@ -1022,7 +1088,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev)
|
||||
eeprom_hdr->v2.magic2 = 0xf;
|
||||
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)) {
|
||||
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->count = 1;
|
||||
tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
|
||||
priv->tx(dev, skb, 1);
|
||||
priv->tx(dev, skb);
|
||||
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));
|
||||
memcpy(sta->addr, addr, ETH_ALEN);
|
||||
priv->tx(dev, skb, 1);
|
||||
priv->tx(dev, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1124,7 +1190,7 @@ static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
|
||||
hdr = (void *)entry->data;
|
||||
cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
|
||||
cancel->req_id = hdr->req_id;
|
||||
priv->tx(dev, skb, 1);
|
||||
priv->tx(dev, skb);
|
||||
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! */
|
||||
if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
|
||||
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;
|
||||
|
||||
err:
|
||||
@ -1428,19 +1498,19 @@ static int p54_setup_mac(struct ieee80211_hw *dev)
|
||||
setup->v2.lpf_bandwidth = cpu_to_le16(65535);
|
||||
setup->v2.osc_start_delay = cpu_to_le16(65535);
|
||||
}
|
||||
priv->tx(dev, skb, 1);
|
||||
priv->tx(dev, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell,
|
||||
u16 frequency)
|
||||
static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
|
||||
{
|
||||
struct p54_common *priv = dev->priv;
|
||||
struct sk_buff *skb;
|
||||
struct p54_scan *chan;
|
||||
unsigned int i;
|
||||
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) +
|
||||
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) {
|
||||
chan->v1.rssical_mul = cpu_to_le16(130);
|
||||
chan->v1.rssical_add = cpu_to_le16(0xfe70);
|
||||
chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
|
||||
chan->v1_rssi.add = cpu_to_le16(priv->rssical_db[band].add);
|
||||
} else {
|
||||
chan->v2.rssical_mul = cpu_to_le16(130);
|
||||
chan->v2.rssical_add = cpu_to_le16(0xfe70);
|
||||
chan->v2.rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
|
||||
chan->v2.rssi.add = cpu_to_le16(priv->rssical_db[band].add);
|
||||
chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
|
||||
memset(chan->v2.rts_rates, 0, 8);
|
||||
}
|
||||
priv->tx(dev, skb, 1);
|
||||
priv->tx(dev, skb);
|
||||
return 0;
|
||||
|
||||
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_temporary = cpu_to_le16(act);
|
||||
led->duration = cpu_to_le16(1000);
|
||||
priv->tx(dev, skb, 1);
|
||||
priv->tx(dev, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1575,21 +1645,7 @@ static int p54_set_edcf(struct ieee80211_hw *dev)
|
||||
edcf->flags = 0;
|
||||
memset(edcf->mapping, 0, sizeof(edcf->mapping));
|
||||
memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
|
||||
priv->tx(dev, skb, 1);
|
||||
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);
|
||||
priv->tx(dev, skb);
|
||||
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[3], 0x0007, 0x000f, 0x03ff, 0);
|
||||
err = p54_set_edcf(dev);
|
||||
if (err)
|
||||
goto out;
|
||||
err = p54_init_stats(dev);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -1698,6 +1751,8 @@ static int p54_start(struct ieee80211_hw *dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
queue_delayed_work(dev->workqueue, &priv->work, 0);
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->conf_mutex);
|
||||
return err;
|
||||
@ -1710,9 +1765,7 @@ static void p54_stop(struct ieee80211_hw *dev)
|
||||
|
||||
mutex_lock(&priv->conf_mutex);
|
||||
priv->mode = NL80211_IFTYPE_UNSPECIFIED;
|
||||
del_timer(&priv->stats_timer);
|
||||
p54_free_skb(dev, priv->cached_stats);
|
||||
priv->cached_stats = NULL;
|
||||
cancel_delayed_work_sync(&priv->work);
|
||||
if (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;
|
||||
}
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||
ret = p54_scan(dev, P54_SCAN_EXIT, 0,
|
||||
conf->channel->center_freq);
|
||||
ret = p54_scan(dev, P54_SCAN_EXIT, 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
@ -1811,8 +1863,7 @@ static int p54_config_interface(struct ieee80211_hw *dev,
|
||||
}
|
||||
|
||||
if (conf->changed & IEEE80211_IFCC_BEACON) {
|
||||
ret = p54_scan(dev, P54_SCAN_EXIT, 0,
|
||||
dev->conf.channel->center_freq);
|
||||
ret = p54_scan(dev, P54_SCAN_EXIT, 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
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->freq = cpu_to_le16(5390);
|
||||
memset(xbow->padding, 0, sizeof(xbow->padding));
|
||||
priv->tx(dev, skb, 1);
|
||||
priv->tx(dev, skb);
|
||||
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 = dev->priv;
|
||||
struct p54_common *priv = container_of(work, struct p54_common,
|
||||
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,
|
||||
@ -1904,17 +1970,7 @@ static int p54_get_stats(struct ieee80211_hw *dev,
|
||||
{
|
||||
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));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1946,8 +2002,7 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
|
||||
priv->basic_rate_mask = info->basic_rates;
|
||||
p54_setup_mac(dev);
|
||||
if (priv->fw_var >= 0x500)
|
||||
p54_scan(dev, P54_SCAN_EXIT, 0,
|
||||
dev->conf.channel->center_freq);
|
||||
p54_scan(dev, P54_SCAN_EXIT, 0);
|
||||
}
|
||||
if (changed & BSS_CHANGED_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);
|
||||
}
|
||||
|
||||
priv->tx(dev, skb, 1);
|
||||
priv->tx(dev, skb);
|
||||
mutex_unlock(&priv->conf_mutex);
|
||||
return 0;
|
||||
}
|
||||
@ -2072,6 +2127,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
|
||||
return NULL;
|
||||
|
||||
priv = dev->priv;
|
||||
priv->hw = dev;
|
||||
priv->mode = NL80211_IFTYPE_UNSPECIFIED;
|
||||
priv->basic_rate_mask = 0x15f;
|
||||
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);
|
||||
init_completion(&priv->eeprom_comp);
|
||||
init_completion(&priv->stats_comp);
|
||||
setup_timer(&priv->stats_timer, p54_statistics_timer,
|
||||
(unsigned long)dev);
|
||||
INIT_DELAYED_WORK(&priv->work, p54_work);
|
||||
|
||||
return dev;
|
||||
}
|
||||
@ -2118,8 +2172,6 @@ EXPORT_SYMBOL_GPL(p54_init_common);
|
||||
void p54_free_common(struct ieee80211_hw *dev)
|
||||
{
|
||||
struct p54_common *priv = dev->priv;
|
||||
del_timer(&priv->stats_timer);
|
||||
kfree_skb(priv->cached_stats);
|
||||
kfree(priv->iq_autocal);
|
||||
kfree(priv->output_limit);
|
||||
kfree(priv->curve_data);
|
||||
|
@ -84,9 +84,6 @@ struct bootrec_desc {
|
||||
#define BR_CODE_END_OF_BRA 0xFF0000FF
|
||||
#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_OUT_PROMISC BIT(0)
|
||||
#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
|
||||
@ -178,6 +175,11 @@ struct pda_pa_curve_data {
|
||||
u8 data[0];
|
||||
} __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
|
||||
* number 553155. The current implementation mirrors version 1.1 of the
|
||||
@ -355,6 +357,11 @@ struct p54_tx_data {
|
||||
u8 align[0];
|
||||
} __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_STATION BIT(0)
|
||||
#define P54_FILTER_TYPE_IBSS BIT(1)
|
||||
@ -424,22 +431,18 @@ struct p54_scan {
|
||||
u8 dup_16qam;
|
||||
u8 dup_64qam;
|
||||
union {
|
||||
struct {
|
||||
__le16 rssical_mul;
|
||||
__le16 rssical_add;
|
||||
} v1 __attribute__ ((packed));
|
||||
struct pda_rssi_cal_entry v1_rssi;
|
||||
|
||||
struct {
|
||||
__le32 basic_rate_mask;
|
||||
u8 rts_rates[8];
|
||||
__le16 rssical_mul;
|
||||
__le16 rssical_add;
|
||||
struct pda_rssi_cal_entry rssi;
|
||||
} v2 __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define P54_SCAN_V1_LEN (sizeof(struct p54_scan)-12)
|
||||
#define P54_SCAN_V2_LEN (sizeof(struct p54_scan))
|
||||
#define P54_SCAN_V1_LEN 0x70
|
||||
#define P54_SCAN_V2_LEN 0x7c
|
||||
|
||||
struct p54_led {
|
||||
__le16 mode;
|
||||
|
@ -227,7 +227,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
|
||||
|
||||
while (i != idx) {
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
|
||||
int free_on_tx)
|
||||
static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct p54p_priv *priv = dev->priv;
|
||||
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]);
|
||||
i = idx % ARRAY_SIZE(ring_control->tx_data);
|
||||
|
||||
priv->tx_buf_data[i] = skb;
|
||||
mapping = pci_map_single(priv->pdev, skb->data, skb->len,
|
||||
PCI_DMA_TODEVICE);
|
||||
desc = &ring_control->tx_data[i];
|
||||
@ -324,10 +326,6 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
|
||||
|
||||
wmb();
|
||||
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);
|
||||
|
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
|
||||
|
@ -138,22 +138,16 @@ static void p54u_rx_cb(struct urb *urb)
|
||||
}
|
||||
}
|
||||
|
||||
static void p54u_tx_reuse_skb_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)
|
||||
static void p54u_tx_cb(struct urb *urb)
|
||||
{
|
||||
struct sk_buff *skb = urb->context;
|
||||
struct ieee80211_hw *dev = (struct ieee80211_hw *)
|
||||
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) { }
|
||||
@ -213,8 +207,7 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb,
|
||||
int free_on_tx)
|
||||
static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct p54u_priv *priv = dev->priv;
|
||||
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);
|
||||
usb_fill_bulk_urb(data_urb, priv->udev,
|
||||
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
|
||||
skb->data, skb->len,
|
||||
free_on_tx ? p54u_tx_free_skb_cb :
|
||||
p54u_tx_reuse_skb_cb, skb);
|
||||
skb->data, skb->len, p54u_tx_cb, skb);
|
||||
|
||||
usb_anchor_urb(addr_urb, &priv->submitted);
|
||||
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);
|
||||
}
|
||||
|
||||
static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb,
|
||||
int free_on_tx)
|
||||
static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct p54u_priv *priv = dev->priv;
|
||||
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_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
|
||||
skb->data, skb->len,
|
||||
free_on_tx ? p54u_tx_free_skb_cb :
|
||||
p54u_tx_reuse_skb_cb, skb);
|
||||
skb->data, skb->len, p54u_tx_cb, skb);
|
||||
|
||||
usb_anchor_urb(data_urb, &priv->submitted);
|
||||
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);
|
||||
}
|
||||
|
||||
static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb,
|
||||
int free_on_tx)
|
||||
static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct p54u_priv *priv = dev->priv;
|
||||
struct urb *int_urb, *data_urb;
|
||||
struct net2280_tx_hdr *hdr;
|
||||
struct net2280_reg_write *reg;
|
||||
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);
|
||||
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));
|
||||
memset(hdr, 0, sizeof(*hdr));
|
||||
hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
|
||||
hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_hdr));
|
||||
hdr->len = len;
|
||||
hdr->device_addr = addr;
|
||||
|
||||
usb_fill_bulk_urb(int_urb, priv->udev,
|
||||
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_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
|
||||
skb->data, skb->len,
|
||||
free_on_tx ? p54u_tx_free_skb_cb :
|
||||
p54u_tx_reuse_skb_cb, skb);
|
||||
skb->data, skb->len, p54u_tx_cb, skb);
|
||||
|
||||
usb_anchor_urb(int_urb, &priv->submitted);
|
||||
err = usb_submit_urb(int_urb, GFP_ATOMIC);
|
||||
|
@ -213,7 +213,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
flags = skb->len;
|
||||
@ -281,7 +281,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
}
|
||||
usb_free_urb(urb);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void rtl8187_rx_cb(struct urb *urb)
|
||||
@ -294,15 +294,16 @@ static void rtl8187_rx_cb(struct urb *urb)
|
||||
int rate, signal;
|
||||
u32 flags;
|
||||
u32 quality;
|
||||
unsigned long f;
|
||||
|
||||
spin_lock(&priv->rx_queue.lock);
|
||||
spin_lock_irqsave(&priv->rx_queue.lock, f);
|
||||
if (skb->next)
|
||||
__skb_unlink(skb, &priv->rx_queue);
|
||||
else {
|
||||
spin_unlock(&priv->rx_queue.lock);
|
||||
spin_unlock_irqrestore(&priv->rx_queue.lock, f);
|
||||
return;
|
||||
}
|
||||
spin_unlock(&priv->rx_queue.lock);
|
||||
spin_unlock_irqrestore(&priv->rx_queue.lock, f);
|
||||
skb_put(skb, urb->actual_length);
|
||||
|
||||
if (unlikely(urb->status)) {
|
||||
@ -942,7 +943,6 @@ static int rtl8187_start(struct ieee80211_hw *dev)
|
||||
static void rtl8187_stop(struct ieee80211_hw *dev)
|
||||
{
|
||||
struct rtl8187_priv *priv = dev->priv;
|
||||
struct rtl8187_rx_info *info;
|
||||
struct sk_buff *skb;
|
||||
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->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)))
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
|
@ -201,13 +201,13 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
|
||||
* @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_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):
|
||||
* 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)
|
||||
* NL80211_SEC_CHAN_DISABLED = HT20 only
|
||||
* NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
|
||||
* NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
|
||||
* NL80211_CHAN_HT20 = HT20 only
|
||||
* NL80211_CHAN_HT40MINUS = secondary channel is below 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_IFNAME: network interface name
|
||||
@ -344,7 +344,7 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_WIPHY_TXQ_PARAMS,
|
||||
NL80211_ATTR_WIPHY_FREQ,
|
||||
NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET,
|
||||
NL80211_ATTR_WIPHY_CHANNEL_TYPE,
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@ -436,6 +462,9 @@ enum nl80211_sta_flags {
|
||||
* @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
|
||||
* @__NL80211_STA_INFO_AFTER_LAST: internal
|
||||
* @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 {
|
||||
__NL80211_STA_INFO_INVALID,
|
||||
@ -445,6 +474,8 @@ enum nl80211_sta_info {
|
||||
NL80211_STA_INFO_LLID,
|
||||
NL80211_STA_INFO_PLID,
|
||||
NL80211_STA_INFO_PLINK_STATE,
|
||||
NL80211_STA_INFO_SIGNAL,
|
||||
NL80211_STA_INFO_TX_BITRATE,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_STA_INFO_AFTER_LAST,
|
||||
@ -774,10 +805,10 @@ enum nl80211_txq_q {
|
||||
NL80211_TXQ_Q_BK
|
||||
};
|
||||
|
||||
enum nl80211_sec_chan_offset {
|
||||
NL80211_SEC_CHAN_NO_HT /* No HT */,
|
||||
NL80211_SEC_CHAN_DISABLED /* HT20 only */,
|
||||
NL80211_SEC_CHAN_BELOW /* HT40- */,
|
||||
NL80211_SEC_CHAN_ABOVE /* HT40+ */
|
||||
enum nl80211_channel_type {
|
||||
NL80211_CHAN_NO_HT,
|
||||
NL80211_CHAN_HT20,
|
||||
NL80211_CHAN_HT40MINUS,
|
||||
NL80211_CHAN_HT40PLUS
|
||||
};
|
||||
#endif /* __LINUX_NL80211_H */
|
||||
|
@ -169,6 +169,9 @@ struct station_parameters {
|
||||
* @STATION_INFO_LLID: @llid filled
|
||||
* @STATION_INFO_PLID: @plid 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 {
|
||||
STATION_INFO_INACTIVE_TIME = 1<<0,
|
||||
@ -177,6 +180,39 @@ enum station_info_flags {
|
||||
STATION_INFO_LLID = 1<<3,
|
||||
STATION_INFO_PLID = 1<<4,
|
||||
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
|
||||
* @plid: mesh peer link id
|
||||
* @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 {
|
||||
u32 filled;
|
||||
@ -200,6 +238,8 @@ struct station_info {
|
||||
u16 llid;
|
||||
u16 plid;
|
||||
u8 plink_state;
|
||||
s8 signal;
|
||||
struct rate_info txrate;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -523,7 +563,7 @@ struct cfg80211_ops {
|
||||
|
||||
int (*set_channel)(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_sec_chan_offset);
|
||||
enum nl80211_channel_type channel_type);
|
||||
};
|
||||
|
||||
/* temporary wext handlers */
|
||||
|
@ -165,14 +165,9 @@ enum ieee80211_bss_change {
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
struct ieee80211_bss_ht_conf {
|
||||
u8 secondary_channel_offset;
|
||||
bool width_40_ok;
|
||||
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
|
||||
* to enable IBSS merging.
|
||||
* @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 {
|
||||
RX_FLAG_MMIC_ERROR = 1<<0,
|
||||
@ -451,7 +449,10 @@ enum mac80211_rx_flags {
|
||||
RX_FLAG_FAILED_FCS_CRC = 1<<5,
|
||||
RX_FLAG_FAILED_PLCP_CRC = 1<<6,
|
||||
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.
|
||||
* @qual: overall signal quality indication, in percent (0-100).
|
||||
* @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_*
|
||||
*/
|
||||
struct ieee80211_rx_status {
|
||||
@ -508,9 +510,7 @@ static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void)
|
||||
|
||||
struct ieee80211_ht_conf {
|
||||
bool enabled;
|
||||
int sec_chan_offset; /* 0 = HT40 disabled; -1 = HT40 enabled, secondary
|
||||
* channel below primary; 1 = HT40 enabled,
|
||||
* secondary channel above primary */
|
||||
enum nl80211_channel_type channel_type;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -854,6 +854,11 @@ enum ieee80211_tkip_key_type {
|
||||
*
|
||||
* @IEEE80211_HW_AMPDU_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 {
|
||||
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
|
||||
@ -866,6 +871,7 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_NOISE_DBM = 1<<8,
|
||||
IEEE80211_HW_SPECTRUM_MGMT = 1<<9,
|
||||
IEEE80211_HW_AMPDU_AGGREGATION = 1<<10,
|
||||
IEEE80211_HW_NO_STACK_DYNAMIC_PS = 1<<11,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -310,12 +310,35 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
|
||||
|
||||
sinfo->filled = STATION_INFO_INACTIVE_TIME |
|
||||
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->rx_bytes = sta->rx_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)) {
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
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 ieee80211_sub_if_data *sdata;
|
||||
int err;
|
||||
int layer2_update;
|
||||
|
||||
/* Prevent a race with changing the rate control algorithm */
|
||||
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);
|
||||
|
||||
layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
err = sta_info_insert(sta);
|
||||
if (err) {
|
||||
/* 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();
|
||||
return err;
|
||||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
|
||||
sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
if (layer2_update)
|
||||
ieee80211_send_layer2_update(sta);
|
||||
|
||||
rcu_read_unlock();
|
||||
@ -1099,12 +1131,12 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
|
||||
|
||||
static int ieee80211_set_channel(struct wiphy *wiphy,
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_bss_ht_conf ht;
|
||||
u32 changed = 0;
|
||||
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];
|
||||
|
||||
@ -112,24 +113,36 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_channel_to_frequency(hti->control_chan))
|
||||
enable_ht = false;
|
||||
|
||||
/*
|
||||
* XXX: This is totally incorrect when there are multiple virtual
|
||||
* interfaces, needs to be fixed later.
|
||||
*/
|
||||
ht_changed = local->hw.conf.ht.enabled != enable_ht;
|
||||
if (enable_ht) {
|
||||
channel_type = NL80211_CHAN_HT20;
|
||||
|
||||
if (!(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)) {
|
||||
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;
|
||||
|
||||
if (ht_changed)
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
|
||||
|
||||
/* disable HT */
|
||||
if (!enable_ht)
|
||||
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);
|
||||
|
||||
/* if bss configuration changed store the new one */
|
||||
|
@ -538,6 +538,11 @@ enum {
|
||||
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. */
|
||||
#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
|
||||
|
||||
@ -554,7 +559,8 @@ struct ieee80211_local {
|
||||
const struct ieee80211_ops *ops;
|
||||
|
||||
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 */
|
||||
int open_count;
|
||||
int monitors, cooked_mntrs;
|
||||
@ -625,7 +631,7 @@ struct ieee80211_local {
|
||||
struct delayed_work scan_work;
|
||||
struct ieee80211_sub_if_data *scan_sdata;
|
||||
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];
|
||||
size_t scan_ssid_len;
|
||||
struct list_head bss_list;
|
||||
@ -689,6 +695,12 @@ struct ieee80211_local {
|
||||
int wifi_wme_noack_test;
|
||||
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
|
||||
struct local_debugfsdentries {
|
||||
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,
|
||||
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
|
||||
#define debug_noinline noinline
|
||||
#else
|
||||
|
@ -195,37 +195,30 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
|
||||
struct ieee80211_channel *chan;
|
||||
int ret = 0;
|
||||
int power;
|
||||
enum nl80211_sec_chan_offset sec_chan_offset;
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (local->sw_scanning) {
|
||||
chan = local->scan_channel;
|
||||
sec_chan_offset = NL80211_SEC_CHAN_NO_HT;
|
||||
channel_type = NL80211_CHAN_NO_HT;
|
||||
} else {
|
||||
chan = local->oper_channel;
|
||||
sec_chan_offset = local->oper_sec_chan_offset;
|
||||
channel_type = local->oper_channel_type;
|
||||
}
|
||||
|
||||
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;
|
||||
switch (sec_chan_offset) {
|
||||
case NL80211_SEC_CHAN_NO_HT:
|
||||
local->hw.conf.ht.channel_type = channel_type;
|
||||
switch (channel_type) {
|
||||
case NL80211_CHAN_NO_HT:
|
||||
local->hw.conf.ht.enabled = false;
|
||||
local->hw.conf.ht.sec_chan_offset = 0;
|
||||
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.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;
|
||||
}
|
||||
changed |= IEEE80211_CONF_CHANGE_CHANNEL;
|
||||
@ -348,7 +341,8 @@ static void ieee80211_tasklet_handler(unsigned long data)
|
||||
dev_kfree_skb(skb);
|
||||
break ;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
WARN(1, "mac80211: Packet is of unknown type %d\n",
|
||||
skb->pkt_type);
|
||||
dev_kfree_skb(skb);
|
||||
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->queue_stop_reason_lock);
|
||||
|
||||
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);
|
||||
|
||||
tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
|
||||
|
@ -309,7 +309,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ASSOC_REQ);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -744,6 +744,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
||||
bss_info_changed |= BSS_CHANGED_BASIC_RATES;
|
||||
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_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 sta_info *sta;
|
||||
u32 changed = 0;
|
||||
u32 changed = 0, config_changed = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
@ -858,8 +869,18 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
rcu_read_unlock();
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
* (=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;
|
||||
}
|
||||
rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
|
||||
} else if (local && local->ops && local->ops->get_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);
|
||||
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);
|
||||
}
|
||||
|
@ -123,7 +123,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
||||
/* radiotap header, set always present flags */
|
||||
rthdr->it_present =
|
||||
cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
|
||||
(1 << IEEE80211_RADIOTAP_RATE) |
|
||||
(1 << IEEE80211_RADIOTAP_CHANNEL) |
|
||||
(1 << IEEE80211_RADIOTAP_ANTENNA) |
|
||||
(1 << IEEE80211_RADIOTAP_RX_FLAGS));
|
||||
@ -149,7 +148,19 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
||||
pos++;
|
||||
|
||||
/* 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++;
|
||||
|
||||
/* IEEE80211_RADIOTAP_CHANNEL */
|
||||
@ -1849,9 +1860,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
||||
if (!(sdata->dev->flags & IFF_PROMISC))
|
||||
return 0;
|
||||
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,
|
||||
BIT(rx->status->rate_idx));
|
||||
BIT(rate_idx));
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
if (!multicast &&
|
||||
@ -2057,7 +2074,13 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
|
||||
tid_agg_rx->reorder_buf[index]->cb,
|
||||
sizeof(status));
|
||||
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,
|
||||
tid_agg_rx->reorder_buf[index],
|
||||
&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,
|
||||
sizeof(status));
|
||||
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],
|
||||
&status, rate);
|
||||
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];
|
||||
|
||||
if (!sband ||
|
||||
status->rate_idx < 0 ||
|
||||
status->rate_idx >= sband->n_bitrates) {
|
||||
if (!sband) {
|
||||
WARN_ON(1);
|
||||
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
|
||||
|
@ -1473,6 +1473,19 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
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;
|
||||
h_pos = skb_transport_header(skb) - skb->data;
|
||||
|
||||
|
@ -330,10 +330,20 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
|
||||
}
|
||||
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);
|
||||
|
||||
/* 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)) {
|
||||
set_bit(queue, local->queues_pending_run);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
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);
|
||||
|
||||
@ -367,12 +429,24 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
|
||||
}
|
||||
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;
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
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);
|
||||
|
||||
@ -641,7 +715,7 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz)
|
||||
chan->flags & IEEE80211_CHAN_NO_IBSS)
|
||||
return ret;
|
||||
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)
|
||||
ret = 0;
|
||||
|
@ -830,25 +830,56 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
|
||||
struct iw_param *wrq,
|
||||
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_conf *conf = &local->hw.conf;
|
||||
int ret = 0, timeout = 0;
|
||||
bool ps;
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return -EINVAL;
|
||||
|
||||
if (wrq->disabled) {
|
||||
conf->flags &= ~IEEE80211_CONF_PS;
|
||||
return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
ps = false;
|
||||
timeout = 0;
|
||||
goto set;
|
||||
}
|
||||
|
||||
switch (wrq->flags & IW_POWER_MODE) {
|
||||
case IW_POWER_ON: /* If not specified */
|
||||
case IW_POWER_MODE: /* If set all mask */
|
||||
case IW_POWER_ALL_R: /* If explicitely state all */
|
||||
conf->flags |= IEEE80211_CONF_PS;
|
||||
ps = true;
|
||||
break;
|
||||
default: /* Otherwise we ignore */
|
||||
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,
|
||||
@ -857,9 +888,8 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev,
|
||||
char *extra)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
|
||||
.len = BUS_ID_SIZE-1 },
|
||||
[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
|
||||
[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_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]) {
|
||||
enum nl80211_sec_chan_offset sec_chan_offset =
|
||||
NL80211_SEC_CHAN_NO_HT;
|
||||
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
|
||||
struct ieee80211_channel *chan;
|
||||
struct ieee80211_sta_ht_cap *ht_cap;
|
||||
u32 freq, sec_freq;
|
||||
@ -375,13 +374,13 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
result = -EINVAL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) {
|
||||
sec_chan_offset = nla_get_u32(info->attrs[
|
||||
NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]);
|
||||
if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT &&
|
||||
sec_chan_offset != NL80211_SEC_CHAN_DISABLED &&
|
||||
sec_chan_offset != NL80211_SEC_CHAN_BELOW &&
|
||||
sec_chan_offset != NL80211_SEC_CHAN_ABOVE)
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
|
||||
channel_type = nla_get_u32(info->attrs[
|
||||
NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
|
||||
if (channel_type != NL80211_CHAN_NO_HT &&
|
||||
channel_type != NL80211_CHAN_HT20 &&
|
||||
channel_type != NL80211_CHAN_HT40PLUS &&
|
||||
channel_type != NL80211_CHAN_HT40MINUS)
|
||||
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)
|
||||
goto bad_res;
|
||||
|
||||
if (sec_chan_offset == NL80211_SEC_CHAN_BELOW)
|
||||
if (channel_type == NL80211_CHAN_HT40MINUS)
|
||||
sec_freq = freq - 20;
|
||||
else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE)
|
||||
else if (channel_type == NL80211_CHAN_HT40PLUS)
|
||||
sec_freq = freq + 20;
|
||||
else
|
||||
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;
|
||||
|
||||
/* no HT capabilities */
|
||||
if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT &&
|
||||
if (channel_type != NL80211_CHAN_NO_HT &&
|
||||
!ht_cap->ht_supported)
|
||||
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,
|
||||
sec_chan_offset);
|
||||
channel_type);
|
||||
if (result)
|
||||
goto bad_res;
|
||||
}
|
||||
@ -1091,12 +1090,46 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags)
|
||||
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,
|
||||
int flags, struct net_device *dev,
|
||||
u8 *mac_addr, struct station_info *sinfo)
|
||||
{
|
||||
void *hdr;
|
||||
struct nlattr *sinfoattr;
|
||||
struct nlattr *sinfoattr, *txrate;
|
||||
u16 bitrate;
|
||||
|
||||
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
|
||||
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)
|
||||
NLA_PUT_U8(msg, NL80211_STA_INFO_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);
|
||||
|
||||
return genlmsg_end(msg, hdr);
|
||||
|
Loading…
Reference in New Issue
Block a user