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

This commit is contained in:
David S. Miller 2009-11-18 10:55:32 -08:00
commit dfef948ed2
121 changed files with 2686 additions and 2219 deletions

View File

@ -121,6 +121,14 @@ static struct fwentry firmwares[] = {
[BOARD_505A] = { "atmel_at76c505a-rfmd2958.bin" },
[BOARD_505AMX] = { "atmel_at76c505amx-rfmd.bin" },
};
MODULE_FIRMWARE("atmel_at76c503-i3861.bin");
MODULE_FIRMWARE("atmel_at76c503-i3863.bin");
MODULE_FIRMWARE("atmel_at76c503-rfmd.bin");
MODULE_FIRMWARE("atmel_at76c503-rfmd-acc.bin");
MODULE_FIRMWARE("atmel_at76c505-rfmd.bin");
MODULE_FIRMWARE("atmel_at76c505-rfmd2958.bin");
MODULE_FIRMWARE("atmel_at76c505a-rfmd2958.bin");
MODULE_FIRMWARE("atmel_at76c505amx-rfmd.bin");
#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops)
@ -524,20 +532,6 @@ static char *hex2str(void *buf, int len)
return ret;
}
#define MAC2STR_BUFFERS 4
static inline char *mac2str(u8 *mac)
{
static atomic_t a = ATOMIC_INIT(0);
static char bufs[MAC2STR_BUFFERS][6 * 3];
char *str;
str = bufs[atomic_inc_return(&a) & (MAC2STR_BUFFERS - 1)];
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return str;
}
/* LED trigger */
static int tx_activity;
static void at76_ledtrig_tx_timerfunc(unsigned long data);
@ -973,13 +967,13 @@ static void at76_dump_mib_mac_addr(struct at76_priv *priv)
goto exit;
}
at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x",
at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %pM res 0x%x 0x%x",
wiphy_name(priv->hw->wiphy),
mac2str(m->mac_addr), m->res[0], m->res[1]);
m->mac_addr, m->res[0], m->res[1]);
for (i = 0; i < ARRAY_SIZE(m->group_addr); i++)
at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %s, "
at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %pM, "
"status %d", wiphy_name(priv->hw->wiphy), i,
mac2str(m->group_addr[i]), m->group_addr_status[i]);
m->group_addr[i], m->group_addr_status[i]);
exit:
kfree(m);
}
@ -1042,7 +1036,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration "
"%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d "
"CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d "
"current_bssid %s current_essid %s current_bss_type %d "
"current_bssid %pM current_essid %s current_bss_type %d "
"pm_mode %d ibss_change %d res %d "
"multi_domain_capability_implemented %d "
"international_roaming %d country_string %.3s",
@ -1051,7 +1045,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
le16_to_cpu(m->medium_occupancy_limit),
le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window),
m->CFP_mode, m->privacy_option_implemented, m->DTIM_period,
m->CFP_period, mac2str(m->current_bssid),
m->CFP_period, m->current_bssid,
hex2str(m->current_essid, IW_ESSID_MAX_SIZE),
m->current_bss_type, m->power_mgmt_mode, m->ibss_change,
m->res, m->multi_domain_capability_implemented,
@ -1080,7 +1074,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv)
"cwmin %d cwmax %d short_retry_time %d long_retry_time %d "
"scan_type %d scan_channel %d probe_delay %u "
"min_channel_time %d max_channel_time %d listen_int %d "
"desired_ssid %s desired_bssid %s desired_bsstype %d",
"desired_ssid %s desired_bssid %pM desired_bsstype %d",
wiphy_name(priv->hw->wiphy),
le32_to_cpu(m->max_tx_msdu_lifetime),
le32_to_cpu(m->max_rx_lifetime),
@ -1092,7 +1086,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv)
le16_to_cpu(m->max_channel_time),
le16_to_cpu(m->listen_interval),
hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE),
mac2str(m->desired_bssid), m->desired_bsstype);
m->desired_bssid, m->desired_bsstype);
exit:
kfree(m);
}
@ -1194,6 +1188,9 @@ static int at76_start_monitor(struct at76_priv *priv)
scan.channel = priv->channel;
scan.scan_type = SCAN_TYPE_PASSIVE;
scan.international_scan = 0;
scan.min_channel_time = cpu_to_le16(priv->scan_min_time);
scan.max_channel_time = cpu_to_le16(priv->scan_max_time);
scan.probe_delay = cpu_to_le16(0);
ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));
if (ret >= 0)
@ -2284,9 +2281,9 @@ static int at76_init_new_device(struct at76_priv *priv,
priv->mac80211_registered = 1;
printk(KERN_INFO "%s: USB %s, MAC %s, firmware %d.%d.%d-%d\n",
printk(KERN_INFO "%s: USB %s, MAC %pM, firmware %d.%d.%d-%d\n",
wiphy_name(priv->hw->wiphy),
dev_name(&interface->dev), mac2str(priv->mac_addr),
dev_name(&interface->dev), priv->mac_addr,
priv->fw_version.major, priv->fw_version.minor,
priv->fw_version.patch, priv->fw_version.build);
printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n",

View File

@ -21,8 +21,28 @@
#include <linux/if_ether.h>
#include <net/mac80211.h>
/*
* The key cache is used for h/w cipher state and also for
* tracking station state such as the current tx antenna.
* We also setup a mapping table between key cache slot indices
* and station state to short-circuit node lookups on rx.
* Different parts have different size key caches. We handle
* up to ATH_KEYMAX entries (could dynamically allocate state).
*/
#define ATH_KEYMAX 128 /* max key cache size we handle */
static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
struct ath_ani {
bool caldone;
int16_t noise_floor;
unsigned int longcal_timer;
unsigned int shortcal_timer;
unsigned int resetcal_timer;
unsigned int checkani_timer;
struct timer_list timer;
};
enum ath_device_state {
ATH_HW_UNAVAILABLE,
ATH_HW_INITIALIZED,
@ -66,6 +86,8 @@ struct ath_common {
int debug_mask;
enum ath_device_state state;
struct ath_ani ani;
u16 cachelsz;
u16 curaid;
u8 macaddr[ETH_ALEN];
@ -75,6 +97,12 @@ struct ath_common {
u8 tx_chainmask;
u8 rx_chainmask;
u32 rx_bufsize;
u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX);
u8 splitmic;
struct ath_regulatory regulatory;
const struct ath_ops *ops;
const struct ath_bus_ops *bus_ops;

View File

@ -323,10 +323,13 @@ static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
static inline void ath5k_rxbuf_free(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
BUG_ON(!bf);
if (!bf->skb)
return;
pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize,
PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(bf->skb);
bf->skb = NULL;
@ -1181,17 +1184,18 @@ struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
* fake physical layer header at the start.
*/
skb = ath_rxbuf_alloc(common,
sc->rxbufsize + common->cachelsz - 1,
common->rx_bufsize,
GFP_ATOMIC);
if (!skb) {
ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
sc->rxbufsize + common->cachelsz - 1);
common->rx_bufsize);
return NULL;
}
*skb_addr = pci_map_single(sc->pdev,
skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
skb->data, common->rx_bufsize,
PCI_DMA_FROMDEVICE);
if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) {
ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
dev_kfree_skb(skb);
@ -1631,10 +1635,10 @@ ath5k_rx_start(struct ath5k_softc *sc)
struct ath5k_buf *bf;
int ret;
sc->rxbufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz);
common->rx_bufsize = roundup(IEEE80211_MAX_LEN, common->cachelsz);
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
common->cachelsz, sc->rxbufsize);
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rx_bufsize %u\n",
common->cachelsz, common->rx_bufsize);
spin_lock_bh(&sc->rxbuflock);
sc->rxlink = NULL;
@ -1679,6 +1683,8 @@ static unsigned int
ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
struct sk_buff *skb, struct ath5k_rx_status *rs)
{
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
struct ieee80211_hdr *hdr = (void *)skb->data;
unsigned int keyix, hlen;
@ -1695,7 +1701,7 @@ ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
skb->len >= hlen + 4) {
keyix = skb->data[hlen + 3] >> 6;
if (test_bit(keyix, sc->keymap))
if (test_bit(keyix, common->keymap))
return RX_FLAG_DECRYPTED;
}
@ -1769,6 +1775,8 @@ ath5k_tasklet_rx(unsigned long data)
struct sk_buff *skb, *next_skb;
dma_addr_t next_skb_addr;
struct ath5k_softc *sc = (void *)data;
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
struct ath5k_buf *bf;
struct ath5k_desc *ds;
int ret;
@ -1846,7 +1854,7 @@ accept:
if (!next_skb)
goto next;
pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize,
PCI_DMA_FROMDEVICE);
skb_put(skb, rs.rs_datalen);
@ -3032,6 +3040,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_key_conf *key)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
int ret = 0;
if (modparam_nohwcrypt)
@ -3064,14 +3074,14 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ATH5K_ERR(sc, "can't set the key\n");
goto unlock;
}
__set_bit(key->keyidx, sc->keymap);
__set_bit(key->keyidx, common->keymap);
key->hw_key_idx = key->keyidx;
key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV |
IEEE80211_KEY_FLAG_GENERATE_MMIC);
break;
case DISABLE_KEY:
ath5k_hw_reset_key(sc->ah, key->keyidx);
__clear_bit(key->keyidx, sc->keymap);
__clear_bit(key->keyidx, common->keymap);
break;
default:
ret = -EINVAL;

View File

@ -153,8 +153,6 @@ struct ath5k_softc {
enum ath5k_int imask; /* interrupt mask copy */
DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */
u8 bssidmask[ETH_ALEN];
unsigned int led_pin, /* GPIO pin for driving LED */

View File

@ -3025,8 +3025,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower);
return -EINVAL;
}
if (txpower == 0)
txpower = AR5K_TUNE_DEFAULT_TXPOWER;
/* Reset TX power values */
memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));

View File

@ -1,5 +1,7 @@
config ATH9K_HW
tristate
config ATH9K_COMMON
tristate
config ATH9K
tristate "Atheros 802.11n wireless cards support"
@ -8,6 +10,7 @@ config ATH9K
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
select ATH9K_COMMON
---help---
This module adds support for wireless adapters based on
Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family

View File

@ -23,3 +23,6 @@ ath9k_hw-y:= hw.o \
mac.o \
obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o
ath9k_common-y:= common.o

View File

@ -19,14 +19,16 @@
#include <linux/etherdevice.h>
#include <linux/device.h>
#include <net/mac80211.h>
#include <linux/leds.h>
#include "hw.h"
#include "rc.h"
#include "debug.h"
#include "../ath.h"
#include "../debug.h"
#include "common.h"
/*
* Header for the ath9k.ko driver core *only* -- hw code nor any other driver
* should rely on this file or its contents.
*/
struct ath_node;
@ -99,18 +101,6 @@ enum buffer_type {
BUF_XRETRY = BIT(5),
};
struct ath_buf_state {
int bfs_nframes;
u16 bfs_al;
u16 bfs_frmlen;
int bfs_seqno;
int bfs_tidno;
int bfs_retries;
u8 bf_type;
u32 bfs_keyix;
enum ath9k_key_type bfs_keytype;
};
#define bf_nframes bf_state.bfs_nframes
#define bf_al bf_state.bfs_al
#define bf_frmlen bf_state.bfs_frmlen
@ -125,21 +115,6 @@ struct ath_buf_state {
#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY)
#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY)
struct ath_buf {
struct list_head list;
struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
an aggregate) */
struct ath_buf *bf_next; /* next subframe in the aggregate */
struct sk_buff *bf_mpdu; /* enclosing frame structure */
struct ath_desc *bf_desc; /* virtual addr of desc */
dma_addr_t bf_daddr; /* physical addr of desc */
dma_addr_t bf_buf_addr; /* physical addr of data buffer */
bool bf_stale;
u16 bf_flags;
struct ath_buf_state bf_state;
dma_addr_t bf_dmacontext;
};
struct ath_descdma {
struct ath_desc *dd_desc;
dma_addr_t dd_desc_paddr;
@ -159,13 +134,9 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_MAX_ANTENNA 3
#define ATH_RXBUF 512
#define WME_NUM_TID 16
#define ATH_TXBUF 512
#define ATH_TXMAXTRY 13
#define ATH_MGT_TXMAXTRY 4
#define WME_BA_BMP_SIZE 64
#define WME_MAX_BA WME_BA_BMP_SIZE
#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA)
#define TID_TO_WME_AC(_tid) \
((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
@ -173,12 +144,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
(((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
WME_AC_VO)
#define WME_AC_BE 0
#define WME_AC_BK 1
#define WME_AC_VI 2
#define WME_AC_VO 3
#define WME_NUM_AC 4
#define ADDBA_EXCHANGE_ATTEMPTS 10
#define ATH_AGGR_DELIM_SZ 4
#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
@ -252,30 +217,6 @@ struct ath_txq {
#define AGGR_ADDBA_COMPLETE BIT(2)
#define AGGR_ADDBA_PROGRESS BIT(3)
struct ath_atx_tid {
struct list_head list;
struct list_head buf_q;
struct ath_node *an;
struct ath_atx_ac *ac;
struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
u16 seq_start;
u16 seq_next;
u16 baw_size;
int tidno;
int baw_head; /* first un-acked tx buffer */
int baw_tail; /* next unused tx buffer slot */
int sched;
int paused;
u8 state;
};
struct ath_atx_ac {
int sched;
int qnum;
struct list_head list;
struct list_head tid_q;
};
struct ath_tx_control {
struct ath_txq *txq;
int if_id;
@ -286,29 +227,6 @@ struct ath_tx_control {
#define ATH_TX_XRETRY 0x02
#define ATH_TX_BAR 0x04
#define ATH_RSSI_LPF_LEN 10
#define RSSI_LPF_THRESHOLD -20
#define ATH_RSSI_EP_MULTIPLIER (1<<7)
#define ATH_EP_MUL(x, mul) ((x) * (mul))
#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
#define ATH_LPF_RSSI(x, y, len) \
((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
#define ATH_RSSI_LPF(x, y) do { \
if ((y) >= RSSI_LPF_THRESHOLD) \
x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
} while (0)
#define ATH_EP_RND(x, mul) \
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
struct ath_node {
struct ath_softc *an_sc;
struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC];
u16 maxampdu;
u8 mpdudensity;
int last_rssi;
};
struct ath_tx {
u16 seq_no;
u32 txqsetup;
@ -323,7 +241,6 @@ struct ath_rx {
u8 defant;
u8 rxotherant;
u32 *rxlink;
int bufsize;
unsigned int rxfilter;
spinlock_t rxflushlock;
spinlock_t rxbuflock;
@ -434,16 +351,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */
#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */
struct ath_ani {
bool caldone;
int16_t noise_floor;
unsigned int longcal_timer;
unsigned int shortcal_timer;
unsigned int resetcal_timer;
unsigned int checkani_timer;
struct timer_list timer;
};
/* Defines the BT AR_BT_COEX_WGHT used */
enum ath_stomp_type {
ATH_BTCOEX_NO_STOMP,
@ -503,18 +410,7 @@ struct ath_led {
#define ATH_CHAN_MAX 255
#define IEEE80211_WEP_NKID 4 /* number of key ids */
/*
* The key cache is used for h/w cipher state and also for
* tracking station state such as the current tx antenna.
* We also setup a mapping table between key cache slot indices
* and station state to short-circuit node lookups on rx.
* Different parts have different size key caches. We handle
* up to ATH_KEYMAX entries (could dynamically allocate state).
*/
#define ATH_KEYMAX 128 /* max key cache size we handle */
#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
#define ATH_RSSI_DUMMY_MARKER 0x127
#define ATH_RATE_DUMMY_MARKER 0
#define SC_OP_INVALID BIT(0)
@ -573,9 +469,6 @@ struct ath_softc {
u16 curtxpow;
u8 nbcnvifs;
u16 nvifs;
u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX);
u8 splitmic;
bool ps_enabled;
unsigned long ps_usecount;
enum ath9k_int imask;
@ -601,7 +494,6 @@ struct ath_softc {
int beacon_interval;
struct ath_ani ani;
#ifdef CONFIG_ATH9K_DEBUG
struct ath9k_debug debug;
#endif
@ -620,6 +512,7 @@ struct ath_wiphy {
ATH_WIPHY_PAUSED,
ATH_WIPHY_SCAN,
} state;
bool idle;
int chan_idx;
int chan_is_ht;
};
@ -654,8 +547,9 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
void ath_update_chainmask(struct ath_softc *sc, int is_ht);
int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
struct ath9k_channel *hchan);
void ath_radio_enable(struct ath_softc *sc);
void ath_radio_disable(struct ath_softc *sc);
void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw);
void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
#ifdef CONFIG_PCI
int ath_pci_init(void);
@ -691,6 +585,10 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
bool ath9k_wiphy_scanning(struct ath_softc *sc);
void ath9k_wiphy_work(struct work_struct *work);
bool ath9k_all_wiphys_idle(struct ath_softc *sc);
void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle);
void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue);
void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
#endif /* ATH9K_H */

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2009 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Module for common driver code between ath9k and ath9k_htc
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include "common.h"
MODULE_AUTHOR("Atheros Communications");
MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
/* Common RX processing */
/* Assumes you've already done the endian to CPU conversion */
static bool ath9k_rx_accept(struct ath_common *common,
struct sk_buff *skb,
struct ieee80211_rx_status *rxs,
struct ath_rx_status *rx_stats,
bool *decrypt_error)
{
struct ath_hw *ah = common->ah;
struct ieee80211_hdr *hdr;
__le16 fc;
hdr = (struct ieee80211_hdr *) skb->data;
fc = hdr->frame_control;
if (!rx_stats->rs_datalen)
return false;
/*
* rs_status follows rs_datalen so if rs_datalen is too large
* we can take a hint that hardware corrupted it, so ignore
* those frames.
*/
if (rx_stats->rs_datalen > common->rx_bufsize)
return false;
/*
* rs_more indicates chained descriptors which can be used
* to link buffers together for a sort of scatter-gather
* operation.
*
* The rx_stats->rs_status will not be set until the end of the
* chained descriptors so it can be ignored if rs_more is set. The
* rs_more will be false at the last element of the chained
* descriptors.
*/
if (!rx_stats->rs_more && rx_stats->rs_status != 0) {
if (rx_stats->rs_status & ATH9K_RXERR_CRC)
rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
if (rx_stats->rs_status & ATH9K_RXERR_PHY)
return false;
if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
*decrypt_error = true;
} else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
if (ieee80211_is_ctl(fc))
/*
* Sometimes, we get invalid
* MIC failures on valid control frames.
* Remove these mic errors.
*/
rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
else
rxs->flag |= RX_FLAG_MMIC_ERROR;
}
/*
* Reject error frames with the exception of
* decryption and MIC failures. For monitor mode,
* we also ignore the CRC error.
*/
if (ah->opmode == NL80211_IFTYPE_MONITOR) {
if (rx_stats->rs_status &
~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
ATH9K_RXERR_CRC))
return false;
} else {
if (rx_stats->rs_status &
~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
return false;
}
}
}
return true;
}
static u8 ath9k_process_rate(struct ath_common *common,
struct ieee80211_hw *hw,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rxs,
struct sk_buff *skb)
{
struct ieee80211_supported_band *sband;
enum ieee80211_band band;
unsigned int i = 0;
band = hw->conf.channel->band;
sband = hw->wiphy->bands[band];
if (rx_stats->rs_rate & 0x80) {
/* HT rate */
rxs->flag |= RX_FLAG_HT;
if (rx_stats->rs_flags & ATH9K_RX_2040)
rxs->flag |= RX_FLAG_40MHZ;
if (rx_stats->rs_flags & ATH9K_RX_GI)
rxs->flag |= RX_FLAG_SHORT_GI;
return rx_stats->rs_rate & 0x7f;
}
for (i = 0; i < sband->n_bitrates; i++) {
if (sband->bitrates[i].hw_value == rx_stats->rs_rate)
return i;
if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
rxs->flag |= RX_FLAG_SHORTPRE;
return i;
}
}
/* No valid hardware bitrate found -- we should not get here */
ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected "
"0x%02x using 1 Mbit\n", rx_stats->rs_rate);
if ((common->debug_mask & ATH_DBG_XMIT))
print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len);
return 0;
}
static void ath9k_process_rssi(struct ath_common *common,
struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ath_rx_status *rx_stats)
{
struct ath_hw *ah = common->ah;
struct ieee80211_sta *sta;
struct ieee80211_hdr *hdr;
struct ath_node *an;
int last_rssi = ATH_RSSI_DUMMY_MARKER;
__le16 fc;
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
rcu_read_lock();
/*
* XXX: use ieee80211_find_sta! This requires quite a bit of work
* under the current ath9k virtual wiphy implementation as we have
* no way of tying a vif to wiphy. Typically vifs are attached to
* at least one sdata of a wiphy on mac80211 but with ath9k virtual
* wiphy you'd have to iterate over every wiphy and each sdata.
*/
sta = ieee80211_find_sta_by_hw(hw, hdr->addr2);
if (sta) {
an = (struct ath_node *) sta->drv_priv;
if (rx_stats->rs_rssi != ATH9K_RSSI_BAD &&
!rx_stats->rs_moreaggr)
ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi);
last_rssi = an->last_rssi;
}
rcu_read_unlock();
if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
ATH_RSSI_EP_MULTIPLIER);
if (rx_stats->rs_rssi < 0)
rx_stats->rs_rssi = 0;
else if (rx_stats->rs_rssi > 127)
rx_stats->rs_rssi = 127;
/* Update Beacon RSSI, this is used by ANI. */
if (ieee80211_is_beacon(fc))
ah->stats.avgbrssi = rx_stats->rs_rssi;
}
/*
* For Decrypt or Demic errors, we only mark packet status here and always push
* up the frame up to let mac80211 handle the actual error case, be it no
* decryption key or real decryption error. This let us keep statistics there.
*/
int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rx_status,
bool *decrypt_error)
{
struct ath_hw *ah = common->ah;
memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error))
return -EINVAL;
ath9k_process_rssi(common, hw, skb, rx_stats);
rx_status->rate_idx = ath9k_process_rate(common, hw,
rx_stats, rx_status, skb);
rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp);
rx_status->band = hw->conf.channel->band;
rx_status->freq = hw->conf.channel->center_freq;
rx_status->noise = common->ani.noise_floor;
rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
rx_status->antenna = rx_stats->rs_antenna;
rx_status->flag |= RX_FLAG_TSFT;
return 0;
}
EXPORT_SYMBOL(ath9k_cmn_rx_skb_preprocess);
void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
struct sk_buff *skb,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rxs,
bool decrypt_error)
{
struct ath_hw *ah = common->ah;
struct ieee80211_hdr *hdr;
int hdrlen, padsize;
u8 keyix;
__le16 fc;
/* see if any padding is done by the hw and remove it */
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
fc = hdr->frame_control;
/* The MAC header is padded to have 32-bit boundary if the
* packet payload is non-zero. The general calculation for
* padsize would take into account odd header lengths:
* padsize = (4 - hdrlen % 4) % 4; However, since only
* even-length headers are used, padding can only be 0 or 2
* bytes and we can optimize this a bit. In addition, we must
* not try to remove padding from short control frames that do
* not have payload. */
padsize = hdrlen & 3;
if (padsize && hdrlen >= 24) {
memmove(skb->data + padsize, skb->data, hdrlen);
skb_pull(skb, padsize);
}
keyix = rx_stats->rs_keyix;
if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
rxs->flag |= RX_FLAG_DECRYPTED;
} else if (ieee80211_has_protected(fc)
&& !decrypt_error && skb->len >= hdrlen + 4) {
keyix = skb->data[hdrlen + 3] >> 6;
if (test_bit(keyix, common->keymap))
rxs->flag |= RX_FLAG_DECRYPTED;
}
if (ah->sw_mgmt_crypto &&
(rxs->flag & RX_FLAG_DECRYPTED) &&
ieee80211_is_mgmt(fc))
/* Use software decrypt for management frames. */
rxs->flag &= ~RX_FLAG_DECRYPTED;
}
EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess);
static int __init ath9k_cmn_init(void)
{
return 0;
}
module_init(ath9k_cmn_init);
static void __exit ath9k_cmn_exit(void)
{
return;
}
module_exit(ath9k_cmn_exit);

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2009 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <net/mac80211.h>
#include "../ath.h"
#include "../debug.h"
#include "hw.h"
/* Common header for Atheros 802.11n base driver cores */
#define WME_NUM_TID 16
#define WME_BA_BMP_SIZE 64
#define WME_MAX_BA WME_BA_BMP_SIZE
#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA)
#define WME_AC_BE 0
#define WME_AC_BK 1
#define WME_AC_VI 2
#define WME_AC_VO 3
#define WME_NUM_AC 4
#define ATH_RSSI_DUMMY_MARKER 0x127
#define ATH_RSSI_LPF_LEN 10
#define RSSI_LPF_THRESHOLD -20
#define ATH_RSSI_EP_MULTIPLIER (1<<7)
#define ATH_EP_MUL(x, mul) ((x) * (mul))
#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
#define ATH_LPF_RSSI(x, y, len) \
((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
#define ATH_RSSI_LPF(x, y) do { \
if ((y) >= RSSI_LPF_THRESHOLD) \
x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
} while (0)
#define ATH_EP_RND(x, mul) \
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
struct ath_atx_ac {
int sched;
int qnum;
struct list_head list;
struct list_head tid_q;
};
struct ath_buf_state {
int bfs_nframes;
u16 bfs_al;
u16 bfs_frmlen;
int bfs_seqno;
int bfs_tidno;
int bfs_retries;
u8 bf_type;
u32 bfs_keyix;
enum ath9k_key_type bfs_keytype;
};
struct ath_buf {
struct list_head list;
struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
an aggregate) */
struct ath_buf *bf_next; /* next subframe in the aggregate */
struct sk_buff *bf_mpdu; /* enclosing frame structure */
struct ath_desc *bf_desc; /* virtual addr of desc */
dma_addr_t bf_daddr; /* physical addr of desc */
dma_addr_t bf_buf_addr; /* physical addr of data buffer */
bool bf_stale;
u16 bf_flags;
struct ath_buf_state bf_state;
dma_addr_t bf_dmacontext;
};
struct ath_atx_tid {
struct list_head list;
struct list_head buf_q;
struct ath_node *an;
struct ath_atx_ac *ac;
struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
u16 seq_start;
u16 seq_next;
u16 baw_size;
int tidno;
int baw_head; /* first un-acked tx buffer */
int baw_tail; /* next unused tx buffer slot */
int sched;
int paused;
u8 state;
};
struct ath_node {
struct ath_common *common;
struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC];
u16 maxampdu;
u8 mpdudensity;
int last_rssi;
};
int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rx_status,
bool *decrypt_error);
void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
struct sk_buff *skb,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rxs,
bool decrypt_error);

