Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
@@ -1206,6 +1206,7 @@ extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
|
||||
/* Beacon control functions */
|
||||
extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah);
|
||||
extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
|
||||
extern void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64);
|
||||
extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
|
||||
extern void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
|
||||
#if 0
|
||||
|
@@ -232,13 +232,14 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
|
||||
int mc_count, struct dev_mc_list *mclist);
|
||||
static int ath5k_set_key(struct ieee80211_hw *hw,
|
||||
enum set_key_cmd cmd,
|
||||
const u8 *local_addr, const u8 *addr,
|
||||
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key);
|
||||
static int ath5k_get_stats(struct ieee80211_hw *hw,
|
||||
struct ieee80211_low_level_stats *stats);
|
||||
static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_queue_stats *stats);
|
||||
static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
|
||||
static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf);
|
||||
static void ath5k_reset_tsf(struct ieee80211_hw *hw);
|
||||
static int ath5k_beacon_update(struct ath5k_softc *sc,
|
||||
struct sk_buff *skb);
|
||||
@@ -261,6 +262,7 @@ static struct ieee80211_ops ath5k_hw_ops = {
|
||||
.conf_tx = NULL,
|
||||
.get_tx_stats = ath5k_get_tx_stats,
|
||||
.get_tsf = ath5k_get_tsf,
|
||||
.set_tsf = ath5k_set_tsf,
|
||||
.reset_tsf = ath5k_reset_tsf,
|
||||
.bss_info_changed = ath5k_bss_info_changed,
|
||||
};
|
||||
@@ -347,9 +349,9 @@ static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
|
||||
}
|
||||
|
||||
/* Interrupt handling */
|
||||
static int ath5k_init(struct ath5k_softc *sc, bool is_resume);
|
||||
static int ath5k_init(struct ath5k_softc *sc);
|
||||
static int ath5k_stop_locked(struct ath5k_softc *sc);
|
||||
static int ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend);
|
||||
static int ath5k_stop_hw(struct ath5k_softc *sc);
|
||||
static irqreturn_t ath5k_intr(int irq, void *dev_id);
|
||||
static void ath5k_tasklet_reset(unsigned long data);
|
||||
|
||||
@@ -653,8 +655,6 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
|
||||
ath5k_led_off(sc);
|
||||
|
||||
ath5k_stop_hw(sc, true);
|
||||
|
||||
free_irq(pdev->irq, sc);
|
||||
pci_save_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
@@ -689,14 +689,9 @@ ath5k_pci_resume(struct pci_dev *pdev)
|
||||
goto err_no_irq;
|
||||
}
|
||||
|
||||
err = ath5k_init(sc, true);
|
||||
if (err)
|
||||
goto err_irq;
|
||||
ath5k_led_enable(sc);
|
||||
|
||||
return 0;
|
||||
err_irq:
|
||||
free_irq(pdev->irq, sc);
|
||||
|
||||
err_no_irq:
|
||||
pci_disable_device(pdev);
|
||||
return err;
|
||||
@@ -1098,6 +1093,42 @@ ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix)
|
||||
* Buffers setup *
|
||||
\***************/
|
||||
|
||||
static
|
||||
struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
unsigned int off;
|
||||
|
||||
/*
|
||||
* Allocate buffer with headroom_needed space for the
|
||||
* fake physical layer header at the start.
|
||||
*/
|
||||
skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1);
|
||||
|
||||
if (!skb) {
|
||||
ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
|
||||
sc->rxbufsize + sc->cachelsz - 1);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Cache-line-align. This is important (for the
|
||||
* 5210 at least) as not doing so causes bogus data
|
||||
* in rx'd frames.
|
||||
*/
|
||||
off = ((unsigned long)skb->data) % sc->cachelsz;
|
||||
if (off != 0)
|
||||
skb_reserve(skb, sc->cachelsz - off);
|
||||
|
||||
*skb_addr = pci_map_single(sc->pdev,
|
||||
skb->data, sc->rxbufsize, 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);
|
||||
return NULL;
|
||||
}
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int
|
||||
ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
||||
{
|
||||
@@ -1105,37 +1136,11 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
||||
struct sk_buff *skb = bf->skb;
|
||||
struct ath5k_desc *ds;
|
||||
|
||||
if (likely(skb == NULL)) {
|
||||
unsigned int off;
|
||||
|
||||
/*
|
||||
* Allocate buffer with headroom_needed space for the
|
||||
* fake physical layer header at the start.
|
||||
*/
|
||||
skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1);
|
||||
if (unlikely(skb == NULL)) {
|
||||
ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
|
||||
sc->rxbufsize + sc->cachelsz - 1);
|
||||
if (!skb) {
|
||||
skb = ath5k_rx_skb_alloc(sc, &bf->skbaddr);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
}
|
||||
/*
|
||||
* Cache-line-align. This is important (for the
|
||||
* 5210 at least) as not doing so causes bogus data
|
||||
* in rx'd frames.
|
||||
*/
|
||||
off = ((unsigned long)skb->data) % sc->cachelsz;
|
||||
if (off != 0)
|
||||
skb_reserve(skb, sc->cachelsz - off);
|
||||
|
||||
bf->skb = skb;
|
||||
bf->skbaddr = pci_map_single(sc->pdev,
|
||||
skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
|
||||
if (unlikely(pci_dma_mapping_error(sc->pdev, bf->skbaddr))) {
|
||||
ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
|
||||
dev_kfree_skb(skb);
|
||||
bf->skb = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1178,6 +1183,10 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
||||
struct ieee80211_rate *rate;
|
||||
unsigned int mrr_rate[3], mrr_tries[3];
|
||||
int i, ret;
|
||||
u16 hw_rate;
|
||||
u16 cts_rate = 0;
|
||||
u16 duration = 0;
|
||||
u8 rc_flags;
|
||||
|
||||
flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
|
||||
|
||||
@@ -1185,11 +1194,30 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
||||
bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
|
||||
PCI_DMA_TODEVICE);
|
||||
|
||||
rate = ieee80211_get_tx_rate(sc->hw, info);
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
|
||||
flags |= AR5K_TXDESC_NOACK;
|
||||
|
||||
rc_flags = info->control.rates[0].flags;
|
||||
hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ?
|
||||
rate->hw_value_short : rate->hw_value;
|
||||
|
||||
pktlen = skb->len;
|
||||
|
||||
if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
|
||||
flags |= AR5K_TXDESC_RTSENA;
|
||||
cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
|
||||
duration = le16_to_cpu(ieee80211_rts_duration(sc->hw,
|
||||
sc->vif, pktlen, info));
|
||||
}
|
||||
if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
|
||||
flags |= AR5K_TXDESC_CTSENA;
|
||||
cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
|
||||
duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw,
|
||||
sc->vif, pktlen, info));
|
||||
}
|
||||
|
||||
if (info->control.hw_key) {
|
||||
keyidx = info->control.hw_key->hw_key_idx;
|
||||
pktlen += info->control.hw_key->icv_len;
|
||||
@@ -1197,8 +1225,9 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
||||
ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
|
||||
ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
|
||||
(sc->power_level * 2),
|
||||
ieee80211_get_tx_rate(sc->hw, info)->hw_value,
|
||||
info->control.rates[0].count, keyidx, 0, flags, 0, 0);
|
||||
hw_rate,
|
||||
info->control.rates[0].count, keyidx, 0, flags,
|
||||
cts_rate, duration);
|
||||
if (ret)
|
||||
goto err_unmap;
|
||||
|
||||
@@ -1664,7 +1693,8 @@ ath5k_tasklet_rx(unsigned long data)
|
||||
{
|
||||
struct ieee80211_rx_status rxs = {};
|
||||
struct ath5k_rx_status rs = {};
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff *skb, *next_skb;
|
||||
dma_addr_t next_skb_addr;
|
||||
struct ath5k_softc *sc = (void *)data;
|
||||
struct ath5k_buf *bf, *bf_last;
|
||||
struct ath5k_desc *ds;
|
||||
@@ -1749,10 +1779,17 @@ ath5k_tasklet_rx(unsigned long data)
|
||||
goto next;
|
||||
}
|
||||
accept:
|
||||
next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr);
|
||||
|
||||
/*
|
||||
* If we can't replace bf->skb with a new skb under memory
|
||||
* pressure, just skip this packet
|
||||
*/
|
||||
if (!next_skb)
|
||||
goto next;
|
||||
|
||||
pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
bf->skb = NULL;
|
||||
|
||||
skb_put(skb, rs.rs_datalen);
|
||||
|
||||
/* The MAC header is padded to have 32-bit boundary if the
|
||||
@@ -1825,6 +1862,9 @@ accept:
|
||||
ath5k_check_ibss_tsf(sc, skb, &rxs);
|
||||
|
||||
__ieee80211_rx(sc->hw, skb, &rxs);
|
||||
|
||||
bf->skb = next_skb;
|
||||
bf->skbaddr = next_skb_addr;
|
||||
next:
|
||||
list_move_tail(&bf->list, &sc->rxbuf);
|
||||
} while (ath5k_rxbuf_setup(sc, bf) == 0);
|
||||
@@ -2207,18 +2247,13 @@ ath5k_beacon_config(struct ath5k_softc *sc)
|
||||
\********************/
|
||||
|
||||
static int
|
||||
ath5k_init(struct ath5k_softc *sc, bool is_resume)
|
||||
ath5k_init(struct ath5k_softc *sc)
|
||||
{
|
||||
struct ath5k_hw *ah = sc->ah;
|
||||
int ret, i;
|
||||
|
||||
mutex_lock(&sc->lock);
|
||||
|
||||
if (is_resume && !test_bit(ATH_STAT_STARTED, sc->status))
|
||||
goto out_ok;
|
||||
|
||||
__clear_bit(ATH_STAT_STARTED, sc->status);
|
||||
|
||||
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode);
|
||||
|
||||
/*
|
||||
@@ -2250,15 +2285,12 @@ ath5k_init(struct ath5k_softc *sc, bool is_resume)
|
||||
for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
|
||||
ath5k_hw_reset_key(ah, i);
|
||||
|
||||
__set_bit(ATH_STAT_STARTED, sc->status);
|
||||
|
||||
/* Set ack to be sent at low bit-rates */
|
||||
ath5k_hw_set_ack_bitrate_high(ah, false);
|
||||
|
||||
mod_timer(&sc->calib_tim, round_jiffies(jiffies +
|
||||
msecs_to_jiffies(ath5k_calinterval * 1000)));
|
||||
|
||||
out_ok:
|
||||
ret = 0;
|
||||
done:
|
||||
mmiowb();
|
||||
@@ -2313,7 +2345,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
|
||||
* stop is preempted).
|
||||
*/
|
||||
static int
|
||||
ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend)
|
||||
ath5k_stop_hw(struct ath5k_softc *sc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -2344,8 +2376,6 @@ ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend)
|
||||
}
|
||||
}
|
||||
ath5k_txbuf_free(sc, sc->bbuf);
|
||||
if (!is_suspend)
|
||||
__clear_bit(ATH_STAT_STARTED, sc->status);
|
||||
|
||||
mmiowb();
|
||||
mutex_unlock(&sc->lock);
|
||||
@@ -2598,6 +2628,17 @@ ath5k_init_leds(struct ath5k_softc *sc)
|
||||
sc->led_pin = 1;
|
||||
sc->led_on = 1; /* active high */
|
||||
}
|
||||
/*
|
||||
* Pin 3 on Foxconn chips used in Acer Aspire One (0x105b:e008) and
|
||||
* in emachines notebooks with AMBIT subsystem.
|
||||
*/
|
||||
if (pdev->subsystem_vendor == PCI_VENDOR_ID_FOXCONN ||
|
||||
pdev->subsystem_vendor == PCI_VENDOR_ID_AMBIT) {
|
||||
__set_bit(ATH_STAT_LEDSOFT, sc->status);
|
||||
sc->led_pin = 3;
|
||||
sc->led_on = 0; /* active low */
|
||||
}
|
||||
|
||||
if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
|
||||
goto out;
|
||||
|
||||
@@ -2745,12 +2786,12 @@ ath5k_reset_wake(struct ath5k_softc *sc)
|
||||
|
||||
static int ath5k_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
return ath5k_init(hw->priv, false);
|
||||
return ath5k_init(hw->priv);
|
||||
}
|
||||
|
||||
static void ath5k_stop(struct ieee80211_hw *hw)
|
||||
{
|
||||
ath5k_stop_hw(hw->priv, false);
|
||||
ath5k_stop_hw(hw->priv);
|
||||
}
|
||||
|
||||
static int ath5k_add_interface(struct ieee80211_hw *hw,
|
||||
@@ -2999,8 +3040,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
|
||||
|
||||
static int
|
||||
ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
const u8 *local_addr, const u8 *addr,
|
||||
struct ieee80211_key_conf *key)
|
||||
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct ath5k_softc *sc = hw->priv;
|
||||
int ret = 0;
|
||||
@@ -3023,7 +3064,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
|
||||
switch (cmd) {
|
||||
case SET_KEY:
|
||||
ret = ath5k_hw_set_key(sc->ah, key->keyidx, key, addr);
|
||||
ret = ath5k_hw_set_key(sc->ah, key->keyidx, key,
|
||||
sta ? sta->addr : NULL);
|
||||
if (ret) {
|
||||
ATH5K_ERR(sc, "can't set the key\n");
|
||||
goto unlock;
|
||||
@@ -3082,6 +3124,14 @@ ath5k_get_tsf(struct ieee80211_hw *hw)
|
||||
return ath5k_hw_get_tsf64(sc->ah);
|
||||
}
|
||||
|
||||
static void
|
||||
ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
|
||||
{
|
||||
struct ath5k_softc *sc = hw->priv;
|
||||
|
||||
ath5k_hw_set_tsf64(sc->ah, tsf);
|
||||
}
|
||||
|
||||
static void
|
||||
ath5k_reset_tsf(struct ieee80211_hw *hw)
|
||||
{
|
||||
|
@@ -148,8 +148,7 @@ struct ath5k_softc {
|
||||
u8 bssidmask[ETH_ALEN];
|
||||
|
||||
unsigned int led_pin, /* GPIO pin for driving LED */
|
||||
led_on, /* pin setting for LED on */
|
||||
led_off; /* off time for current blink */
|
||||
led_on; /* pin setting for LED on */
|
||||
|
||||
struct tasklet_struct restq; /* reset tasklet */
|
||||
|
||||
|
@@ -85,7 +85,8 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
|
||||
/* Enable 802.11b if a 2GHz capable radio (2111/5112) is
|
||||
* connected */
|
||||
if (AR5K_EEPROM_HDR_11B(ee_header) ||
|
||||
AR5K_EEPROM_HDR_11G(ee_header)) {
|
||||
(AR5K_EEPROM_HDR_11G(ee_header) &&
|
||||
ah->ah_version != AR5K_AR5211)) {
|
||||
/* 2312 */
|
||||
ah->ah_capabilities.cap_range.range_2ghz_min = 2412;
|
||||
ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
|
||||
@@ -94,7 +95,8 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
|
||||
__set_bit(AR5K_MODE_11B,
|
||||
ah->ah_capabilities.cap_mode);
|
||||
|
||||
if (AR5K_EEPROM_HDR_11G(ee_header))
|
||||
if (AR5K_EEPROM_HDR_11G(ee_header) &&
|
||||
ah->ah_version != AR5K_AR5211)
|
||||
__set_bit(AR5K_MODE_11G,
|
||||
ah->ah_capabilities.cap_mode);
|
||||
}
|
||||
|
@@ -193,43 +193,6 @@ static const struct file_operations fops_registers = {
|
||||
};
|
||||
|
||||
|
||||
/* debugfs: TSF */
|
||||
|
||||
static ssize_t read_file_tsf(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath5k_softc *sc = file->private_data;
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof(buf), "0x%016llx\n",
|
||||
(unsigned long long)ath5k_hw_get_tsf64(sc->ah));
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, 19);
|
||||
}
|
||||
|
||||
static ssize_t write_file_tsf(struct file *file,
|
||||
const char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath5k_softc *sc = file->private_data;
|
||||
char buf[20];
|
||||
|
||||
if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
|
||||
return -EFAULT;
|
||||
|
||||
if (strncmp(buf, "reset", 5) == 0) {
|
||||
ath5k_hw_reset_tsf(sc->ah);
|
||||
printk(KERN_INFO "debugfs reset TSF\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_tsf = {
|
||||
.read = read_file_tsf,
|
||||
.write = write_file_tsf,
|
||||
.open = ath5k_debugfs_open,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
/* debugfs: beacons */
|
||||
|
||||
static ssize_t read_file_beacon(struct file *file, char __user *user_buf,
|
||||
@@ -423,9 +386,6 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
|
||||
sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO,
|
||||
sc->debug.debugfs_phydir, sc, &fops_registers);
|
||||
|
||||
sc->debug.debugfs_tsf = debugfs_create_file("tsf", S_IWUSR | S_IRUGO,
|
||||
sc->debug.debugfs_phydir, sc, &fops_tsf);
|
||||
|
||||
sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO,
|
||||
sc->debug.debugfs_phydir, sc, &fops_beacon);
|
||||
|
||||
@@ -444,7 +404,6 @@ ath5k_debug_finish_device(struct ath5k_softc *sc)
|
||||
{
|
||||
debugfs_remove(sc->debug.debugfs_debug);
|
||||
debugfs_remove(sc->debug.debugfs_registers);
|
||||
debugfs_remove(sc->debug.debugfs_tsf);
|
||||
debugfs_remove(sc->debug.debugfs_beacon);
|
||||
debugfs_remove(sc->debug.debugfs_reset);
|
||||
debugfs_remove(sc->debug.debugfs_phydir);
|
||||
|
@@ -72,7 +72,6 @@ struct ath5k_dbg_info {
|
||||
struct dentry *debugfs_phydir;
|
||||
struct dentry *debugfs_debug;
|
||||
struct dentry *debugfs_registers;
|
||||
struct dentry *debugfs_tsf;
|
||||
struct dentry *debugfs_beacon;
|
||||
struct dentry *debugfs_reset;
|
||||
};
|
||||
|
@@ -137,6 +137,18 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah)
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
|
||||
|
||||
/* XXX: Don't know which versions include these two */
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2);
|
||||
|
||||
if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3)
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3);
|
||||
|
||||
if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) {
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4);
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5);
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6);
|
||||
}
|
||||
}
|
||||
|
||||
if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
|
||||
@@ -213,7 +225,8 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
|
||||
}
|
||||
|
||||
/*
|
||||
* Read supported modes from eeprom
|
||||
* Read supported modes and some mode-specific calibration data
|
||||
* from eeprom
|
||||
*/
|
||||
static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
|
||||
unsigned int mode)
|
||||
@@ -315,6 +328,9 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
|
||||
if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0)
|
||||
goto done;
|
||||
|
||||
/* Note: >= v5 have bg freq piers on another location
|
||||
* so these freq piers are ignored for >= v5 (should be 0xff
|
||||
* anyway) */
|
||||
switch(mode) {
|
||||
case AR5K_EEPROM_MODE_11A:
|
||||
if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)
|
||||
@@ -442,7 +458,7 @@ ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Read mode-specific data (except power calibration data) */
|
||||
static int
|
||||
ath5k_eeprom_init_modes(struct ath5k_hw *ah)
|
||||
{
|
||||
@@ -488,6 +504,16 @@ ath5k_eeprom_init_modes(struct ath5k_hw *ah)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Used to match PCDAC steps with power values on RF5111 chips
|
||||
* (eeprom versions < 4). For RF5111 we have 10 pre-defined PCDAC
|
||||
* steps that match with the power values we read from eeprom. On
|
||||
* older eeprom versions (< 3.2) these steps are equaly spaced at
|
||||
* 10% of the pcdac curve -until the curve reaches it's maximum-
|
||||
* (10 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
|
||||
* these 10 steps are spaced in a different way. This function returns
|
||||
* the pcdac steps based on eeprom version and curve min/max so that we
|
||||
* can have pcdac/pwr points.
|
||||
*/
|
||||
static inline void
|
||||
ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
|
||||
{
|
||||
@@ -507,37 +533,48 @@ ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
|
||||
*vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100;
|
||||
}
|
||||
|
||||
/* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff
|
||||
* frequency mask) */
|
||||
static inline int
|
||||
ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
|
||||
struct ath5k_chan_pcal_info *pc, u8 *count)
|
||||
struct ath5k_chan_pcal_info *pc, unsigned int mode)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
int o = *offset;
|
||||
int i = 0;
|
||||
u8 f1, f2;
|
||||
u8 freq1, freq2;
|
||||
int ret;
|
||||
u16 val;
|
||||
|
||||
while(i < max) {
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
|
||||
f1 = (val >> 8) & 0xff;
|
||||
f2 = val & 0xff;
|
||||
freq1 = (val >> 8) & 0xff;
|
||||
freq2 = val & 0xff;
|
||||
|
||||
if (f1)
|
||||
pc[i++].freq = f1;
|
||||
if (freq1) {
|
||||
pc[i++].freq = ath5k_eeprom_bin2freq(ee,
|
||||
freq1, mode);
|
||||
ee->ee_n_piers[mode]++;
|
||||
}
|
||||
|
||||
if (f2)
|
||||
pc[i++].freq = f2;
|
||||
if (freq2) {
|
||||
pc[i++].freq = ath5k_eeprom_bin2freq(ee,
|
||||
freq2, mode);
|
||||
ee->ee_n_piers[mode]++;
|
||||
}
|
||||
|
||||
if (!f1 || !f2)
|
||||
if (!freq1 || !freq2)
|
||||
break;
|
||||
}
|
||||
|
||||
/* return new offset */
|
||||
*offset = o;
|
||||
*count = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read frequency piers for 802.11a */
|
||||
static int
|
||||
ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
|
||||
{
|
||||
@@ -550,7 +587,7 @@ ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
|
||||
if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
|
||||
ath5k_eeprom_read_freq_list(ah, &offset,
|
||||
AR5K_EEPROM_N_5GHZ_CHAN, pcal,
|
||||
&ee->ee_n_piers[AR5K_EEPROM_MODE_11A]);
|
||||
AR5K_EEPROM_MODE_11A);
|
||||
} else {
|
||||
mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version);
|
||||
|
||||
@@ -577,23 +614,25 @@ ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
pcal[9].freq |= (val >> 10) & 0x3f;
|
||||
ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10;
|
||||
}
|
||||
|
||||
for(i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i += 1) {
|
||||
pcal[i].freq = ath5k_eeprom_bin2freq(ee,
|
||||
/* Fixed number of piers */
|
||||
ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10;
|
||||
|
||||
for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) {
|
||||
pcal[i].freq = ath5k_eeprom_bin2freq(ee,
|
||||
pcal[i].freq, AR5K_EEPROM_MODE_11A);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read frequency piers for 802.11bg on eeprom versions >= 5 and eemap >= 2 */
|
||||
static inline int
|
||||
ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
struct ath5k_chan_pcal_info *pcal;
|
||||
int i;
|
||||
|
||||
switch(mode) {
|
||||
case AR5K_EEPROM_MODE_11B:
|
||||
@@ -608,23 +647,25 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
|
||||
|
||||
ath5k_eeprom_read_freq_list(ah, &offset,
|
||||
AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal,
|
||||
&ee->ee_n_piers[mode]);
|
||||
for(i = 0; i < AR5K_EEPROM_N_2GHZ_CHAN_2413; i += 1) {
|
||||
pcal[i].freq = ath5k_eeprom_bin2freq(ee,
|
||||
pcal[i].freq, mode);
|
||||
}
|
||||
mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Read power calibration for RF5111 chips
|
||||
* For RF5111 we have an XPD -eXternal Power Detector- curve
|
||||
* for each calibrated channel. Each curve has PCDAC steps on
|
||||
* x axis and power on y axis and looks like a logarithmic
|
||||
* function. To recreate the curve and pass the power values
|
||||
* on the pcdac table, we read 10 points here and interpolate later.
|
||||
*/
|
||||
static int
|
||||
ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
struct ath5k_chan_pcal_info *pcal;
|
||||
int offset, ret;
|
||||
int i, j;
|
||||
int i;
|
||||
u16 val;
|
||||
|
||||
offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
|
||||
@@ -704,16 +745,22 @@ ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
|
||||
|
||||
ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min,
|
||||
cdata->pcdac_max, cdata->pcdac);
|
||||
|
||||
for (j = 0; j < AR5K_EEPROM_N_PCDAC; j++) {
|
||||
cdata->pwr[j] = (u16)
|
||||
(AR5K_EEPROM_POWER_STEP * cdata->pwr[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read power calibration for RF5112 chips
|
||||
* For RF5112 we have 4 XPD -eXternal Power Detector- curves
|
||||
* for each calibrated channel on 0, -6, -12 and -18dbm but we only
|
||||
* use the higher (3) and the lower (0) curves. Each curve has PCDAC
|
||||
* steps on x axis and power on y axis and looks like a linear
|
||||
* function. To recreate the curve and pass the power values
|
||||
* on the pcdac table, we read 4 points for xpd 0 and 3 points
|
||||
* for xpd 3 here and interpolate later.
|
||||
*
|
||||
* Note: Many vendors just use xpd 0 so xpd 3 is zeroed.
|
||||
*/
|
||||
static int
|
||||
ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
|
||||
{
|
||||
@@ -790,7 +837,7 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
|
||||
|
||||
/* PCDAC steps
|
||||
* corresponding to the above power
|
||||
* measurements (static) */
|
||||
* measurements (fixed) */
|
||||
chan_pcal_info->pcdac_x3[0] = 20;
|
||||
chan_pcal_info->pcdac_x3[1] = 35;
|
||||
chan_pcal_info->pcdac_x3[2] = 63;
|
||||
@@ -814,6 +861,13 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For RF2413 power calibration data doesn't start on a fixed location and
|
||||
* if a mode is not supported, it's section is missing -not zeroed-.
|
||||
* So we need to calculate the starting offset for each section by using
|
||||
* these two functions */
|
||||
|
||||
/* Return the size of each section based on the mode and the number of pd
|
||||
* gains available (maximum 4). */
|
||||
static inline unsigned int
|
||||
ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode)
|
||||
{
|
||||
@@ -826,6 +880,8 @@ ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode)
|
||||
return sz;
|
||||
}
|
||||
|
||||
/* Return the starting offset for a section based on the modes supported
|
||||
* and each section's size. */
|
||||
static unsigned int
|
||||
ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
|
||||
{
|
||||
@@ -834,11 +890,13 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
|
||||
switch(mode) {
|
||||
case AR5K_EEPROM_MODE_11G:
|
||||
if (AR5K_EEPROM_HDR_11B(ee->ee_header))
|
||||
offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + 2;
|
||||
offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) +
|
||||
AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
|
||||
/* fall through */
|
||||
case AR5K_EEPROM_MODE_11B:
|
||||
if (AR5K_EEPROM_HDR_11A(ee->ee_header))
|
||||
offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + 5;
|
||||
offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) +
|
||||
AR5K_EEPROM_N_5GHZ_CHAN / 2;
|
||||
/* fall through */
|
||||
case AR5K_EEPROM_MODE_11A:
|
||||
break;
|
||||
@@ -849,6 +907,17 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
|
||||
return offset;
|
||||
}
|
||||
|
||||
/* Read power calibration for RF2413 chips
|
||||
* For RF2413 we have a PDDAC table (Power Detector) instead
|
||||
* of a PCDAC and 4 pd gain curves for each calibrated channel.
|
||||
* Each curve has PDDAC steps on x axis and power on y axis and
|
||||
* looks like an exponential function. To recreate the curves
|
||||
* we read here the points and interpolate later. Note that
|
||||
* in most cases only higher and lower curves are used (like
|
||||
* RF5112) but vendors have the oportunity to include all 4
|
||||
* curves on eeprom. The final curve (higher power) has an extra
|
||||
* point for better accuracy like RF5112.
|
||||
*/
|
||||
static int
|
||||
ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
|
||||
{
|
||||
@@ -868,6 +937,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
|
||||
ee->ee_pd_gains[mode] = pd_gains;
|
||||
|
||||
offset = ath5k_cal_data_offset_2413(ee, mode);
|
||||
ee->ee_n_piers[mode] = 0;
|
||||
switch (mode) {
|
||||
case AR5K_EEPROM_MODE_11A:
|
||||
if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
|
||||
@@ -1163,6 +1233,20 @@ static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read per channel calibration info from EEPROM
|
||||
*
|
||||
* This info is used to calibrate the baseband power table. Imagine
|
||||
* that for each channel there is a power curve that's hw specific
|
||||
* (depends on amplifier etc) and we try to "correct" this curve using
|
||||
* offests we pass on to phy chip (baseband -> before amplifier) so that
|
||||
* it can use accurate power values when setting tx power (takes amplifier's
|
||||
* performance on each channel into account).
|
||||
*
|
||||
* EEPROM provides us with the offsets for some pre-calibrated channels
|
||||
* and we have to interpolate to create the full table for these channels and
|
||||
* also the table for any channel.
|
||||
*/
|
||||
static int
|
||||
ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
|
||||
{
|
||||
@@ -1193,7 +1277,7 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read conformance test limits */
|
||||
/* Read conformance test limits used for regulatory control */
|
||||
static int
|
||||
ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
|
||||
{
|
||||
|
@@ -83,7 +83,7 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
|
||||
int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (gpio > AR5K_NUM_GPIO)
|
||||
if (gpio >= AR5K_NUM_GPIO)
|
||||
return -EINVAL;
|
||||
|
||||
ath5k_hw_reg_write(ah,
|
||||
@@ -99,7 +99,7 @@ int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
|
||||
int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (gpio > AR5K_NUM_GPIO)
|
||||
if (gpio >= AR5K_NUM_GPIO)
|
||||
return -EINVAL;
|
||||
|
||||
ath5k_hw_reg_write(ah,
|
||||
@@ -115,7 +115,7 @@ int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
|
||||
u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (gpio > AR5K_NUM_GPIO)
|
||||
if (gpio >= AR5K_NUM_GPIO)
|
||||
return 0xffffffff;
|
||||
|
||||
/* GPIO input magic */
|
||||
@@ -131,7 +131,7 @@ int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
|
||||
u32 data;
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
if (gpio > AR5K_NUM_GPIO)
|
||||
if (gpio >= AR5K_NUM_GPIO)
|
||||
return -EINVAL;
|
||||
|
||||
/* GPIO output magic */
|
||||
@@ -154,7 +154,7 @@ void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
|
||||
u32 data;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (gpio > AR5K_NUM_GPIO)
|
||||
if (gpio >= AR5K_NUM_GPIO)
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@@ -645,6 +645,23 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
|
||||
return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_set_tsf64 - Set a new 64bit TSF
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
* @tsf64: The new 64bit TSF
|
||||
*
|
||||
* Sets the new TSF
|
||||
*/
|
||||
void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
ath5k_hw_reg_write(ah, 0x00000000, AR5K_TSF_L32);
|
||||
ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
|
||||
ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_reset_tsf - Force a TSF reset
|
||||
*
|
||||
@@ -1026,6 +1043,9 @@ int ath5k_keycache_type(const struct ieee80211_key_conf *key)
|
||||
return AR5K_KEYTABLE_TYPE_40;
|
||||
else if (key->keylen == LEN_WEP104)
|
||||
return AR5K_KEYTABLE_TYPE_104;
|
||||
return -EINVAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1041,7 +1061,7 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
|
||||
__le32 key_v[5] = {};
|
||||
__le32 key0 = 0, key1 = 0;
|
||||
__le32 *rxmic, *txmic;
|
||||
u32 keytype;
|
||||
int keytype;
|
||||
u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
|
||||
bool is_tkip;
|
||||
const u8 *key_ptr;
|
||||
@@ -1139,7 +1159,7 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
|
||||
|
||||
/* MAC may be NULL if it's a broadcast key. In this case no need to
|
||||
* to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */
|
||||
if (unlikely(mac == NULL)) {
|
||||
if (!mac) {
|
||||
low_id = 0xffffffff;
|
||||
high_id = 0xffff | AR5K_KEYTABLE_VALID;
|
||||
} else {
|
||||
|
@@ -148,6 +148,7 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
|
||||
*/
|
||||
u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
|
||||
{
|
||||
u32 pending;
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
|
||||
|
||||
@@ -159,7 +160,15 @@ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
return false;
|
||||
|
||||
return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT;
|
||||
pending = (AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT);
|
||||
|
||||
/* It's possible to have no frames pending even if TXE
|
||||
* is set. To indicate that q has not stopped return
|
||||
* true */
|
||||
if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
|
||||
return true;
|
||||
|
||||
return pending;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -324,8 +333,18 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
||||
/*
|
||||
* Set misc registers
|
||||
*/
|
||||
ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY,
|
||||
AR5K_QUEUE_MISC(queue));
|
||||
/* Enable DCU early termination for this queue */
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
|
||||
AR5K_QCU_MISC_DCU_EARLY);
|
||||
|
||||
/* Enable DCU to wait for next fragment from QCU */
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
|
||||
AR5K_DCU_MISC_FRAG_WAIT);
|
||||
|
||||
/* On Maui and Spirit use the global seqnum on DCU */
|
||||
if (ah->ah_mac_version < AR5K_SREV_AR5211)
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
|
||||
AR5K_DCU_MISC_SEQNUM_CTL);
|
||||
|
||||
if (tq->tqi_cbr_period) {
|
||||
ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
|
||||
@@ -341,7 +360,8 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
||||
AR5K_QCU_MISC_CBR_THRES_ENABLE);
|
||||
}
|
||||
|
||||
if (tq->tqi_ready_time)
|
||||
if (tq->tqi_ready_time &&
|
||||
(tq->tqi_type != AR5K_TX_QUEUE_ID_CAB))
|
||||
ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
|
||||
AR5K_QCU_RDYTIMECFG_INTVAL) |
|
||||
AR5K_QCU_RDYTIMECFG_ENABLE,
|
||||
@@ -383,13 +403,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
||||
AR5K_DCU_MISC_ARBLOCK_CTL_S) |
|
||||
AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
|
||||
AR5K_DCU_MISC_BCN_ENABLE);
|
||||
|
||||
ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
|
||||
(AR5K_TUNE_SW_BEACON_RESP -
|
||||
AR5K_TUNE_DMA_BEACON_RESP) -
|
||||
AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
|
||||
AR5K_QCU_RDYTIMECFG_ENABLE,
|
||||
AR5K_QUEUE_RDYTIMECFG(queue));
|
||||
break;
|
||||
|
||||
case AR5K_TX_QUEUE_CAB:
|
||||
@@ -398,6 +411,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
||||
AR5K_QCU_MISC_CBREXP_DIS |
|
||||
AR5K_QCU_MISC_CBREXP_BCN_DIS);
|
||||
|
||||
ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
|
||||
(AR5K_TUNE_SW_BEACON_RESP -
|
||||
AR5K_TUNE_DMA_BEACON_RESP) -
|
||||
AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
|
||||
AR5K_QCU_RDYTIMECFG_ENABLE,
|
||||
AR5K_QUEUE_RDYTIMECFG(queue));
|
||||
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
|
||||
(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
|
||||
AR5K_DCU_MISC_ARBLOCK_CTL_S));
|
||||
@@ -413,6 +433,8 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO: Handle frame compression */
|
||||
|
||||
/*
|
||||
* Enable interrupts for this tx queue
|
||||
* in the secondary interrupt mask registers
|
||||
@@ -483,6 +505,9 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
||||
* by setting AR5K_TXNOFRM to zero */
|
||||
if (ah->ah_txq_imr_nofrm == 0)
|
||||
ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
|
||||
|
||||
/* Set QCU mask for this DCU to save power */
|
||||
AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user