View File

@ -3710,6 +3710,21 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
}
EXPORT_SYMBOL(ath9k_hw_set_tsfadjust);
/*
* Extend 15-bit time stamp from rx descriptor to
* a full 64-bit TSF using the current h/w TSF.
*/
u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp)
{
u64 tsf;
tsf = ath9k_hw_gettsf64(ah);
if ((tsf & 0x7fff) < rstamp)
tsf -= 0x8000;
return (tsf & ~0x7fff) | rstamp;
}
EXPORT_SYMBOL(ath9k_hw_extend_tsf);
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
{
if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {

View File

@ -432,7 +432,7 @@ struct ath9k_hw_version {
* Using de Bruijin sequence to to look up 1's index in a 32 bit number
* debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
*/
#define debruijn32 0x077CB531UL
#define debruijn32 0x077CB531U
struct ath_gen_timer_configuration {
u32 next_addr;
@ -689,6 +689,7 @@ u64 ath9k_hw_gettsf64(struct ath_hw *ah);
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
void ath9k_hw_reset_tsf(struct ath_hw *ah);
void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting);
u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp);
bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
void ath9k_hw_set11nmac2040(struct ath_hw *ah);
void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);

View File

@ -405,34 +405,34 @@ static void ath_ani_calibrate(unsigned long data)
ath9k_ps_wakeup(sc);
/* Long calibration runs independently of short calibration. */
if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
longcal = true;
ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
sc->ani.longcal_timer = timestamp;
common->ani.longcal_timer = timestamp;
}
/* Short calibration applies only while caldone is false */
if (!sc->ani.caldone) {
if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) {
if (!common->ani.caldone) {
if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
shortcal = true;
ath_print(common, ATH_DBG_ANI,
"shortcal @%lu\n", jiffies);
sc->ani.shortcal_timer = timestamp;
sc->ani.resetcal_timer = timestamp;
common->ani.shortcal_timer = timestamp;
common->ani.resetcal_timer = timestamp;
}
} else {
if ((timestamp - sc->ani.resetcal_timer) >=
if ((timestamp - common->ani.resetcal_timer) >=
ATH_RESTART_CALINTERVAL) {
sc->ani.caldone = ath9k_hw_reset_calvalid(ah);
if (sc->ani.caldone)
sc->ani.resetcal_timer = timestamp;
common->ani.caldone = ath9k_hw_reset_calvalid(ah);
if (common->ani.caldone)
common->ani.resetcal_timer = timestamp;
}
}
/* Verify whether we must check ANI */
if ((timestamp - sc->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
aniflag = true;
sc->ani.checkani_timer = timestamp;
common->ani.checkani_timer = timestamp;
}
/* Skip all processing if there's nothing to do. */
@ -443,21 +443,21 @@ static void ath_ani_calibrate(unsigned long data)
/* Perform calibration if necessary */
if (longcal || shortcal) {
sc->ani.caldone =
common->ani.caldone =
ath9k_hw_calibrate(ah,
ah->curchan,
common->rx_chainmask,
longcal);
if (longcal)
sc->ani.noise_floor = ath9k_hw_getchan_noise(ah,
common->ani.noise_floor = ath9k_hw_getchan_noise(ah,
ah->curchan);
ath_print(common, ATH_DBG_ANI,
" calibrate chan %u/%x nf: %d\n",
ah->curchan->channel,
ah->curchan->channelFlags,
sc->ani.noise_floor);
common->ani.noise_floor);
}
}
@ -473,21 +473,21 @@ set_timer:
cal_interval = ATH_LONG_CALINTERVAL;
if (sc->sc_ah->config.enable_ani)
cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
if (!sc->ani.caldone)
if (!common->ani.caldone)
cal_interval = min(cal_interval, (u32)short_cal_interval);
mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
}
static void ath_start_ani(struct ath_softc *sc)
static void ath_start_ani(struct ath_common *common)
{
unsigned long timestamp = jiffies_to_msecs(jiffies);
sc->ani.longcal_timer = timestamp;
sc->ani.shortcal_timer = timestamp;
sc->ani.checkani_timer = timestamp;
common->ani.longcal_timer = timestamp;
common->ani.shortcal_timer = timestamp;
common->ani.checkani_timer = timestamp;
mod_timer(&sc->ani.timer,
mod_timer(&common->ani.timer,
jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
}
@ -733,10 +733,11 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
return chanmode;
}
static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
struct ath9k_keyval *hk, const u8 *addr,
bool authenticator)
{
struct ath_hw *ah = common->ah;
const u8 *key_rxmic;
const u8 *key_txmic;
@ -756,42 +757,42 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
}
return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr);
return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
}
if (!sc->splitmic) {
if (!common->splitmic) {
/* TX and RX keys share the same key cache entry. */
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr);
return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
}
/* Separate key cache entries for TX and RX */
/* TX key goes at first index, RX key at +32. */
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) {
if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) {
/* TX MIC entry failed. No need to proceed further */
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
ath_print(common, ATH_DBG_FATAL,
"Setting TX MIC Key Failed\n");
return 0;
}
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
/* XXX delete tx key on failure? */
return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix + 32, hk, addr);
return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr);
}
static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc)
static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
{
int i;
for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) {
if (test_bit(i, sc->keymap) ||
test_bit(i + 64, sc->keymap))
for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
if (test_bit(i, common->keymap) ||
test_bit(i + 64, common->keymap))
continue; /* At least one part of TKIP key allocated */
if (sc->splitmic &&
(test_bit(i + 32, sc->keymap) ||
test_bit(i + 64 + 32, sc->keymap)))
if (common->splitmic &&
(test_bit(i + 32, common->keymap) ||
test_bit(i + 64 + 32, common->keymap)))
continue; /* At least one part of TKIP key allocated */
/* Found a free slot for a TKIP key */
@ -800,60 +801,60 @@ static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc)
return -1;
}
static int ath_reserve_key_cache_slot(struct ath_softc *sc)
static int ath_reserve_key_cache_slot(struct ath_common *common)
{
int i;
/* First, try to find slots that would not be available for TKIP. */
if (sc->splitmic) {
for (i = IEEE80211_WEP_NKID; i < sc->keymax / 4; i++) {
if (!test_bit(i, sc->keymap) &&
(test_bit(i + 32, sc->keymap) ||
test_bit(i + 64, sc->keymap) ||
test_bit(i + 64 + 32, sc->keymap)))
if (common->splitmic) {
for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
if (!test_bit(i, common->keymap) &&
(test_bit(i + 32, common->keymap) ||
test_bit(i + 64, common->keymap) ||
test_bit(i + 64 + 32, common->keymap)))
return i;
if (!test_bit(i + 32, sc->keymap) &&
(test_bit(i, sc->keymap) ||
test_bit(i + 64, sc->keymap) ||
test_bit(i + 64 + 32, sc->keymap)))
if (!test_bit(i + 32, common->keymap) &&
(test_bit(i, common->keymap) ||
test_bit(i + 64, common->keymap) ||
test_bit(i + 64 + 32, common->keymap)))
return i + 32;
if (!test_bit(i + 64, sc->keymap) &&
(test_bit(i , sc->keymap) ||
test_bit(i + 32, sc->keymap) ||
test_bit(i + 64 + 32, sc->keymap)))
if (!test_bit(i + 64, common->keymap) &&
(test_bit(i , common->keymap) ||
test_bit(i + 32, common->keymap) ||
test_bit(i + 64 + 32, common->keymap)))
return i + 64;
if (!test_bit(i + 64 + 32, sc->keymap) &&
(test_bit(i, sc->keymap) ||
test_bit(i + 32, sc->keymap) ||
test_bit(i + 64, sc->keymap)))
if (!test_bit(i + 64 + 32, common->keymap) &&
(test_bit(i, common->keymap) ||
test_bit(i + 32, common->keymap) ||
test_bit(i + 64, common->keymap)))
return i + 64 + 32;
}
} else {
for (i = IEEE80211_WEP_NKID; i < sc->keymax / 2; i++) {
if (!test_bit(i, sc->keymap) &&
test_bit(i + 64, sc->keymap))
for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
if (!test_bit(i, common->keymap) &&
test_bit(i + 64, common->keymap))
return i;
if (test_bit(i, sc->keymap) &&
!test_bit(i + 64, sc->keymap))
if (test_bit(i, common->keymap) &&
!test_bit(i + 64, common->keymap))
return i + 64;
}
}
/* No partially used TKIP slots, pick any available slot */
for (i = IEEE80211_WEP_NKID; i < sc->keymax; i++) {
for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {
/* Do not allow slots that could be needed for TKIP group keys
* to be used. This limitation could be removed if we know that
* TKIP will not be used. */
if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
continue;
if (sc->splitmic) {
if (common->splitmic) {
if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
continue;
if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
continue;
}
if (!test_bit(i, sc->keymap))
if (!test_bit(i, common->keymap))
return i; /* Found a free slot for a key */
}
@ -861,11 +862,12 @@ static int ath_reserve_key_cache_slot(struct ath_softc *sc)
return -1;
}
static int ath_key_config(struct ath_softc *sc,
static int ath_key_config(struct ath_common *common,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct ath_hw *ah = common->ah;
struct ath9k_keyval hk;
const u8 *mac = NULL;
int ret = 0;
@ -911,48 +913,50 @@ static int ath_key_config(struct ath_softc *sc,
mac = sta->addr;
if (key->alg == ALG_TKIP)
idx = ath_reserve_key_cache_slot_tkip(sc);
idx = ath_reserve_key_cache_slot_tkip(common);
else
idx = ath_reserve_key_cache_slot(sc);
idx = ath_reserve_key_cache_slot(common);
if (idx < 0)
return -ENOSPC; /* no free key cache entries */
}
if (key->alg == ALG_TKIP)
ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac,
ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
vif->type == NL80211_IFTYPE_AP);
else
ret = ath9k_hw_set_keycache_entry(sc->sc_ah, idx, &hk, mac);
ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac);
if (!ret)
return -EIO;
set_bit(idx, sc->keymap);
set_bit(idx, common->keymap);
if (key->alg == ALG_TKIP) {
set_bit(idx + 64, sc->keymap);
if (sc->splitmic) {
set_bit(idx + 32, sc->keymap);
set_bit(idx + 64 + 32, sc->keymap);
set_bit(idx + 64, common->keymap);
if (common->splitmic) {
set_bit(idx + 32, common->keymap);
set_bit(idx + 64 + 32, common->keymap);
}
}
return idx;
}
static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
{
ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx);
struct ath_hw *ah = common->ah;
ath9k_hw_keyreset(ah, key->hw_key_idx);
if (key->hw_key_idx < IEEE80211_WEP_NKID)
return;
clear_bit(key->hw_key_idx, sc->keymap);
clear_bit(key->hw_key_idx, common->keymap);
if (key->alg != ALG_TKIP)
return;
clear_bit(key->hw_key_idx + 64, sc->keymap);
if (sc->splitmic) {
clear_bit(key->hw_key_idx + 32, sc->keymap);
clear_bit(key->hw_key_idx + 64 + 32, sc->keymap);
clear_bit(key->hw_key_idx + 64, common->keymap);
if (common->splitmic) {
clear_bit(key->hw_key_idx + 32, common->keymap);
clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
}
}
@ -1023,12 +1027,12 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
/* Reset rssi stats */
sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
ath_start_ani(sc);
ath_start_ani(common);
} else {
ath_print(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
common->curaid = 0;
/* Stop ANI */
del_timer_sync(&sc->ani.timer);
del_timer_sync(&common->ani.timer);
}
}
@ -1200,11 +1204,11 @@ fail:
ath_deinit_leds(sc);
}
void ath_radio_enable(struct ath_softc *sc)
void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_channel *channel = sc->hw->conf.channel;
struct ieee80211_channel *channel = hw->conf.channel;
int r;
ath9k_ps_wakeup(sc);
@ -1241,18 +1245,18 @@ void ath_radio_enable(struct ath_softc *sc)
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(ah, ah->led_pin, 0);
ieee80211_wake_queues(sc->hw);
ieee80211_wake_queues(hw);
ath9k_ps_restore(sc);
}
void ath_radio_disable(struct ath_softc *sc)
void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
{
struct ath_hw *ah = sc->sc_ah;
struct ieee80211_channel *channel = sc->hw->conf.channel;
struct ieee80211_channel *channel = hw->conf.channel;
int r;
ath9k_ps_wakeup(sc);
ieee80211_stop_queues(sc->hw);
ieee80211_stop_queues(hw);
/* Disable LED */
ath9k_hw_set_gpio(ah, ah->led_pin, 1);
@ -1266,7 +1270,7 @@ void ath_radio_disable(struct ath_softc *sc)
ath_flushrecv(sc); /* flush recv queue */
if (!ah->curchan)
ah->curchan = ath_get_curchannel(sc, sc->hw);
ah->curchan = ath_get_curchannel(sc, hw);
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, ah->curchan, false);
@ -1679,19 +1683,19 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
}
/* Get the hardware key cache size. */
sc->keymax = ah->caps.keycache_size;
if (sc->keymax > ATH_KEYMAX) {
common->keymax = ah->caps.keycache_size;
if (common->keymax > ATH_KEYMAX) {
ath_print(common, ATH_DBG_ANY,
"Warning, using only %u entries in %u key cache\n",
ATH_KEYMAX, sc->keymax);
sc->keymax = ATH_KEYMAX;
ATH_KEYMAX, common->keymax);
common->keymax = ATH_KEYMAX;
}
/*
* Reset the key cache since some parts do not
* reset the contents on initial power up.
*/
for (i = 0; i < sc->keymax; i++)
for (i = 0; i < common->keymax; i++)
ath9k_hw_keyreset(ah, (u16) i);
/* default to MONITOR mode */
@ -1761,8 +1765,8 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
/* Initializes the noise floor to a reasonable default value.
* Later on this will be updated during ANI processing. */
sc->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
setup_timer(&sc->ani.timer, ath_ani_calibrate, (unsigned long)sc);
common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR;
setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
ATH9K_CIPHER_TKIP, NULL)) {
@ -1788,7 +1792,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
ATH9K_CIPHER_MIC, NULL)
&& ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
0, NULL))
sc->splitmic = 1;
common->splitmic = 1;
/* turn on mcast key search if possible */
if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
@ -2634,7 +2638,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
if (conf->type == NL80211_IFTYPE_AP ||
conf->type == NL80211_IFTYPE_ADHOC ||
conf->type == NL80211_IFTYPE_MONITOR)
ath_start_ani(sc);
ath_start_ani(common);
out:
mutex_unlock(&sc->mutex);
@ -2655,7 +2659,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
/* Stop ANI */
del_timer_sync(&sc->ani.timer);
del_timer_sync(&common->ani.timer);
/* Reclaim beacon resources */
if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
@ -2688,23 +2692,38 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_conf *conf = &hw->conf;
struct ath_hw *ah = sc->sc_ah;
bool all_wiphys_idle = false, disable_radio = false;
bool disable_radio;
mutex_lock(&sc->mutex);
/* Leave this as the first check */
/*
* Leave this as the first check because we need to turn on the
* radio if it was disabled before prior to processing the rest
* of the changes. Likewise we must only disable the radio towards
* the end.
*/
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
bool enable_radio;
bool all_wiphys_idle;
bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
spin_lock_bh(&sc->wiphy_lock);
all_wiphys_idle = ath9k_all_wiphys_idle(sc);
ath9k_set_wiphy_idle(aphy, idle);
if (!idle && all_wiphys_idle)
enable_radio = true;
/*
* After we unlock here its possible another wiphy
* can be re-renabled so to account for that we will
* only disable the radio toward the end of this routine
* if by then all wiphys are still idle.
*/
spin_unlock_bh(&sc->wiphy_lock);
if (conf->flags & IEEE80211_CONF_IDLE){
if (all_wiphys_idle)
disable_radio = true;
}
else if (all_wiphys_idle) {
ath_radio_enable(sc);
if (enable_radio) {
ath_radio_enable(sc, hw);
ath_print(common, ATH_DBG_CONFIG,
"not-idle: enabling radio\n");
}
@ -2779,9 +2798,13 @@ skip_chan_change:
if (changed & IEEE80211_CONF_CHANGE_POWER)
sc->config.txpowlimit = 2 * conf->power_level;
spin_lock_bh(&sc->wiphy_lock);
disable_radio = ath9k_all_wiphys_idle(sc);
spin_unlock_bh(&sc->wiphy_lock);
if (disable_radio) {
ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
ath_radio_disable(sc);
ath_radio_disable(sc, hw);
}
mutex_unlock(&sc->mutex);
@ -2898,7 +2921,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
switch (cmd) {
case SET_KEY:
ret = ath_key_config(sc, vif, sta, key);
ret = ath_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */
@ -2911,7 +2934,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
}
break;
case DISABLE_KEY:
ath_key_delete(sc, key);
ath_key_delete(common, key);
break;
default:
ret = -EINVAL;

View File

@ -19,6 +19,8 @@
#ifndef RC_H
#define RC_H
#include "hw.h"
struct ath_softc;
#define ATH_RATE_MAX 30

View File

@ -48,6 +48,7 @@ static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc,
static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_desc *ds;
struct sk_buff *skb;
@ -62,11 +63,13 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
BUG_ON(skb == NULL);
ds->ds_vdata = skb->data;
/* setup rx descriptors. The rx.bufsize here tells the harware
/*
* setup rx descriptors. The rx_bufsize here tells the hardware
* how much data it can DMA to us and that we are prepared
* to process */
* to process
*/
ath9k_hw_setuprxdesc(ah, ds,
sc->rx.bufsize,
common->rx_bufsize,
0);
if (sc->rx.rxlink == NULL)
@ -86,190 +89,6 @@ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
sc->rx.rxotherant = 0;
}
/*
* Extend 15-bit time stamp from rx descriptor to
* a full 64-bit TSF using the current h/w TSF.
*/
static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
{
u64 tsf;
tsf = ath9k_hw_gettsf64(sc->sc_ah);
if ((tsf & 0x7fff) < rstamp)
tsf -= 0x8000;
return (tsf & ~0x7fff) | rstamp;
}
/*
* For Decrypt or Demic errors, we only mark packet status here and always push
* up the frame up to let mac80211 handle the actual error case, be it no
* decryption key or real decryption error. This let us keep statistics there.
*/
static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
struct ieee80211_rx_status *rx_status, bool *decrypt_error,
struct ath_softc *sc)
{
struct ieee80211_hdr *hdr;
u8 ratecode;
__le16 fc;
struct ieee80211_hw *hw;
struct ieee80211_sta *sta;
struct ath_node *an;
int last_rssi = ATH_RSSI_DUMMY_MARKER;
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
hw = ath_get_virt_hw(sc, hdr);
if (ds->ds_rxstat.rs_more) {
/*
* Frame spans multiple descriptors; this cannot happen yet
* as we don't support jumbograms. If not in monitor mode,
* discard the frame. Enable this if you want to see
* error frames in Monitor mode.
*/
if (sc->sc_ah->opmode != NL80211_IFTYPE_MONITOR)
goto rx_next;
} else if (ds->ds_rxstat.rs_status != 0) {
if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY)
goto rx_next;
if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
*decrypt_error = true;
} else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
if (ieee80211_is_ctl(fc))
/*
* Sometimes, we get invalid
* MIC failures on valid control frames.
* Remove these mic errors.
*/
ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC;
else
rx_status->flag |= RX_FLAG_MMIC_ERROR;
}
/*
* Reject error frames with the exception of
* decryption and MIC failures. For monitor mode,
* we also ignore the CRC error.
*/
if (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR) {
if (ds->ds_rxstat.rs_status &
~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
ATH9K_RXERR_CRC))
goto rx_next;
} else {
if (ds->ds_rxstat.rs_status &
~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
goto rx_next;
}
}
}
ratecode = ds->ds_rxstat.rs_rate;
if (ratecode & 0x80) {
/* HT rate */
rx_status->flag |= RX_FLAG_HT;
if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040)
rx_status->flag |= RX_FLAG_40MHZ;
if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
rx_status->flag |= RX_FLAG_SHORT_GI;
rx_status->rate_idx = ratecode & 0x7f;
} else {
int i = 0, cur_band, n_rates;
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;
}
}
}
rcu_read_lock();
/* XXX: use ieee80211_find_sta! */
sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr2);
if (sta) {
an = (struct ath_node *) sta->drv_priv;
if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
!ds->ds_rxstat.rs_moreaggr)
ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
last_rssi = an->last_rssi;
}
rcu_read_unlock();
if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi,
ATH_RSSI_EP_MULTIPLIER);
if (ds->ds_rxstat.rs_rssi < 0)
ds->ds_rxstat.rs_rssi = 0;
else if (ds->ds_rxstat.rs_rssi > 127)
ds->ds_rxstat.rs_rssi = 127;
/* Update Beacon RSSI, this is used by ANI. */
if (ieee80211_is_beacon(fc))
sc->sc_ah->stats.avgbrssi = ds->ds_rxstat.rs_rssi;
rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
rx_status->band = hw->conf.channel->band;
rx_status->freq = hw->conf.channel->center_freq;
rx_status->noise = sc->ani.noise_floor;
rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi;
rx_status->antenna = ds->ds_rxstat.rs_antenna;
/*
* Theory for reporting quality:
*
* At a hardware RSSI of 45 you will be able to use MCS 7 reliably.
* At a hardware RSSI of 45 you will be able to use MCS 15 reliably.
* At a hardware RSSI of 35 you should be able use 54 Mbps reliably.
*
* MCS 7 is the highets MCS index usable by a 1-stream device.
* MCS 15 is the highest MCS index usable by a 2-stream device.
*
* All ath9k devices are either 1-stream or 2-stream.
*
* How many bars you see is derived from the qual reporting.
*
* A more elaborate scheme can be used here but it requires tables
* of SNR/throughput for each possible mode used. For the MCS table
* you can refer to the wireless wiki:
*
* http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
*
*/
if (conf_is_ht(&hw->conf))
rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
else
rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 35;
/* rssi can be more than 45 though, anything above that
* should be considered at 100% */
if (rx_status->qual > 100)
rx_status->qual = 100;
rx_status->flag |= RX_FLAG_TSFT;
return 1;
rx_next:
return 0;
}
static void ath_opmode_init(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
@ -307,11 +126,11 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
sc->sc_flags &= ~SC_OP_RXFLUSH;
spin_lock_init(&sc->rx.rxbuflock);
sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
min(common->cachelsz, (u16)64));
common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
min(common->cachelsz, (u16)64));
ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
common->cachelsz, sc->rx.bufsize);
common->cachelsz, common->rx_bufsize);
/* Initialize rx descriptors */
@ -324,7 +143,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
}
list_for_each_entry(bf, &sc->rx.rxbuf, list) {
skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_KERNEL);
skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL);
if (skb == NULL) {
error = -ENOMEM;
goto err;
@ -332,7 +151,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
bf->bf_mpdu = skb;
bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
sc->rx.bufsize,
common->rx_bufsize,
DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(sc->dev,
bf->bf_buf_addr))) {
@ -356,6 +175,8 @@ err:
void ath_rx_cleanup(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct sk_buff *skb;
struct ath_buf *bf;
@ -363,7 +184,7 @@ void ath_rx_cleanup(struct ath_softc *sc)
skb = bf->bf_mpdu;
if (skb) {
dma_unmap_single(sc->dev, bf->bf_buf_addr,
sc->rx.bufsize, DMA_FROM_DEVICE);
common->rx_bufsize, DMA_FROM_DEVICE);
dev_kfree_skb(skb);
}
}
@ -616,8 +437,9 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
}
}
static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status)
static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw,
struct ath_softc *sc, struct sk_buff *skb,
struct ieee80211_rx_status *rxs)
{
struct ieee80211_hdr *hdr;
@ -637,19 +459,14 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
if (aphy == NULL)
continue;
nskb = skb_copy(skb, GFP_ATOMIC);
if (nskb) {
memcpy(IEEE80211_SKB_RXCB(nskb), rx_status,
sizeof(*rx_status));
ieee80211_rx(aphy->hw, nskb);
}
if (!nskb)
continue;
ieee80211_rx(aphy->hw, nskb);
}
memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
ieee80211_rx(sc->hw, skb);
} else {
} else
/* Deliver unicast frames based on receiver address */
memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
ieee80211_rx(ath_get_virt_hw(sc, hdr), skb);
}
ieee80211_rx(hw, skb);
}
int ath_rx_tasklet(struct ath_softc *sc, int flush)
@ -660,15 +477,20 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
struct ath_buf *bf;
struct ath_desc *ds;
struct ath_rx_status *rx_stats;
struct sk_buff *skb = NULL, *requeue_skb;
struct ieee80211_rx_status rx_status;
struct ieee80211_rx_status *rxs;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
/*
* The hw can techncically differ from common->hw when using ath9k
* virtual wiphy so to account for that we iterate over the active
* wiphys and find the appropriate wiphy and therefore hw.
*/
struct ieee80211_hw *hw = NULL;
struct ieee80211_hdr *hdr;
int hdrlen, padsize, retval;
int retval;
bool decrypt_error = false;
u8 keyix;
__le16 fc;
spin_lock_bh(&sc->rx.rxbuflock);
@ -740,9 +562,15 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
* 2. requeueing the same buffer to h/w
*/
dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
sc->rx.bufsize,
common->rx_bufsize,
DMA_FROM_DEVICE);
hdr = (struct ieee80211_hdr *) skb->data;
rxs = IEEE80211_SKB_RXCB(skb);
hw = ath_get_virt_hw(sc, hdr);
rx_stats = &ds->ds_rxstat;
/*
* If we're asked to flush receive queue, directly
* chain it back at the queue without processing it.
@ -750,19 +578,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
if (flush)
goto requeue;
if (!ds->ds_rxstat.rs_datalen)
goto requeue;
/* The status portion of the descriptor could get corrupted. */
if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen)
goto requeue;
if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc))
retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, rx_stats,
rxs, &decrypt_error);
if (retval)
goto requeue;
/* Ensure we always have an skb to requeue once we are done
* processing the current buffer's skb */
requeue_skb = ath_rxbuf_alloc(common, sc->rx.bufsize, GFP_ATOMIC);
requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC);
/* If there is no memory we ignore the current RX'd frame,
* tell hardware it can give us a new frame using the old
@ -773,60 +596,26 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
/* Unmap the frame */
dma_unmap_single(sc->dev, bf->bf_buf_addr,
sc->rx.bufsize,
common->rx_bufsize,
DMA_FROM_DEVICE);
skb_put(skb, ds->ds_rxstat.rs_datalen);
skb_put(skb, rx_stats->rs_datalen);
/* see if any padding is done by the hw and remove it */
hdr = (struct ieee80211_hdr *)skb->data;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
fc = hdr->frame_control;
/* The MAC header is padded to have 32-bit boundary if the
* packet payload is non-zero. The general calculation for
* padsize would take into account odd header lengths:
* padsize = (4 - hdrlen % 4) % 4; However, since only
* even-length headers are used, padding can only be 0 or 2
* bytes and we can optimize this a bit. In addition, we must
* not try to remove padding from short control frames that do
* not have payload. */
padsize = hdrlen & 3;
if (padsize && hdrlen >= 24) {
memmove(skb->data + padsize, skb->data, hdrlen);
skb_pull(skb, padsize);
}
keyix = ds->ds_rxstat.rs_keyix;
if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
rx_status.flag |= RX_FLAG_DECRYPTED;
} else if (ieee80211_has_protected(fc)
&& !decrypt_error && skb->len >= hdrlen + 4) {
keyix = skb->data[hdrlen + 3] >> 6;
if (test_bit(keyix, sc->keymap))
rx_status.flag |= RX_FLAG_DECRYPTED;
}
if (ah->sw_mgmt_crypto &&
(rx_status.flag & RX_FLAG_DECRYPTED) &&
ieee80211_is_mgmt(fc)) {
/* Use software decrypt for management frames. */
rx_status.flag &= ~RX_FLAG_DECRYPTED;
}
ath9k_cmn_rx_skb_postprocess(common, skb, rx_stats,
rxs, decrypt_error);
/* We will now give hardware our shiny new allocated skb */
bf->bf_mpdu = requeue_skb;
bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data,
sc->rx.bufsize,
DMA_FROM_DEVICE);
common->rx_bufsize,
DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(sc->dev,
bf->bf_buf_addr))) {
dev_kfree_skb_any(requeue_skb);
bf->bf_mpdu = NULL;
ath_print(common, ATH_DBG_FATAL,
"dma_mapping_error() on RX\n");
ath_rx_send_to_mac80211(sc, skb, &rx_status);
ath_rx_send_to_mac80211(hw, sc, skb, rxs);
break;
}
bf->bf_dmacontext = bf->bf_buf_addr;
@ -837,7 +626,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
*/
if (sc->rx.defant != ds->ds_rxstat.rs_antenna) {
if (++sc->rx.rxotherant >= 3)
ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna);
ath_setdefantenna(sc, rx_stats->rs_antenna);
} else {
sc->rx.rxotherant = 0;
}
@ -847,7 +636,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
SC_OP_WAIT_FOR_PSPOLL_DATA)))
ath_rx_ps(sc, skb);
ath_rx_send_to_mac80211(sc, skb, &rx_status);
ath_rx_send_to_mac80211(hw, sc, skb, rxs);
requeue:
list_move_tail(&bf->list, &sc->rx.rxbuf);

View File

@ -971,10 +971,10 @@ enum {
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S 4
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7
#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00000400
#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 10
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12
#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00001000
#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 1
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15
#define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000

View File

@ -298,6 +298,7 @@ static void ath9k_wiphy_unpause_channel(struct ath_softc *sc)
void ath9k_wiphy_chan_work(struct work_struct *work)
{
struct ath_softc *sc = container_of(work, struct ath_softc, chan_work);
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_wiphy *aphy = sc->next_wiphy;
if (aphy == NULL)
@ -313,6 +314,10 @@ void ath9k_wiphy_chan_work(struct work_struct *work)
/* XXX: remove me eventually */
ath9k_update_ichannel(sc, aphy->hw,
&sc->sc_ah->channels[sc->chan_idx]);
/* sync hw configuration for hw code */
common->hw = aphy->hw;
ath_update_chainmask(sc, sc->chan_is_ht);
if (ath_set_channel(sc, aphy->hw,
&sc->sc_ah->channels[sc->chan_idx]) < 0) {
@ -521,8 +526,9 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy)
* frame being completed)
*/
spin_unlock_bh(&sc->wiphy_lock);
ath_radio_disable(sc);
ath_radio_enable(sc);
ath_radio_disable(sc, aphy->hw);
ath_radio_enable(sc, aphy->hw);
/* Only the primary wiphy hw is used for queuing work */
ieee80211_queue_work(aphy->sc->hw,
&aphy->sc->chan_work);
return -EBUSY; /* previous select still in progress */
@ -668,15 +674,78 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
bool ath9k_all_wiphys_idle(struct ath_softc *sc)
{
unsigned int i;
if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
if (!sc->pri_wiphy->idle)
return false;
}
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
if (!aphy)
continue;
if (aphy->state != ATH_WIPHY_INACTIVE)
if (!aphy->idle)
return false;
}
return true;
}
/* caller must hold wiphy_lock */
void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle)
{
struct ath_softc *sc = aphy->sc;
aphy->idle = idle;
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
"Marking %s as %s\n",
wiphy_name(aphy->hw->wiphy),
idle ? "idle" : "not-idle");
}
/* Only bother starting a queue on an active virtual wiphy */
void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue)
{
struct ieee80211_hw *hw = sc->pri_wiphy->hw;
unsigned int i;
spin_lock_bh(&sc->wiphy_lock);
/* Start the primary wiphy */
if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) {
ieee80211_wake_queue(hw, skb_queue);
goto unlock;
}
/* Now start the secondary wiphy queues */
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
if (!aphy)
continue;
if (aphy->state != ATH_WIPHY_ACTIVE)
continue;
hw = aphy->hw;
ieee80211_wake_queue(hw, skb_queue);
break;
}
unlock:
spin_unlock_bh(&sc->wiphy_lock);
}
/* Go ahead and propagate information to all virtual wiphys, it won't hurt */
void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue)
{
struct ieee80211_hw *hw = sc->pri_wiphy->hw;
unsigned int i;
spin_lock_bh(&sc->wiphy_lock);
/* Stop the primary wiphy */
ieee80211_stop_queue(hw, skb_queue);
/* Now stop the secondary wiphy queues */
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
if (!aphy)
continue;
hw = aphy->hw;
ieee80211_stop_queue(hw, skb_queue);
}
spin_unlock_bh(&sc->wiphy_lock);
}

View File

@ -267,7 +267,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_node *an = NULL;
struct sk_buff *skb;
struct ieee80211_sta *sta;
struct ieee80211_hw *hw;
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info;
struct ath_tx_info_priv *tx_info_priv;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
struct ath_desc *ds = bf_last->bf_desc;
@ -280,10 +283,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
tx_info = IEEE80211_SKB_CB(skb);
tx_info_priv = (struct ath_tx_info_priv *) tx_info->rate_driver_data[0];
hw = tx_info_priv->aphy->hw;
rcu_read_lock();
/* XXX: use ieee80211_find_sta! */
sta = ieee80211_find_sta_by_hw(sc->hw, hdr->addr1);
sta = ieee80211_find_sta_by_hw(hw, hdr->addr1);
if (!sta) {
rcu_read_unlock();
return;
@ -908,9 +915,10 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
{
struct ath_txq *txq = NULL;
u16 skb_queue = skb_get_queue_mapping(skb);
int qnum;
qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
qnum = ath_get_hal_qnum(skb_queue, sc);
txq = &sc->tx.txq[qnum];
spin_lock_bh(&txq->axq_lock);
@ -919,7 +927,7 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT,
"TX queue: %d is full, depth: %d\n",
qnum, txq->axq_depth);
ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb));
ath_mac80211_stop_queue(sc, skb_queue);
txq->stopped = 1;
spin_unlock_bh(&txq->axq_lock);
return NULL;
@ -1569,7 +1577,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
if (conf_is_ht(&sc->hw->conf) && !is_pae(skb))
if (conf_is_ht(&hw->conf) && !is_pae(skb))
bf->bf_state.bf_type |= BUF_HT;
bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
@ -1698,8 +1706,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
* on the queue */
spin_lock_bh(&txq->axq_lock);
if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) {
ieee80211_stop_queue(sc->hw,
skb_get_queue_mapping(skb));
ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
txq->stopped = 1;
}
spin_unlock_bh(&txq->axq_lock);
@ -1939,7 +1946,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) {
qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
if (qnum != -1) {
ieee80211_wake_queue(sc->hw, qnum);
ath_mac80211_start_queue(sc, qnum);
txq->stopped = 0;
}
}

View File

@ -99,6 +99,22 @@ static struct {
{ ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" },
{ ATMEL_FW_TYPE_NONE, NULL, NULL }
};
MODULE_FIRMWARE("atmel_at76c502-wpa.bin");
MODULE_FIRMWARE("atmel_at76c502.bin");
MODULE_FIRMWARE("atmel_at76c502d-wpa.bin");
MODULE_FIRMWARE("atmel_at76c502d.bin");
MODULE_FIRMWARE("atmel_at76c502e-wpa.bin");
MODULE_FIRMWARE("atmel_at76c502e.bin");
MODULE_FIRMWARE("atmel_at76c502_3com-wpa.bin");
MODULE_FIRMWARE("atmel_at76c502_3com.bin");
MODULE_FIRMWARE("atmel_at76c504-wpa.bin");
MODULE_FIRMWARE("atmel_at76c504.bin");
MODULE_FIRMWARE("atmel_at76c504_2958-wpa.bin");
MODULE_FIRMWARE("atmel_at76c504_2958.bin");
MODULE_FIRMWARE("atmel_at76c504a_2958-wpa.bin");
MODULE_FIRMWARE("atmel_at76c504a_2958.bin");
MODULE_FIRMWARE("atmel_at76c506-wpa.bin");
MODULE_FIRMWARE("atmel_at76c506.bin");
#define MAX_SSID_LENGTH 32
#define MGMT_JIFFIES (256 * HZ / 100)

View File

@ -1157,18 +1157,17 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
}
static int dma_tx_fragment(struct b43_dmaring *ring,
struct sk_buff **in_skb)
struct sk_buff *skb)
{
struct sk_buff *skb = *in_skb;
const struct b43_dma_ops *ops = ring->ops;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct b43_private_tx_info *priv_info = b43_get_priv_tx_info(info);
u8 *header;
int slot, old_top_slot, old_used_slots;
int err;
struct b43_dmadesc_generic *desc;
struct b43_dmadesc_meta *meta;
struct b43_dmadesc_meta *meta_hdr;
struct sk_buff *bounce_skb;
u16 cookie;
size_t hdrsize = b43_txhdr_size(ring->dev);
@ -1212,34 +1211,28 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
meta->skb = skb;
meta->is_last_fragment = 1;
priv_info->bouncebuffer = NULL;
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
/* create a bounce buffer in zone_dma on mapping failure. */
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb) {
priv_info->bouncebuffer = kmalloc(skb->len, GFP_ATOMIC | GFP_DMA);
if (!priv_info->bouncebuffer) {
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
err = -ENOMEM;
goto out_unmap_hdr;
}
memcpy(priv_info->bouncebuffer, skb->data, skb->len);
memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb));
bounce_skb->dev = skb->dev;
skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb));
info = IEEE80211_SKB_CB(bounce_skb);
dev_kfree_skb_any(skb);
skb = bounce_skb;
*in_skb = bounce_skb;
meta->skb = skb;
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
meta->dmaaddr = map_descbuffer(ring, priv_info->bouncebuffer, skb->len, 1);
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
kfree(priv_info->bouncebuffer);
priv_info->bouncebuffer = NULL;
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
err = -EIO;
goto out_free_bounce;
goto out_unmap_hdr;
}
}
@ -1256,8 +1249,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
ops->poke_tx(ring, next_slot(ring, slot));
return 0;
out_free_bounce:
dev_kfree_skb_any(skb);
out_unmap_hdr:
unmap_descbuffer(ring, meta_hdr->dmaaddr,
hdrsize, 1);
@ -1362,11 +1353,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
* static, so we don't need to store it per frame. */
ring->queue_prio = skb_get_queue_mapping(skb);
/* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing
* into the skb data or cb now. */
hdr = NULL;
info = NULL;
err = dma_tx_fragment(ring, &skb);
err = dma_tx_fragment(ring, skb);
if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key
* anymore and must not transmit it unencrypted. */
@ -1413,12 +1400,17 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
desc = ops->idx2desc(ring, slot, &meta);
if (meta->skb)
unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len,
1);
else
if (meta->skb) {
struct b43_private_tx_info *priv_info =
b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
kfree(priv_info->bouncebuffer);
priv_info->bouncebuffer = NULL;
} else {
unmap_descbuffer(ring, meta->dmaaddr,
b43_txhdr_size(dev), 1);
}
if (meta->is_last_fragment) {
struct ieee80211_tx_info *info;

View File

@ -761,7 +761,11 @@ data_ready:
rx_error:
if (err_msg)
b43dbg(q->dev->wl, "PIO RX error: %s\n", err_msg);
b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY);
if (q->rev >= 8)
b43_piorx_write32(q, B43_PIO8_RXCTL, B43_PIO8_RXCTL_DATARDY);
else
b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY);
return 1;
}

View File

@ -2,6 +2,8 @@
#define B43_XMIT_H_
#include "main.h"
#include <net/mac80211.h>
#define _b43_declare_plcp_hdr(size) \
struct b43_plcp_hdr##size { \
@ -332,4 +334,21 @@ static inline u8 b43_kidx_to_raw(struct b43_wldev *dev, u8 firmware_kidx)
return raw_kidx;
}
/* struct b43_private_tx_info - TX info private to b43.
* The structure is placed in (struct ieee80211_tx_info *)->rate_driver_data
*
* @bouncebuffer: DMA Bouncebuffer (if used)
*/
struct b43_private_tx_info {
void *bouncebuffer;
};
static inline struct b43_private_tx_info *
b43_get_priv_tx_info(struct ieee80211_tx_info *info)
{
BUILD_BUG_ON(sizeof(struct b43_private_tx_info) >
sizeof(info->rate_driver_data));
return (struct b43_private_tx_info *)info->rate_driver_data;
}
#endif /* B43_XMIT_H_ */

View File

@ -8462,6 +8462,12 @@ static int ipw2100_get_firmware(struct ipw2100_priv *priv,
return 0;
}
MODULE_FIRMWARE(IPW2100_FW_NAME("-i"));
#ifdef CONFIG_IPW2100_MONITOR
MODULE_FIRMWARE(IPW2100_FW_NAME("-p"));
#endif
MODULE_FIRMWARE(IPW2100_FW_NAME(""));
static void ipw2100_release_firmware(struct ipw2100_priv *priv,
struct ipw2100_fw *fw)
{

View File

@ -80,6 +80,11 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
MODULE_FIRMWARE("ipw2200-ibss.fw");
#ifdef CONFIG_IPW2200_MONITOR
MODULE_FIRMWARE("ipw2200-sniffer.fw");
#endif
MODULE_FIRMWARE("ipw2200-bss.fw");
static int cmdlog = 0;
static int debug = 0;

View File

@ -564,7 +564,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
return;
}
skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC);
if (!skb) {
IWL_ERR(priv, "alloc_skb failed\n");
return;
@ -575,6 +575,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
(struct ieee80211_hdr *)rxb_addr(rxb),
le32_to_cpu(rx_end->status), stats);
skb_reserve(skb, IWL_LINK_HDR_MAX);
skb_add_rx_frag(skb, 0, rxb->page,
(void *)rx_hdr->payload - (void *)pkt, len);

View File

@ -1449,14 +1449,14 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
if (is_ht40 &&
(priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
(priv->staging_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
ctrl_chan_high = 1;
cmd.band = band;
cmd.expect_beacon = 0;
cmd.channel = cpu_to_le16(channel);
cmd.rxon_flags = priv->active_rxon.flags;
cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
cmd.rxon_flags = priv->staging_rxon.flags;
cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
@ -1473,8 +1473,10 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
return rc;
}
rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
return rc;
priv->switch_rxon.channel = cpu_to_le16(channel);
priv->switch_rxon.switch_in_progress = true;
return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
}
/**
@ -2228,7 +2230,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
.num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
.mod_params = &iwl4965_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.valid_rx_ant = ANT_ABC,
.pll_cfg_val = 0,
.set_l0s = true,
.use_bsm = true,

View File

@ -661,9 +661,13 @@ int iwl5000_alive_notify(struct iwl_priv *priv)
iwl_txq_ctx_activate(priv, i);
iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
}
/* TODO - need to initialize those FIFOs inside the loop above,
* not only mark them as active */
iwl_txq_ctx_activate(priv, 4);
/*
* TODO - need to initialize these queues and map them to FIFOs
* in the loop above, not only mark them as active. We do this
* because we want the first aggregation queue to be queue #10,
* but do not use 8 or 9 otherwise yet.
*/
iwl_txq_ctx_activate(priv, 7);
iwl_txq_ctx_activate(priv, 8);
iwl_txq_ctx_activate(priv, 9);
@ -1387,8 +1391,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
priv->active_rxon.channel, channel);
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
cmd.channel = cpu_to_le16(channel);
cmd.rxon_flags = priv->active_rxon.flags;
cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
cmd.rxon_flags = priv->staging_rxon.flags;
cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
ch_info = iwl_get_channel_info(priv, priv->band, channel);
if (ch_info)
@ -1398,6 +1402,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
priv->active_rxon.channel, channel);
return -EFAULT;
}
priv->switch_rxon.channel = cpu_to_le16(channel);
priv->switch_rxon.switch_in_progress = true;
return iwl_send_cmd_sync(priv, &hcmd);
}

View File

@ -90,11 +90,7 @@ static void iwl6000_nic_config(struct iwl_priv *priv)
CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
/* no locking required for register write */
if (priv->cfg->pa_type == IWL_PA_HYBRID) {
/* 2x2 hybrid phy type */
iwl_write32(priv, CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB);
} else if (priv->cfg->pa_type == IWL_PA_INTERNAL) {
if (priv->cfg->pa_type == IWL_PA_INTERNAL) {
/* 2x2 IPA phy type */
iwl_write32(priv, CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA);
@ -166,9 +162,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_TX_IQ_PERD) |
BIT(IWL_CALIB_BASE_BAND);
return 0;
}
@ -188,8 +182,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
cmd.channel = cpu_to_le16(channel);
cmd.rxon_flags = priv->active_rxon.flags;
cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
cmd.rxon_flags = priv->staging_rxon.flags;
cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
ch_info = iwl_get_channel_info(priv, priv->band, channel);
if (ch_info)
@ -199,6 +193,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
priv->active_rxon.channel, channel);
return -EFAULT;
}
priv->switch_rxon.channel = cpu_to_le16(channel);
priv->switch_rxon.switch_in_progress = true;
return iwl_send_cmd_sync(priv, &hcmd);
}
@ -279,98 +275,6 @@ static struct iwl_ops iwl6050_ops = {
.led = &iwlagn_led_ops,
};
/*
* "h": Hybrid configuration, use both internal and external Power Amplifier
*/
struct iwl_cfg iwl6000h_2agn_cfg = {
.name = "6000 Series 2x2 AGN",
.fw_name_pre = IWL6000_FW_PRE,
.ucode_api_max = IWL6000_UCODE_API_MAX,
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.pll_cfg_val = 0,
.set_l0s = true,
.use_bsm = false,
.pa_type = IWL_PA_HYBRID,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
.use_rts_for_ht = true, /* use rts/cts protection */
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
};
struct iwl_cfg iwl6000h_2abg_cfg = {
.name = "6000 Series 2x2 ABG",
.fw_name_pre = IWL6000_FW_PRE,
.ucode_api_max = IWL6000_UCODE_API_MAX,
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
.ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.pll_cfg_val = 0,
.set_l0s = true,
.use_bsm = false,
.pa_type = IWL_PA_HYBRID,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
};
struct iwl_cfg iwl6000h_2bg_cfg = {
.name = "6000 Series 2x2 BG",
.fw_name_pre = IWL6000_FW_PRE,
.ucode_api_max = IWL6000_UCODE_API_MAX,
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_G,
.ops = &iwl6000_ops,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.num_of_queues = IWL50_NUM_QUEUES,
.num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.pll_cfg_val = 0,
.set_l0s = true,
.use_bsm = false,
.pa_type = IWL_PA_HYBRID,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.ht_greenfield_support = true,
.led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.supports_idle = true,
.adv_thermal_throttle = true,
.support_ct_kill_exit = true,
};
/*
* "i": Internal configuration, use internal Power Amplifier
*/

View File

@ -122,6 +122,17 @@ int iwl_commit_rxon(struct iwl_priv *priv)
return -EINVAL;
}
/*
* receive commit_rxon request
* abort any previous channel switch if still in process
*/
if (priv->switch_rxon.switch_in_progress &&
(priv->switch_rxon.channel != priv->staging_rxon.channel)) {
IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
le16_to_cpu(priv->switch_rxon.channel));
priv->switch_rxon.switch_in_progress = false;
}
/* If we don't need to send a full RXON, we can use
* iwl_rxon_assoc_cmd which is used to reconfigure filter
* and other flags for the current radio configuration. */
@ -133,6 +144,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
}
memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
iwl_print_rx_config_cmd(priv);
return 0;
}
@ -228,6 +240,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
}
memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
}
iwl_print_rx_config_cmd(priv);
iwl_init_sensitivity(priv);
@ -1071,6 +1084,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
u32 inta = 0;
u32 handled = 0;
unsigned long flags;
u32 i;
#ifdef CONFIG_IWLWIFI_DEBUG
u32 inta_mask;
#endif
@ -1181,12 +1195,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
if (inta & CSR_INT_BIT_WAKEUP) {
IWL_DEBUG_ISR(priv, "Wakeup interrupt\n");
iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
iwl_txq_update_write_ptr(priv, &priv->txq[0]);
iwl_txq_update_write_ptr(priv, &priv->txq[1]);
iwl_txq_update_write_ptr(priv, &priv->txq[2]);
iwl_txq_update_write_ptr(priv, &priv->txq[3]);
iwl_txq_update_write_ptr(priv, &priv->txq[4]);
iwl_txq_update_write_ptr(priv, &priv->txq[5]);
for (i = 0; i < priv->hw_params.max_txq_num; i++)
iwl_txq_update_write_ptr(priv, &priv->txq[i]);
priv->isr_stats.wakeup++;
@ -1653,6 +1663,7 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
u32 ptr; /* SRAM byte address of log data */
u32 ev, time, data; /* event log data */
unsigned long reg_flags;
if (num_events == 0)
return;
@ -1668,27 +1679,39 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
/* Make sure device is powered up for SRAM reads */
spin_lock_irqsave(&priv->reg_lock, reg_flags);
iwl_grab_nic_access(priv);
/* Set starting address; reads will auto-increment */
_iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr);
rmb();
/* "time" is actually "data" for mode 0 (no timestamp).
* place event id # at far right for easier visual parsing. */
for (i = 0; i < num_events; i++) {
ev = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
time = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
if (mode == 0) {
/* data, ev */
trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
} else {
data = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
time, data, ev);
trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
}
}
/* Allow device to power down */
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
/* For sanity check only. Actual size is determined by uCode, typ. 512 */
#define MAX_EVENT_LOG_SIZE (512)
void iwl_dump_nic_event_log(struct iwl_priv *priv)
{
u32 base; /* SRAM byte address of event log header */
@ -1714,6 +1737,18 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
if (capacity > MAX_EVENT_LOG_SIZE) {
IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
capacity, MAX_EVENT_LOG_SIZE);
capacity = MAX_EVENT_LOG_SIZE;
}
if (next_entry > MAX_EVENT_LOG_SIZE) {
IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
next_entry, MAX_EVENT_LOG_SIZE);
next_entry = MAX_EVENT_LOG_SIZE;
}
size = num_wraps ? capacity : next_entry;
/* bail out if nothing in log */
@ -1899,19 +1934,17 @@ static void __iwl_down(struct iwl_priv *priv)
/* device going down, Stop using ICT table */
iwl_disable_ict(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_clear_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
spin_unlock_irqrestore(&priv->lock, flags);
iwl_txq_ctx_stop(priv);
iwl_rxq_stop(priv);
iwl_write_prph(priv, APMG_CLK_DIS_REG,
APMG_CLK_VAL_DMA_CLK_RQT);
/* Power-down device's busmaster DMA clocks */
iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
udelay(5);
/* Make sure (redundant) we've released our request to stay awake */
iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/* Stop the device, and put it in low power state */
priv->cfg->ops->lib->apm_ops.stop(priv);
@ -3439,14 +3472,6 @@ static struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)},
/* 6x00 Series */
{IWL_PCI_DEVICE(0x008D, 0x1301, iwl6000h_2agn_cfg)},
{IWL_PCI_DEVICE(0x008D, 0x1321, iwl6000h_2agn_cfg)},
{IWL_PCI_DEVICE(0x008D, 0x1326, iwl6000h_2abg_cfg)},
{IWL_PCI_DEVICE(0x008D, 0x1306, iwl6000h_2abg_cfg)},
{IWL_PCI_DEVICE(0x008D, 0x1307, iwl6000h_2bg_cfg)},
{IWL_PCI_DEVICE(0x008E, 0x1311, iwl6000h_2agn_cfg)},
{IWL_PCI_DEVICE(0x008E, 0x1316, iwl6000h_2abg_cfg)},
{IWL_PCI_DEVICE(0x422B, 0x1101, iwl6000_3agn_cfg)},
{IWL_PCI_DEVICE(0x422B, 0x1121, iwl6000_3agn_cfg)},
{IWL_PCI_DEVICE(0x422C, 0x1301, iwl6000i_2agn_cfg)},

View File

@ -2566,9 +2566,10 @@ struct iwl_scan_channel {
/**
* struct iwl_ssid_ie - directed scan network information element
*
* Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field
* in struct iwl_scan_channel; each channel may select different ssids from
* among the 4 entries. SSID IEs get transmitted in reverse order of entry.
* Up to 20 of these may appear in REPLY_SCAN_CMD (Note: Only 4 are in
* 3945 SCAN api), selected by "type" bit field in struct iwl_scan_channel;
* each channel may select different ssids from among the 20 (4) entries.
* SSID IEs get transmitted in reverse order of entry.
*/
struct iwl_ssid_ie {
u8 id;

View File

@ -1316,19 +1316,24 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
if (!le32_to_cpu(csa->status)) {
rxon->channel = csa->channel;
priv->staging_rxon.channel = csa->channel;
IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
le16_to_cpu(csa->channel));
} else
IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
le16_to_cpu(csa->channel));
if (priv->switch_rxon.switch_in_progress) {
if (!le32_to_cpu(csa->status) &&
(csa->channel == priv->switch_rxon.channel)) {
rxon->channel = csa->channel;
priv->staging_rxon.channel = csa->channel;
IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
le16_to_cpu(csa->channel));
} else
IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
le16_to_cpu(csa->channel));
priv->switch_rxon.switch_in_progress = false;
}
}
EXPORT_SYMBOL(iwl_rx_csa);
#ifdef CONFIG_IWLWIFI_DEBUG
static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
void iwl_print_rx_config_cmd(struct iwl_priv *priv)
{
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
@ -1346,6 +1351,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
IWL_DEBUG_RADIO(priv, "u8[6] bssid_addr: %pM\n", rxon->bssid_addr);
IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
}
EXPORT_SYMBOL(iwl_print_rx_config_cmd);
#endif
/**
* iwl_irq_handle_error - called for HW or SW error interrupt from card
@ -2310,12 +2316,6 @@ static void iwl_ht_conf(struct iwl_priv *priv,
>> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
maxstreams += 1;
ht_conf->sm_ps =
(u8)((ht_cap->cap & IEEE80211_HT_CAP_SM_PS)
>> 2);
IWL_DEBUG_MAC80211(priv, "sm_ps: 0x%x\n",
ht_conf->sm_ps);
if ((ht_cap->mcs.rx_mask[1] == 0) &&
(ht_cap->mcs.rx_mask[2] == 0))
ht_conf->single_chain_sufficient = true;
@ -2689,14 +2689,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
goto set_ch_out;
}
if (iwl_is_associated(priv) &&
(le16_to_cpu(priv->active_rxon.channel) != ch) &&
priv->cfg->ops->lib->set_channel_switch) {
ret = priv->cfg->ops->lib->set_channel_switch(priv,
ch);
goto out;
}
spin_lock_irqsave(&priv->lock, flags);
/* Configure HT40 channels */
@ -2731,6 +2723,22 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
iwl_set_flags_for_band(priv, conf->channel->band);
spin_unlock_irqrestore(&priv->lock, flags);
if (iwl_is_associated(priv) &&
(le16_to_cpu(priv->active_rxon.channel) != ch) &&
priv->cfg->ops->lib->set_channel_switch) {
iwl_set_rate(priv);
/*
* at this point, staging_rxon has the
* configuration for channel switch
*/
ret = priv->cfg->ops->lib->set_channel_switch(priv,
ch);
if (!ret) {
iwl_print_rx_config_cmd(priv);
goto out;
}
priv->switch_rxon.switch_in_progress = false;
}
set_ch_out:
/* The list of supported rates and rate mask can be different
* for each band; since the band may have changed, reset

View File

@ -579,6 +579,7 @@ int iwl_pci_resume(struct pci_dev *pdev);
#ifdef CONFIG_IWLWIFI_DEBUG
void iwl_dump_nic_event_log(struct iwl_priv *priv);
void iwl_dump_nic_error_log(struct iwl_priv *priv);
void iwl_print_rx_config_cmd(struct iwl_priv *priv);
#else
static inline void iwl_dump_nic_event_log(struct iwl_priv *priv)
{
@ -587,6 +588,10 @@ static inline void iwl_dump_nic_event_log(struct iwl_priv *priv)
static inline void iwl_dump_nic_error_log(struct iwl_priv *priv)
{
}
static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv)
{
}
#endif
void iwl_clear_isr_stats(struct iwl_priv *priv);

View File

@ -324,8 +324,9 @@ struct iwl_channel_info {
#define IWL_MIN_NUM_QUEUES 10
/*
* uCode queue management definitions ...
* Queue #4 is the command queue for 3945/4965/5x00/1000/6x00.
* Queue #4 is the command queue for 3945/4965/5x00/1000/6x00,
* the driver maps it into the appropriate device FIFO for the
* uCode.
*/
#define IWL_CMD_QUEUE_NUM 4
@ -926,13 +927,11 @@ enum iwl_access_mode {
/**
* enum iwl_pa_type - Power Amplifier type
* @IWL_PA_SYSTEM: based on uCode configuration
* @IWL_PA_HYBRID: use both Internal and external PA
* @IWL_PA_INTERNAL: use Internal only
*/
enum iwl_pa_type {
IWL_PA_SYSTEM = 0,
IWL_PA_HYBRID = 1,
IWL_PA_INTERNAL = 2,
IWL_PA_INTERNAL = 1,
};
/* interrupt statistics */
@ -993,6 +992,17 @@ struct traffic_stats {
};
#endif
/*
* iwl_switch_rxon: "channel switch" structure
*
* @ switch_in_progress: channel switch in progress
* @ channel: new channel
*/
struct iwl_switch_rxon {
bool switch_in_progress;
__le16 channel;
};
struct iwl_priv {
/* ieee device used by generic ieee processing code */
@ -1086,7 +1096,7 @@ struct iwl_priv {
const struct iwl_rxon_cmd active_rxon;
struct iwl_rxon_cmd staging_rxon;
struct iwl_rxon_cmd recovery_rxon;
struct iwl_switch_rxon switch_rxon;
/* 1st responses from initialize and runtime uCode images.
* 4965's initialize alive response contains some calibration data. */

View File

@ -199,13 +199,13 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
}
if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
IWL_DEBUG_INFO(priv, "Command %s aborted: RF KILL Switch\n",
IWL_ERR(priv, "Command %s aborted: RF KILL Switch\n",
get_cmd_string(cmd->id));
ret = -ECANCELED;
goto fail;
}
if (test_bit(STATUS_FW_ERROR, &priv->status)) {
IWL_DEBUG_INFO(priv, "Command %s failed: FW Error\n",
IWL_ERR(priv, "Command %s failed: FW Error\n",
get_cmd_string(cmd->id));
ret = -EIO;
goto fail;

View File

@ -200,6 +200,26 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv)
/* this bit wakes up the NIC */
_iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/*
* These bits say the device is running, and should keep running for
* at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
* but they do not indicate that embedded SRAM is restored yet;
* 3945 and 4965 have volatile SRAM, and must save/restore contents
* to/from host DRAM when sleeping/waking for power-saving.
* Each direction takes approximately 1/4 millisecond; with this
* overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
* series of register accesses are expected (e.g. reading Event Log),
* to keep device from sleeping.
*
* CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
* SRAM is okay/restored. We don't check that here because this call
* is just for hardware register access; but GP1 MAC_SLEEP check is a
* good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
*
* 5000 series and later (including 1000 series) have non-volatile SRAM,
* and do not save/restore SRAM when power cycling.
*/
ret = _iwl_poll_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
(CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |

View File

@ -254,7 +254,8 @@
* device. A queue maps to only one (selectable by driver) Tx DMA channel,
* but one DMA channel may take input from several queues.
*
* Tx DMA channels have dedicated purposes. For 4965, they are used as follows:
* Tx DMA channels have dedicated purposes. For 4965, they are used as follows
* (cf. default_queue_to_tx_fifo in iwl-4965.c):
*
* 0 -- EDCA BK (background) frames, lowest priority
* 1 -- EDCA BE (best effort) frames, normal priority
@ -265,9 +266,21 @@
* 6 -- HCCA long frames
* 7 -- not used by driver (device-internal only)
*
* For 5000 series and up, they are used slightly differently
* (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c):
*
* 0 -- EDCA BK (background) frames, lowest priority
* 1 -- EDCA BE (best effort) frames, normal priority
* 2 -- EDCA VI (video) frames, higher priority
* 3 -- EDCA VO (voice) and management frames, highest priority
* 4 -- (TBD)
* 5 -- HCCA short frames
* 6 -- HCCA long frames
* 7 -- Commands
*
* Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6.
* In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to
* support 11n aggregation via EDCA DMA channels.
* In addition, driver can map the remaining queues to Tx DMA/FIFO
* channels 0-3 to support 11n aggregation via EDCA DMA channels.
*
* The driver sets up each queue to work in one of two modes:
*

View File

@ -140,6 +140,8 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
IWL_DEBUG_INFO(priv, "Rx queue requesting wakeup, GP1 = 0x%x\n",
reg);
iwl_set_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
goto exit_unlock;
@ -937,12 +939,13 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
return;
skb = alloc_skb(IWL_LINK_HDR_MAX, GFP_ATOMIC);
skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC);
if (!skb) {
IWL_ERR(priv, "alloc_skb failed\n");
return;
}
skb_reserve(skb, IWL_LINK_HDR_MAX);
skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
/* mac80211 currently doesn't support paged SKB. Convert it to

View File

@ -581,6 +581,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
u8 rate;
bool is_active = false;
int chan_mod;
u8 active_chains;
conf = ieee80211_get_hw_conf(priv->hw);
@ -734,9 +735,22 @@ static void iwl_bg_request_scan(struct work_struct *data)
rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
/* In power save mode use one chain, otherwise use all chains */
if (test_bit(STATUS_POWER_PMI, &priv->status)) {
/* rx_ant has been set to all valid chains previously */
active_chains = rx_ant &
((u8)(priv->chain_noise_data.active_chains));
if (!active_chains)
active_chains = rx_ant;
IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n",
priv->chain_noise_data.active_chains);
rx_ant = first_antenna(active_chains);
}
/* MIMO is not used here, but value is required */
rx_chain |= ANT_ABC << RXON_RX_CHAIN_VALID_POS;
rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
scan->rx_chain = cpu_to_le16(rx_chain);

View File

@ -96,7 +96,8 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
IWL_DEBUG_INFO(priv, "Requesting wakeup, GP1 = 0x%x\n", reg);
IWL_DEBUG_INFO(priv, "Tx queue %d requesting wakeup, GP1 = 0x%x\n",
txq_id, reg);
iwl_set_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
return ret;
@ -364,8 +365,13 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
txq->need_update = 0;
/* aggregation TX queues will get their ID when aggregation begins */
if (txq_id <= IWL_TX_FIFO_AC3)
/*
* Aggregation TX queues will get their ID when aggregation begins;
* they overwrite the setting done here. The command FIFO doesn't
* need an swq_id so don't set one to catch errors, all others can
* be set up to the identity mapping.
*/
if (txq_id != IWL_CMD_QUEUE_NUM)
txq->swq_id = txq_id;
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise

View File

@ -1570,6 +1570,7 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
u32 ptr; /* SRAM byte address of log data */
u32 ev, time, data; /* event log data */
unsigned long reg_flags;
if (num_events == 0)
return;
@ -1583,26 +1584,38 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx,
ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
/* Make sure device is powered up for SRAM reads */
spin_lock_irqsave(&priv->reg_lock, reg_flags);
iwl_grab_nic_access(priv);
/* Set starting address; reads will auto-increment */
_iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr);
rmb();
/* "time" is actually "data" for mode 0 (no timestamp).
* place event id # at far right for easier visual parsing. */
for (i = 0; i < num_events; i++) {
ev = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
time = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
if (mode == 0) {
/* data, ev */
IWL_ERR(priv, "0x%08x\t%04u\n", time, ev);
trace_iwlwifi_dev_ucode_event(priv, 0, time, ev);
} else {
data = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
IWL_ERR(priv, "%010u\t0x%08x\t%04u\n", time, data, ev);
trace_iwlwifi_dev_ucode_event(priv, time, data, ev);
}
}
/* Allow device to power down */
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
}
/* For sanity check only. Actual size is determined by uCode, typ. 512 */
#define IWL3945_MAX_EVENT_LOG_SIZE (512)
void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
{
u32 base; /* SRAM byte address of event log header */
@ -1624,6 +1637,18 @@ void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
if (capacity > IWL3945_MAX_EVENT_LOG_SIZE) {
IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
capacity, IWL3945_MAX_EVENT_LOG_SIZE);
capacity = IWL3945_MAX_EVENT_LOG_SIZE;
}
if (next_entry > IWL3945_MAX_EVENT_LOG_SIZE) {
IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
next_entry, IWL3945_MAX_EVENT_LOG_SIZE);
next_entry = IWL3945_MAX_EVENT_LOG_SIZE;
}
size = num_wraps ? capacity : next_entry;
/* bail out if nothing in log */
@ -2575,9 +2600,8 @@ static void __iwl3945_down(struct iwl_priv *priv)
iwl3945_hw_txq_ctx_stop(priv);
iwl3945_hw_rxq_stop(priv);
iwl_write_prph(priv, APMG_CLK_DIS_REG,
APMG_CLK_VAL_DMA_CLK_RQT);
/* Power-down device's busmaster DMA clocks */
iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
udelay(5);
/* Stop the device, and put it in low power state */

View File

@ -399,6 +399,9 @@ static struct iwm_if_ops if_sdio_ops = {
.calib_lmac_name = "iwmc3200wifi-calib-sdio.bin",
.lmac_name = "iwmc3200wifi-lmac-sdio.bin",
};
MODULE_FIRMWARE("iwmc3200wifi-umac-sdio.bin");
MODULE_FIRMWARE("iwmc3200wifi-calib-sdio.bin");
MODULE_FIRMWARE("iwmc3200wifi-lmac-sdio.bin");
static int iwm_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)

View File

@ -48,6 +48,7 @@
MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE("libertas_cs_helper.fw");

View File

@ -99,6 +99,12 @@ static struct if_sdio_model if_sdio_models[] = {
.firmware = "sd8688.bin",
},
};
MODULE_FIRMWARE("sd8385_helper.bin");
MODULE_FIRMWARE("sd8385.bin");
MODULE_FIRMWARE("sd8686_helper.bin");
MODULE_FIRMWARE("sd8686.bin");
MODULE_FIRMWARE("sd8688_helper.bin");
MODULE_FIRMWARE("sd8688.bin");
struct if_sdio_packet {
struct if_sdio_packet *next;

View File

@ -902,6 +902,10 @@ static int if_spi_calculate_fw_names(u16 card_id,
chip_id_to_device_name[i].name);
return 0;
}
MODULE_FIRMWARE("libertas/gspi8385_hlp.bin");
MODULE_FIRMWARE("libertas/gspi8385.bin");
MODULE_FIRMWARE("libertas/gspi8686_hlp.bin");
MODULE_FIRMWARE("libertas/gspi8686.bin");
static int __devinit if_spi_probe(struct spi_device *spi)
{

View File

@ -28,6 +28,8 @@
static char *lbs_fw_name = "usb8388.bin";
module_param_named(fw_name, lbs_fw_name, charp, 0644);
MODULE_FIRMWARE("usb8388.bin");
static struct usb_device_id if_usb_table[] = {
/* Enter the device signature inside */
{ USB_DEVICE(0x1286, 0x2001) },

View File

@ -23,6 +23,8 @@
static char *lbtf_fw_name = "lbtf_usb.bin";
module_param_named(fw_name, lbtf_fw_name, charp, 0644);
MODULE_FIRMWARE("lbtf_usb.bin");
static struct usb_device_id if_usb_table[] = {
/* Enter the device signature inside */
{ USB_DEVICE(0x1286, 0x2001) },

View File

@ -400,6 +400,9 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv)
return 0;
}
MODULE_FIRMWARE("mwl8k/helper_8687.fw");
MODULE_FIRMWARE("mwl8k/fmimage_8687.fw");
struct mwl8k_cmd_pkt {
__le16 code;
__le16 length;

View File

@ -28,6 +28,12 @@ static const struct fw_info orinoco_fw[] = {
{ NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
};
MODULE_FIRMWARE("agere_sta_fw.bin");
MODULE_FIRMWARE("agere_ap_fw.bin");
MODULE_FIRMWARE("prism_sta_fw.bin");
MODULE_FIRMWARE("prism_ap_fw.bin");
MODULE_FIRMWARE("symbol_sp24t_prim_fw");
MODULE_FIRMWARE("symbol_sp24t_sec_fw");
/* Structure used to access fields in FW
* Make sure LE decoding macros are used

View File

@ -40,6 +40,9 @@
#define ISL3877_IMAGE_FILE "isl3877"
#define ISL3886_IMAGE_FILE "isl3886"
#define ISL3890_IMAGE_FILE "isl3890"
MODULE_FIRMWARE(ISL3877_IMAGE_FILE);
MODULE_FIRMWARE(ISL3886_IMAGE_FILE);
MODULE_FIRMWARE(ISL3890_IMAGE_FILE);
static int prism54_bring_down(islpci_private *);
static int islpci_alloc_memory(islpci_private *);

View File

@ -2074,7 +2074,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
del_timer(&local->timer);
local->timer.expires = jiffies + HZ * 5;
local->timer.data = (long)local;
if (status == CCS_START_NETWORK) {
if (cmd == CCS_START_NETWORK) {
DEBUG(0,
"ray_cs interrupt network \"%s\" start failed\n",
local->sparm.b4.a_current_ess_id);

View File

@ -1072,6 +1072,8 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version,
auth_mode = NDIS_80211_AUTH_SHARED;
else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
auth_mode = NDIS_80211_AUTH_OPEN;
else if (auth_type == NL80211_AUTHTYPE_AUTOMATIC)
auth_mode = NDIS_80211_AUTH_AUTO_SWITCH;
else
return -ENOTSUPP;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -1341,6 +1341,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
rt2x00_set_chip_rf(rt2x00dev, value, reg);
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_rf(&rt2x00dev->chip, RF2420) &&
!rt2x00_rf(&rt2x00dev->chip, RF2421)) {

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -1505,6 +1505,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
rt2x00_set_chip_rf(rt2x00dev, value, reg);
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
!rt2x00_rf(&rt2x00dev->chip, RF2523) &&

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -715,139 +715,6 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev,
qual->vgc_level = value;
}
/*
* NOTE: This function is directly ported from legacy driver, but
* despite it being declared it was never called. Although link tuning
* sounds like a good idea, and usually works well for the other drivers,
* it does _not_ work with rt2500usb. Enabling this function will result
* in TX capabilities only until association kicks in. Immediately
* after the successful association all TX frames will be kept in the
* hardware queue and never transmitted.
*/
#if 0
static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev)
{
int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
u16 bbp_thresh;
u16 vgc_bound;
u16 sens;
u16 r24;
u16 r25;
u16 r61;
u16 r17_sens;
u8 r17;
u8 up_bound;
u8 low_bound;
/*
* Read current r17 value, as well as the sensitivity values
* for the r17 register.
*/
rt2500usb_bbp_read(rt2x00dev, 17, &r17);
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens);
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound);
up_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER);
low_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCLOWER);
/*
* If we are not associated, we should go straight to the
* dynamic CCA tuning.
*/
if (!rt2x00dev->intf_associated)
goto dynamic_cca_tune;
/*
* Determine the BBP tuning threshold and correctly
* set BBP 24, 25 and 61.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &bbp_thresh);
bbp_thresh = rt2x00_get_field16(bbp_thresh, EEPROM_BBPTUNE_THRESHOLD);
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &r24);
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &r25);
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &r61);
if ((rssi + bbp_thresh) > 0) {
r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_HIGH);
r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_HIGH);
r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_HIGH);
} else {
r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_LOW);
r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_LOW);
r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_LOW);
}
rt2500usb_bbp_write(rt2x00dev, 24, r24);
rt2500usb_bbp_write(rt2x00dev, 25, r25);
rt2500usb_bbp_write(rt2x00dev, 61, r61);
/*
* A too low RSSI will cause too much false CCA which will
* then corrupt the R17 tuning. To remidy this the tuning should
* be stopped (While making sure the R17 value will not exceed limits)
*/
if (rssi >= -40) {
if (r17 != 0x60)
rt2500usb_bbp_write(rt2x00dev, 17, 0x60);
return;
}
/*
* Special big-R17 for short distance
*/
if (rssi >= -58) {
sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_LOW);
if (r17 != sens)
rt2500usb_bbp_write(rt2x00dev, 17, sens);
return;
}
/*
* Special mid-R17 for middle distance
*/
if (rssi >= -74) {
sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_HIGH);
if (r17 != sens)
rt2500usb_bbp_write(rt2x00dev, 17, sens);
return;
}
/*
* Leave short or middle distance condition, restore r17
* to the dynamic tuning range.
*/
low_bound = 0x32;
if (rssi < -77)
up_bound -= (-77 - rssi);
if (up_bound < low_bound)
up_bound = low_bound;
if (r17 > up_bound) {
rt2500usb_bbp_write(rt2x00dev, 17, up_bound);
rt2x00dev->link.vgc_level = up_bound;
return;
}
dynamic_cca_tune:
/*
* R17 is inside the dynamic tuning range,
* start tuning the link based on the false cca counter.
*/
if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) {
rt2500usb_bbp_write(rt2x00dev, 17, ++r17);
rt2x00dev->link.vgc_level = r17;
} else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) {
rt2500usb_bbp_write(rt2x00dev, 17, --r17);
rt2x00dev->link.vgc_level = r17;
}
}
#else
#define rt2500usb_link_tuner NULL
#endif
/*
* Initialization functions.
*/
@ -1542,6 +1409,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2500usb_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) ||
rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
@ -1910,7 +1778,6 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.rfkill_poll = rt2500usb_rfkill_poll,
.link_stats = rt2500usb_link_stats,
.reset_tuner = rt2500usb_reset_tuner,
.link_tuner = rt2500usb_link_tuner,
.write_tx_desc = rt2500usb_write_tx_desc,
.write_tx_data = rt2x00usb_write_tx_data,
.write_beacon = rt2500usb_write_beacon,

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,12 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com>
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
Copyright (C) 2009 Bart Zolnierkiewicz <bzolnier@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -361,6 +368,35 @@
#define RF_CSR_CFG_WRITE FIELD32(0x00010000)
#define RF_CSR_CFG_BUSY FIELD32(0x00020000)
/*
* EFUSE_CSR: RT30x0 EEPROM
*/
#define EFUSE_CTRL 0x0580
#define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000)
#define EFUSE_CTRL_MODE FIELD32(0x000000c0)
#define EFUSE_CTRL_KICK FIELD32(0x40000000)
#define EFUSE_CTRL_PRESENT FIELD32(0x80000000)
/*
* EFUSE_DATA0
*/
#define EFUSE_DATA0 0x0590
/*
* EFUSE_DATA1
*/
#define EFUSE_DATA1 0x0594
/*
* EFUSE_DATA2
*/
#define EFUSE_DATA2 0x0598
/*
* EFUSE_DATA3
*/
#define EFUSE_DATA3 0x059c
/*
* MAC Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us.

View File

@ -1,9 +1,15 @@
/*
Copyright (C) 2009 Bartlomiej Zolnierkiewicz
Copyright (C) 2009 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Copyright (C) 2009 Gertjan van Wingerde <gwingerde@gmail.com>
Based on the original rt2800pci.c and rt2800usb.c:
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Based on the original rt2800pci.c and rt2800usb.c.
Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com>
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -555,7 +561,8 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, conf->sync);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE,
(conf->sync == TSF_SYNC_BEACON));
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
}
@ -769,7 +776,7 @@ static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev,
u8 rfcsr;
rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1);
rt2800_rfcsr_write(rt2x00dev, 2, rf->rf3);
rt2800_rfcsr_write(rt2x00dev, 3, rf->rf3);
rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2);
@ -801,10 +808,15 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
unsigned int tx_pin;
u8 bbp;
if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION)
rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info);
else
if ((rt2x00_rt(&rt2x00dev->chip, RT3070) ||
rt2x00_rt(&rt2x00dev->chip, RT3090)) &&
(rt2x00_rf(&rt2x00dev->chip, RF2020) ||
rt2x00_rf(&rt2x00dev->chip, RF3020) ||
rt2x00_rf(&rt2x00dev->chip, RF3021) ||
rt2x00_rf(&rt2x00dev->chip, RF3022)))
rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info);
else
rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info);
/*
* Change BBP settings
@ -1084,7 +1096,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
if (rt2x00_intf_is_usb(rt2x00dev)) {
/*
* Wait untill BBP and RF are ready.
* Wait until BBP and RF are ready.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
@ -1659,6 +1671,466 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2800_init_rfcsr);
int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
rt2800_register_read(rt2x00dev, EFUSE_CTRL, &reg);
return rt2x00_get_field32(reg, EFUSE_CTRL_PRESENT);
}
EXPORT_SYMBOL_GPL(rt2800_efuse_detect);
static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i)
{
u32 reg;
mutex_lock(&rt2x00dev->csr_mutex);
rt2800_register_read_lock(rt2x00dev, EFUSE_CTRL, &reg);
rt2x00_set_field32(&reg, EFUSE_CTRL_ADDRESS_IN, i);
rt2x00_set_field32(&reg, EFUSE_CTRL_MODE, 0);
rt2x00_set_field32(&reg, EFUSE_CTRL_KICK, 1);
rt2800_register_write_lock(rt2x00dev, EFUSE_CTRL, reg);
/* Wait until the EEPROM has been loaded */
rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, &reg);
/* Apparently the data is read from end to start */
rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3,
(u32 *)&rt2x00dev->eeprom[i]);
rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2,
(u32 *)&rt2x00dev->eeprom[i + 2]);
rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1,
(u32 *)&rt2x00dev->eeprom[i + 4]);
rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0,
(u32 *)&rt2x00dev->eeprom[i + 6]);
mutex_unlock(&rt2x00dev->csr_mutex);
}
void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
{
unsigned int i;
for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8)
rt2800_efuse_read(rt2x00dev, i);
}
EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse);
int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
{
u16 word;
u8 *mac;
u8 default_lna_gain;
/*
* Start validation of the data that has been read.
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
random_ether_addr(mac);
EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1);
rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
} else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) {
/*
* There is a max of 2 RX streams for RT28x0 series
*/
if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2)
rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0);
rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0);
rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0);
rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
if ((word & 0x00ff) == 0x00ff) {
rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,
LED_MODE_TXRX_ACTIVITY);
rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);
EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
}
/*
* During the LNA validation we are going to use
* lna0 as correct value. Note that EEPROM_LNA
* is never validated.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word);
default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0);
if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 ||
rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff)
rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1,
default_lna_gain);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0);
if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 ||
rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff)
rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2,
default_lna_gain);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_validate_eeprom);
int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
u16 value;
u16 eeprom;
/*
* Read EEPROM word for configuration.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
/*
* Identify RF chipset.
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip_rf(rt2x00dev, value, reg);
if (rt2x00_intf_is_usb(rt2x00dev)) {
struct rt2x00_chip *chip = &rt2x00dev->chip;
/*
* The check for rt2860 is not a typo, some rt2870 hardware
* identifies itself as rt2860 in the CSR register.
*/
if (rt2x00_check_rev(chip, 0xfff00000, 0x28600000) ||
rt2x00_check_rev(chip, 0xfff00000, 0x28700000) ||
rt2x00_check_rev(chip, 0xfff00000, 0x28800000)) {
rt2x00_set_chip_rt(rt2x00dev, RT2870);
} else if (rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) {
rt2x00_set_chip_rt(rt2x00dev, RT3070);
} else {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}
}
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_rf(&rt2x00dev->chip, RF2820) &&
!rt2x00_rf(&rt2x00dev->chip, RF2850) &&
!rt2x00_rf(&rt2x00dev->chip, RF2720) &&
!rt2x00_rf(&rt2x00dev->chip, RF2750) &&
!rt2x00_rf(&rt2x00dev->chip, RF3020) &&
!rt2x00_rf(&rt2x00dev->chip, RF2020) &&
!rt2x00_rf(&rt2x00dev->chip, RF3021) &&
!rt2x00_rf(&rt2x00dev->chip, RF3022)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
/*
* Identify default antenna configuration.
*/
rt2x00dev->default_ant.tx =
rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH);
rt2x00dev->default_ant.rx =
rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH);
/*
* Read frequency offset and RF programming sequence.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
/*
* Read external LNA informations.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
__set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
/*
* Detect if this device has an hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
/*
* Store led settings, for correct led behaviour.
*/
#ifdef CONFIG_RT2X00_LIB_LEDS
rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO);
rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg);
#endif /* CONFIG_RT2X00_LIB_LEDS */
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_init_eeprom);
/*
* RF value list for rt28x0
* Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750)
*/
static const struct rf_channel rf_vals[] = {
{ 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b },
{ 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f },
{ 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b },
{ 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f },
{ 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b },
{ 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f },
{ 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b },
{ 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f },
{ 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b },
{ 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f },
{ 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b },
{ 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f },
{ 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b },
{ 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 },
/* 802.11 UNI / HyperLan 2 */
{ 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 },
{ 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 },
{ 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 },
{ 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 },
{ 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b },
{ 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b },
{ 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 },
{ 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 },
{ 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b },
{ 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 },
{ 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 },
{ 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 },
/* 802.11 HyperLan 2 */
{ 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 },
{ 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 },
{ 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 },
{ 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 },
{ 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 },
{ 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b },
{ 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 },
{ 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 },
{ 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 },
{ 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 },
{ 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b },
{ 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 },
{ 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b },
{ 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 },
{ 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b },
{ 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 },
/* 802.11 UNII */
{ 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 },
{ 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 },
{ 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f },
{ 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f },
{ 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 },
{ 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 },
{ 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 },
{ 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f },
{ 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 },
{ 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 },
{ 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f },
/* 802.11 Japan */
{ 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b },
{ 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 },
{ 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b },
{ 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 },
{ 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 },
{ 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b },
{ 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 },
};
/*
* RF value list for rt3070
* Supports: 2.4 GHz
*/
static const struct rf_channel rf_vals_302x[] = {
{1, 241, 2, 2 },
{2, 241, 2, 7 },
{3, 242, 2, 2 },
{4, 242, 2, 7 },
{5, 243, 2, 2 },
{6, 243, 2, 7 },
{7, 244, 2, 2 },
{8, 244, 2, 7 },
{9, 245, 2, 2 },
{10, 245, 2, 7 },
{11, 246, 2, 2 },
{12, 246, 2, 7 },
{13, 247, 2, 2 },
{14, 248, 2, 4 },
};
int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct rt2x00_chip *chip = &rt2x00dev->chip;
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
char *tx_power1;
char *tx_power2;
unsigned int i;
u16 eeprom;
/*
* Initialize all hw fields.
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
if (rt2x00_intf_is_usb(rt2x00dev))
rt2x00dev->hw->extra_tx_headroom =
TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
else if (rt2x00_intf_is_pci(rt2x00dev))
rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE;
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
rt2x00_eeprom_addr(rt2x00dev,
EEPROM_MAC_ADDR_0));
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
/*
* Initialize hw_mode information.
*/
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
if (rt2x00_rf(chip, RF2820) ||
rt2x00_rf(chip, RF2720) ||
(rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(chip, RF3052))) {
spec->num_channels = 14;
spec->channels = rf_vals;
} else if (rt2x00_rf(chip, RF2850) || rt2x00_rf(chip, RF2750)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals);
spec->channels = rf_vals;
} else if (rt2x00_rf(chip, RF3020) ||
rt2x00_rf(chip, RF2020) ||
rt2x00_rf(chip, RF3021) ||
rt2x00_rf(chip, RF3022)) {
spec->num_channels = ARRAY_SIZE(rf_vals_302x);
spec->channels = rf_vals_302x;
}
/*
* Initialize HT information.
*/
spec->ht.ht_supported = true;
spec->ht.cap =
IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_TX_STBC |
IEEE80211_HT_CAP_RX_STBC |
IEEE80211_HT_CAP_PSMP_SUPPORT;
spec->ht.ampdu_factor = 3;
spec->ht.ampdu_density = 4;
spec->ht.mcs.tx_params =
IEEE80211_HT_MCS_TX_DEFINED |
IEEE80211_HT_MCS_TX_RX_DIFF |
((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) <<
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) {
case 3:
spec->ht.mcs.rx_mask[2] = 0xff;
case 2:
spec->ht.mcs.rx_mask[1] = 0xff;
case 1:
spec->ht.mcs.rx_mask[0] = 0xff;
spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */
break;
}
/*
* Create channel information array
*/
info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
spec->channels_info = info;
tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
for (i = 0; i < 14; i++) {
info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]);
info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]);
}
if (spec->num_channels > 14) {
tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
for (i = 14; i < spec->num_channels; i++) {
info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]);
info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]);
}
}
return 0;
}
EXPORT_SYMBOL_GPL(rt2800_probe_hw_mode);
/*
* IEEE80211 stack callback functions.
*/

View File

@ -23,6 +23,8 @@
struct rt2800_ops {
void (*register_read)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset, u32 *value);
void (*register_read_lock)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset, u32 *value);
void (*register_write)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset, u32 value);
void (*register_write_lock)(struct rt2x00_dev *rt2x00dev,
@ -49,6 +51,15 @@ static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
rt2800ops->register_read(rt2x00dev, offset, value);
}
static inline void rt2800_register_read_lock(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 *value)
{
const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
rt2800ops->register_read_lock(rt2x00dev, offset, value);
}
static inline void rt2800_register_write(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u32 value)
@ -129,6 +140,12 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev);
int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev);
int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev);
int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev);
int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev);
int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev);
extern const struct ieee80211_ops rt2800_mac80211_ops;
#endif /* RT2800LIB_H */

View File

@ -1,5 +1,12 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com>
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
Copyright (C) 2009 Bart Zolnierkiewicz <bzolnier@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -145,43 +152,25 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
EEPROM_SIZE / sizeof(u16));
}
static void rt2800pci_efuse_read(struct rt2x00_dev *rt2x00dev,
unsigned int i)
static int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
rt2800_register_read(rt2x00dev, EFUSE_CTRL, &reg);
rt2x00_set_field32(&reg, EFUSE_CTRL_ADDRESS_IN, i);
rt2x00_set_field32(&reg, EFUSE_CTRL_MODE, 0);
rt2x00_set_field32(&reg, EFUSE_CTRL_KICK, 1);
rt2800_register_write(rt2x00dev, EFUSE_CTRL, reg);
/* Wait until the EEPROM has been loaded */
rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, &reg);
/* Apparently the data is read from end to start */
rt2800_register_read(rt2x00dev, EFUSE_DATA3,
(u32 *)&rt2x00dev->eeprom[i]);
rt2800_register_read(rt2x00dev, EFUSE_DATA2,
(u32 *)&rt2x00dev->eeprom[i + 2]);
rt2800_register_read(rt2x00dev, EFUSE_DATA1,
(u32 *)&rt2x00dev->eeprom[i + 4]);
rt2800_register_read(rt2x00dev, EFUSE_DATA0,
(u32 *)&rt2x00dev->eeprom[i + 6]);
return rt2800_efuse_detect(rt2x00dev);
}
static void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
{
unsigned int i;
for (i = 0; i < EEPROM_SIZE / sizeof(u16); i += 8)
rt2800pci_efuse_read(rt2x00dev, i);
rt2800_read_eeprom_efuse(rt2x00dev);
}
#else
static inline void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
{
}
static inline int rt2800pci_efuse_detect(struct rt2x00_dev *rt2x00dev)
{
return 0;
}
static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
{
}
@ -1079,379 +1068,28 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
*/
static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
{
u16 word;
u8 *mac;
u8 default_lna_gain;
/*
* Read EEPROM into buffer
*/
switch(rt2x00dev->chip.rt) {
switch (rt2x00dev->chip.rt) {
case RT2880:
case RT3052:
rt2800pci_read_eeprom_soc(rt2x00dev);
break;
case RT3090:
rt2800pci_read_eeprom_efuse(rt2x00dev);
break;
default:
rt2800pci_read_eeprom_pci(rt2x00dev);
if (rt2800pci_efuse_detect(rt2x00dev))
rt2800pci_read_eeprom_efuse(rt2x00dev);
else
rt2800pci_read_eeprom_pci(rt2x00dev);
break;
}
/*
* Start validation of the data that has been read.
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
random_ether_addr(mac);
EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1);
rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
} else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) {
/*
* There is a max of 2 RX streams for RT2860 series
*/
if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2)
rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0);
rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0);
rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0);
rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
if ((word & 0x00ff) == 0x00ff) {
rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,
LED_MODE_TXRX_ACTIVITY);
rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);
EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
}
/*
* During the LNA validation we are going to use
* lna0 as correct value. Note that EEPROM_LNA
* is never validated.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word);
default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0);
if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 ||
rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff)
rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1,
default_lna_gain);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0);
if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 ||
rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff)
rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2,
default_lna_gain);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
return 0;
}
static int rt2800pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
u16 value;
u16 eeprom;
/*
* Read EEPROM word for configuration.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
/*
* Identify RF chipset.
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip_rf(rt2x00dev, value, reg);
if (!rt2x00_rf(&rt2x00dev->chip, RF2820) &&
!rt2x00_rf(&rt2x00dev->chip, RF2850) &&
!rt2x00_rf(&rt2x00dev->chip, RF2720) &&
!rt2x00_rf(&rt2x00dev->chip, RF2750) &&
!rt2x00_rf(&rt2x00dev->chip, RF3020) &&
!rt2x00_rf(&rt2x00dev->chip, RF2020) &&
!rt2x00_rf(&rt2x00dev->chip, RF3021) &&
!rt2x00_rf(&rt2x00dev->chip, RF3022)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
/*
* Identify default antenna configuration.
*/
rt2x00dev->default_ant.tx =
rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH);
rt2x00dev->default_ant.rx =
rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH);
/*
* Read frequency offset and RF programming sequence.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
/*
* Read external LNA informations.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
__set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
/*
* Detect if this device has an hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
/*
* Store led settings, for correct led behaviour.
*/
#ifdef CONFIG_RT2X00_LIB_LEDS
rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO);
rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg);
#endif /* CONFIG_RT2X00_LIB_LEDS */
return 0;
}
/*
* RF value list for rt2860
* Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750)
*/
static const struct rf_channel rf_vals[] = {
{ 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b },
{ 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f },
{ 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b },
{ 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f },
{ 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b },
{ 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f },
{ 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b },
{ 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f },
{ 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b },
{ 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f },
{ 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b },
{ 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f },
{ 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b },
{ 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 },
/* 802.11 UNI / HyperLan 2 */
{ 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 },
{ 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 },
{ 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 },
{ 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 },
{ 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b },
{ 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b },
{ 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 },
{ 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 },
{ 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b },
{ 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 },
{ 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 },
{ 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 },
/* 802.11 HyperLan 2 */
{ 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 },
{ 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 },
{ 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 },
{ 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 },
{ 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 },
{ 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b },
{ 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 },
{ 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 },
{ 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 },
{ 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 },
{ 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b },
{ 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 },
{ 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b },
{ 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 },
{ 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b },
{ 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 },
/* 802.11 UNII */
{ 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 },
{ 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 },
{ 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f },
{ 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f },
{ 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 },
{ 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 },
{ 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 },
/* 802.11 Japan */
{ 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b },
{ 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 },
{ 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b },
{ 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 },
{ 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 },
{ 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b },
{ 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 },
};
static int rt2800pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
char *tx_power1;
char *tx_power2;
unsigned int i;
u16 eeprom;
/*
* Initialize all hw fields.
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = TXWI_DESC_SIZE;
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
rt2x00_eeprom_addr(rt2x00dev,
EEPROM_MAC_ADDR_0));
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
/*
* Initialize hw_mode information.
*/
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
if (rt2x00_rf(&rt2x00dev->chip, RF2820) ||
rt2x00_rf(&rt2x00dev->chip, RF2720) ||
rt2x00_rf(&rt2x00dev->chip, RF3020) ||
rt2x00_rf(&rt2x00dev->chip, RF3021) ||
rt2x00_rf(&rt2x00dev->chip, RF3022) ||
rt2x00_rf(&rt2x00dev->chip, RF2020) ||
rt2x00_rf(&rt2x00dev->chip, RF3052)) {
spec->num_channels = 14;
spec->channels = rf_vals;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2850) ||
rt2x00_rf(&rt2x00dev->chip, RF2750)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals);
spec->channels = rf_vals;
}
/*
* Initialize HT information.
*/
spec->ht.ht_supported = true;
spec->ht.cap =
IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_TX_STBC |
IEEE80211_HT_CAP_RX_STBC |
IEEE80211_HT_CAP_PSMP_SUPPORT;
spec->ht.ampdu_factor = 3;
spec->ht.ampdu_density = 4;
spec->ht.mcs.tx_params =
IEEE80211_HT_MCS_TX_DEFINED |
IEEE80211_HT_MCS_TX_RX_DIFF |
((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) <<
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) {
case 3:
spec->ht.mcs.rx_mask[2] = 0xff;
case 2:
spec->ht.mcs.rx_mask[1] = 0xff;
case 1:
spec->ht.mcs.rx_mask[0] = 0xff;
spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */
break;
}
/*
* Create channel information array
*/
info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
spec->channels_info = info;
tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
for (i = 0; i < 14; i++) {
info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]);
info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]);
}
if (spec->num_channels > 14) {
tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
for (i = 14; i < spec->num_channels; i++) {
info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]);
info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]);
}
}
return 0;
return rt2800_validate_eeprom(rt2x00dev);
}
static const struct rt2800_ops rt2800pci_rt2800_ops = {
.register_read = rt2x00pci_register_read,
.register_read_lock = rt2x00pci_register_read, /* same for PCI */
.register_write = rt2x00pci_register_write,
.register_write_lock = rt2x00pci_register_write, /* same for PCI */
@ -1465,8 +1103,6 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
rt2x00dev->priv = (void *)&rt2800pci_rt2800_ops;
/*
@ -1476,14 +1112,14 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
if (retval)
return retval;
retval = rt2800pci_init_eeprom(rt2x00dev);
retval = rt2800_init_eeprom(rt2x00dev);
if (retval)
return retval;
/*
* Initialize hw specifications.
*/
retval = rt2800pci_probe_hw_mode(rt2x00dev);
retval = rt2800_probe_hw_mode(rt2x00dev);
if (retval)
return retval;

View File

@ -1,5 +1,12 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Alban Browaeys <prahal@yahoo.com>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Luis Correia <luis.f.correia@gmail.com>
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
Copyright (C) 2009 Mark Asselstine <asselsm@gmail.com>
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
Copyright (C) 2009 Bart Zolnierkiewicz <bzolnier@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -55,34 +62,6 @@
#define TX_CTX_IDX(__x) TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET)
#define TX_DTX_IDX(__x) TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET)
/*
* EFUSE_CSR: RT3090 EEPROM
*/
#define EFUSE_CTRL 0x0580
#define EFUSE_CTRL_ADDRESS_IN FIELD32(0x03fe0000)
#define EFUSE_CTRL_MODE FIELD32(0x000000c0)
#define EFUSE_CTRL_KICK FIELD32(0x40000000)
/*
* EFUSE_DATA0
*/
#define EFUSE_DATA0 0x0590
/*
* EFUSE_DATA1
*/
#define EFUSE_DATA1 0x0594
/*
* EFUSE_DATA2
*/
#define EFUSE_DATA2 0x0598
/*
* EFUSE_DATA3
*/
#define EFUSE_DATA3 0x059c
/*
* 8051 firmware image.
*/

View File

@ -1,5 +1,9 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
Copyright (C) 2009 Axel Kollhofer <rain_maker@root-forum.org>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -594,16 +598,16 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
rt2x00_desc_read(rxwi, 2, &rxwi2);
rt2x00_desc_read(rxwi, 3, &rxwi3);
if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR))
if (rt2x00_get_field32(rxd0, RXINFO_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
rxdesc->cipher_status =
rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR);
rt2x00_get_field32(rxd0, RXINFO_W0_CIPHER_ERROR);
}
if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) {
if (rt2x00_get_field32(rxd0, RXINFO_W0_DECRYPTED)) {
/*
* Hardware has stripped IV/EIV data from 802.11 frame during
* decryption. Unfortunately the descriptor doesn't contain
@ -618,10 +622,10 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
rxdesc->flags |= RX_FLAG_MMIC_ERROR;
}
if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS))
if (rt2x00_get_field32(rxd0, RXINFO_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD)) {
if (rt2x00_get_field32(rxd0, RXINFO_W0_L2PAD)) {
rxdesc->dev_flags |= RXDONE_L2PAD;
skbdesc->flags |= SKBDESC_L2_PADDED;
}
@ -667,400 +671,18 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
*/
static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
{
u16 word;
u8 *mac;
u8 default_lna_gain;
if (rt2800_efuse_detect(rt2x00dev))
rt2800_read_eeprom_efuse(rt2x00dev);
else
rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
EEPROM_SIZE);
rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE);
/*
* Start validation of the data that has been read.
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
random_ether_addr(mac);
EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1);
rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
} else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) {
/*
* There is a max of 2 RX streams for RT2870 series
*/
if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2)
rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0);
rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0);
rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0);
rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
if ((word & 0x00ff) == 0x00ff) {
rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,
LED_MODE_TXRX_ACTIVITY);
rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);
EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
}
/*
* During the LNA validation we are going to use
* lna0 as correct value. Note that EEPROM_LNA
* is never validated.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &word);
default_lna_gain = rt2x00_get_field16(word, EEPROM_LNA_A0);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET0)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET0, 0);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG_OFFSET1)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_BG_OFFSET1, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG, word);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_BG2_OFFSET2)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_BG2_OFFSET2, 0);
if (rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0x00 ||
rt2x00_get_field16(word, EEPROM_RSSI_BG2_LNA_A1) == 0xff)
rt2x00_set_field16(&word, EEPROM_RSSI_BG2_LNA_A1,
default_lna_gain);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_BG2, word);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET0)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET0, 0);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A_OFFSET1)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_A_OFFSET1, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A, word);
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &word);
if (abs(rt2x00_get_field16(word, EEPROM_RSSI_A2_OFFSET2)) > 10)
rt2x00_set_field16(&word, EEPROM_RSSI_A2_OFFSET2, 0);
if (rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0x00 ||
rt2x00_get_field16(word, EEPROM_RSSI_A2_LNA_A2) == 0xff)
rt2x00_set_field16(&word, EEPROM_RSSI_A2_LNA_A2,
default_lna_gain);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word);
return 0;
}
static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
u16 value;
u16 eeprom;
/*
* Read EEPROM word for configuration.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
/*
* Identify RF chipset.
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, RT2870, value, reg);
/*
* The check for rt2860 is not a typo, some rt2870 hardware
* identifies itself as rt2860 in the CSR register.
*/
if (!rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28600000) &&
!rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28700000) &&
!rt2x00_check_rev(&rt2x00dev->chip, 0xfff00000, 0x28800000) &&
!rt2x00_check_rev(&rt2x00dev->chip, 0xffff0000, 0x30700000)) {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}
if (!rt2x00_rf(&rt2x00dev->chip, RF2820) &&
!rt2x00_rf(&rt2x00dev->chip, RF2850) &&
!rt2x00_rf(&rt2x00dev->chip, RF2720) &&
!rt2x00_rf(&rt2x00dev->chip, RF2750) &&
!rt2x00_rf(&rt2x00dev->chip, RF3020) &&
!rt2x00_rf(&rt2x00dev->chip, RF2020)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
}
/*
* Identify default antenna configuration.
*/
rt2x00dev->default_ant.tx =
rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH);
rt2x00dev->default_ant.rx =
rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH);
/*
* Read frequency offset and RF programming sequence.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
/*
* Read external LNA informations.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
__set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
/*
* Detect if this device has an hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
/*
* Store led settings, for correct led behaviour.
*/
#ifdef CONFIG_RT2X00_LIB_LEDS
rt2800_init_led(rt2x00dev, &rt2x00dev->led_radio, LED_TYPE_RADIO);
rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ,
&rt2x00dev->led_mcu_reg);
#endif /* CONFIG_RT2X00_LIB_LEDS */
return 0;
}
/*
* RF value list for rt2870
* Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750)
*/
static const struct rf_channel rf_vals[] = {
{ 1, 0x18402ecc, 0x184c0786, 0x1816b455, 0x1800510b },
{ 2, 0x18402ecc, 0x184c0786, 0x18168a55, 0x1800519f },
{ 3, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800518b },
{ 4, 0x18402ecc, 0x184c078a, 0x18168a55, 0x1800519f },
{ 5, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800518b },
{ 6, 0x18402ecc, 0x184c078e, 0x18168a55, 0x1800519f },
{ 7, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800518b },
{ 8, 0x18402ecc, 0x184c0792, 0x18168a55, 0x1800519f },
{ 9, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800518b },
{ 10, 0x18402ecc, 0x184c0796, 0x18168a55, 0x1800519f },
{ 11, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800518b },
{ 12, 0x18402ecc, 0x184c079a, 0x18168a55, 0x1800519f },
{ 13, 0x18402ecc, 0x184c079e, 0x18168a55, 0x1800518b },
{ 14, 0x18402ecc, 0x184c07a2, 0x18168a55, 0x18005193 },
/* 802.11 UNI / HyperLan 2 */
{ 36, 0x18402ecc, 0x184c099a, 0x18158a55, 0x180ed1a3 },
{ 38, 0x18402ecc, 0x184c099e, 0x18158a55, 0x180ed193 },
{ 40, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed183 },
{ 44, 0x18402ec8, 0x184c0682, 0x18158a55, 0x180ed1a3 },
{ 46, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed18b },
{ 48, 0x18402ec8, 0x184c0686, 0x18158a55, 0x180ed19b },
{ 52, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed193 },
{ 54, 0x18402ec8, 0x184c068a, 0x18158a55, 0x180ed1a3 },
{ 56, 0x18402ec8, 0x184c068e, 0x18158a55, 0x180ed18b },
{ 60, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed183 },
{ 62, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed193 },
{ 64, 0x18402ec8, 0x184c0692, 0x18158a55, 0x180ed1a3 },
/* 802.11 HyperLan 2 */
{ 100, 0x18402ec8, 0x184c06b2, 0x18178a55, 0x180ed783 },
{ 102, 0x18402ec8, 0x184c06b2, 0x18578a55, 0x180ed793 },
{ 104, 0x18402ec8, 0x185c06b2, 0x18578a55, 0x180ed1a3 },
{ 108, 0x18402ecc, 0x185c0a32, 0x18578a55, 0x180ed193 },
{ 110, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed183 },
{ 112, 0x18402ecc, 0x184c0a36, 0x18178a55, 0x180ed19b },
{ 116, 0x18402ecc, 0x184c0a3a, 0x18178a55, 0x180ed1a3 },
{ 118, 0x18402ecc, 0x184c0a3e, 0x18178a55, 0x180ed193 },
{ 120, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed183 },
{ 124, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed193 },
{ 126, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed15b },
{ 128, 0x18402ec4, 0x184c0382, 0x18178a55, 0x180ed1a3 },
{ 132, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed18b },
{ 134, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed193 },
{ 136, 0x18402ec4, 0x184c0386, 0x18178a55, 0x180ed19b },
{ 140, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed183 },
/* 802.11 UNII */
{ 149, 0x18402ec4, 0x184c038a, 0x18178a55, 0x180ed1a7 },
{ 151, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed187 },
{ 153, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed18f },
{ 157, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed19f },
{ 159, 0x18402ec4, 0x184c038e, 0x18178a55, 0x180ed1a7 },
{ 161, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed187 },
{ 165, 0x18402ec4, 0x184c0392, 0x18178a55, 0x180ed197 },
{ 167, 0x18402ec4, 0x184c03d2, 0x18179855, 0x1815531f },
{ 169, 0x18402ec4, 0x184c03d2, 0x18179855, 0x18155327 },
{ 171, 0x18402ec4, 0x184c03d6, 0x18179855, 0x18155307 },
{ 173, 0x18402ec4, 0x184c03d6, 0x18179855, 0x1815530f },
/* 802.11 Japan */
{ 184, 0x15002ccc, 0x1500491e, 0x1509be55, 0x150c0a0b },
{ 188, 0x15002ccc, 0x15004922, 0x1509be55, 0x150c0a13 },
{ 192, 0x15002ccc, 0x15004926, 0x1509be55, 0x150c0a1b },
{ 196, 0x15002ccc, 0x1500492a, 0x1509be55, 0x150c0a23 },
{ 208, 0x15002ccc, 0x1500493a, 0x1509be55, 0x150c0a13 },
{ 212, 0x15002ccc, 0x1500493e, 0x1509be55, 0x150c0a1b },
{ 216, 0x15002ccc, 0x15004982, 0x1509be55, 0x150c0a23 },
};
/*
* RF value list for rt3070
* Supports: 2.4 GHz
*/
static const struct rf_channel rf_vals_3070[] = {
{1, 241, 2, 2 },
{2, 241, 2, 7 },
{3, 242, 2, 2 },
{4, 242, 2, 7 },
{5, 243, 2, 2 },
{6, 243, 2, 7 },
{7, 244, 2, 2 },
{8, 244, 2, 7 },
{9, 245, 2, 2 },
{10, 245, 2, 7 },
{11, 246, 2, 2 },
{12, 246, 2, 7 },
{13, 247, 2, 2 },
{14, 248, 2, 4 },
};
static int rt2800usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
struct channel_info *info;
char *tx_power1;
char *tx_power2;
unsigned int i;
u16 eeprom;
/*
* Initialize all hw fields.
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK;
rt2x00dev->hw->extra_tx_headroom = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
rt2x00_eeprom_addr(rt2x00dev,
EEPROM_MAC_ADDR_0));
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
/*
* Initialize HT information.
*/
spec->ht.ht_supported = true;
spec->ht.cap =
IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_TX_STBC |
IEEE80211_HT_CAP_RX_STBC |
IEEE80211_HT_CAP_PSMP_SUPPORT;
spec->ht.ampdu_factor = 3;
spec->ht.ampdu_density = 4;
spec->ht.mcs.tx_params =
IEEE80211_HT_MCS_TX_DEFINED |
IEEE80211_HT_MCS_TX_RX_DIFF |
((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) <<
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) {
case 3:
spec->ht.mcs.rx_mask[2] = 0xff;
case 2:
spec->ht.mcs.rx_mask[1] = 0xff;
case 1:
spec->ht.mcs.rx_mask[0] = 0xff;
spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */
break;
}
/*
* Initialize hw_mode information.
*/
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
if (rt2x00_rf(&rt2x00dev->chip, RF2820) ||
rt2x00_rf(&rt2x00dev->chip, RF2720)) {
spec->num_channels = 14;
spec->channels = rf_vals;
} else if (rt2x00_rf(&rt2x00dev->chip, RF2850) ||
rt2x00_rf(&rt2x00dev->chip, RF2750)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals);
spec->channels = rf_vals;
} else if (rt2x00_rf(&rt2x00dev->chip, RF3020) ||
rt2x00_rf(&rt2x00dev->chip, RF2020)) {
spec->num_channels = ARRAY_SIZE(rf_vals_3070);
spec->channels = rf_vals_3070;
}
/*
* Create channel information array
*/
info = kzalloc(spec->num_channels * sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
spec->channels_info = info;
tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1);
tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2);
for (i = 0; i < 14; i++) {
info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]);
info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]);
}
if (spec->num_channels > 14) {
tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1);
tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2);
for (i = 14; i < spec->num_channels; i++) {
info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]);
info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]);
}
}
return 0;
return rt2800_validate_eeprom(rt2x00dev);
}
static const struct rt2800_ops rt2800usb_rt2800_ops = {
.register_read = rt2x00usb_register_read,
.register_read_lock = rt2x00usb_register_read_lock,
.register_write = rt2x00usb_register_write,
.register_write_lock = rt2x00usb_register_write_lock,
@ -1074,8 +696,6 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
rt2x00dev->priv = (void *)&rt2800usb_rt2800_ops;
/*
@ -1085,14 +705,14 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
if (retval)
return retval;
retval = rt2800usb_init_eeprom(rt2x00dev);
retval = rt2800_init_eeprom(rt2x00dev);
if (retval)
return retval;
/*
* Initialize hw specifications.
*/
retval = rt2800usb_probe_hw_mode(rt2x00dev);
retval = rt2800_probe_hw_mode(rt2x00dev);
if (retval)
return retval;

View File

@ -1,5 +1,9 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2009 Mattias Nissler <mattias.nissler@gmx.de>
Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
Copyright (C) 2009 Xose Vazquez Perez <xose.vazquez@gmail.com>
Copyright (C) 2009 Axel Kollhofer <rain_maker@root-forum.org>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -111,25 +115,25 @@
* AMSDU: rx with 802.3 header, not 802.11 header.
*/
#define RXD_W0_BA FIELD32(0x00000001)
#define RXD_W0_DATA FIELD32(0x00000002)
#define RXD_W0_NULLDATA FIELD32(0x00000004)
#define RXD_W0_FRAG FIELD32(0x00000008)
#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000010)
#define RXD_W0_MULTICAST FIELD32(0x00000020)
#define RXD_W0_BROADCAST FIELD32(0x00000040)
#define RXD_W0_MY_BSS FIELD32(0x00000080)
#define RXD_W0_CRC_ERROR FIELD32(0x00000100)
#define RXD_W0_CIPHER_ERROR FIELD32(0x00000600)
#define RXD_W0_AMSDU FIELD32(0x00000800)
#define RXD_W0_HTC FIELD32(0x00001000)
#define RXD_W0_RSSI FIELD32(0x00002000)
#define RXD_W0_L2PAD FIELD32(0x00004000)
#define RXD_W0_AMPDU FIELD32(0x00008000)
#define RXD_W0_DECRYPTED FIELD32(0x00010000)
#define RXD_W0_PLCP_RSSI FIELD32(0x00020000)
#define RXD_W0_CIPHER_ALG FIELD32(0x00040000)
#define RXD_W0_LAST_AMSDU FIELD32(0x00080000)
#define RXD_W0_PLCP_SIGNAL FIELD32(0xfff00000)
#define RXINFO_W0_BA FIELD32(0x00000001)
#define RXINFO_W0_DATA FIELD32(0x00000002)
#define RXINFO_W0_NULLDATA FIELD32(0x00000004)
#define RXINFO_W0_FRAG FIELD32(0x00000008)
#define RXINFO_W0_UNICAST_TO_ME FIELD32(0x00000010)
#define RXINFO_W0_MULTICAST FIELD32(0x00000020)
#define RXINFO_W0_BROADCAST FIELD32(0x00000040)
#define RXINFO_W0_MY_BSS FIELD32(0x00000080)
#define RXINFO_W0_CRC_ERROR FIELD32(0x00000100)
#define RXINFO_W0_CIPHER_ERROR FIELD32(0x00000600)
#define RXINFO_W0_AMSDU FIELD32(0x00000800)
#define RXINFO_W0_HTC FIELD32(0x00001000)
#define RXINFO_W0_RSSI FIELD32(0x00002000)
#define RXINFO_W0_L2PAD FIELD32(0x00004000)
#define RXINFO_W0_AMPDU FIELD32(0x00008000)
#define RXINFO_W0_DECRYPTED FIELD32(0x00010000)
#define RXINFO_W0_PLCP_RSSI FIELD32(0x00020000)
#define RXINFO_W0_CIPHER_ALG FIELD32(0x00040000)
#define RXINFO_W0_LAST_AMSDU FIELD32(0x00080000)
#define RXINFO_W0_PLCP_SIGNAL FIELD32(0xfff00000)
#endif /* RT2800USB_H */

View File

@ -1,5 +1,6 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -171,6 +172,7 @@ struct rt2x00_chip {
#define RT3052 0x3052 /* WSOC */
#define RT3090 0x3090 /* 2.4GHz PCIe */
#define RT2870 0x1600
#define RT3070 0x1800
u16 rf;
u32 rev;
@ -312,13 +314,6 @@ struct link {
*/
struct avg_val avg_rssi;
/*
* Currently precalculated percentages of successful
* TX and RX frames.
*/
int rx_percentage;
int tx_percentage;
/*
* Work structure for scheduling periodic link tuning.
*/
@ -911,10 +906,6 @@ static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev,
static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev,
const u16 rt, const u16 rf, const u32 rev)
{
INFO(rt2x00dev,
"Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n",
rt, rf, rev);
rt2x00dev->chip.rt = rt;
rt2x00dev->chip.rf = rf;
rt2x00dev->chip.rev = rev;
@ -932,6 +923,13 @@ static inline void rt2x00_set_chip_rf(struct rt2x00_dev *rt2x00dev,
rt2x00_set_chip(rt2x00dev, rt2x00dev->chip.rt, rf, rev);
}
static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev)
{
INFO(rt2x00dev,
"Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n",
rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev);
}
static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip)
{
return (chipset->rt == chip);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -430,7 +430,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
rx_status->mactime = rxdesc.timestamp;
rx_status->rate_idx = rate_idx;
rx_status->qual = rt2x00link_calculate_signal(rt2x00dev, rxdesc.rssi);
rx_status->signal = rxdesc.rssi;
rx_status->noise = rxdesc.noise;
rx_status->flag = rxdesc.flags;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,6 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,6 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -222,19 +223,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct rxdone_entry_desc *rxdesc);
/**
* rt2x00link_calculate_signal - Calculate signal quality
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @rssi: RX Frame RSSI
*
* Calculate the signal quality of a frame based on the rssi
* measured during the receiving of the frame and the global
* link quality statistics measured since the start of the
* link tuning. The result is a value between 0 and 100 which
* is an indication of the signal quality.
*/
int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi);
/**
* rt2x00link_start_tuner - Start periodic link tuner work
* @rt2x00dev: Pointer to &struct rt2x00_dev.

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -35,24 +35,6 @@
*/
#define DEFAULT_RSSI -128
/*
* When no TX/RX percentage could be calculated due to lack of
* frames on the air, we fallback to a percentage of 50%.
* This will assure we will get at least get some decent value
* when the link tuner starts.
* The value will be dropped and overwritten with the correct (measured)
* value anyway during the first run of the link tuner.
*/
#define DEFAULT_PERCENTAGE 50
/*
* Small helper macro for percentage calculation
* This is a very simple macro with the only catch that it will
* produce a default value in case no total value was provided.
*/
#define PERCENTAGE(__value, __total) \
( (__total) ? (((__value) * 100) / (__total)) : (DEFAULT_PERCENTAGE) )
/*
* Helper struct and macro to work with moving/walking averages.
* When adding a value to the average value the following calculation
@ -91,27 +73,6 @@
__new; \
})
/*
* For calculating the Signal quality we have determined
* the total number of success and failed RX and TX frames.
* With the addition of the average RSSI value we can determine
* the link quality using the following algorithm:
*
* rssi_percentage = (avg_rssi * 100) / rssi_offset
* rx_percentage = (rx_success * 100) / rx_total
* tx_percentage = (tx_success * 100) / tx_total
* avg_signal = ((WEIGHT_RSSI * avg_rssi) +
* (WEIGHT_TX * tx_percentage) +
* (WEIGHT_RX * rx_percentage)) / 100
*
* This value should then be checked to not be greater then 100.
* This means the values of WEIGHT_RSSI, WEIGHT_RX, WEIGHT_TX must
* sum up to 100 as well.
*/
#define WEIGHT_RSSI 20
#define WEIGHT_RX 40
#define WEIGHT_TX 40
static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
{
struct link_ant *ant = &rt2x00dev->link.ant;
@ -304,46 +265,6 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi);
}
static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
{
struct link *link = &rt2x00dev->link;
struct link_qual *qual = &rt2x00dev->link.qual;
link->rx_percentage =
PERCENTAGE(qual->rx_success, qual->rx_failed + qual->rx_success);
link->tx_percentage =
PERCENTAGE(qual->tx_success, qual->tx_failed + qual->tx_success);
}
int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi)
{
struct link *link = &rt2x00dev->link;
int rssi_percentage = 0;
int signal;
/*
* We need a positive value for the RSSI.
*/
if (rssi < 0)
rssi += rt2x00dev->rssi_offset;
/*
* Calculate the different percentages,
* which will be used for the signal.
*/
rssi_percentage = PERCENTAGE(rssi, rt2x00dev->rssi_offset);
/*
* Add the individual percentages and use the WEIGHT
* defines to calculate the current link signal.
*/
signal = ((WEIGHT_RSSI * rssi_percentage) +
(WEIGHT_TX * link->tx_percentage) +
(WEIGHT_RX * link->rx_percentage)) / 100;
return max_t(int, signal, 100);
}
void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
{
struct link *link = &rt2x00dev->link;
@ -357,9 +278,6 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)
return;
link->rx_percentage = DEFAULT_PERCENTAGE;
link->tx_percentage = DEFAULT_PERCENTAGE;
rt2x00link_reset_tuner(rt2x00dev, false);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
@ -447,12 +365,6 @@ static void rt2x00link_tuner(struct work_struct *work)
if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
/*
* Precalculate a portion of the link signal which is
* in based on the tx/rx success/failure counters.
*/
rt2x00link_precalculate_signal(rt2x00dev);
/*
* Send a signal to the led to update the led signal strength.
*/

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -310,6 +310,8 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
rt2x00dev->irq = pci_dev->irq;
rt2x00dev->name = pci_name(pci_dev);
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
/*
* Determine RT chipset by reading PCI header.
*/

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,6 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,6 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
Copyright (C) 2004 - 2009 Felix Fietkau <nbd@openwrt.org>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -93,6 +94,11 @@ int rt2x00soc_probe(struct platform_device *pdev,
rt2x00dev->irq = platform_get_irq(pdev, 0);
rt2x00dev->name = pdev->dev.driver->name;
/*
* SoC devices mimic PCI behavior.
*/
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
rt2x00_set_chip_rt(rt2x00dev, chipset);
retval = rt2x00soc_alloc_reg(rt2x00dev);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -653,6 +653,8 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
rt2x00dev->ops = ops;
rt2x00dev->hw = hw;
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_USB);
retval = rt2x00usb_alloc_reg(rt2x00dev);
if (retval)
goto exit_free_device;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -26,6 +26,8 @@
#ifndef RT2X00USB_H
#define RT2X00USB_H
#include <linux/usb.h>
#define to_usb_device_intf(d) \
({ \
struct usb_interface *intf = to_usb_interface(d); \

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -51,7 +51,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
* These indirect registers work with busy bits,
* and we will try maximal REGISTER_BUSY_COUNT times to access
* the register while taking a REGISTER_BUSY_DELAY us delay
* between each attampt. When the busy bit is still set at that time,
* between each attempt. When the busy bit is still set at that time,
* the access attempt is considered to have failed,
* and we will print an error.
*/
@ -386,7 +386,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
* The driver does not support the IV/EIV generation
* in hardware. However it doesn't support the IV/EIV
* inside the ieee80211 frame either, but requires it
* to be provided seperately for the descriptor.
* to be provided separately for the descriptor.
* rt2x00lib will cut the IV/EIV data out of all frames
* given to us by mac80211, but we must tell mac80211
* to generate the IV/EIV data.
@ -397,7 +397,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
/*
* SEC_CSR0 contains only single-bit fields to indicate
* a particular key is valid. Because using the FIELD32()
* defines directly will cause a lot of overhead we use
* defines directly will cause a lot of overhead, we use
* a calculation to determine the correct bit directly.
*/
mask = 1 << key->hw_key_idx;
@ -425,11 +425,11 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
/*
* rt2x00lib can't determine the correct free
* key_idx for pairwise keys. We have 2 registers
* with key valid bits. The goal is simple, read
* the first register, if that is full move to
* with key valid bits. The goal is simple: read
* the first register. If that is full, move to
* the next register.
* When both registers are full, we drop the key,
* otherwise we use the first invalid entry.
* When both registers are full, we drop the key.
* Otherwise, we use the first invalid entry.
*/
rt2x00pci_register_read(rt2x00dev, SEC_CSR2, &reg);
if (reg && reg == ~0) {
@ -464,8 +464,8 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
&addr_entry, sizeof(addr_entry));
/*
* Enable pairwise lookup table for given BSS idx,
* without this received frames will not be decrypted
* Enable pairwise lookup table for given BSS idx.
* Without this, received frames will not be decrypted
* by the hardware.
*/
rt2x00pci_register_read(rt2x00dev, SEC_CSR4, &reg);
@ -487,7 +487,7 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
/*
* SEC_CSR2 and SEC_CSR3 contain only single-bit fields to indicate
* a particular key is valid. Because using the FIELD32()
* defines directly will cause a lot of overhead we use
* defines directly will cause a lot of overhead, we use
* a calculation to determine the correct bit directly.
*/
if (key->hw_key_idx < 32) {
@ -556,7 +556,7 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev,
if (flags & CONFIG_UPDATE_TYPE) {
/*
* Clear current synchronisation setup.
* For the Beacon base registers we only need to clear
* For the Beacon base registers, we only need to clear
* the first byte since that byte contains the VALID and OWNER
* bits which (when set to 0) will invalidate the entire beacon.
*/
@ -1168,8 +1168,8 @@ static int rt61pci_check_firmware(struct rt2x00_dev *rt2x00dev,
return FW_BAD_LENGTH;
/*
* The last 2 bytes in the firmware array are the crc checksum itself,
* this means that we should never pass those 2 bytes to the crc
* The last 2 bytes in the firmware array are the crc checksum itself.
* This means that we should never pass those 2 bytes to the crc
* algorithm.
*/
fw_crc = (data[len - 2] << 8 | data[len - 1]);
@ -1986,7 +1986,7 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
/*
* Hardware has stripped IV/EIV data from 802.11 frame during
* decryption. It has provided the data seperately but rt2x00lib
* decryption. It has provided the data separately but rt2x00lib
* should decide if it should be reinserted.
*/
rxdesc->flags |= RX_FLAG_IV_STRIPPED;
@ -2042,7 +2042,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
* During each loop we will compare the freshly read
* STA_CSR4 register value with the value read from
* the previous loop. If the 2 values are equal then
* we should stop processing because the chance it
* we should stop processing because the chance is
* quite big that the device has been unplugged and
* we risk going into an endless loop.
*/
@ -2300,6 +2300,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip_rf(rt2x00dev, value, reg);
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_rf(&rt2x00dev->chip, RF5225) &&
!rt2x00_rf(&rt2x00dev->chip, RF5325) &&
@ -2330,7 +2331,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
__set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
/*
* Detect if this device has an hardware controlled radio.
* Detect if this device has a hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
@ -2355,7 +2356,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
/*
* When working with a RF2529 chip without double antenna
* When working with a RF2529 chip without double antenna,
* the antenna settings should be gathered from the NIC
* eeprom word.
*/
@ -2668,7 +2669,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
/*
* We only need to perform additional register initialization
* for WMM queues/
* for WMM queues.
*/
if (queue_idx >= 4)
return 0;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
@ -1825,6 +1825,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
rt2x00usb_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
rt2x00_print_chip(rt2x00dev);
if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) ||
rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify

View File

@ -1431,3 +1431,4 @@ MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kalle.valo@nokia.com>");
MODULE_ALIAS("spi:wl1251");
MODULE_FIRMWARE(WL1251_FW_NAME);

View File

@ -1979,3 +1979,4 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
MODULE_FIRMWARE(WL1271_FW_NAME);

View File

@ -112,6 +112,9 @@ exit:
return err;
}
MODULE_FIRMWARE("zd1201-ap.fw");
MODULE_FIRMWARE("zd1201.fw");
static void zd1201_usbfree(struct urb *urb)
{
struct zd1201 *zd = urb->context;

View File

@ -318,6 +318,13 @@ error:
return r;
}
MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ur");
MODULE_FIRMWARE(FW_ZD1211_PREFIX "ur");
MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ub");
MODULE_FIRMWARE(FW_ZD1211_PREFIX "ub");
MODULE_FIRMWARE(FW_ZD1211B_PREFIX "uphr");
MODULE_FIRMWARE(FW_ZD1211_PREFIX "uphr");
/* Read data from device address space using "firmware interface" which does
* not require firmware to be loaded. */
int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len)

View File

@ -103,8 +103,7 @@
#include <asm/io.h>
#include <asm/dma.h>
/* This include could be elsewhere, since it is not wireless specific */
#include "wireless/i82593.h"
#include <linux/i82593.h>
static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n";

View File

@ -1,6 +1,6 @@
config ARLAN
tristate "Aironet Arlan 655 & IC2200 DS support"
depends on ISA && !64BIT
depends on ISA && !64BIT && WLAN
select WIRELESS_EXT
---help---
Aironet makes Arlan, a class of wireless LAN adapters. These use the

View File

@ -1,6 +1,6 @@
config PCMCIA_NETWAVE
tristate "Xircom Netwave AirSurfer Pcmcia wireless support"
depends on PCMCIA
depends on PCMCIA && WLAN
select WIRELESS_EXT
select WEXT_PRIV
help

View File

@ -1,6 +1,6 @@
config WAVELAN
tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support"
depends on ISA
depends on ISA && WLAN
select WIRELESS_EXT
select WEXT_SPY
select WEXT_PRIV
@ -25,7 +25,7 @@ config WAVELAN
config PCMCIA_WAVELAN
tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support"
depends on PCMCIA
depends on PCMCIA && WLAN
select WIRELESS_EXT
select WEXT_SPY
select WEXT_PRIV

View File

@ -446,7 +446,7 @@
#include <pcmcia/ds.h>
/* Wavelan declarations */
#include "i82593.h" /* Definitions for the Intel chip */
#include <linux/i82593.h> /* Definitions for the Intel chip */
#include "wavelan_cs.h" /* Others bits of the hardware */

Some files were not shown because too many files have changed in this diff Show More