diff options
Diffstat (limited to 'drivers/net/wireless/ath')
95 files changed, 26052 insertions, 8664 deletions
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 4e7a7fd695c..0a75be027af 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -3,7 +3,7 @@ menuconfig ATH_COMMON depends on CFG80211 ---help--- This will enable the support for the Atheros wireless drivers. - ath5k, ath9k and ar9170 drivers share some common code, this option + ath5k, ath9k, ath9k_htc and ar9170 drivers share some common code, this option enables the common ath.ko module which shares common helpers. For more information and documentation on this module you can visit: diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h index dc662b76a1c..4f845f80c09 100644 --- a/drivers/net/wireless/ath/ar9170/ar9170.h +++ b/drivers/net/wireless/ath/ar9170/ar9170.h @@ -109,41 +109,6 @@ struct ar9170_rxstream_mpdu_merge { bool has_plcp; }; -#define AR9170_NUM_TID 16 -#define WME_BA_BMP_SIZE 64 -#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE) - -#define WME_AC_BE 2 -#define WME_AC_BK 3 -#define WME_AC_VI 1 -#define WME_AC_VO 0 - -#define TID_TO_WME_AC(_tid) \ - ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ - (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ - (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ - WME_AC_VO) - -#define BAW_WITHIN(_start, _bawsz, _seqno) \ - ((((_seqno) - (_start)) & 0xfff) < (_bawsz)) - -enum ar9170_tid_state { - AR9170_TID_STATE_INVALID, - AR9170_TID_STATE_SHUTDOWN, - AR9170_TID_STATE_PROGRESS, - AR9170_TID_STATE_COMPLETE, -}; - -struct ar9170_sta_tid { - struct list_head list; - struct sk_buff_head queue; - u8 addr[ETH_ALEN]; - u16 ssn; - u16 tid; - enum ar9170_tid_state state; - bool active; -}; - struct ar9170_tx_queue_stats { unsigned int len; unsigned int limit; @@ -152,14 +117,11 @@ struct ar9170_tx_queue_stats { #define AR9170_QUEUE_TIMEOUT 64 #define AR9170_TX_TIMEOUT 8 -#define AR9170_BA_TIMEOUT 4 #define AR9170_JANITOR_DELAY 128 #define AR9170_TX_INVALID_RATE 0xffffffff -#define AR9170_NUM_TX_STATUS 128 -#define AR9170_NUM_TX_AGG_MAX 30 -#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH -#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10) +#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH +#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10) struct ar9170 { struct ieee80211_hw *hw; @@ -234,11 +196,6 @@ struct ar9170 { struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; struct delayed_work tx_janitor; - /* tx ampdu */ - struct sk_buff_head tx_status_ampdu; - spinlock_t tx_ampdu_list_lock; - struct list_head tx_ampdu_list; - atomic_t tx_ampdu_pending; /* rxstream mpdu merge */ struct ar9170_rxstream_mpdu_merge rx_mpdu; @@ -250,11 +207,6 @@ struct ar9170 { u8 global_ampdu_factor; }; -struct ar9170_sta_info { - struct ar9170_sta_tid agg[AR9170_NUM_TID]; - unsigned int ampdu_max_len; -}; - struct ar9170_tx_info { unsigned long timeout; }; diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h index 826c45e6b27..ec8134b4b94 100644 --- a/drivers/net/wireless/ath/ar9170/cmd.h +++ b/drivers/net/wireless/ath/ar9170/cmd.h @@ -79,7 +79,7 @@ __regwrite_out : \ if (__nreg) { \ if (IS_ACCEPTING_CMD(__ar)) \ __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ - 8 * __nreg, \ + 8 * __nreg, \ (u8 *) &__ar->cmdbuf[1], \ 0, NULL); \ __nreg = 0; \ diff --git a/drivers/net/wireless/ath/ar9170/eeprom.h b/drivers/net/wireless/ath/ar9170/eeprom.h index d2c8cc83f1d..6c466388342 100644 --- a/drivers/net/wireless/ath/ar9170/eeprom.h +++ b/drivers/net/wireless/ath/ar9170/eeprom.h @@ -127,8 +127,8 @@ struct ar9170_eeprom { __le16 checksum; __le16 version; u8 operating_flags; -#define AR9170_OPFLAG_5GHZ 1 -#define AR9170_OPFLAG_2GHZ 2 +#define AR9170_OPFLAG_5GHZ 1 +#define AR9170_OPFLAG_2GHZ 2 u8 misc; __le16 reg_domain[2]; u8 mac_address[6]; diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h index 0a1d4c28e68..06f1f3c951a 100644 --- a/drivers/net/wireless/ath/ar9170/hw.h +++ b/drivers/net/wireless/ath/ar9170/hw.h @@ -425,5 +425,6 @@ enum ar9170_txq { #define AR9170_TXQ_DEPTH 32 #define AR9170_TX_MAX_PENDING 128 +#define AR9170_RX_STREAM_MAX_SIZE 65535 #endif /* __AR9170_HW_H */ diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index c5369298099..2abc8757899 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -50,10 +50,6 @@ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -static int modparam_ht; -module_param_named(ht, modparam_ht, bool, S_IRUGO); -MODULE_PARM_DESC(ht, "enable MPDU aggregation."); - #define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ .bitrate = (_bitrate), \ .flags = (_flags), \ @@ -182,7 +178,6 @@ static struct ieee80211_supported_band ar9170_band_5GHz = { }; static void ar9170_tx(struct ar9170 *ar); -static bool ar9170_tx_ampdu(struct ar9170 *ar); static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr) { @@ -195,21 +190,7 @@ static inline u16 ar9170_get_seq(struct sk_buff *skb) return ar9170_get_seq_h((void *) txc->frame_data); } -static inline u16 ar9170_get_tid_h(struct ieee80211_hdr *hdr) -{ - return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; -} - -static inline u16 ar9170_get_tid(struct sk_buff *skb) -{ - struct ar9170_tx_control *txc = (void *) skb->data; - return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data); -} - -#define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff) -#define GET_NEXT_SEQ_FROM_SKB(skb) (GET_NEXT_SEQ(ar9170_get_seq(skb))) - -#if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG) +#ifdef AR9170_QUEUE_DEBUG static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) { struct ar9170_tx_control *txc = (void *) skb->data; @@ -236,7 +217,7 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar, wiphy_name(ar->hw->wiphy), skb_queue_len(queue)); skb_queue_walk(queue, skb) { - printk(KERN_DEBUG "index:%d => \n", i++); + printk(KERN_DEBUG "index:%d =>\n", i++); ar9170_print_txheader(ar, skb); } if (i != skb_queue_len(queue)) @@ -244,7 +225,7 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar, "mismatch %d != %d\n", skb_queue_len(queue), i); printk(KERN_DEBUG "---[ end ]---\n"); } -#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */ +#endif /* AR9170_QUEUE_DEBUG */ #ifdef AR9170_QUEUE_DEBUG static void ar9170_dump_txqueue(struct ar9170 *ar, @@ -275,20 +256,6 @@ static void __ar9170_dump_txstats(struct ar9170 *ar) } #endif /* AR9170_QUEUE_STOP_DEBUG */ -#ifdef AR9170_TXAGG_DEBUG -static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar) -{ - unsigned long flags; - - spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags); - printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n", - wiphy_name(ar->hw->wiphy)); - __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu); - spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags); -} - -#endif /* AR9170_TXAGG_DEBUG */ - /* caller must guarantee exclusive access for _bin_ queue. */ static void ar9170_recycle_expired(struct ar9170 *ar, struct sk_buff_head *queue, @@ -308,7 +275,7 @@ static void ar9170_recycle_expired(struct ar9170 *ar, if (time_is_before_jiffies(arinfo->timeout)) { #ifdef AR9170_QUEUE_DEBUG printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => " - "recycle \n", wiphy_name(ar->hw->wiphy), + "recycle\n", wiphy_name(ar->hw->wiphy), jiffies, arinfo->timeout); ar9170_print_txheader(ar, skb); #endif /* AR9170_QUEUE_DEBUG */ @@ -360,70 +327,6 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, ieee80211_tx_status_irqsafe(ar->hw, skb); } -static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar) -{ - struct sk_buff_head success; - struct sk_buff *skb; - unsigned int i; - unsigned long queue_bitmap = 0; - - skb_queue_head_init(&success); - - while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS) - __skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu)); - - ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success); - -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n", - wiphy_name(ar->hw->wiphy), skb_queue_len(&success)); - __ar9170_dump_txqueue(ar, &success); -#endif /* AR9170_TXAGG_DEBUG */ - - while ((skb = __skb_dequeue(&success))) { - struct ieee80211_tx_info *txinfo; - - queue_bitmap |= BIT(skb_get_queue_mapping(skb)); - - txinfo = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(txinfo); - - txinfo->flags |= IEEE80211_TX_STAT_ACK; - txinfo->status.rates[0].count = 1; - - skb_pull(skb, sizeof(struct ar9170_tx_control)); - ieee80211_tx_status_irqsafe(ar->hw, skb); - } - - for_each_set_bit(i, &queue_bitmap, BITS_PER_BYTE) { -#ifdef AR9170_QUEUE_STOP_DEBUG - printk(KERN_DEBUG "%s: wake queue %d\n", - wiphy_name(ar->hw->wiphy), i); - __ar9170_dump_txstats(ar); -#endif /* AR9170_QUEUE_STOP_DEBUG */ - ieee80211_wake_queue(ar->hw, i); - } - - if (queue_bitmap) - ar9170_tx(ar); -} - -static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); - struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; - - arinfo->timeout = jiffies + - msecs_to_jiffies(AR9170_BA_TIMEOUT); - - skb_queue_tail(&ar->tx_status_ampdu, skb); - ar9170_tx_fake_ampdu_status(ar); - - if (atomic_dec_and_test(&ar->tx_ampdu_pending) && - !list_empty(&ar->tx_ampdu_list)) - ar9170_tx_ampdu(ar); -} - void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -447,14 +350,10 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) if (info->flags & IEEE80211_TX_CTL_NO_ACK) { ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED); } else { - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - ar9170_tx_ampdu_callback(ar, skb); - } else { - arinfo->timeout = jiffies + - msecs_to_jiffies(AR9170_TX_TIMEOUT); + arinfo->timeout = jiffies + + msecs_to_jiffies(AR9170_TX_TIMEOUT); - skb_queue_tail(&ar->tx_status[queue], skb); - } + skb_queue_tail(&ar->tx_status[queue], skb); } if (!ar->tx_stats[queue].len && @@ -524,38 +423,6 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, return NULL; } -static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r) -{ - struct sk_buff *skb; - struct ieee80211_tx_info *txinfo; - - while (count) { - skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r); - if (!skb) - break; - - txinfo = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(txinfo); - - /* FIXME: maybe more ? */ - txinfo->status.rates[0].count = 1; - - skb_pull(skb, sizeof(struct ar9170_tx_control)); - ieee80211_tx_status_irqsafe(ar->hw, skb); - count--; - } - -#ifdef AR9170_TXAGG_DEBUG - if (count) { - printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more " - "suitable frames left in tx_status queue.\n", - wiphy_name(ar->hw->wiphy), count); - - ar9170_dump_tx_status_ampdu(ar); - } -#endif /* AR9170_TXAGG_DEBUG */ -} - /* * This worker tries to keeps an maintain tx_status queues. * So we can guarantee that incoming tx_status reports are @@ -592,8 +459,6 @@ static void ar9170_tx_janitor(struct work_struct *work) resched = true; } - ar9170_tx_fake_ampdu_status(ar); - if (!resched) return; @@ -673,10 +538,6 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) case 0xc5: /* BlockACK events */ - ar9170_handle_block_ack(ar, - le16_to_cpu(cmd->ba_fail_cnt.failed), - le16_to_cpu(cmd->ba_fail_cnt.rate)); - ar9170_tx_fake_ampdu_status(ar); break; case 0xc6: @@ -689,7 +550,8 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) /* firmware debug */ case 0xca: - printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, (char *)buf + 4); + printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, + (char *)buf + 4); break; case 0xcb: len -= 4; @@ -926,7 +788,6 @@ static void ar9170_rx_phy_status(struct ar9170 *ar, /* TODO: we could do something with phy_errors */ status->signal = ar->noise[0] + phy->rssi_combined; - status->noise = ar->noise[0]; } static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len) @@ -1247,7 +1108,6 @@ static int ar9170_op_start(struct ieee80211_hw *hw) ar->global_ampdu_density = 6; ar->global_ampdu_factor = 3; - atomic_set(&ar->tx_ampdu_pending, 0); ar->bad_hw_nagger = jiffies; err = ar->open(ar); @@ -1310,40 +1170,10 @@ static void ar9170_op_stop(struct ieee80211_hw *hw) skb_queue_purge(&ar->tx_pending[i]); skb_queue_purge(&ar->tx_status[i]); } - skb_queue_purge(&ar->tx_status_ampdu); mutex_unlock(&ar->mutex); } -static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ar9170_tx_control *txc = (void *) skb->data; - - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU); -} - -static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst, - struct sk_buff *src) -{ - struct ar9170_tx_control *dst_txc, *src_txc; - struct ieee80211_tx_info *dst_info, *src_info; - struct ar9170_tx_info *dst_arinfo, *src_arinfo; - - src_txc = (void *) src->data; - src_info = IEEE80211_SKB_CB(src); - src_arinfo = (void *) src_info->rate_driver_data; - - dst_txc = (void *) dst->data; - dst_info = IEEE80211_SKB_CB(dst); - dst_arinfo = (void *) dst_info->rate_driver_data; - - dst_txc->phy_control = src_txc->phy_control; - - /* same MCS for the whole aggregate */ - memcpy(dst_info->driver_rates, src_info->driver_rates, - sizeof(dst_info->driver_rates)); -} - static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) { struct ieee80211_hdr *hdr; @@ -1420,14 +1250,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) txc->phy_control |= cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - if (unlikely(!info->control.sta)) - goto err_out; - - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); - } else { - txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); - } + txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); } return 0; @@ -1537,158 +1360,6 @@ static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb) txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); } -static bool ar9170_tx_ampdu(struct ar9170 *ar) -{ - struct sk_buff_head agg; - struct ar9170_sta_tid *tid_info = NULL, *tmp; - struct sk_buff *skb, *first = NULL; - unsigned long flags, f2; - unsigned int i = 0; - u16 seq, queue, tmpssn; - bool run = false; - - skb_queue_head_init(&agg); - - spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); - if (list_empty(&ar->tx_ampdu_list)) { -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: aggregation list is empty.\n", - wiphy_name(ar->hw->wiphy)); -#endif /* AR9170_TXAGG_DEBUG */ - goto out_unlock; - } - - list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) { - if (tid_info->state != AR9170_TID_STATE_COMPLETE) { -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: dangling aggregation entry!\n", - wiphy_name(ar->hw->wiphy)); -#endif /* AR9170_TXAGG_DEBUG */ - continue; - } - - if (++i > 64) { -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: enough frames aggregated.\n", - wiphy_name(ar->hw->wiphy)); -#endif /* AR9170_TXAGG_DEBUG */ - break; - } - - queue = TID_TO_WME_AC(tid_info->tid); - - if (skb_queue_len(&ar->tx_pending[queue]) >= - AR9170_NUM_TX_AGG_MAX) { -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: queue %d full.\n", - wiphy_name(ar->hw->wiphy), queue); -#endif /* AR9170_TXAGG_DEBUG */ - continue; - } - - list_del_init(&tid_info->list); - - spin_lock_irqsave(&tid_info->queue.lock, f2); - tmpssn = seq = tid_info->ssn; - first = skb_peek(&tid_info->queue); - - if (likely(first)) - tmpssn = ar9170_get_seq(first); - - if (unlikely(tmpssn != seq)) { -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.", - wiphy_name(ar->hw->wiphy), seq, tmpssn); -#endif /* AR9170_TXAGG_DEBUG */ - tid_info->ssn = tmpssn; - } - -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with " - "%d queued frames.\n", wiphy_name(ar->hw->wiphy), - tid_info->tid, tid_info->ssn, - skb_queue_len(&tid_info->queue)); - __ar9170_dump_txqueue(ar, &tid_info->queue); -#endif /* AR9170_TXAGG_DEBUG */ - - while ((skb = skb_peek(&tid_info->queue))) { - if (unlikely(ar9170_get_seq(skb) != seq)) - break; - - __skb_unlink(skb, &tid_info->queue); - tid_info->ssn = seq = GET_NEXT_SEQ(seq); - - if (unlikely(skb_get_queue_mapping(skb) != queue)) { -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d " - "!match.\n", wiphy_name(ar->hw->wiphy), - tid_info->tid, - TID_TO_WME_AC(tid_info->tid), - skb_get_queue_mapping(skb)); -#endif /* AR9170_TXAGG_DEBUG */ - dev_kfree_skb_any(skb); - continue; - } - - if (unlikely(first == skb)) { - ar9170_tx_prepare_phy(ar, skb); - __skb_queue_tail(&agg, skb); - first = skb; - } else { - ar9170_tx_copy_phy(ar, skb, first); - __skb_queue_tail(&agg, skb); - } - - if (unlikely(skb_queue_len(&agg) == - AR9170_NUM_TX_AGG_MAX)) - break; - } - - if (skb_queue_empty(&tid_info->queue)) - tid_info->active = false; - else - list_add_tail(&tid_info->list, - &ar->tx_ampdu_list); - - spin_unlock_irqrestore(&tid_info->queue.lock, f2); - - if (unlikely(skb_queue_empty(&agg))) { -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: queued empty list!\n", - wiphy_name(ar->hw->wiphy)); -#endif /* AR9170_TXAGG_DEBUG */ - continue; - } - - /* - * tell the FW/HW that this is the last frame, - * that way it will wait for the immediate block ack. - */ - ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg)); - -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n", - wiphy_name(ar->hw->wiphy)); - __ar9170_dump_txqueue(ar, &agg); -#endif /* AR9170_TXAGG_DEBUG */ - - spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - - spin_lock_irqsave(&ar->tx_pending[queue].lock, flags); - skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]); - spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags); - run = true; - - spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); - } - -out_unlock: - spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - __skb_queue_purge(&agg); - - return run; -} - static void ar9170_tx(struct ar9170 *ar) { struct sk_buff *skb; @@ -1728,7 +1399,7 @@ static void ar9170_tx(struct ar9170 *ar) printk(KERN_DEBUG "%s: queue %d full\n", wiphy_name(ar->hw->wiphy), i); - printk(KERN_DEBUG "%s: stuck frames: ===> \n", + printk(KERN_DEBUG "%s: stuck frames: ===>\n", wiphy_name(ar->hw->wiphy)); ar9170_dump_txqueue(ar, &ar->tx_pending[i]); ar9170_dump_txqueue(ar, &ar->tx_status[i]); @@ -1763,9 +1434,6 @@ static void ar9170_tx(struct ar9170 *ar) arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_TX_TIMEOUT); - if (info->flags & IEEE80211_TX_CTL_AMPDU) - atomic_inc(&ar->tx_ampdu_pending); - #ifdef AR9170_QUEUE_DEBUG printk(KERN_DEBUG "%s: send frame q:%d =>\n", wiphy_name(ar->hw->wiphy), i); @@ -1774,9 +1442,6 @@ static void ar9170_tx(struct ar9170 *ar) err = ar->tx(ar, skb); if (unlikely(err)) { - if (info->flags & IEEE80211_TX_CTL_AMPDU) - atomic_dec(&ar->tx_ampdu_pending); - frames_failed++; dev_kfree_skb_any(skb); } else { @@ -1823,94 +1488,11 @@ static void ar9170_tx(struct ar9170 *ar) msecs_to_jiffies(AR9170_JANITOR_DELAY)); } -static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb) -{ - struct ieee80211_tx_info *txinfo; - struct ar9170_sta_info *sta_info; - struct ar9170_sta_tid *agg; - struct sk_buff *iter; - unsigned long flags, f2; - unsigned int max; - u16 tid, seq, qseq; - bool run = false, queue = false; - - tid = ar9170_get_tid(skb); - seq = ar9170_get_seq(skb); - txinfo = IEEE80211_SKB_CB(skb); - sta_info = (void *) txinfo->control.sta->drv_priv; - agg = &sta_info->agg[tid]; - max = sta_info->ampdu_max_len; - - spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); - - if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) { -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: BlockACK session not fully initialized " - "for ESS:%pM tid:%d state:%d.\n", - wiphy_name(ar->hw->wiphy), agg->addr, agg->tid, - agg->state); -#endif /* AR9170_TXAGG_DEBUG */ - goto err_unlock; - } - - if (!agg->active) { - agg->active = true; - agg->ssn = seq; - queue = true; - } - - /* check if seq is within the BA window */ - if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) { -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not " - "fit into BA window (%d - %d)\n", - wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn, - (agg->ssn + max) & 0xfff); -#endif /* AR9170_TXAGG_DEBUG */ - goto err_unlock; - } - - spin_lock_irqsave(&agg->queue.lock, f2); - - skb_queue_reverse_walk(&agg->queue, iter) { - qseq = ar9170_get_seq(iter); - - if (GET_NEXT_SEQ(qseq) == seq) { - __skb_queue_after(&agg->queue, iter, skb); - goto queued; - } - } - - __skb_queue_head(&agg->queue, skb); - -queued: - spin_unlock_irqrestore(&agg->queue.lock, f2); - -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_DEBUG "%s: new aggregate %p queued.\n", - wiphy_name(ar->hw->wiphy), skb); - __ar9170_dump_txqueue(ar, &agg->queue); -#endif /* AR9170_TXAGG_DEBUG */ - - if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX) - run = true; - - if (queue) - list_add_tail(&agg->list, &ar->tx_ampdu_list); - - spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - return run; - -err_unlock: - spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - dev_kfree_skb_irq(skb); - return false; -} - int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ar9170 *ar = hw->priv; struct ieee80211_tx_info *info; + unsigned int queue; if (unlikely(!IS_STARTED(ar))) goto err_free; @@ -1918,18 +1500,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (unlikely(ar9170_tx_prepare(ar, skb))) goto err_free; + queue = skb_get_queue_mapping(skb); info = IEEE80211_SKB_CB(skb); - if (info->flags & IEEE80211_TX_CTL_AMPDU) { - bool run = ar9170_tx_ampdu_queue(ar, skb); - - if (run || !atomic_read(&ar->tx_ampdu_pending)) - ar9170_tx_ampdu(ar); - } else { - unsigned int queue = skb_get_queue_mapping(skb); - - ar9170_tx_prepare_phy(ar, skb); - skb_queue_tail(&ar->tx_pending[queue], skb); - } + ar9170_tx_prepare_phy(ar, skb); + skb_queue_tail(&ar->tx_pending[queue], skb); ar9170_tx(ar); return NETDEV_TX_OK; @@ -2046,21 +1620,17 @@ out: return err; } -static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count, - struct dev_addr_list *mclist) +static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list) { u64 mchash; - int i; + struct netdev_hw_addr *ha; /* always get broadcast frames */ mchash = 1ULL << (0xff >> 2); - for (i = 0; i < mc_count; i++) { - if (WARN_ON(!mclist)) - break; - mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); - mclist = mclist->next; - } + netdev_hw_addr_list_for_each(ha, mc_list) + mchash |= 1ULL << (ha->addr[5] >> 2); return mchash; } @@ -2330,57 +1900,6 @@ out: return err; } -static int ar9170_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct ar9170 *ar = hw->priv; - struct ar9170_sta_info *sta_info = (void *) sta->drv_priv; - unsigned int i; - - memset(sta_info, 0, sizeof(*sta_info)); - - if (!sta->ht_cap.ht_supported) - return 0; - - if (sta->ht_cap.ampdu_density > ar->global_ampdu_density) - ar->global_ampdu_density = sta->ht_cap.ampdu_density; - - if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor) - ar->global_ampdu_factor = sta->ht_cap.ampdu_factor; - - for (i = 0; i < AR9170_NUM_TID; i++) { - sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN; - sta_info->agg[i].active = false; - sta_info->agg[i].ssn = 0; - sta_info->agg[i].tid = i; - INIT_LIST_HEAD(&sta_info->agg[i].list); - skb_queue_head_init(&sta_info->agg[i].queue); - } - - sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor); - - return 0; -} - -static int ar9170_sta_remove(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct ar9170_sta_info *sta_info = (void *) sta->drv_priv; - unsigned int i; - - if (!sta->ht_cap.ht_supported) - return 0; - - for (i = 0; i < AR9170_NUM_TID; i++) { - sta_info->agg[i].state = AR9170_TID_STATE_INVALID; - skb_queue_purge(&sta_info->agg[i].queue); - } - - return 0; -} - static int ar9170_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { @@ -2423,55 +1942,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { - struct ar9170 *ar = hw->priv; - struct ar9170_sta_info *sta_info = (void *) sta->drv_priv; - struct ar9170_sta_tid *tid_info = &sta_info->agg[tid]; - unsigned long flags; - - if (!modparam_ht) - return -EOPNOTSUPP; - switch (action) { - case IEEE80211_AMPDU_TX_START: - spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); - if (tid_info->state != AR9170_TID_STATE_SHUTDOWN || - !list_empty(&tid_info->list)) { - spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] " - "is in a very bad state!\n", - wiphy_name(hw->wiphy), sta->addr, tid); -#endif /* AR9170_TXAGG_DEBUG */ - return -EBUSY; - } - - *ssn = tid_info->ssn; - tid_info->state = AR9170_TID_STATE_PROGRESS; - tid_info->active = false; - spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - - case IEEE80211_AMPDU_TX_STOP: - spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); - tid_info->state = AR9170_TID_STATE_SHUTDOWN; - list_del_init(&tid_info->list); - tid_info->active = false; - skb_queue_purge(&tid_info->queue); - spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; - - case IEEE80211_AMPDU_TX_OPERATIONAL: -#ifdef AR9170_TXAGG_DEBUG - printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n", - wiphy_name(hw->wiphy), sta->addr, tid); -#endif /* AR9170_TXAGG_DEBUG */ - spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags); - sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE; - spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags); - break; - case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_STOP: /* Handled by firmware */ @@ -2497,8 +1968,6 @@ static const struct ieee80211_ops ar9170_ops = { .bss_info_changed = ar9170_op_bss_info_changed, .get_tsf = ar9170_op_get_tsf, .set_key = ar9170_set_key, - .sta_add = ar9170_sta_add, - .sta_remove = ar9170_sta_remove, .get_stats = ar9170_get_stats, .ampdu_action = ar9170_ampdu_action, }; @@ -2516,7 +1985,7 @@ void *ar9170_alloc(size_t priv_size) * tends to split the streams into separate rx descriptors. */ - skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE, GFP_KERNEL); + skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL); if (!skb) goto err_nomem; @@ -2531,8 +2000,6 @@ void *ar9170_alloc(size_t priv_size) mutex_init(&ar->mutex); spin_lock_init(&ar->cmdlock); spin_lock_init(&ar->tx_stats_lock); - spin_lock_init(&ar->tx_ampdu_list_lock); - skb_queue_head_init(&ar->tx_status_ampdu); for (i = 0; i < __AR9170_NUM_TXQ; i++) { skb_queue_head_init(&ar->tx_status[i]); skb_queue_head_init(&ar->tx_pending[i]); @@ -2540,7 +2007,6 @@ void *ar9170_alloc(size_t priv_size) ar9170_rx_reset_rx_mpdu(ar); INIT_WORK(&ar->beacon_work, ar9170_new_beacon); INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); - INIT_LIST_HEAD(&ar->tx_ampdu_list); /* all hw supports 2.4 GHz, so set channel to 1 by default */ ar->channel = &ar9170_2ghz_chantable[0]; @@ -2551,19 +2017,10 @@ void *ar9170_alloc(size_t priv_size) BIT(NL80211_IFTYPE_ADHOC); ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; - - if (modparam_ht) { - ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; - } else { - ar9170_band_2GHz.ht_cap.ht_supported = false; - ar9170_band_5GHz.ht_cap.ht_supported = false; - } + IEEE80211_HW_SIGNAL_DBM; ar->hw->queues = __AR9170_NUM_TXQ; ar->hw->extra_tx_headroom = 8; - ar->hw->sta_data_size = sizeof(struct ar9170_sta_info); ar->hw->max_rates = 1; ar->hw->max_rate_tries = 3; diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c index 99a6da464bd..82ab532a492 100644 --- a/drivers/net/wireless/ath/ar9170/usb.c +++ b/drivers/net/wireless/ath/ar9170/usb.c @@ -42,6 +42,7 @@ #include <linux/usb.h> #include <linux/firmware.h> #include <linux/etherdevice.h> +#include <linux/device.h> #include <net/mac80211.h> #include "ar9170.h" #include "cmd.h" @@ -67,18 +68,28 @@ static struct usb_device_id ar9170_usb_ids[] = { { USB_DEVICE(0x0cf3, 0x1001) }, /* TP-Link TL-WN821N v2 */ { USB_DEVICE(0x0cf3, 0x1002) }, + /* 3Com Dual Band 802.11n USB Adapter */ + { USB_DEVICE(0x0cf3, 0x1010) }, + /* H3C Dual Band 802.11n USB Adapter */ + { USB_DEVICE(0x0cf3, 0x1011) }, /* Cace Airpcap NX */ { USB_DEVICE(0xcace, 0x0300) }, /* D-Link DWA 160 A1 */ { USB_DEVICE(0x07d1, 0x3c10) }, /* D-Link DWA 160 A2 */ { USB_DEVICE(0x07d1, 0x3a09) }, + /* Netgear WNA1000 */ + { USB_DEVICE(0x0846, 0x9040) }, /* Netgear WNDA3100 */ { USB_DEVICE(0x0846, 0x9010) }, /* Netgear WN111 v2 */ { USB_DEVICE(0x0846, 0x9001) }, /* Zydas ZD1221 */ { USB_DEVICE(0x0ace, 0x1221) }, + /* Proxim ORiNOCO 802.11n USB */ + { USB_DEVICE(0x1435, 0x0804) }, + /* WNC Generic 11n USB Dongle */ + { USB_DEVICE(0x1435, 0x0326) }, /* ZyXEL NWD271N */ { USB_DEVICE(0x0586, 0x3417) }, /* Z-Com UB81 BG */ @@ -99,6 +110,8 @@ static struct usb_device_id ar9170_usb_ids[] = { { USB_DEVICE(0x0409, 0x0249) }, /* AVM FRITZ!WLAN USB Stick N 2.4 */ { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY }, + /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */ + { USB_DEVICE(0x1668, 0x1200) }, /* terminate */ {} @@ -202,7 +215,7 @@ resubmit: return; free: - usb_buffer_free(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma); + usb_free_coherent(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma); } static void ar9170_usb_rx_completed(struct urb *urb) @@ -283,7 +296,7 @@ static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru) if (!urb) goto out; - ibuf = usb_buffer_alloc(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma); + ibuf = usb_alloc_coherent(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma); if (!ibuf) goto out; @@ -296,8 +309,8 @@ static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru) err = usb_submit_urb(urb, GFP_KERNEL); if (err) { usb_unanchor_urb(urb); - usb_buffer_free(aru->udev, 64, urb->transfer_buffer, - urb->transfer_dma); + usb_free_coherent(aru->udev, 64, urb->transfer_buffer, + urb->transfer_dma); } out: @@ -727,12 +740,16 @@ static void ar9170_usb_firmware_failed(struct ar9170_usb *aru) { struct device *parent = aru->udev->dev.parent; + complete(&aru->firmware_loading_complete); + /* unbind anything failed */ if (parent) - down(&parent->sem); + device_lock(parent); device_release_driver(&aru->udev->dev); if (parent) - up(&parent->sem); + device_unlock(parent); + + usb_put_dev(aru->udev); } static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) @@ -761,6 +778,8 @@ static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context) if (err) goto err_unrx; + complete(&aru->firmware_loading_complete); + usb_put_dev(aru->udev); return; err_unrx: @@ -858,6 +877,7 @@ static int ar9170_usb_probe(struct usb_interface *intf, init_usb_anchor(&aru->tx_pending); init_usb_anchor(&aru->tx_submitted); init_completion(&aru->cmd_wait); + init_completion(&aru->firmware_loading_complete); spin_lock_init(&aru->tx_urb_lock); aru->tx_pending_urbs = 0; @@ -877,6 +897,7 @@ static int ar9170_usb_probe(struct usb_interface *intf, if (err) goto err_freehw; + usb_get_dev(aru->udev); return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw", &aru->udev->dev, GFP_KERNEL, aru, ar9170_usb_firmware_step2); @@ -896,6 +917,9 @@ static void ar9170_usb_disconnect(struct usb_interface *intf) return; aru->common.state = AR9170_IDLE; + + wait_for_completion(&aru->firmware_loading_complete); + ar9170_unregister(&aru->common); ar9170_usb_cancel_urbs(aru); diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h index a2ce3b169ce..919b06046eb 100644 --- a/drivers/net/wireless/ath/ar9170/usb.h +++ b/drivers/net/wireless/ath/ar9170/usb.h @@ -71,6 +71,7 @@ struct ar9170_usb { unsigned int tx_pending_urbs; struct completion cmd_wait; + struct completion firmware_loading_complete; int readlen; u8 *readbuf; diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 71fc960814f..d32f2828b09 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -48,6 +48,12 @@ enum ath_device_state { ATH_HW_INITIALIZED, }; +enum ath_bus_type { + ATH_PCI, + ATH_AHB, + ATH_USB, +}; + struct reg_dmn_pair_mapping { u16 regDmnEnum; u16 reg_5ghz_ctl; @@ -65,17 +71,30 @@ struct ath_regulatory { struct reg_dmn_pair_mapping *regpair; }; +/** + * struct ath_ops - Register read/write operations + * + * @read: Register read + * @write: Register write + * @enable_write_buffer: Enable multiple register writes + * @disable_write_buffer: Disable multiple register writes + * @write_flush: Flush buffered register writes + */ struct ath_ops { unsigned int (*read)(void *, u32 reg_offset); - void (*write)(void *, u32 val, u32 reg_offset); + void (*write)(void *, u32 val, u32 reg_offset); + void (*enable_write_buffer)(void *); + void (*disable_write_buffer)(void *); + void (*write_flush) (void *); }; struct ath_common; struct ath_bus_ops { - void (*read_cachesize)(struct ath_common *common, int *csz); - bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); - void (*bt_coex_prep)(struct ath_common *common); + enum ath_bus_type ath_bus_type; + void (*read_cachesize)(struct ath_common *common, int *csz); + bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); + void (*bt_coex_prep)(struct ath_common *common); }; struct ath_common { diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile index 090dc6d268a..cc09595b781 100644 --- a/drivers/net/wireless/ath/ath5k/Makefile +++ b/drivers/net/wireless/ath/ath5k/Makefile @@ -12,5 +12,6 @@ ath5k-y += attach.o ath5k-y += base.o ath5k-y += led.o ath5k-y += rfkill.o +ath5k-y += ani.o ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c new file mode 100644 index 00000000000..f2311ab3550 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -0,0 +1,744 @@ +/* + * Copyright (C) 2010 Bruno Randolf <br1@einfach.org> + * + * 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 "ath5k.h" +#include "base.h" +#include "reg.h" +#include "debug.h" +#include "ani.h" + +/** + * DOC: Basic ANI Operation + * + * Adaptive Noise Immunity (ANI) controls five noise immunity parameters + * depending on the amount of interference in the environment, increasing + * or reducing sensitivity as necessary. + * + * The parameters are: + * - "noise immunity" + * - "spur immunity" + * - "firstep level" + * - "OFDM weak signal detection" + * - "CCK weak signal detection" + * + * Basically we look at the amount of ODFM and CCK timing errors we get and then + * raise or lower immunity accordingly by setting one or more of these + * parameters. + * Newer chipsets have PHY error counters in hardware which will generate a MIB + * interrupt when they overflow. Older hardware has too enable PHY error frames + * by setting a RX flag and then count every single PHY error. When a specified + * threshold of errors has been reached we will raise immunity. + * Also we regularly check the amount of errors and lower or raise immunity as + * necessary. + */ + + +/*** ANI parameter control ***/ + +/** + * ath5k_ani_set_noise_immunity_level() - Set noise immunity level + * + * @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL + */ +void +ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) +{ + /* TODO: + * ANI documents suggest the following five levels to use, but the HAL + * and ath9k use only use the last two levels, making this + * essentially an on/off option. There *may* be a reason for this (???), + * so i stick with the HAL version for now... + */ +#if 0 + const s8 hi[] = { -18, -18, -16, -14, -12 }; + const s8 lo[] = { -52, -56, -60, -64, -70 }; + const s8 sz[] = { -34, -41, -48, -55, -62 }; + const s8 fr[] = { -70, -72, -75, -78, -80 }; +#else + const s8 sz[] = { -55, -62 }; + const s8 lo[] = { -64, -70 }; + const s8 hi[] = { -14, -12 }; + const s8 fr[] = { -78, -80 }; +#endif + if (level < 0 || level >= ARRAY_SIZE(sz)) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "level out of range %d", level); + return; + } + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, + AR5K_PHY_DESIRED_SIZE_TOT, sz[level]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE, + AR5K_PHY_AGCCOARSE_LO, lo[level]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE, + AR5K_PHY_AGCCOARSE_HI, hi[level]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG, + AR5K_PHY_SIG_FIRPWR, fr[level]); + + ah->ah_sc->ani_state.noise_imm_level = level; + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level); +} + + +/** + * ath5k_ani_set_spur_immunity_level() - Set spur immunity level + * + * @level: level between 0 and @max_spur_level (the maximum level is dependent + * on the chip revision). + */ +void +ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) +{ + const int val[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; + + if (level < 0 || level >= ARRAY_SIZE(val) || + level > ah->ah_sc->ani_state.max_spur_level) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "level out of range %d", level); + return; + } + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR, + AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, val[level]); + + ah->ah_sc->ani_state.spur_level = level; + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level); +} + + +/** + * ath5k_ani_set_firstep_level() - Set "firstep" level + * + * @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL + */ +void +ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level) +{ + const int val[] = { 0, 4, 8 }; + + if (level < 0 || level >= ARRAY_SIZE(val)) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "level out of range %d", level); + return; + } + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG, + AR5K_PHY_SIG_FIRSTEP, val[level]); + + ah->ah_sc->ani_state.firstep_level = level; + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level); +} + + +/** + * ath5k_ani_set_ofdm_weak_signal_detection() - Control OFDM weak signal + * detection + * + * @on: turn on or off + */ +void +ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on) +{ + const int m1l[] = { 127, 50 }; + const int m2l[] = { 127, 40 }; + const int m1[] = { 127, 0x4d }; + const int m2[] = { 127, 0x40 }; + const int m2cnt[] = { 31, 16 }; + const int m2lcnt[] = { 63, 48 }; + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, + AR5K_PHY_WEAK_OFDM_LOW_THR_M1, m1l[on]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, + AR5K_PHY_WEAK_OFDM_LOW_THR_M2, m2l[on]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR, + AR5K_PHY_WEAK_OFDM_HIGH_THR_M1, m1[on]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR, + AR5K_PHY_WEAK_OFDM_HIGH_THR_M2, m2[on]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR, + AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT, m2cnt[on]); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, + AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT, m2lcnt[on]); + + if (on) + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, + AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR, + AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN); + + ah->ah_sc->ani_state.ofdm_weak_sig = on; + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "turned %s", + on ? "on" : "off"); +} + + +/** + * ath5k_ani_set_cck_weak_signal_detection() - control CCK weak signal detection + * + * @on: turn on or off + */ +void +ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on) +{ + const int val[] = { 8, 6 }; + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_CCK_CROSSCORR, + AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR, val[on]); + ah->ah_sc->ani_state.cck_weak_sig = on; + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "turned %s", + on ? "on" : "off"); +} + + +/*** ANI algorithm ***/ + +/** + * ath5k_ani_raise_immunity() - Increase noise immunity + * + * @ofdm_trigger: If this is true we are called because of too many OFDM errors, + * the algorithm will tune more parameters then. + * + * Try to raise noise immunity (=decrease sensitivity) in several steps + * depending on the average RSSI of the beacons we received. + */ +static void +ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, + bool ofdm_trigger) +{ + int rssi = ah->ah_beacon_rssi_avg.avg; + + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "raise immunity (%s)", + ofdm_trigger ? "ODFM" : "CCK"); + + /* first: raise noise immunity */ + if (as->noise_imm_level < ATH5K_ANI_MAX_NOISE_IMM_LVL) { + ath5k_ani_set_noise_immunity_level(ah, as->noise_imm_level + 1); + return; + } + + /* only OFDM: raise spur immunity level */ + if (ofdm_trigger && + as->spur_level < ah->ah_sc->ani_state.max_spur_level) { + ath5k_ani_set_spur_immunity_level(ah, as->spur_level + 1); + return; + } + + /* AP mode */ + if (ah->ah_sc->opmode == NL80211_IFTYPE_AP) { + if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) + ath5k_ani_set_firstep_level(ah, as->firstep_level + 1); + return; + } + + /* STA and IBSS mode */ + + /* TODO: for IBSS mode it would be better to keep a beacon RSSI average + * per each neighbour node and use the minimum of these, to make sure we + * don't shut out a remote node by raising immunity too high. */ + + if (rssi > ATH5K_ANI_RSSI_THR_HIGH) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "beacon RSSI high"); + /* only OFDM: beacon RSSI is high, we can disable ODFM weak + * signal detection */ + if (ofdm_trigger && as->ofdm_weak_sig == true) { + ath5k_ani_set_ofdm_weak_signal_detection(ah, false); + ath5k_ani_set_spur_immunity_level(ah, 0); + return; + } + /* as a last resort or CCK: raise firstep level */ + if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) { + ath5k_ani_set_firstep_level(ah, as->firstep_level + 1); + return; + } + } else if (rssi > ATH5K_ANI_RSSI_THR_LOW) { + /* beacon RSSI in mid range, we need OFDM weak signal detect, + * but can raise firstep level */ + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "beacon RSSI mid"); + if (ofdm_trigger && as->ofdm_weak_sig == false) + ath5k_ani_set_ofdm_weak_signal_detection(ah, true); + if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) + ath5k_ani_set_firstep_level(ah, as->firstep_level + 1); + return; + } else if (ah->ah_current_channel->band == IEEE80211_BAND_2GHZ) { + /* beacon RSSI is low. in B/G mode turn of OFDM weak signal + * detect and zero firstep level to maximize CCK sensitivity */ + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "beacon RSSI low, 2GHz"); + if (ofdm_trigger && as->ofdm_weak_sig == true) + ath5k_ani_set_ofdm_weak_signal_detection(ah, false); + if (as->firstep_level > 0) + ath5k_ani_set_firstep_level(ah, 0); + return; + } + + /* TODO: why not?: + if (as->cck_weak_sig == true) { + ath5k_ani_set_cck_weak_signal_detection(ah, false); + } + */ +} + + +/** + * ath5k_ani_lower_immunity() - Decrease noise immunity + * + * Try to lower noise immunity (=increase sensitivity) in several steps + * depending on the average RSSI of the beacons we received. + */ +static void +ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) +{ + int rssi = ah->ah_beacon_rssi_avg.avg; + + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "lower immunity"); + + if (ah->ah_sc->opmode == NL80211_IFTYPE_AP) { + /* AP mode */ + if (as->firstep_level > 0) { + ath5k_ani_set_firstep_level(ah, as->firstep_level - 1); + return; + } + } else { + /* STA and IBSS mode (see TODO above) */ + if (rssi > ATH5K_ANI_RSSI_THR_HIGH) { + /* beacon signal is high, leave OFDM weak signal + * detection off or it may oscillate + * TODO: who said it's off??? */ + } else if (rssi > ATH5K_ANI_RSSI_THR_LOW) { + /* beacon RSSI is mid-range: turn on ODFM weak signal + * detection and next, lower firstep level */ + if (as->ofdm_weak_sig == false) { + ath5k_ani_set_ofdm_weak_signal_detection(ah, + true); + return; + } + if (as->firstep_level > 0) { + ath5k_ani_set_firstep_level(ah, + as->firstep_level - 1); + return; + } + } else { + /* beacon signal is low: only reduce firstep level */ + if (as->firstep_level > 0) { + ath5k_ani_set_firstep_level(ah, + as->firstep_level - 1); + return; + } + } + } + + /* all modes */ + if (as->spur_level > 0) { + ath5k_ani_set_spur_immunity_level(ah, as->spur_level - 1); + return; + } + + /* finally, reduce noise immunity */ + if (as->noise_imm_level > 0) { + ath5k_ani_set_noise_immunity_level(ah, as->noise_imm_level - 1); + return; + } +} + + +/** + * ath5k_hw_ani_get_listen_time() - Calculate time spent listening + * + * Return an approximation of the time spent "listening" in milliseconds (ms) + * since the last call of this function by deducting the cycles spent + * transmitting and receiving from the total cycle count. + * Save profile count values for debugging/statistics and because we might want + * to use them later. + * + * We assume no one else clears these registers! + */ +static int +ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as) +{ + int listen; + + /* freeze */ + ath5k_hw_reg_write(ah, AR5K_MIBC_FMC, AR5K_MIBC); + /* read */ + as->pfc_cycles = ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE); + as->pfc_busy = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR); + as->pfc_tx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX); + as->pfc_rx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX); + /* clear */ + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); + /* un-freeze */ + ath5k_hw_reg_write(ah, 0, AR5K_MIBC); + + /* TODO: where does 44000 come from? (11g clock rate?) */ + listen = (as->pfc_cycles - as->pfc_rx - as->pfc_tx) / 44000; + + if (as->pfc_cycles == 0 || listen < 0) + return 0; + return listen; +} + + +/** + * ath5k_ani_save_and_clear_phy_errors() - Clear and save PHY error counters + * + * Clear the PHY error counters as soon as possible, since this might be called + * from a MIB interrupt and we want to make sure we don't get interrupted again. + * Add the count of CCK and OFDM errors to our internal state, so it can be used + * by the algorithm later. + * + * Will be called from interrupt and tasklet context. + * Returns 0 if both counters are zero. + */ +static int +ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah, + struct ath5k_ani_state *as) +{ + unsigned int ofdm_err, cck_err; + + if (!ah->ah_capabilities.cap_has_phyerr_counters) + return 0; + + ofdm_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1); + cck_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2); + + /* reset counters first, we might be in a hurry (interrupt) */ + ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH, + AR5K_PHYERR_CNT1); + ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH, + AR5K_PHYERR_CNT2); + + ofdm_err = ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - ofdm_err); + cck_err = ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - cck_err); + + /* sometimes both can be zero, especially when there is a superfluous + * second interrupt. detect that here and return an error. */ + if (ofdm_err <= 0 && cck_err <= 0) + return 0; + + /* avoid negative values should one of the registers overflow */ + if (ofdm_err > 0) { + as->ofdm_errors += ofdm_err; + as->sum_ofdm_errors += ofdm_err; + } + if (cck_err > 0) { + as->cck_errors += cck_err; + as->sum_cck_errors += cck_err; + } + return 1; +} + + +/** + * ath5k_ani_period_restart() - Restart ANI period + * + * Just reset counters, so they are clear for the next "ani period". + */ +static void +ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as) +{ + /* keep last values for debugging */ + as->last_ofdm_errors = as->ofdm_errors; + as->last_cck_errors = as->cck_errors; + as->last_listen = as->listen_time; + + as->ofdm_errors = 0; + as->cck_errors = 0; + as->listen_time = 0; +} + + +/** + * ath5k_ani_calibration() - The main ANI calibration function + * + * We count OFDM and CCK errors relative to the time where we did not send or + * receive ("listen" time) and raise or lower immunity accordingly. + * This is called regularly (every second) from the calibration timer, but also + * when an error threshold has been reached. + * + * In order to synchronize access from different contexts, this should be + * called only indirectly by scheduling the ANI tasklet! + */ +void +ath5k_ani_calibration(struct ath5k_hw *ah) +{ + struct ath5k_ani_state *as = &ah->ah_sc->ani_state; + int listen, ofdm_high, ofdm_low, cck_high, cck_low; + + if (as->ani_mode != ATH5K_ANI_MODE_AUTO) + return; + + /* get listen time since last call and add it to the counter because we + * might not have restarted the "ani period" last time */ + listen = ath5k_hw_ani_get_listen_time(ah, as); + as->listen_time += listen; + + ath5k_ani_save_and_clear_phy_errors(ah, as); + + ofdm_high = as->listen_time * ATH5K_ANI_OFDM_TRIG_HIGH / 1000; + cck_high = as->listen_time * ATH5K_ANI_CCK_TRIG_HIGH / 1000; + ofdm_low = as->listen_time * ATH5K_ANI_OFDM_TRIG_LOW / 1000; + cck_low = as->listen_time * ATH5K_ANI_CCK_TRIG_LOW / 1000; + + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "listen %d (now %d)", as->listen_time, listen); + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "check high ofdm %d/%d cck %d/%d", + as->ofdm_errors, ofdm_high, as->cck_errors, cck_high); + + if (as->ofdm_errors > ofdm_high || as->cck_errors > cck_high) { + /* too many PHY errors - we have to raise immunity */ + bool ofdm_flag = as->ofdm_errors > ofdm_high ? true : false; + ath5k_ani_raise_immunity(ah, as, ofdm_flag); + ath5k_ani_period_restart(ah, as); + + } else if (as->listen_time > 5 * ATH5K_ANI_LISTEN_PERIOD) { + /* If more than 5 (TODO: why 5?) periods have passed and we got + * relatively little errors we can try to lower immunity */ + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "check low ofdm %d/%d cck %d/%d", + as->ofdm_errors, ofdm_low, as->cck_errors, cck_low); + + if (as->ofdm_errors <= ofdm_low && as->cck_errors <= cck_low) + ath5k_ani_lower_immunity(ah, as); + + ath5k_ani_period_restart(ah, as); + } +} + + +/*** INTERRUPT HANDLER ***/ + +/** + * ath5k_ani_mib_intr() - Interrupt handler for ANI MIB counters + * + * Just read & reset the registers quickly, so they don't generate more + * interrupts, save the counters and schedule the tasklet to decide whether + * to raise immunity or not. + * + * We just need to handle PHY error counters, ath5k_hw_update_mib_counters() + * should take care of all "normal" MIB interrupts. + */ +void +ath5k_ani_mib_intr(struct ath5k_hw *ah) +{ + struct ath5k_ani_state *as = &ah->ah_sc->ani_state; + + /* nothing to do here if HW does not have PHY error counters - they + * can't be the reason for the MIB interrupt then */ + if (!ah->ah_capabilities.cap_has_phyerr_counters) + return; + + /* not in use but clear anyways */ + ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT); + ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); + + if (ah->ah_sc->ani_state.ani_mode != ATH5K_ANI_MODE_AUTO) + return; + + /* if one of the errors triggered, we can get a superfluous second + * interrupt, even though we have already reset the register. the + * function detects that so we can return early */ + if (ath5k_ani_save_and_clear_phy_errors(ah, as) == 0) + return; + + if (as->ofdm_errors > ATH5K_ANI_OFDM_TRIG_HIGH || + as->cck_errors > ATH5K_ANI_CCK_TRIG_HIGH) + tasklet_schedule(&ah->ah_sc->ani_tasklet); +} + + +/** + * ath5k_ani_phy_error_report() - Used by older HW to report PHY errors + * + * This is used by hardware without PHY error counters to report PHY errors + * on a frame-by-frame basis, instead of the interrupt. + */ +void +ath5k_ani_phy_error_report(struct ath5k_hw *ah, + enum ath5k_phy_error_code phyerr) +{ + struct ath5k_ani_state *as = &ah->ah_sc->ani_state; + + if (phyerr == AR5K_RX_PHY_ERROR_OFDM_TIMING) { + as->ofdm_errors++; + if (as->ofdm_errors > ATH5K_ANI_OFDM_TRIG_HIGH) + tasklet_schedule(&ah->ah_sc->ani_tasklet); + } else if (phyerr == AR5K_RX_PHY_ERROR_CCK_TIMING) { + as->cck_errors++; + if (as->cck_errors > ATH5K_ANI_CCK_TRIG_HIGH) + tasklet_schedule(&ah->ah_sc->ani_tasklet); + } +} + + +/*** INIT ***/ + +/** + * ath5k_enable_phy_err_counters() - Enable PHY error counters + * + * Enable PHY error counters for OFDM and CCK timing errors. + */ +static void +ath5k_enable_phy_err_counters(struct ath5k_hw *ah) +{ + ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH, + AR5K_PHYERR_CNT1); + ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH, + AR5K_PHYERR_CNT2); + ath5k_hw_reg_write(ah, AR5K_PHY_ERR_FIL_OFDM, AR5K_PHYERR_CNT1_MASK); + ath5k_hw_reg_write(ah, AR5K_PHY_ERR_FIL_CCK, AR5K_PHYERR_CNT2_MASK); + + /* not in use */ + ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT); + ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); +} + + +/** + * ath5k_disable_phy_err_counters() - Disable PHY error counters + * + * Disable PHY error counters for OFDM and CCK timing errors. + */ +static void +ath5k_disable_phy_err_counters(struct ath5k_hw *ah) +{ + ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT1); + ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT2); + ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT1_MASK); + ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT2_MASK); + + /* not in use */ + ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT); + ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT); +} + + +/** + * ath5k_ani_init() - Initialize ANI + * @mode: Which mode to use (auto, manual high, manual low, off) + * + * Initialize ANI according to mode. + */ +void +ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode) +{ + /* ANI is only possible on 5212 and newer */ + if (ah->ah_version < AR5K_AR5212) + return; + + /* clear old state information */ + memset(&ah->ah_sc->ani_state, 0, sizeof(ah->ah_sc->ani_state)); + + /* older hardware has more spur levels than newer */ + if (ah->ah_mac_srev < AR5K_SREV_AR2414) + ah->ah_sc->ani_state.max_spur_level = 7; + else + ah->ah_sc->ani_state.max_spur_level = 2; + + /* initial values for our ani parameters */ + if (mode == ATH5K_ANI_MODE_OFF) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI off\n"); + } else if (mode == ATH5K_ANI_MODE_MANUAL_LOW) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "ANI manual low -> high sensitivity\n"); + ath5k_ani_set_noise_immunity_level(ah, 0); + ath5k_ani_set_spur_immunity_level(ah, 0); + ath5k_ani_set_firstep_level(ah, 0); + ath5k_ani_set_ofdm_weak_signal_detection(ah, true); + ath5k_ani_set_cck_weak_signal_detection(ah, true); + } else if (mode == ATH5K_ANI_MODE_MANUAL_HIGH) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, + "ANI manual high -> low sensitivity\n"); + ath5k_ani_set_noise_immunity_level(ah, + ATH5K_ANI_MAX_NOISE_IMM_LVL); + ath5k_ani_set_spur_immunity_level(ah, + ah->ah_sc->ani_state.max_spur_level); + ath5k_ani_set_firstep_level(ah, ATH5K_ANI_MAX_FIRSTEP_LVL); + ath5k_ani_set_ofdm_weak_signal_detection(ah, false); + ath5k_ani_set_cck_weak_signal_detection(ah, false); + } else if (mode == ATH5K_ANI_MODE_AUTO) { + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI auto\n"); + ath5k_ani_set_noise_immunity_level(ah, 0); + ath5k_ani_set_spur_immunity_level(ah, 0); + ath5k_ani_set_firstep_level(ah, 0); + ath5k_ani_set_ofdm_weak_signal_detection(ah, true); + ath5k_ani_set_cck_weak_signal_detection(ah, false); + } + + /* newer hardware has PHY error counter registers which we can use to + * get OFDM and CCK error counts. older hardware has to set rxfilter and + * report every single PHY error by calling ath5k_ani_phy_error_report() + */ + if (mode == ATH5K_ANI_MODE_AUTO) { + if (ah->ah_capabilities.cap_has_phyerr_counters) + ath5k_enable_phy_err_counters(ah); + else + ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) | + AR5K_RX_FILTER_PHYERR); + } else { + if (ah->ah_capabilities.cap_has_phyerr_counters) + ath5k_disable_phy_err_counters(ah); + else + ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) & + ~AR5K_RX_FILTER_PHYERR); + } + + ah->ah_sc->ani_state.ani_mode = mode; +} + + +/*** DEBUG ***/ + +#ifdef CONFIG_ATH5K_DEBUG + +void +ath5k_ani_print_counters(struct ath5k_hw *ah) +{ + /* clears too */ + printk(KERN_NOTICE "ACK fail\t%d\n", + ath5k_hw_reg_read(ah, AR5K_ACK_FAIL)); + printk(KERN_NOTICE "RTS fail\t%d\n", + ath5k_hw_reg_read(ah, AR5K_RTS_FAIL)); + printk(KERN_NOTICE "RTS success\t%d\n", + ath5k_hw_reg_read(ah, AR5K_RTS_OK)); + printk(KERN_NOTICE "FCS error\t%d\n", + ath5k_hw_reg_read(ah, AR5K_FCS_FAIL)); + + /* no clear */ + printk(KERN_NOTICE "tx\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX)); + printk(KERN_NOTICE "rx\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX)); + printk(KERN_NOTICE "busy\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR)); + printk(KERN_NOTICE "cycles\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE)); + + printk(KERN_NOTICE "AR5K_PHYERR_CNT1\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1)); + printk(KERN_NOTICE "AR5K_PHYERR_CNT2\t%d\n", + ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2)); + printk(KERN_NOTICE "AR5K_OFDM_FIL_CNT\t%d\n", + ath5k_hw_reg_read(ah, AR5K_OFDM_FIL_CNT)); + printk(KERN_NOTICE "AR5K_CCK_FIL_CNT\t%d\n", + ath5k_hw_reg_read(ah, AR5K_CCK_FIL_CNT)); +} + +#endif diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h new file mode 100644 index 00000000000..55cf26d8522 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/ani.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2010 Bruno Randolf <br1@einfach.org> + * + * 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. + */ +#ifndef ANI_H +#define ANI_H + +/* these thresholds are relative to the ATH5K_ANI_LISTEN_PERIOD */ +#define ATH5K_ANI_LISTEN_PERIOD 100 +#define ATH5K_ANI_OFDM_TRIG_HIGH 500 +#define ATH5K_ANI_OFDM_TRIG_LOW 200 +#define ATH5K_ANI_CCK_TRIG_HIGH 200 +#define ATH5K_ANI_CCK_TRIG_LOW 100 + +/* average beacon RSSI thresholds */ +#define ATH5K_ANI_RSSI_THR_HIGH 40 +#define ATH5K_ANI_RSSI_THR_LOW 7 + +/* maximum availabe levels */ +#define ATH5K_ANI_MAX_FIRSTEP_LVL 2 +#define ATH5K_ANI_MAX_NOISE_IMM_LVL 1 + + +/** + * enum ath5k_ani_mode - mode for ANI / noise sensitivity + * + * @ATH5K_ANI_MODE_OFF: Turn ANI off. This can be useful to just stop the ANI + * algorithm after it has been on auto mode. + * ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low, + * maximizing sensitivity. ANI will not run. + * ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high, + * minimizing sensitivity. ANI will not run. + * ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the + * amount of OFDM and CCK frame errors (default). + */ +enum ath5k_ani_mode { + ATH5K_ANI_MODE_OFF = 0, + ATH5K_ANI_MODE_MANUAL_LOW = 1, + ATH5K_ANI_MODE_MANUAL_HIGH = 2, + ATH5K_ANI_MODE_AUTO = 3 +}; + + +/** + * struct ath5k_ani_state - ANI state and associated counters + * + * @max_spur_level: the maximum spur level is chip dependent + */ +struct ath5k_ani_state { + enum ath5k_ani_mode ani_mode; + + /* state */ + int noise_imm_level; + int spur_level; + int firstep_level; + bool ofdm_weak_sig; + bool cck_weak_sig; + + int max_spur_level; + + /* used by the algorithm */ + unsigned int listen_time; + unsigned int ofdm_errors; + unsigned int cck_errors; + + /* debug/statistics only: numbers from last ANI calibration */ + unsigned int pfc_tx; + unsigned int pfc_rx; + unsigned int pfc_busy; + unsigned int pfc_cycles; + unsigned int last_listen; + unsigned int last_ofdm_errors; + unsigned int last_cck_errors; + unsigned int sum_ofdm_errors; + unsigned int sum_cck_errors; +}; + +void ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode); +void ath5k_ani_mib_intr(struct ath5k_hw *ah); +void ath5k_ani_calibration(struct ath5k_hw *ah); +void ath5k_ani_phy_error_report(struct ath5k_hw *ah, + enum ath5k_phy_error_code phyerr); + +/* for manual control */ +void ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level); +void ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level); +void ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level); +void ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on); +void ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on); + +void ath5k_ani_print_counters(struct ath5k_hw *ah); + +#endif /* ANI_H */ diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index ac67f02e26d..2785946f659 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -202,7 +202,8 @@ #define AR5K_TUNE_MAX_TXPOWER 63 #define AR5K_TUNE_DEFAULT_TXPOWER 25 #define AR5K_TUNE_TPC_TXPOWER false -#define AR5K_TUNE_HWTXTRIES 4 +#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 10000 /* 10 sec */ +#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */ #define AR5K_INIT_CARR_SENSE_EN 1 @@ -614,28 +615,6 @@ struct ath5k_rx_status { #define AR5K_BEACON_ENA 0x00800000 /*enable beacon xmit*/ #define AR5K_BEACON_RESET_TSF 0x01000000 /*force a TSF reset*/ -#if 0 -/** - * struct ath5k_beacon_state - Per-station beacon timer state. - * @bs_interval: in TU's, can also include the above flags - * @bs_cfp_max_duration: if non-zero hw is setup to coexist with a - * Point Coordination Function capable AP - */ -struct ath5k_beacon_state { - u32 bs_next_beacon; - u32 bs_next_dtim; - u32 bs_interval; - u8 bs_dtim_period; - u8 bs_cfp_period; - u16 bs_cfp_max_duration; - u16 bs_cfp_du_remain; - u16 bs_tim_offset; - u16 bs_sleep_duration; - u16 bs_bmiss_threshold; - u32 bs_cfp_next; -}; -#endif - /* * TSF to TU conversion: @@ -822,9 +801,9 @@ struct ath5k_athchan_2ghz { * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold * We currently do increments on interrupt by * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 - * @AR5K_INT_MIB: Indicates the Management Information Base counters should be - * checked. We should do this with ath5k_hw_update_mib_counters() but - * it seems we should also then do some noise immunity work. + * @AR5K_INT_MIB: Indicates the either Management Information Base counters or + * one of the PHY error counters reached the maximum value and should be + * read and cleared. * @AR5K_INT_RXPHY: RX PHY Error * @AR5K_INT_RXKCM: RX Key cache miss * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a @@ -912,10 +891,11 @@ enum ath5k_int { AR5K_INT_NOCARD = 0xffffffff }; -/* Software interrupts used for calibration */ -enum ath5k_software_interrupt { - AR5K_SWI_FULL_CALIBRATION = 0x01, - AR5K_SWI_SHORT_CALIBRATION = 0x02, +/* mask which calibration is active at the moment */ +enum ath5k_calibration_mask { + AR5K_CALIBRATION_FULL = 0x01, + AR5K_CALIBRATION_SHORT = 0x02, + AR5K_CALIBRATION_ANI = 0x04, }; /* @@ -1004,6 +984,8 @@ struct ath5k_capabilities { struct { u8 q_tx_num; } cap_queues; + + bool cap_has_phyerr_counters; }; /* size of noise floor history (keep it a power of two) */ @@ -1014,6 +996,15 @@ struct ath5k_nfcal_hist s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */ }; +/** + * struct avg_val - Helper structure for average calculation + * @avg: contains the actual average value + * @avg_weight: is used internally during calculation to prevent rounding errors + */ +struct ath5k_avg_val { + int avg; + int avg_weight; +}; /***************************************\ HARDWARE ABSTRACTION LAYER STRUCTURE @@ -1028,7 +1019,6 @@ struct ath5k_nfcal_hist /* TODO: Clean up and merge with ath5k_softc */ struct ath5k_hw { - u32 ah_magic; struct ath_common common; struct ath5k_softc *ah_sc; @@ -1036,7 +1026,6 @@ struct ath5k_hw { enum ath5k_int ah_imr; - enum nl80211_iftype ah_op_mode; struct ieee80211_channel *ah_current_channel; bool ah_turbo; bool ah_calibration; @@ -1049,7 +1038,6 @@ struct ath5k_hw { u32 ah_phy; u32 ah_mac_srev; u16 ah_mac_version; - u16 ah_mac_revision; u16 ah_phy_revision; u16 ah_radio_5ghz_revision; u16 ah_radio_2ghz_revision; @@ -1071,8 +1059,6 @@ struct ath5k_hw { u8 ah_def_ant; bool ah_software_retry; - int ah_gpio_npins; - struct ath5k_capabilities ah_capabilities; struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES]; @@ -1123,17 +1109,18 @@ struct ath5k_hw { struct ath5k_nfcal_hist ah_nfcal_hist; + /* average beacon RSSI in our BSS (used by ANI) */ + struct ath5k_avg_val ah_beacon_rssi_avg; + /* noise floor from last periodic calibration */ s32 ah_noise_floor; /* Calibration timestamp */ - unsigned long ah_cal_tstamp; - - /* Calibration interval (secs) */ - u8 ah_cal_intval; + unsigned long ah_cal_next_full; + unsigned long ah_cal_next_ani; - /* Software interrupt mask */ - u8 ah_swi_mask; + /* Calibration mask */ + u8 ah_cal_mask; /* * Function pointers @@ -1141,9 +1128,9 @@ struct ath5k_hw { int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc, u32 size, unsigned int flags); int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, - unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, + unsigned int, unsigned int, int, enum ath5k_pkt_type, unsigned int, unsigned int, unsigned int, unsigned int, - unsigned int, unsigned int, unsigned int); + unsigned int, unsigned int, unsigned int, unsigned int); int (*ah_setup_mrr_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); @@ -1158,158 +1145,145 @@ struct ath5k_hw { */ /* Attach/Detach Functions */ -extern int ath5k_hw_attach(struct ath5k_softc *sc); -extern void ath5k_hw_detach(struct ath5k_hw *ah); +int ath5k_hw_attach(struct ath5k_softc *sc); +void ath5k_hw_detach(struct ath5k_hw *ah); /* LED functions */ -extern int ath5k_init_leds(struct ath5k_softc *sc); -extern void ath5k_led_enable(struct ath5k_softc *sc); -extern void ath5k_led_off(struct ath5k_softc *sc); -extern void ath5k_unregister_leds(struct ath5k_softc *sc); +int ath5k_init_leds(struct ath5k_softc *sc); +void ath5k_led_enable(struct ath5k_softc *sc); +void ath5k_led_off(struct ath5k_softc *sc); +void ath5k_unregister_leds(struct ath5k_softc *sc); /* Reset Functions */ -extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); -extern int ath5k_hw_on_hold(struct ath5k_hw *ah); -extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel); +int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); +int ath5k_hw_on_hold(struct ath5k_hw *ah); +int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, + struct ieee80211_channel *channel, bool change_channel); +int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, + bool is_set); /* Power management functions */ -extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); /* DMA Related Functions */ -extern void ath5k_hw_start_rx_dma(struct ath5k_hw *ah); -extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah); -extern u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah); -extern void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr); -extern int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue); -extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue); -extern u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue); -extern int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, +void ath5k_hw_start_rx_dma(struct ath5k_hw *ah); +int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah); +u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah); +void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr); +int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue); +int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue); +u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue); +int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr); -extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase); +int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase); /* Interrupt handling */ -extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); -extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); -extern enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum -ath5k_int new_mask); -extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_low_level_stats *stats); +bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); +int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); +enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask); +void ath5k_hw_update_mib_counters(struct ath5k_hw *ah); /* EEPROM access functions */ -extern int ath5k_eeprom_init(struct ath5k_hw *ah); -extern void ath5k_eeprom_detach(struct ath5k_hw *ah); -extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); -extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah); +int ath5k_eeprom_init(struct ath5k_hw *ah); +void ath5k_eeprom_detach(struct ath5k_hw *ah); +int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); /* Protocol Control Unit Functions */ -extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); -extern void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class); +extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode); +void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class); /* BSSID Functions */ -extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); -extern void ath5k_hw_set_associd(struct ath5k_hw *ah); -extern void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); +int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); +void ath5k_hw_set_associd(struct ath5k_hw *ah); +void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); /* Receive start/stop functions */ -extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah); -extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah); +void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah); +void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah); /* RX Filter functions */ -extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1); -extern int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index); -extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index); -extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah); -extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter); +void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1); +u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah); +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 -extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_beacon_state *state); -extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah); -extern int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr); -#endif +u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah); +void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64); +void ath5k_hw_reset_tsf(struct ath5k_hw *ah); +void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval); /* ACK bit rate */ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high); -/* ACK/CTS Timeouts */ -extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout); -extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah); -extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout); -extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah); /* Clock rate related functions */ unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec); unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock); unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah); /* Key table (WEP) functions */ -extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry); -extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry); -extern int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac); -extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac); +int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry); +int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, + const struct ieee80211_key_conf *key, const u8 *mac); +int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac); /* Queue Control Unit, DFS Control Unit Functions */ -extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info); -extern int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, - const struct ath5k_txq_info *queue_info); -extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, - enum ath5k_tx_queue queue_type, - struct ath5k_txq_info *queue_info); -extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue); -extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue); -extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue); -extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah); -extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time); +int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, + struct ath5k_txq_info *queue_info); +int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue, + const struct ath5k_txq_info *queue_info); +int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, + enum ath5k_tx_queue queue_type, + struct ath5k_txq_info *queue_info); +u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue); +void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue); +int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue); +int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time); /* Hardware Descriptor Functions */ -extern int ath5k_hw_init_desc_functions(struct ath5k_hw *ah); +int ath5k_hw_init_desc_functions(struct ath5k_hw *ah); /* GPIO Functions */ -extern void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state); -extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio); -extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio); -extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio); -extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); -extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); +void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state); +int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio); +int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio); +u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio); +int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); +void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, + u32 interrupt_level); /* rfkill Functions */ -extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah); -extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah); +void ath5k_rfkill_hw_start(struct ath5k_hw *ah); +void ath5k_rfkill_hw_stop(struct ath5k_hw *ah); /* Misc functions */ int ath5k_hw_set_capabilities(struct ath5k_hw *ah); -extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result); -extern int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id); -extern int ath5k_hw_disable_pspoll(struct ath5k_hw *ah); +int ath5k_hw_get_capability(struct ath5k_hw *ah, + enum ath5k_capability_type cap_type, u32 capability, + u32 *result); +int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id); +int ath5k_hw_disable_pspoll(struct ath5k_hw *ah); /* Initial register settings functions */ -extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel); +int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel); /* Initialize RF */ -extern int ath5k_hw_rfregs_init(struct ath5k_hw *ah, - struct ieee80211_channel *channel, - unsigned int mode); -extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq); -extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah); -extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah); +int ath5k_hw_rfregs_init(struct ath5k_hw *ah, + struct ieee80211_channel *channel, + unsigned int mode); +int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq); +enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah); +int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah); /* PHY/RF channel functions */ -extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); -extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); +bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); +int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); /* PHY calibration */ void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah); -extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); -extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); -extern s16 ath5k_hw_get_noise_floor(struct ath5k_hw *ah); -extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah); +int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, + struct ieee80211_channel *channel); /* Spur mitigation */ bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, - struct ieee80211_channel *channel); + struct ieee80211_channel *channel); void ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, - struct ieee80211_channel *channel); + struct ieee80211_channel *channel); /* Misc PHY functions */ -extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan); -extern int ath5k_hw_phy_disable(struct ath5k_hw *ah); +u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan); +int ath5k_hw_phy_disable(struct ath5k_hw *ah); /* Antenna control */ -extern void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode); -extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant); -extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); +void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode); /* TX power setup */ -extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 ee_mode, u8 txpower); -extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower); +int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, + u8 ee_mode, u8 txpower); +int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower); /* * Functions used internaly @@ -1335,29 +1309,6 @@ static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg) iowrite32(val, ah->ah_iobase + reg); } -#if defined(_ATH5K_RESET) || defined(_ATH5K_PHY) -/* - * Check if a register write has been completed - */ -static int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, - u32 val, bool is_set) -{ - int i; - u32 data; - - for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) { - data = ath5k_hw_reg_read(ah, reg); - if (is_set && (data & flag)) - break; - else if ((data & flag) == val) - break; - udelay(15); - } - - return (i <= 0) ? -EAGAIN : 0; -} -#endif - static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) { u32 retval = 0, bit, i; @@ -1370,9 +1321,27 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) return retval; } -static inline int ath5k_pad_size(int hdrlen) +#define AVG_SAMPLES 8 +#define AVG_FACTOR 1000 + +/** + * ath5k_moving_average - Exponentially weighted moving average + * @avg: average structure + * @val: current value + * + * This implementation make use of a struct ath5k_avg_val to prevent rounding + * errors. + */ +static inline struct ath5k_avg_val +ath5k_moving_average(const struct ath5k_avg_val avg, const int val) { - return (hdrlen < 24) ? 0 : hdrlen & 3; + struct ath5k_avg_val new; + new.avg_weight = avg.avg_weight ? + (((avg.avg_weight * ((AVG_SAMPLES) - 1)) + + (val * (AVG_FACTOR))) / (AVG_SAMPLES)) : + (val * (AVG_FACTOR)); + new.avg = new.avg_weight / (AVG_FACTOR); + return new; } #endif diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index dc0786cc263..e0c244b02f0 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -114,7 +114,6 @@ int ath5k_hw_attach(struct ath5k_softc *sc) /* * HW information */ - ah->ah_op_mode = NL80211_IFTYPE_STATION; ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; ah->ah_turbo = false; ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; @@ -124,6 +123,9 @@ int ath5k_hw_attach(struct ath5k_softc *sc) ah->ah_cw_min = AR5K_TUNE_CWMIN; ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; ah->ah_software_retry = false; + ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT; + ah->ah_noise_floor = -95; /* until first NF calibration is run */ + sc->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO; /* * Find the mac version @@ -149,7 +151,6 @@ int ath5k_hw_attach(struct ath5k_softc *sc) /* Get MAC, PHY and RADIO revisions */ ah->ah_mac_srev = srev; ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); - ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV); ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) & 0xffffffff; ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, @@ -328,7 +329,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc) /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN); ath5k_hw_set_associd(ah); - ath5k_hw_set_opmode(ah); + ath5k_hw_set_opmode(ah, sc->opmode); ath5k_hw_rfgain_opt_init(ah); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 3abbe7513ab..5f04cf38a5b 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -59,8 +59,8 @@ #include "base.h" #include "reg.h" #include "debug.h" +#include "ani.h" -static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); @@ -199,7 +199,7 @@ static void __devexit ath5k_pci_remove(struct pci_dev *pdev); static int ath5k_pci_suspend(struct device *dev); static int ath5k_pci_resume(struct device *dev); -SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume); +static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume); #define ATH5K_PM_OPS (&ath5k_pm_ops) #else #define ATH5K_PM_OPS NULL @@ -231,7 +231,7 @@ static void ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); static int ath5k_config(struct ieee80211_hw *hw, u32 changed); static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, - int mc_count, struct dev_addr_list *mc_list); + struct netdev_hw_addr_list *mc_list); static void ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, @@ -242,6 +242,8 @@ static int ath5k_set_key(struct ieee80211_hw *hw, struct ieee80211_key_conf *key); static int ath5k_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); +static int ath5k_get_survey(struct ieee80211_hw *hw, + int idx, struct survey_info *survey); 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); @@ -267,6 +269,7 @@ static const struct ieee80211_ops ath5k_hw_ops = { .configure_filter = ath5k_configure_filter, .set_key = ath5k_set_key, .get_stats = ath5k_get_stats, + .get_survey = ath5k_get_survey, .conf_tx = NULL, .get_tsf = ath5k_get_tsf, .set_tsf = ath5k_set_tsf, @@ -308,7 +311,7 @@ static int ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf); static int ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, - struct ath5k_txq *txq); + struct ath5k_txq *txq, int padsize); static inline void ath5k_txbuf_free(struct ath5k_softc *sc, struct ath5k_buf *bf) { @@ -365,6 +368,7 @@ static void ath5k_beacon_send(struct ath5k_softc *sc); static void ath5k_beacon_config(struct ath5k_softc *sc); static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); static void ath5k_tasklet_beacon(unsigned long data); +static void ath5k_tasklet_ani(unsigned long data); static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) { @@ -544,8 +548,7 @@ ath5k_pci_probe(struct pci_dev *pdev, SET_IEEE80211_DEV(hw, &pdev->dev); hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; + IEEE80211_HW_SIGNAL_DBM; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP) | @@ -830,6 +833,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc); tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); + tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc); ret = ath5k_eeprom_read_mac(ah, mac); if (ret) { @@ -1138,8 +1142,6 @@ ath5k_mode_setup(struct ath5k_softc *sc) struct ath5k_hw *ah = sc->ah; u32 rfilt; - ah->ah_op_mode = sc->opmode; - /* configure rx filter */ rfilt = sc->filter_flags; ath5k_hw_set_rx_filter(ah, rfilt); @@ -1148,8 +1150,9 @@ ath5k_mode_setup(struct ath5k_softc *sc) ath5k_hw_set_bssid_mask(ah, sc->bssidmask); /* configure operational mode */ - ath5k_hw_set_opmode(ah); + ath5k_hw_set_opmode(ah, sc->opmode); + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d\n", sc->opmode); ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); } @@ -1272,7 +1275,7 @@ static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb) static int ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, - struct ath5k_txq *txq) + struct ath5k_txq *txq, int padsize) { struct ath5k_hw *ah = sc->ah; struct ath5k_desc *ds = bf->desc; @@ -1324,7 +1327,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, sc->vif, pktlen, info)); } ret = ah->ah_setup_tx_desc(ah, ds, pktlen, - ieee80211_get_hdrlen_from_skb(skb), + ieee80211_get_hdrlen_from_skb(skb), padsize, get_hw_packet_type(skb), (sc->power_level * 2), hw_rate, @@ -1636,7 +1639,6 @@ ath5k_txq_cleanup(struct ath5k_softc *sc) sc->txqs[i].link); } } - ieee80211_wake_queues(sc->hw); /* XXX move to callers */ for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) if (sc->txqs[i].setup) @@ -1807,6 +1809,86 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, } static void +ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + struct ath5k_hw *ah = sc->ah; + struct ath_common *common = ath5k_hw_common(ah); + + /* only beacons from our BSSID */ + if (!ieee80211_is_beacon(mgmt->frame_control) || + memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) + return; + + ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg, + rssi); + + /* in IBSS mode we should keep RSSI statistics per neighbour */ + /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */ +} + +/* + * Compute padding position. skb must contains an IEEE 802.11 frame + */ +static int ath5k_common_padpos(struct sk_buff *skb) +{ + struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; + __le16 frame_control = hdr->frame_control; + int padpos = 24; + + if (ieee80211_has_a4(frame_control)) { + padpos += ETH_ALEN; + } + if (ieee80211_is_data_qos(frame_control)) { + padpos += IEEE80211_QOS_CTL_LEN; + } + + return padpos; +} + +/* + * This function expects a 802.11 frame and returns the number of + * bytes added, or -1 if we don't have enought header room. + */ + +static int ath5k_add_padding(struct sk_buff *skb) +{ + int padpos = ath5k_common_padpos(skb); + int padsize = padpos & 3; + + if (padsize && skb->len>padpos) { + + if (skb_headroom(skb) < padsize) + return -1; + + skb_push(skb, padsize); + memmove(skb->data, skb->data+padsize, padpos); + return padsize; + } + + return 0; +} + +/* + * This function expects a 802.11 frame and returns the number of + * bytes removed + */ + +static int ath5k_remove_padding(struct sk_buff *skb) +{ + int padpos = ath5k_common_padpos(skb); + int padsize = padpos & 3; + + if (padsize && skb->len>=padpos+padsize) { + memmove(skb->data + padsize, skb->data, padpos); + skb_pull(skb, padsize); + return padsize; + } + + return 0; +} + +static void ath5k_tasklet_rx(unsigned long data) { struct ieee80211_rx_status *rxs; @@ -1819,8 +1901,6 @@ ath5k_tasklet_rx(unsigned long data) struct ath5k_buf *bf; struct ath5k_desc *ds; int ret; - int hdrlen; - int padsize; int rx_flag; spin_lock(&sc->rxbuflock); @@ -1845,18 +1925,24 @@ ath5k_tasklet_rx(unsigned long data) break; else if (unlikely(ret)) { ATH5K_ERR(sc, "error in processing rx descriptor\n"); + sc->stats.rxerr_proc++; spin_unlock(&sc->rxbuflock); return; } - if (unlikely(rs.rs_more)) { - ATH5K_WARN(sc, "unsupported jumbo\n"); - goto next; - } + sc->stats.rx_all_count++; if (unlikely(rs.rs_status)) { - if (rs.rs_status & AR5K_RXERR_PHY) + if (rs.rs_status & AR5K_RXERR_CRC) + sc->stats.rxerr_crc++; + if (rs.rs_status & AR5K_RXERR_FIFO) + sc->stats.rxerr_fifo++; + if (rs.rs_status & AR5K_RXERR_PHY) { + sc->stats.rxerr_phy++; + if (rs.rs_phyerr > 0 && rs.rs_phyerr < 32) + sc->stats.rxerr_phy_code[rs.rs_phyerr]++; goto next; + } if (rs.rs_status & AR5K_RXERR_DECRYPT) { /* * Decrypt error. If the error occurred @@ -1868,12 +1954,14 @@ ath5k_tasklet_rx(unsigned long data) * * XXX do key cache faulting */ + sc->stats.rxerr_decrypt++; if (rs.rs_keyix == AR5K_RXKEYIX_INVALID && !(rs.rs_status & AR5K_RXERR_CRC)) goto accept; } if (rs.rs_status & AR5K_RXERR_MIC) { rx_flag |= RX_FLAG_MMIC_ERROR; + sc->stats.rxerr_mic++; goto accept; } @@ -1883,6 +1971,12 @@ ath5k_tasklet_rx(unsigned long data) sc->opmode != NL80211_IFTYPE_MONITOR) goto next; } + + if (unlikely(rs.rs_more)) { + sc->stats.rxerr_jumbo++; + goto next; + + } accept: next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr); @@ -1905,12 +1999,8 @@ accept: * bytes and we can optimize this a bit. In addition, we must * not try to remove padding from short control frames that do * not have payload. */ - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - padsize = ath5k_pad_size(hdrlen); - if (padsize) { - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); - } + ath5k_remove_padding(skb); + rxs = IEEE80211_SKB_RXCB(skb); /* @@ -1939,10 +2029,15 @@ accept: rxs->freq = sc->curchan->center_freq; rxs->band = sc->curband->band; - rxs->noise = sc->ah->ah_noise_floor; - rxs->signal = rxs->noise + rs.rs_rssi; + rxs->signal = sc->ah->ah_noise_floor + rs.rs_rssi; rxs->antenna = rs.rs_antenna; + + if (rs.rs_antenna > 0 && rs.rs_antenna < 5) + sc->stats.antenna_rx[rs.rs_antenna]++; + else + sc->stats.antenna_rx[0]++; /* invalid */ + rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); @@ -1952,6 +2047,8 @@ accept: ath5k_debug_dump_skb(sc, skb, "RX ", 0); + ath5k_update_beacon_rssi(sc, skb, rs.rs_rssi); + /* check beacons in IBSS mode */ if (sc->opmode == NL80211_IFTYPE_ADHOC) ath5k_check_ibss_tsf(sc, skb, rxs); @@ -1988,6 +2085,17 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) list_for_each_entry_safe(bf, bf0, &txq->q, list) { ds = bf->desc; + /* + * It's possible that the hardware can say the buffer is + * completed when it hasn't yet loaded the ds_link from + * host memory and moved on. If there are more TX + * descriptors in the queue, wait for TXDP to change + * before processing this one. + */ + if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr && + !list_is_last(&bf->list, &txq->q)) + break; + ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); if (unlikely(ret == -EINPROGRESS)) break; @@ -1997,6 +2105,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) break; } + sc->stats.tx_all_count++; skb = bf->skb; info = IEEE80211_SKB_CB(skb); bf->skb = NULL; @@ -2022,14 +2131,31 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) info->status.rates[ts.ts_final_idx].count++; if (unlikely(ts.ts_status)) { - sc->ll_stats.dot11ACKFailureCount++; - if (ts.ts_status & AR5K_TXERR_FILT) + sc->stats.ack_fail++; + if (ts.ts_status & AR5K_TXERR_FILT) { info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + sc->stats.txerr_filt++; + } + if (ts.ts_status & AR5K_TXERR_XRETRY) + sc->stats.txerr_retry++; + if (ts.ts_status & AR5K_TXERR_FIFO) + sc->stats.txerr_fifo++; } else { info->flags |= IEEE80211_TX_STAT_ACK; info->status.ack_signal = ts.ts_rssi; } + /* + * Remove MAC header padding before giving the frame + * back to mac80211. + */ + ath5k_remove_padding(skb); + + if (ts.ts_antenna > 0 && ts.ts_antenna < 5) + sc->stats.antenna_tx[ts.ts_antenna]++; + else + sc->stats.antenna_tx[0]++; /* invalid */ + ieee80211_tx_status(sc->hw, skb); spin_lock(&sc->txbuflock); @@ -2073,6 +2199,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) int ret = 0; u8 antenna; u32 flags; + const int padsize = 0; bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); @@ -2120,7 +2247,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) * from tx power (value is in dB units already) */ ds->ds_data = bf->skbaddr; ret = ah->ah_setup_tx_desc(ah, ds, skb->len, - ieee80211_get_hdrlen_from_skb(skb), + ieee80211_get_hdrlen_from_skb(skb), padsize, AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), ieee80211_get_tx_rate(sc->hw, info)->hw_value, 1, AR5K_TXKEYIX_INVALID, @@ -2407,9 +2534,6 @@ ath5k_init(struct ath5k_softc *sc) */ ath5k_stop_locked(sc); - /* Set PHY calibration interval */ - ah->ah_cal_intval = ath5k_calinterval; - /* * The basic interface to setting the hardware in a good * state is ``reset''. On return the hardware is known to @@ -2421,7 +2545,8 @@ ath5k_init(struct ath5k_softc *sc) sc->curband = &sc->sbands[sc->curchan->band]; sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | - AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI; + AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; + ret = ath5k_reset(sc, NULL); if (ret) goto done; @@ -2435,8 +2560,7 @@ ath5k_init(struct ath5k_softc *sc) for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) ath5k_hw_reset_key(ah, i); - /* Set ack to be sent at low bit-rates */ - ath5k_hw_set_ack_bitrate_high(ah, false); + ath5k_hw_set_ack_bitrate_high(ah, true); ret = 0; done: mmiowb(); @@ -2533,12 +2657,33 @@ ath5k_stop_hw(struct ath5k_softc *sc) tasklet_kill(&sc->restq); tasklet_kill(&sc->calib); tasklet_kill(&sc->beacontq); + tasklet_kill(&sc->ani_tasklet); ath5k_rfkill_hw_stop(sc->ah); return ret; } +static void +ath5k_intr_calibration_poll(struct ath5k_hw *ah) +{ + if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) && + !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) { + /* run ANI only when full calibration is not active */ + ah->ah_cal_next_ani = jiffies + + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); + tasklet_schedule(&ah->ah_sc->ani_tasklet); + + } else if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) { + ah->ah_cal_next_full = jiffies + + msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); + tasklet_schedule(&ah->ah_sc->calib); + } + /* we could use SWI to generate enough interrupts to meet our + * calibration interval requirements, if necessary: + * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ +} + static irqreturn_t ath5k_intr(int irq, void *dev_id) { @@ -2562,7 +2707,20 @@ ath5k_intr(int irq, void *dev_id) */ tasklet_schedule(&sc->restq); } else if (unlikely(status & AR5K_INT_RXORN)) { - tasklet_schedule(&sc->restq); + /* + * Receive buffers are full. Either the bus is busy or + * the CPU is not fast enough to process all received + * frames. + * Older chipsets need a reset to come out of this + * condition, but we treat it as RX for newer chips. + * We don't know exactly which versions need a reset - + * this guess is copied from the HAL. + */ + sc->stats.rxorn_intr++; + if (ah->ah_mac_srev < AR5K_SREV_AR5212) + tasklet_schedule(&sc->restq); + else + tasklet_schedule(&sc->rxtq); } else { if (status & AR5K_INT_SWBA) { tasklet_hi_schedule(&sc->beacontq); @@ -2587,15 +2745,10 @@ ath5k_intr(int irq, void *dev_id) if (status & AR5K_INT_BMISS) { /* TODO */ } - if (status & AR5K_INT_SWI) { - tasklet_schedule(&sc->calib); - } if (status & AR5K_INT_MIB) { - /* - * These stats are also used for ANI i think - * so how about updating them more often ? - */ - ath5k_hw_update_mib_counters(ah, &sc->ll_stats); + sc->stats.mib_intr++; + ath5k_hw_update_mib_counters(ah); + ath5k_ani_mib_intr(ah); } if (status & AR5K_INT_GPIO) tasklet_schedule(&sc->rf_kill.toggleq); @@ -2606,7 +2759,7 @@ ath5k_intr(int irq, void *dev_id) if (unlikely(!counter)) ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); - ath5k_hw_calibration_poll(ah); + ath5k_intr_calibration_poll(ah); return IRQ_HANDLED; } @@ -2630,8 +2783,7 @@ ath5k_tasklet_calibrate(unsigned long data) struct ath5k_hw *ah = sc->ah; /* Only full calibration for now */ - if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION) - return; + ah->ah_cal_mask |= AR5K_CALIBRATION_FULL; /* Stop queues so that calibration * doesn't interfere with tx */ @@ -2647,18 +2799,29 @@ ath5k_tasklet_calibrate(unsigned long data) * to load new gain values. */ ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); - ath5k_reset_wake(sc); + ath5k_reset(sc, sc->curchan); } if (ath5k_hw_phy_calibrate(ah, sc->curchan)) ATH5K_ERR(sc, "calibration of channel %u failed\n", ieee80211_frequency_to_channel( sc->curchan->center_freq)); - ah->ah_swi_mask = 0; - /* Wake queues */ ieee80211_wake_queues(sc->hw); + ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; +} + + +static void +ath5k_tasklet_ani(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + struct ath5k_hw *ah = sc->ah; + + ah->ah_cal_mask |= AR5K_CALIBRATION_ANI; + ath5k_ani_calibration(ah); + ah->ah_cal_mask &= ~AR5K_CALIBRATION_ANI; } @@ -2680,7 +2843,6 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath5k_softc *sc = hw->priv; struct ath5k_buf *bf; unsigned long flags; - int hdrlen; int padsize; ath5k_debug_dump_skb(sc, skb, "TX ", 1); @@ -2692,17 +2854,11 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, * the hardware expects the header padded to 4 byte boundaries * if this is not the case we add the padding after the header */ - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - padsize = ath5k_pad_size(hdrlen); - if (padsize) { - - if (skb_headroom(skb) < padsize) { - ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" - " headroom to pad %d\n", hdrlen, padsize); - goto drop_packet; - } - skb_push(skb, padsize); - memmove(skb->data, skb->data+padsize, hdrlen); + padsize = ath5k_add_padding(skb); + if (padsize < 0) { + ATH5K_ERR(sc, "tx hdrlen not %%4: not enough" + " headroom to pad"); + goto drop_packet; } spin_lock_irqsave(&sc->txbuflock, flags); @@ -2721,7 +2877,7 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, bf->skb = skb; - if (ath5k_txbuf_setup(sc, bf, txq)) { + if (ath5k_txbuf_setup(sc, bf, txq, padsize)) { bf->skb = NULL; spin_lock_irqsave(&sc->txbuflock, flags); list_add_tail(&bf->list, &sc->txbuf); @@ -2768,6 +2924,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) goto err; } + ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode); + /* * Change channels and update the h/w rate map if we're switching; * e.g. 11a to 11b/g. @@ -2836,6 +2994,8 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, goto end; } + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode); + ath5k_hw_set_lladdr(sc->ah, vif->addr); ath5k_mode_setup(sc); @@ -2906,7 +3066,7 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) * then we must allow the user to set how many tx antennas we * have available */ - ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT); + ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); unlock: mutex_unlock(&sc->lock); @@ -2914,22 +3074,20 @@ unlock: } static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, - int mc_count, struct dev_addr_list *mclist) + struct netdev_hw_addr_list *mc_list) { u32 mfilt[2], val; - int i; u8 pos; + struct netdev_hw_addr *ha; mfilt[0] = 0; mfilt[1] = 1; - for (i = 0; i < mc_count; i++) { - if (!mclist) - break; + netdev_hw_addr_list_for_each(ha, mc_list) { /* calculate XOR of eight 6-bit values */ - val = get_unaligned_le32(mclist->dmi_addr + 0); + val = get_unaligned_le32(ha->addr + 0); pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - val = get_unaligned_le32(mclist->dmi_addr + 3); + val = get_unaligned_le32(ha->addr + 3); pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; pos &= 0x3f; mfilt[pos / 32] |= (1 << (pos % 32)); @@ -2937,8 +3095,7 @@ static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, * but not sure, needs testing, if we do use this we'd * neet to inform below to not reset the mcast */ /* ath5k_hw_set_mcast_filterindex(ah, - * mclist->dmi_addr[5]); */ - mclist = mclist->next; + * ha->addr[5]); */ } return ((u64)(mfilt[1]) << 32) | mfilt[0]; @@ -3124,12 +3281,30 @@ ath5k_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { struct ath5k_softc *sc = hw->priv; - struct ath5k_hw *ah = sc->ah; /* Force update */ - ath5k_hw_update_mib_counters(ah, &sc->ll_stats); + ath5k_hw_update_mib_counters(sc->ah); + + stats->dot11ACKFailureCount = sc->stats.ack_fail; + stats->dot11RTSFailureCount = sc->stats.rts_fail; + stats->dot11RTSSuccessCount = sc->stats.rts_ok; + stats->dot11FCSErrorCount = sc->stats.fcs_error; + + return 0; +} + +static int ath5k_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct ath5k_softc *sc = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + + if (idx != 0) + return -ENOENT; - memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats)); + survey->channel = conf->channel; + survey->filled = SURVEY_INFO_NOISE_DBM; + survey->noise = sc->ah->ah_noise_floor; return 0; } diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 7e1a88a5abd..56221bc7c8c 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -50,6 +50,7 @@ #include "ath5k.h" #include "debug.h" +#include "ani.h" #include "../regd.h" #include "../ath.h" @@ -105,6 +106,38 @@ struct ath5k_rfkill { struct tasklet_struct toggleq; }; +/* statistics */ +struct ath5k_statistics { + /* antenna use */ + unsigned int antenna_rx[5]; /* frames count per antenna RX */ + unsigned int antenna_tx[5]; /* frames count per antenna TX */ + + /* frame errors */ + unsigned int rx_all_count; /* all RX frames, including errors */ + unsigned int tx_all_count; /* all TX frames, including errors */ + unsigned int rxerr_crc; + unsigned int rxerr_phy; + unsigned int rxerr_phy_code[32]; + unsigned int rxerr_fifo; + unsigned int rxerr_decrypt; + unsigned int rxerr_mic; + unsigned int rxerr_proc; + unsigned int rxerr_jumbo; + unsigned int txerr_retry; + unsigned int txerr_fifo; + unsigned int txerr_filt; + + /* MIB counters */ + unsigned int ack_fail; + unsigned int rts_fail; + unsigned int rts_ok; + unsigned int fcs_error; + unsigned int beacons; + + unsigned int mib_intr; + unsigned int rxorn_intr; +}; + #if CHAN_DEBUG #define ATH_CHAN_MAX (26+26+26+200+200) #else @@ -117,7 +150,6 @@ struct ath5k_softc { struct pci_dev *pdev; /* for dma mapping */ void __iomem *iobase; /* address of the device */ struct mutex lock; /* dev-level lock */ - struct ieee80211_low_level_stats ll_stats; struct ieee80211_hw *hw; /* IEEE 802.11 common */ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; struct ieee80211_channel channels[ATH_CHAN_MAX]; @@ -191,6 +223,11 @@ struct ath5k_softc { int power_level; /* Requested tx power in dbm */ bool assoc; /* associate state */ bool enable_beacon; /* true if beacons are on */ + + struct ath5k_statistics stats; + + struct ath5k_ani_state ani_state; + struct tasklet_struct ani_tasklet; /* ANI calibration */ }; #define ath5k_hw_hasbssidmask(_ah) \ diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index 367a6c7d3cc..74f007126f4 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -102,9 +102,6 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) } } - /* GPIO */ - ah->ah_gpio_npins = AR5K_NUM_GPIO; - /* Set number of supported TX queues */ if (ah->ah_version == AR5K_AR5210) ah->ah_capabilities.cap_queues.q_tx_num = @@ -112,6 +109,12 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) else ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; + /* newer hardware has PHY error counters */ + if (ah->ah_mac_srev >= AR5K_SREV_AR5213A) + ah->ah_capabilities.cap_has_phyerr_counters = true; + else + ah->ah_capabilities.cap_has_phyerr_counters = false; + return 0; } diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 747508c15d3..6fb5c5ffa5b 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -69,6 +69,7 @@ module_param_named(debug, ath5k_debug, uint, 0); #include <linux/seq_file.h> #include "reg.h" +#include "ani.h" static struct dentry *ath5k_global_debugfs; @@ -307,6 +308,7 @@ static const struct { { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" }, { ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" }, { ATH5K_DEBUG_TRACE, "trace", "trace function calls" }, + { ATH5K_DEBUG_ANI, "ani", "adaptive noise immunity" }, { ATH5K_DEBUG_ANY, "all", "show all debug levels" }, }; @@ -364,6 +366,369 @@ static const struct file_operations fops_debug = { }; +/* debugfs: antenna */ + +static ssize_t read_file_antenna(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + char buf[700]; + unsigned int len = 0; + unsigned int i; + unsigned int v; + + len += snprintf(buf+len, sizeof(buf)-len, "antenna mode\t%d\n", + sc->ah->ah_ant_mode); + len += snprintf(buf+len, sizeof(buf)-len, "default antenna\t%d\n", + sc->ah->ah_def_ant); + len += snprintf(buf+len, sizeof(buf)-len, "tx antenna\t%d\n", + sc->ah->ah_tx_ant); + + len += snprintf(buf+len, sizeof(buf)-len, "\nANTENNA\t\tRX\tTX\n"); + for (i = 1; i < ARRAY_SIZE(sc->stats.antenna_rx); i++) { + len += snprintf(buf+len, sizeof(buf)-len, + "[antenna %d]\t%d\t%d\n", + i, sc->stats.antenna_rx[i], sc->stats.antenna_tx[i]); + } + len += snprintf(buf+len, sizeof(buf)-len, "[invalid]\t%d\t%d\n", + sc->stats.antenna_rx[0], sc->stats.antenna_tx[0]); + + v = ath5k_hw_reg_read(sc->ah, AR5K_DEFAULT_ANTENNA); + len += snprintf(buf+len, sizeof(buf)-len, + "\nAR5K_DEFAULT_ANTENNA\t0x%08x\n", v); + + v = ath5k_hw_reg_read(sc->ah, AR5K_STA_ID1); + len += snprintf(buf+len, sizeof(buf)-len, + "AR5K_STA_ID1_DEFAULT_ANTENNA\t%d\n", + (v & AR5K_STA_ID1_DEFAULT_ANTENNA) != 0); + len += snprintf(buf+len, sizeof(buf)-len, + "AR5K_STA_ID1_DESC_ANTENNA\t%d\n", + (v & AR5K_STA_ID1_DESC_ANTENNA) != 0); + len += snprintf(buf+len, sizeof(buf)-len, + "AR5K_STA_ID1_RTS_DEF_ANTENNA\t%d\n", + (v & AR5K_STA_ID1_RTS_DEF_ANTENNA) != 0); + len += snprintf(buf+len, sizeof(buf)-len, + "AR5K_STA_ID1_SELFGEN_DEF_ANT\t%d\n", + (v & AR5K_STA_ID1_SELFGEN_DEF_ANT) != 0); + + v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_AGCCTL); + len += snprintf(buf+len, sizeof(buf)-len, + "\nAR5K_PHY_AGCCTL_OFDM_DIV_DIS\t%d\n", + (v & AR5K_PHY_AGCCTL_OFDM_DIV_DIS) != 0); + + v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_RESTART); + len += snprintf(buf+len, sizeof(buf)-len, + "AR5K_PHY_RESTART_DIV_GC\t\t%x\n", + (v & AR5K_PHY_RESTART_DIV_GC) >> AR5K_PHY_RESTART_DIV_GC_S); + + v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_FAST_ANT_DIV); + len += snprintf(buf+len, sizeof(buf)-len, + "AR5K_PHY_FAST_ANT_DIV_EN\t%d\n", + (v & AR5K_PHY_FAST_ANT_DIV_EN) != 0); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_antenna(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + unsigned int i; + char buf[20]; + + if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) + return -EFAULT; + + if (strncmp(buf, "diversity", 9) == 0) { + ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_DEFAULT); + printk(KERN_INFO "ath5k debug: enable diversity\n"); + } else if (strncmp(buf, "fixed-a", 7) == 0) { + ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_A); + printk(KERN_INFO "ath5k debugfs: fixed antenna A\n"); + } else if (strncmp(buf, "fixed-b", 7) == 0) { + ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_B); + printk(KERN_INFO "ath5k debug: fixed antenna B\n"); + } else if (strncmp(buf, "clear", 5) == 0) { + for (i = 0; i < ARRAY_SIZE(sc->stats.antenna_rx); i++) { + sc->stats.antenna_rx[i] = 0; + sc->stats.antenna_tx[i] = 0; + } + printk(KERN_INFO "ath5k debug: cleared antenna stats\n"); + } + return count; +} + +static const struct file_operations fops_antenna = { + .read = read_file_antenna, + .write = write_file_antenna, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, +}; + + +/* debugfs: frameerrors */ + +static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_statistics *st = &sc->stats; + char buf[700]; + unsigned int len = 0; + int i; + + len += snprintf(buf+len, sizeof(buf)-len, + "RX\n---------------------\n"); + len += snprintf(buf+len, sizeof(buf)-len, "CRC\t%d\t(%d%%)\n", + st->rxerr_crc, + st->rx_all_count > 0 ? + st->rxerr_crc*100/st->rx_all_count : 0); + len += snprintf(buf+len, sizeof(buf)-len, "PHY\t%d\t(%d%%)\n", + st->rxerr_phy, + st->rx_all_count > 0 ? + st->rxerr_phy*100/st->rx_all_count : 0); + for (i = 0; i < 32; i++) { + if (st->rxerr_phy_code[i]) + len += snprintf(buf+len, sizeof(buf)-len, + " phy_err[%d]\t%d\n", + i, st->rxerr_phy_code[i]); + } + + len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n", + st->rxerr_fifo, + st->rx_all_count > 0 ? + st->rxerr_fifo*100/st->rx_all_count : 0); + len += snprintf(buf+len, sizeof(buf)-len, "decrypt\t%d\t(%d%%)\n", + st->rxerr_decrypt, + st->rx_all_count > 0 ? + st->rxerr_decrypt*100/st->rx_all_count : 0); + len += snprintf(buf+len, sizeof(buf)-len, "MIC\t%d\t(%d%%)\n", + st->rxerr_mic, + st->rx_all_count > 0 ? + st->rxerr_mic*100/st->rx_all_count : 0); + len += snprintf(buf+len, sizeof(buf)-len, "process\t%d\t(%d%%)\n", + st->rxerr_proc, + st->rx_all_count > 0 ? + st->rxerr_proc*100/st->rx_all_count : 0); + len += snprintf(buf+len, sizeof(buf)-len, "jumbo\t%d\t(%d%%)\n", + st->rxerr_jumbo, + st->rx_all_count > 0 ? + st->rxerr_jumbo*100/st->rx_all_count : 0); + len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%d]\n", + st->rx_all_count); + + len += snprintf(buf+len, sizeof(buf)-len, + "\nTX\n---------------------\n"); + len += snprintf(buf+len, sizeof(buf)-len, "retry\t%d\t(%d%%)\n", + st->txerr_retry, + st->tx_all_count > 0 ? + st->txerr_retry*100/st->tx_all_count : 0); + len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n", + st->txerr_fifo, + st->tx_all_count > 0 ? + st->txerr_fifo*100/st->tx_all_count : 0); + len += snprintf(buf+len, sizeof(buf)-len, "filter\t%d\t(%d%%)\n", + st->txerr_filt, + st->tx_all_count > 0 ? + st->txerr_filt*100/st->tx_all_count : 0); + len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n", + st->tx_all_count); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_frameerrors(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_statistics *st = &sc->stats; + char buf[20]; + + if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) + return -EFAULT; + + if (strncmp(buf, "clear", 5) == 0) { + st->rxerr_crc = 0; + st->rxerr_phy = 0; + st->rxerr_fifo = 0; + st->rxerr_decrypt = 0; + st->rxerr_mic = 0; + st->rxerr_proc = 0; + st->rxerr_jumbo = 0; + st->rx_all_count = 0; + st->txerr_retry = 0; + st->txerr_fifo = 0; + st->txerr_filt = 0; + st->tx_all_count = 0; + printk(KERN_INFO "ath5k debug: cleared frameerrors stats\n"); + } + return count; +} + +static const struct file_operations fops_frameerrors = { + .read = read_file_frameerrors, + .write = write_file_frameerrors, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, +}; + + +/* debugfs: ani */ + +static ssize_t read_file_ani(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_statistics *st = &sc->stats; + struct ath5k_ani_state *as = &sc->ani_state; + + char buf[700]; + unsigned int len = 0; + + len += snprintf(buf+len, sizeof(buf)-len, + "HW has PHY error counters:\t%s\n", + sc->ah->ah_capabilities.cap_has_phyerr_counters ? + "yes" : "no"); + len += snprintf(buf+len, sizeof(buf)-len, + "HW max spur immunity level:\t%d\n", + as->max_spur_level); + len += snprintf(buf+len, sizeof(buf)-len, + "\nANI state\n--------------------------------------------\n"); + len += snprintf(buf+len, sizeof(buf)-len, "operating mode:\t\t\t"); + switch (as->ani_mode) { + case ATH5K_ANI_MODE_OFF: + len += snprintf(buf+len, sizeof(buf)-len, "OFF\n"); + break; + case ATH5K_ANI_MODE_MANUAL_LOW: + len += snprintf(buf+len, sizeof(buf)-len, + "MANUAL LOW\n"); + break; + case ATH5K_ANI_MODE_MANUAL_HIGH: + len += snprintf(buf+len, sizeof(buf)-len, + "MANUAL HIGH\n"); + break; + case ATH5K_ANI_MODE_AUTO: + len += snprintf(buf+len, sizeof(buf)-len, "AUTO\n"); + break; + default: + len += snprintf(buf+len, sizeof(buf)-len, + "??? (not good)\n"); + break; + } + len += snprintf(buf+len, sizeof(buf)-len, + "noise immunity level:\t\t%d\n", + as->noise_imm_level); + len += snprintf(buf+len, sizeof(buf)-len, + "spur immunity level:\t\t%d\n", + as->spur_level); + len += snprintf(buf+len, sizeof(buf)-len, "firstep level:\t\t\t%d\n", + as->firstep_level); + len += snprintf(buf+len, sizeof(buf)-len, + "OFDM weak signal detection:\t%s\n", + as->ofdm_weak_sig ? "on" : "off"); + len += snprintf(buf+len, sizeof(buf)-len, + "CCK weak signal detection:\t%s\n", + as->cck_weak_sig ? "on" : "off"); + + len += snprintf(buf+len, sizeof(buf)-len, + "\nMIB INTERRUPTS:\t\t%u\n", + st->mib_intr); + len += snprintf(buf+len, sizeof(buf)-len, + "beacon RSSI average:\t%d\n", + sc->ah->ah_beacon_rssi_avg.avg); + len += snprintf(buf+len, sizeof(buf)-len, "profcnt tx\t\t%u\t(%d%%)\n", + as->pfc_tx, + as->pfc_cycles > 0 ? + as->pfc_tx*100/as->pfc_cycles : 0); + len += snprintf(buf+len, sizeof(buf)-len, "profcnt rx\t\t%u\t(%d%%)\n", + as->pfc_rx, + as->pfc_cycles > 0 ? + as->pfc_rx*100/as->pfc_cycles : 0); + len += snprintf(buf+len, sizeof(buf)-len, "profcnt busy\t\t%u\t(%d%%)\n", + as->pfc_busy, + as->pfc_cycles > 0 ? + as->pfc_busy*100/as->pfc_cycles : 0); + len += snprintf(buf+len, sizeof(buf)-len, "profcnt cycles\t\t%u\n", + as->pfc_cycles); + len += snprintf(buf+len, sizeof(buf)-len, + "listen time\t\t%d\tlast: %d\n", + as->listen_time, as->last_listen); + len += snprintf(buf+len, sizeof(buf)-len, + "OFDM errors\t\t%u\tlast: %u\tsum: %u\n", + as->ofdm_errors, as->last_ofdm_errors, + as->sum_ofdm_errors); + len += snprintf(buf+len, sizeof(buf)-len, + "CCK errors\t\t%u\tlast: %u\tsum: %u\n", + as->cck_errors, as->last_cck_errors, + as->sum_cck_errors); + len += snprintf(buf+len, sizeof(buf)-len, + "AR5K_PHYERR_CNT1\t%x\t(=%d)\n", + ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1), + ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - + ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1))); + len += snprintf(buf+len, sizeof(buf)-len, + "AR5K_PHYERR_CNT2\t%x\t(=%d)\n", + ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2), + ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - + ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2))); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_ani(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, "sens-low", 8) == 0) { + ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_MANUAL_HIGH); + } else if (strncmp(buf, "sens-high", 9) == 0) { + ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_MANUAL_LOW); + } else if (strncmp(buf, "ani-off", 7) == 0) { + ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_OFF); + } else if (strncmp(buf, "ani-on", 6) == 0) { + ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_AUTO); + } else if (strncmp(buf, "noise-low", 9) == 0) { + ath5k_ani_set_noise_immunity_level(sc->ah, 0); + } else if (strncmp(buf, "noise-high", 10) == 0) { + ath5k_ani_set_noise_immunity_level(sc->ah, + ATH5K_ANI_MAX_NOISE_IMM_LVL); + } else if (strncmp(buf, "spur-low", 8) == 0) { + ath5k_ani_set_spur_immunity_level(sc->ah, 0); + } else if (strncmp(buf, "spur-high", 9) == 0) { + ath5k_ani_set_spur_immunity_level(sc->ah, + sc->ani_state.max_spur_level); + } else if (strncmp(buf, "fir-low", 7) == 0) { + ath5k_ani_set_firstep_level(sc->ah, 0); + } else if (strncmp(buf, "fir-high", 8) == 0) { + ath5k_ani_set_firstep_level(sc->ah, ATH5K_ANI_MAX_FIRSTEP_LVL); + } else if (strncmp(buf, "ofdm-off", 8) == 0) { + ath5k_ani_set_ofdm_weak_signal_detection(sc->ah, false); + } else if (strncmp(buf, "ofdm-on", 7) == 0) { + ath5k_ani_set_ofdm_weak_signal_detection(sc->ah, true); + } else if (strncmp(buf, "cck-off", 7) == 0) { + ath5k_ani_set_cck_weak_signal_detection(sc->ah, false); + } else if (strncmp(buf, "cck-on", 6) == 0) { + ath5k_ani_set_cck_weak_signal_detection(sc->ah, true); + } + return count; +} + +static const struct file_operations fops_ani = { + .read = read_file_ani, + .write = write_file_ani, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, +}; + + /* init */ void @@ -393,6 +758,20 @@ ath5k_debug_init_device(struct ath5k_softc *sc) sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, sc->debug.debugfs_phydir, sc, &fops_reset); + + sc->debug.debugfs_antenna = debugfs_create_file("antenna", + S_IWUSR | S_IRUSR, + sc->debug.debugfs_phydir, sc, &fops_antenna); + + sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors", + S_IWUSR | S_IRUSR, + sc->debug.debugfs_phydir, sc, + &fops_frameerrors); + + sc->debug.debugfs_ani = debugfs_create_file("ani", + S_IWUSR | S_IRUSR, + sc->debug.debugfs_phydir, sc, + &fops_ani); } void @@ -408,6 +787,9 @@ ath5k_debug_finish_device(struct ath5k_softc *sc) debugfs_remove(sc->debug.debugfs_registers); debugfs_remove(sc->debug.debugfs_beacon); debugfs_remove(sc->debug.debugfs_reset); + debugfs_remove(sc->debug.debugfs_antenna); + debugfs_remove(sc->debug.debugfs_frameerrors); + debugfs_remove(sc->debug.debugfs_ani); debugfs_remove(sc->debug.debugfs_phydir); } diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index 66f69f04e55..ddd5b3a99e8 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -74,6 +74,9 @@ struct ath5k_dbg_info { struct dentry *debugfs_registers; struct dentry *debugfs_beacon; struct dentry *debugfs_reset; + struct dentry *debugfs_antenna; + struct dentry *debugfs_frameerrors; + struct dentry *debugfs_ani; }; /** @@ -113,6 +116,7 @@ enum ath5k_debug_level { ATH5K_DEBUG_DUMP_TX = 0x00000200, ATH5K_DEBUG_DUMPBANDS = 0x00000400, ATH5K_DEBUG_TRACE = 0x00001000, + ATH5K_DEBUG_ANI = 0x00002000, ATH5K_DEBUG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index dc30a2b70a6..7d7b646ab65 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -35,7 +35,8 @@ */ static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, - unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type, + unsigned int pkt_len, unsigned int hdr_len, int padsize, + enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, unsigned int key_index, unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, unsigned int rtscts_duration) @@ -71,7 +72,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, /* Verify and set frame length */ /* remove padding we might have added before */ - frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN; + frame_len = pkt_len - padsize + FCS_LEN; if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; @@ -100,7 +101,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); } - /*Diferences between 5210-5211*/ + /*Differences between 5210-5211*/ if (ah->ah_version == AR5K_AR5210) { switch (type) { case AR5K_PKT_TYPE_BEACON: @@ -165,6 +166,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, */ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, + int padsize, enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, unsigned int key_index, unsigned int antenna_mode, unsigned int flags, @@ -206,7 +208,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, /* Verify and set frame length */ /* remove padding we might have added before */ - frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN; + frame_len = pkt_len - padsize + FCS_LEN; if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; @@ -229,7 +231,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); tx_ctl->tx_control_1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); - tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, + tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; @@ -643,6 +645,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, rs->rs_status |= AR5K_RXERR_PHY; rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1, AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); + ath5k_ani_phy_error_report(ah, rs->rs_phyerr); } if (rx_status->rx_status_1 & @@ -668,12 +671,6 @@ int ath5k_hw_init_desc_functions(struct ath5k_hw *ah) ah->ah_version != AR5K_AR5212) return -ENOTSUPP; - /* XXX: What is this magic value and where is it used ? */ - if (ah->ah_version == AR5K_AR5212) - ah->ah_magic = AR5K_EEPROM_MAGIC_5212; - else if (ah->ah_version == AR5K_AR5211) - ah->ah_magic = AR5K_EEPROM_MAGIC_5211; - if (ah->ah_version == AR5K_AR5212) { ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc; ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; diff --git a/drivers/net/wireless/ath/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h index 56158c804e3..64538fbe416 100644 --- a/drivers/net/wireless/ath/ath5k/desc.h +++ b/drivers/net/wireless/ath/ath5k/desc.h @@ -112,15 +112,32 @@ struct ath5k_hw_rx_error { #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00 #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8 -/* PHY Error codes */ -#define AR5K_DESC_RX_PHY_ERROR_NONE 0x00 -#define AR5K_DESC_RX_PHY_ERROR_TIMING 0x20 -#define AR5K_DESC_RX_PHY_ERROR_PARITY 0x40 -#define AR5K_DESC_RX_PHY_ERROR_RATE 0x60 -#define AR5K_DESC_RX_PHY_ERROR_LENGTH 0x80 -#define AR5K_DESC_RX_PHY_ERROR_64QAM 0xa0 -#define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 -#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 +/** + * enum ath5k_phy_error_code - PHY Error codes + */ +enum ath5k_phy_error_code { + AR5K_RX_PHY_ERROR_UNDERRUN = 0, /* Transmit underrun */ + AR5K_RX_PHY_ERROR_TIMING = 1, /* Timing error */ + AR5K_RX_PHY_ERROR_PARITY = 2, /* Illegal parity */ + AR5K_RX_PHY_ERROR_RATE = 3, /* Illegal rate */ + AR5K_RX_PHY_ERROR_LENGTH = 4, /* Illegal length */ + AR5K_RX_PHY_ERROR_RADAR = 5, /* Radar detect */ + AR5K_RX_PHY_ERROR_SERVICE = 6, /* Illegal service */ + AR5K_RX_PHY_ERROR_TOR = 7, /* Transmit override receive */ + /* these are specific to the 5212 */ + AR5K_RX_PHY_ERROR_OFDM_TIMING = 17, + AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY = 18, + AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL = 19, + AR5K_RX_PHY_ERROR_OFDM_LENGTH_ILLEGAL = 20, + AR5K_RX_PHY_ERROR_OFDM_POWER_DROP = 21, + AR5K_RX_PHY_ERROR_OFDM_SERVICE = 22, + AR5K_RX_PHY_ERROR_OFDM_RESTART = 23, + AR5K_RX_PHY_ERROR_CCK_TIMING = 25, + AR5K_RX_PHY_ERROR_CCK_HEADER_CRC = 26, + AR5K_RX_PHY_ERROR_CCK_RATE_ILLEGAL = 27, + AR5K_RX_PHY_ERROR_CCK_SERVICE = 30, + AR5K_RX_PHY_ERROR_CCK_RESTART = 31, +}; /* * 5210/5211 hardware 2-word TX control descriptor diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 67665cdc7af..ed0263672d6 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -331,7 +331,8 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, ee->ee_x_gain[mode] = (val >> 1) & 0xf; ee->ee_xpd[mode] = val & 0x1; - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 && + mode != AR5K_EEPROM_MODE_11B) ee->ee_fixed_bias[mode] = (val >> 13) & 0x1; if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) { @@ -341,6 +342,7 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, if (mode == AR5K_EEPROM_MODE_11A) ee->ee_xr_power[mode] = val & 0x3f; else { + /* b_DB_11[bg] and b_OB_11[bg] */ ee->ee_ob[mode][0] = val & 0x7; ee->ee_db[mode][0] = (val >> 3) & 0x7; } diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 473a483bb9c..c4a6d5f26af 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -24,9 +24,6 @@ * SERDES infos are present */ #define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */ #define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */ -#define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */ -#define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */ -#define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ #define AR5K_EEPROM_IS_HB63 0x000b /* Talon detect */ @@ -78,9 +75,9 @@ #define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1) #define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1) #define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1) -#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */ -#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */ -#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7) +#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz */ +#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for < 2W power consumption */ +#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7) /* Device type (1 Cardbus, 2 PCI, 3 MiniPCI, 4 AP) */ #define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ #define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz */ @@ -101,7 +98,7 @@ #define AR5K_EEPROM_MISC1 AR5K_EEPROM_INFO(5) #define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) +#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) /* has 32KHz crystal for sleep mode */ #define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v) (((_v) >> 15) & 0x1) #define AR5K_EEPROM_MISC2 AR5K_EEPROM_INFO(6) @@ -114,26 +111,27 @@ #define AR5K_EEPROM_MISC4 AR5K_EEPROM_INFO(8) #define AR5K_EEPROM_CAL_DATA_START(_v) (((_v) >> 4) & 0xfff) -#define AR5K_EEPROM_MASK_R0(_v) (((_v) >> 2) & 0x3) -#define AR5K_EEPROM_MASK_R1(_v) ((_v) & 0x3) +#define AR5K_EEPROM_MASK_R0(_v) (((_v) >> 2) & 0x3) /* modes supported by radio 0 (bit 1: G, bit 2: A) */ +#define AR5K_EEPROM_MASK_R1(_v) ((_v) & 0x3) /* modes supported by radio 1 (bit 1: G, bit 2: A) */ #define AR5K_EEPROM_MISC5 AR5K_EEPROM_INFO(9) -#define AR5K_EEPROM_COMP_DIS(_v) ((_v) & 0x1) -#define AR5K_EEPROM_AES_DIS(_v) (((_v) >> 1) & 0x1) -#define AR5K_EEPROM_FF_DIS(_v) (((_v) >> 2) & 0x1) -#define AR5K_EEPROM_BURST_DIS(_v) (((_v) >> 3) & 0x1) -#define AR5K_EEPROM_MAX_QCU(_v) (((_v) >> 4) & 0xf) -#define AR5K_EEPROM_HEAVY_CLIP_EN(_v) (((_v) >> 8) & 0x1) -#define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf) +#define AR5K_EEPROM_COMP_DIS(_v) ((_v) & 0x1) /* disable compression */ +#define AR5K_EEPROM_AES_DIS(_v) (((_v) >> 1) & 0x1) /* disable AES */ +#define AR5K_EEPROM_FF_DIS(_v) (((_v) >> 2) & 0x1) /* disable fast frames */ +#define AR5K_EEPROM_BURST_DIS(_v) (((_v) >> 3) & 0x1) /* disable bursting */ +#define AR5K_EEPROM_MAX_QCU(_v) (((_v) >> 4) & 0xf) /* max number of QCUs. defaults to 10 */ +#define AR5K_EEPROM_HEAVY_CLIP_EN(_v) (((_v) >> 8) & 0x1) /* enable heayy clipping */ +#define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf) /* key cache size. defaults to 128 */ #define AR5K_EEPROM_MISC6 AR5K_EEPROM_INFO(10) -#define AR5K_EEPROM_TX_CHAIN_DIS ((_v) & 0x8) -#define AR5K_EEPROM_RX_CHAIN_DIS (((_v) >> 3) & 0x8) -#define AR5K_EEPROM_FCC_MID_EN (((_v) >> 6) & 0x1) -#define AR5K_EEPROM_JAP_U1EVEN_EN (((_v) >> 7) & 0x1) -#define AR5K_EEPROM_JAP_U2_EN (((_v) >> 8) & 0x1) -#define AR5K_EEPROM_JAP_U1ODD_EN (((_v) >> 9) & 0x1) -#define AR5K_EEPROM_JAP_11A_NEW_EN (((_v) >> 10) & 0x1) +#define AR5K_EEPROM_TX_CHAIN_DIS ((_v) & 0x7) /* MIMO chains disabled for TX bitmask */ +#define AR5K_EEPROM_RX_CHAIN_DIS (((_v) >> 3) & 0x7) /* MIMO chains disabled for RX bitmask */ +#define AR5K_EEPROM_FCC_MID_EN (((_v) >> 6) & 0x1) /* 5.47-5.7GHz supported */ +#define AR5K_EEPROM_JAP_U1EVEN_EN (((_v) >> 7) & 0x1) /* Japan UNII1 band (5.15-5.25GHz) on even channels (5180, 5200, 5220, 5240) supported */ +#define AR5K_EEPROM_JAP_U2_EN (((_v) >> 8) & 0x1) /* Japan UNII2 band (5.25-5.35GHz) supported */ +#define AR5K_EEPROM_JAP_MID_EN (((_v) >> 9) & 0x1) /* Japan band from 5.47-5.7GHz supported */ +#define AR5K_EEPROM_JAP_U1ODD_EN (((_v) >> 10) & 0x1) /* Japan UNII2 band (5.15-5.25GHz) on odd channels (5170, 5190, 5210, 5230) supported */ +#define AR5K_EEPROM_JAP_11A_NEW_EN (((_v) >> 11) & 0x1) /* Japan A mode enabled (using even channels) */ /* calibration settings */ #define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4) @@ -389,7 +387,49 @@ struct ath5k_edge_power { bool flag; }; -/* EEPROM calibration data */ +/** + * struct ath5k_eeprom_info - EEPROM calibration data + * + * @ee_regdomain: ath/regd.c takes care of COUNTRY_ERD and WORLDWIDE_ROAMING + * flags + * @ee_ant_gain: Antenna gain in 0.5dB steps signed [5211 only?] + * @ee_cck_ofdm_gain_delta: difference in gainF to output the same power for + * OFDM and CCK packets + * @ee_cck_ofdm_power_delta: power difference between OFDM (6Mbps) and CCK + * (11Mbps) rate in G mode. 0.1dB steps + * @ee_scaled_cck_delta: for Japan Channel 14: 0.1dB resolution + * + * @ee_i_cal: Initial I coefficient to correct I/Q mismatch in the receive path + * @ee_q_cal: Initial Q coefficient to correct I/Q mismatch in the receive path + * @ee_fixed_bias: use ee_ob and ee_db settings or use automatic control + * @ee_switch_settling: RX/TX Switch settling time + * @ee_atn_tx_rx: Difference in attenuation between TX and RX in 1dB steps + * @ee_ant_control: Antenna Control Settings + * @ee_ob: Bias current for Output stage of PA + * B/G mode: Index [0] is used for AR2112/5112, otherwise [1] + * A mode: [0] 5.15-5.25 [1] 5.25-5.50 [2] 5.50-5.70 [3] 5.70-5.85 GHz + * @ee_db: Bias current for Output stage of PA. see @ee_ob + * @ee_tx_end2xlna_enable: Time difference from when BB finishes sending a frame + * to when the external LNA is activated + * @ee_tx_end2xpa_disable: Time difference from when BB finishes sending a frame + * to when the external PA switch is deactivated + * @ee_tx_frm2xpa_enable: Time difference from when MAC sends frame to when + * external PA switch is activated + * @ee_thr_62: Clear Channel Assessment (CCA) sensitivity + * (IEEE802.11a section 17.3.10.5 ) + * @ee_xlna_gain: Total gain of the LNA (information only) + * @ee_xpd: Use external (1) or internal power detector + * @ee_x_gain: Gain for external power detector output (differences in EEMAP + * versions!) + * @ee_i_gain: Initial gain value after reset + * @ee_margin_tx_rx: Margin in dB when final attenuation stage should be used + * + * @ee_false_detect: Backoff in Sensitivity (dB) on channels with spur signals + * @ee_noise_floor_thr: Noise floor threshold in 1dB steps + * @ee_adc_desired_size: Desired amplitude for ADC, used by AGC; in 0.5 dB steps + * @ee_pga_desired_size: Desired output of PGA (for BB gain) in 0.5 dB steps + * @ee_pd_gain_overlap: PD ADC curves need to overlap in 0.5dB steps (ee_map>=2) + */ struct ath5k_eeprom_info { /* Header information */ diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index aefe84f9c04..5212e275f1c 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -39,16 +39,16 @@ * ath5k_hw_set_opmode - Set PCU operating mode * * @ah: The &struct ath5k_hw + * @op_mode: &enum nl80211_iftype operating mode * * Initialize PCU for the various operating modes (AP/STA etc) - * - * NOTE: ah->ah_op_mode must be set before calling this. */ -int ath5k_hw_set_opmode(struct ath5k_hw *ah) +int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode) { struct ath_common *common = ath5k_hw_common(ah); u32 pcu_reg, beacon_reg, low_id, high_id; + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode); /* Preserve rest settings */ pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; @@ -61,7 +61,7 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah) ATH5K_TRACE(ah->ah_sc); - switch (ah->ah_op_mode) { + switch (op_mode) { case NL80211_IFTYPE_ADHOC: pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; beacon_reg |= AR5K_BCR_ADHOC; @@ -113,39 +113,26 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah) } /** - * ath5k_hw_update - Update mib counters (mac layer statistics) + * ath5k_hw_update - Update MIB counters (mac layer statistics) * * @ah: The &struct ath5k_hw - * @stats: The &struct ieee80211_low_level_stats we use to track - * statistics on the driver * - * Reads MIB counters from PCU and updates sw statistics. Must be - * called after a MIB interrupt. + * Reads MIB counters from PCU and updates sw statistics. Is called after a + * MIB interrupt, because one of these counters might have reached their maximum + * and triggered the MIB interrupt, to let us read and clear the counter. + * + * Is called in interrupt context! */ -void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, - struct ieee80211_low_level_stats *stats) +void ath5k_hw_update_mib_counters(struct ath5k_hw *ah) { - ATH5K_TRACE(ah->ah_sc); + struct ath5k_statistics *stats = &ah->ah_sc->stats; /* Read-And-Clear */ - stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); - stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); - stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK); - stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); - - /* XXX: Should we use this to track beacon count ? - * -we read it anyway to clear the register */ - ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); - - /* Reset profile count registers on 5212*/ - if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); - ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); - } - - /* TODO: Handle ANI stats */ + stats->ack_fail += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); + stats->rts_fail += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); + stats->rts_ok += ath5k_hw_reg_read(ah, AR5K_RTS_OK); + stats->fcs_error += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); + stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); } /** @@ -167,9 +154,9 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) else { u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; if (high) - AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); - else AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); + else + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); } } @@ -179,25 +166,12 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) \******************/ /** - * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec - * - * @ah: The &struct ath5k_hw - */ -unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - - return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah, - AR5K_TIME_OUT), AR5K_TIME_OUT_ACK)); -} - -/** * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU * * @ah: The &struct ath5k_hw * @timeout: Timeout in usec */ -int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) +static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) { ATH5K_TRACE(ah->ah_sc); if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK)) @@ -211,24 +185,12 @@ int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) } /** - * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec - * - * @ah: The &struct ath5k_hw - */ -unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah, - AR5K_TIME_OUT), AR5K_TIME_OUT_CTS)); -} - -/** * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU * * @ah: The &struct ath5k_hw * @timeout: Timeout in usec */ -int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) +static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) { ATH5K_TRACE(ah->ah_sc); if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS)) @@ -290,7 +252,7 @@ unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) * * @ah: The &struct ath5k_hw */ -unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) +static unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) { struct ieee80211_channel *channel = ah->ah_current_channel; @@ -308,7 +270,7 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) * * @ah: The &struct ath5k_hw */ -unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) +static unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) { struct ieee80211_channel *channel = ah->ah_current_channel; @@ -417,7 +379,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) * (ACK etc). * * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma - * TODO: Init ANI here */ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) { @@ -451,42 +412,6 @@ void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); } -/* - * Set multicast filter by index - */ -int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index) -{ - - ATH5K_TRACE(ah->ah_sc); - if (index >= 64) - return -EINVAL; - else if (index >= 32) - AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1, - (1 << (index - 32))); - else - AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); - - return 0; -} - -/* - * Clear Multicast filter by index - */ -int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index) -{ - - ATH5K_TRACE(ah->ah_sc); - if (index >= 64) - return -EINVAL; - else if (index >= 32) - AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1, - (1 << (index - 32))); - else - AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); - - return 0; -} - /** * ath5k_hw_get_rx_filter - Get current rx filter * @@ -571,18 +496,7 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) * Beacon control * \****************/ -/** - * ath5k_hw_get_tsf32 - Get a 32bit TSF - * - * @ah: The &struct ath5k_hw - * - * Returns lower 32 bits of current TSF - */ -u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_reg_read(ah, AR5K_TSF_L32); -} +#define ATH5K_MAX_TSF_READ 10 /** * ath5k_hw_get_tsf64 - Get the full 64bit TSF @@ -593,10 +507,35 @@ u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah) */ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) { - u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32); + u32 tsf_lower, tsf_upper1, tsf_upper2; + int i; + + /* + * While reading TSF upper and then lower part, the clock is still + * counting (or jumping in case of IBSS merge) so we might get + * inconsistent values. To avoid this, we read the upper part again + * and check it has not been changed. We make the hypothesis that a + * maximum of 3 changes can happens in a row (we use 10 as a safe + * value). + * + * Impact on performance is pretty small, since in most cases, only + * 3 register reads are needed. + */ + + tsf_upper1 = ath5k_hw_reg_read(ah, AR5K_TSF_U32); + for (i = 0; i < ATH5K_MAX_TSF_READ; i++) { + tsf_lower = ath5k_hw_reg_read(ah, AR5K_TSF_L32); + tsf_upper2 = ath5k_hw_reg_read(ah, AR5K_TSF_U32); + if (tsf_upper2 == tsf_upper1) + break; + tsf_upper1 = tsf_upper2; + } + + WARN_ON( i == ATH5K_MAX_TSF_READ ); + ATH5K_TRACE(ah->ah_sc); - return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32); + return (((u64)tsf_upper1 << 32) | tsf_lower); } /** @@ -651,7 +590,7 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) /* * Set the additional timers by mode */ - switch (ah->ah_op_mode) { + switch (ah->ah_sc->opmode) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_STATION: /* In STA mode timer1 is used as next wakeup @@ -688,8 +627,8 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) * Set the beacon register and enable all timers. */ /* When in AP or Mesh Point mode zero timer0 to start TSF */ - if (ah->ah_op_mode == NL80211_IFTYPE_AP || - ah->ah_op_mode == NL80211_IFTYPE_MESH_POINT) + if (ah->ah_sc->opmode == NL80211_IFTYPE_AP || + ah->ah_sc->opmode == NL80211_IFTYPE_MESH_POINT) ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); @@ -722,203 +661,6 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) } -#if 0 -/* - * Set beacon timers - */ -int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, - const struct ath5k_beacon_state *state) -{ - u32 cfp_period, next_cfp, dtim, interval, next_beacon; - - /* - * TODO: should be changed through *state - * review struct ath5k_beacon_state struct - * - * XXX: These are used for cfp period bellow, are they - * ok ? Is it O.K. for tsf here to be 0 or should we use - * get_tsf ? - */ - u32 dtim_count = 0; /* XXX */ - u32 cfp_count = 0; /* XXX */ - u32 tsf = 0; /* XXX */ - - ATH5K_TRACE(ah->ah_sc); - /* Return on an invalid beacon state */ - if (state->bs_interval < 1) - return -EINVAL; - - interval = state->bs_interval; - dtim = state->bs_dtim_period; - - /* - * PCF support? - */ - if (state->bs_cfp_period > 0) { - /* - * Enable PCF mode and set the CFP - * (Contention Free Period) and timer registers - */ - cfp_period = state->bs_cfp_period * state->bs_dtim_period * - state->bs_interval; - next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * - state->bs_interval; - - AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_DEFAULT_ANTENNA | - AR5K_STA_ID1_PCF); - ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD); - ath5k_hw_reg_write(ah, state->bs_cfp_max_duration, - AR5K_CFP_DUR); - ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period : - next_cfp)) << 3, AR5K_TIMER2); - } else { - /* Disable PCF mode */ - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_DEFAULT_ANTENNA | - AR5K_STA_ID1_PCF); - } - - /* - * Enable the beacon timer register - */ - ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0); - - /* - * Start the beacon timers - */ - ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) & - ~(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) | - AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, - AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, - AR5K_BEACON_PERIOD), AR5K_BEACON); - - /* - * Write new beacon miss threshold, if it appears to be valid - * XXX: Figure out right values for min <= bs_bmiss_threshold <= max - * and return if its not in range. We can test this by reading value and - * setting value to a largest value and seeing which values register. - */ - - AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS, - state->bs_bmiss_threshold); - - /* - * Set sleep control register - * XXX: Didn't find this in 5210 code but since this register - * exists also in ar5k's 5210 headers i leave it as common code. - */ - AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR, - (state->bs_sleep_duration - 3) << 3); - - /* - * Set enhanced sleep registers on 5212 - */ - if (ah->ah_version == AR5K_AR5212) { - if (state->bs_sleep_duration > state->bs_interval && - roundup(state->bs_sleep_duration, interval) == - state->bs_sleep_duration) - interval = state->bs_sleep_duration; - - if (state->bs_sleep_duration > dtim && (dtim == 0 || - roundup(state->bs_sleep_duration, dtim) == - state->bs_sleep_duration)) - dtim = state->bs_sleep_duration; - - if (interval > dtim) - return -EINVAL; - - next_beacon = interval == dtim ? state->bs_next_dtim : - state->bs_next_beacon; - - ath5k_hw_reg_write(ah, - AR5K_REG_SM((state->bs_next_dtim - 3) << 3, - AR5K_SLEEP0_NEXT_DTIM) | - AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) | - AR5K_SLEEP0_ENH_SLEEP_EN | - AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0); - - ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3, - AR5K_SLEEP1_NEXT_TIM) | - AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1); - - ath5k_hw_reg_write(ah, - AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) | - AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2); - } - - return 0; -} - -/* - * Reset beacon timers - */ -void ath5k_hw_reset_beacon(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - /* - * Disable beacon timer - */ - ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); - - /* - * Disable some beacon register values - */ - AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, - AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); - ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON); -} - -/* - * Wait for beacon queue to finish - */ -int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) -{ - unsigned int i; - int ret; - - ATH5K_TRACE(ah->ah_sc); - - /* 5210 doesn't have QCU*/ - if (ah->ah_version == AR5K_AR5210) { - /* - * Wait for beaconn queue to finish by checking - * Control Register and Beacon Status Register. - */ - for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) { - if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F) - || - !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F)) - break; - udelay(10); - } - - /* Timeout... */ - if (i <= 0) { - /* - * Re-schedule the beacon queue - */ - ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1); - ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, - AR5K_BCR); - - return -EIO; - } - ret = 0; - } else { - /*5211/5212*/ - ret = ath5k_hw_register_timeout(ah, - AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON), - AR5K_QCU_STS_FRMPENDCNT, 0, false); - - if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON)) - return -EIO; - } - - return ret; -} -#endif - /*********************\ * Key table functions * @@ -971,19 +713,6 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) return 0; } -/* - * Check if a table entry is valid - */ -int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) -{ - ATH5K_TRACE(ah->ah_sc); - AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); - - /* Check the validation flag at the end of the entry */ - return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) & - AR5K_KEYTABLE_VALID; -} - static int ath5k_keycache_type(const struct ieee80211_key_conf *key) { diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 68e2bccd90d..1b81c477880 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -20,8 +20,6 @@ * */ -#define _ATH5K_PHY - #include <linux/delay.h> #include <linux/slab.h> @@ -982,7 +980,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, return -EINVAL; data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); - } else if ((c - (c % 5)) != 2 || c > 5435) { + } else if ((c % 5) != 2 || c > 5435) { if (!(c % 20) && c >= 5120) { data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); data2 = ath5k_hw_bitswap(3, 2); @@ -995,7 +993,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, } else return -EINVAL; } else { - data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); + data0 = ath5k_hw_bitswap((10 * (c - 2 - 4800)) / 25 + 1, 8); data2 = ath5k_hw_bitswap(0, 2); } @@ -1023,7 +1021,7 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, data0 = ath5k_hw_bitswap((c - 2272), 8); data2 = 0; /* ? 5GHz ? */ - } else if ((c - (c % 5)) != 2 || c > 5435) { + } else if ((c % 5) != 2 || c > 5435) { if (!(c % 20) && c < 5120) data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); else if (!(c % 10)) @@ -1034,7 +1032,7 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah, return -EINVAL; data2 = ath5k_hw_bitswap(1, 2); } else { - data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8); + data0 = ath5k_hw_bitswap((10 * (c - 2 - 4800)) / 25 + 1, 8); data2 = ath5k_hw_bitswap(0, 2); } @@ -1105,28 +1103,6 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) PHY calibration \*****************/ -void -ath5k_hw_calibration_poll(struct ath5k_hw *ah) -{ - /* Calibration interval in jiffies */ - unsigned long cal_intval; - - cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000); - - /* Initialize timestamp if needed */ - if (!ah->ah_cal_tstamp) - ah->ah_cal_tstamp = jiffies; - - /* For now we always do full calibration - * Mark software interrupt mask and fire software - * interrupt (bit gets auto-cleared) */ - if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) { - ah->ah_cal_tstamp = jiffies; - ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION; - AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); - } -} - static int sign_extend(int val, const int nbits) { int order = BIT(nbits-1); @@ -1191,7 +1167,7 @@ static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah) * The median of the values in the history is then loaded into the * hardware for its own use for RSSI and CCA measurements. */ -void ath5k_hw_update_noise_floor(struct ath5k_hw *ah) +static void ath5k_hw_update_noise_floor(struct ath5k_hw *ah) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u32 val; @@ -1400,7 +1376,11 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, } i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; - q_coffd = q_pwr >> 7; + + if (ah->ah_version == AR5K_AR5211) + q_coffd = q_pwr >> 6; + else + q_coffd = q_pwr >> 7; /* protect against divide by 0 and loss of sign bits */ if (i_coffd == 0 || q_coffd < 2) @@ -1409,7 +1389,10 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, i_coff = (-iq_corr) / i_coffd; i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */ - q_coff = (i_pwr / q_coffd) - 128; + if (ah->ah_version == AR5K_AR5211) + q_coff = (i_pwr / q_coffd) - 64; + else + q_coff = (i_pwr / q_coffd) - 128; q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */ ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, @@ -1769,7 +1752,7 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) * Antenna control * \*****************/ -void /*TODO:Boundary check*/ +static void /*TODO:Boundary check*/ ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant) { ATH5K_TRACE(ah->ah_sc); @@ -1778,16 +1761,6 @@ ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant) ath5k_hw_reg_write(ah, ant & 0x7, AR5K_DEFAULT_ANTENNA); } -unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah) -{ - ATH5K_TRACE(ah->ah_sc); - - if (ah->ah_version != AR5K_AR5210) - return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA) & 0x7; - - return false; /*XXX: What do we return for 5210 ?*/ -} - /* * Enable/disable fast rx antenna diversity */ @@ -1931,6 +1904,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode) ah->ah_tx_ant = tx_ant; ah->ah_ant_mode = ant_mode; + ah->ah_def_ant = def_ant; sta_id1 |= use_def_for_tx ? AR5K_STA_ID1_DEFAULT_ANTENNA : 0; sta_id1 |= update_def_on_tx ? AR5K_STA_ID1_DESC_ANTENNA : 0; @@ -2171,8 +2145,6 @@ ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah, done: *pcinfo_l = &pcinfo[idx_l]; *pcinfo_r = &pcinfo[idx_r]; - - return; } /* @@ -2441,19 +2413,6 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, pcdac_tmp = pcdac_high_pwr; edge_flag = 0x40; -#if 0 - /* If both min and max power limits are in lower - * power curve's range, only use the low power curve. - * TODO: min/max levels are related to target - * power values requested from driver/user - * XXX: Is this really needed ? */ - if (min_pwr < table_max[1] && - max_pwr < table_max[1]) { - edge_flag = 0; - pcdac_tmp = pcdac_low_pwr; - max_pwr_idx = (table_max[1] - table_min[1])/2; - } -#endif } else { pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */ pcdac_high_pwr = ah->ah_txpower.tmpL[0]; @@ -2600,7 +2559,7 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, max_idx = (pdadc_n < table_size) ? pdadc_n : table_size; /* Fill pdadc_out table */ - while (pdadc_0 < max_idx) + while (pdadc_0 < max_idx && pdadc_i < 128) pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++]; /* Need to extrapolate above this pdgain? */ @@ -3144,5 +3103,3 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower) return ath5k_hw_txpower(ah, channel, ee_mode, txpower); } - -#undef _ATH5K_PHY diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 9122a8556f4..f5831da33f7 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -517,23 +517,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) } /* - * Get slot time from DCU - */ -unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) -{ - unsigned int slot_time_clock; - - ATH5K_TRACE(ah->ah_sc); - - if (ah->ah_version == AR5K_AR5210) - slot_time_clock = ath5k_hw_reg_read(ah, AR5K_SLOT_TIME); - else - slot_time_clock = ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT); - - return ath5k_hw_clocktoh(ah, slot_time_clock & 0xffff); -} - -/* * Set slot time on DCU */ int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 1464f89b249..55b4ac6d236 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -212,10 +212,10 @@ * MIB control register */ #define AR5K_MIBC 0x0040 /* Register Address */ -#define AR5K_MIBC_COW 0x00000001 /* Warn test indicator */ +#define AR5K_MIBC_COW 0x00000001 /* Counter Overflow Warning */ #define AR5K_MIBC_FMC 0x00000002 /* Freeze MIB Counters */ -#define AR5K_MIBC_CMC 0x00000004 /* Clean MIB Counters */ -#define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe */ +#define AR5K_MIBC_CMC 0x00000004 /* Clear MIB Counters */ +#define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe, increment all */ /* * Timeout prescale register @@ -1139,8 +1139,8 @@ #define AR5K_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */ #define AR5K_STA_ID1_DESC_ANTENNA 0x00400000 /* Update antenna from descriptor */ #define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS */ -#define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS */ -#define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate for ACK/CTS [5211+] */ +#define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Rate to use for ACK/CTS. 0: highest mandatory rate <= RX rate; 1: 1Mbps in B mode */ +#define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* 802.11b base rate. 0: 1, 2, 5.5 and 11Mbps; 1: 1 and 2Mbps. [5211+] */ #define AR5K_STA_ID1_SELFGEN_DEF_ANT 0x04000000 /* Use def. antenna for self generated frames */ #define AR5K_STA_ID1_CRYPT_MIC_EN 0x08000000 /* Enable MIC */ #define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Look up key when key id != 0 */ @@ -1516,7 +1516,14 @@ AR5K_NAV_5210 : AR5K_NAV_5211) /* - * RTS success register + * MIB counters: + * + * max value is 0xc000, if this is reached we get a MIB interrupt. + * they can be controlled via AR5K_MIBC and are cleared on read. + */ + +/* + * RTS success (MIB counter) */ #define AR5K_RTS_OK_5210 0x8090 #define AR5K_RTS_OK_5211 0x8088 @@ -1524,7 +1531,7 @@ AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211) /* - * RTS failure register + * RTS failure (MIB counter) */ #define AR5K_RTS_FAIL_5210 0x8094 #define AR5K_RTS_FAIL_5211 0x808c @@ -1532,7 +1539,7 @@ AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211) /* - * ACK failure register + * ACK failure (MIB counter) */ #define AR5K_ACK_FAIL_5210 0x8098 #define AR5K_ACK_FAIL_5211 0x8090 @@ -1540,7 +1547,7 @@ AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211) /* - * FCS failure register + * FCS failure (MIB counter) */ #define AR5K_FCS_FAIL_5210 0x809c #define AR5K_FCS_FAIL_5211 0x8094 @@ -1667,11 +1674,17 @@ /* * Profile count registers + * + * These registers can be cleared and freezed with ATH5K_MIBC, but they do not + * generate a MIB interrupt. + * Instead of overflowing, they shift by one bit to the right. All registers + * shift together, i.e. when one reaches the max, all shift at the same time by + * one bit to the right. This way we should always get consistent values. */ #define AR5K_PROFCNT_TX 0x80ec /* Tx count */ #define AR5K_PROFCNT_RX 0x80f0 /* Rx count */ -#define AR5K_PROFCNT_RXCLR 0x80f4 /* Clear Rx count */ -#define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle count (?) */ +#define AR5K_PROFCNT_RXCLR 0x80f4 /* Busy count */ +#define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle counter */ /* * Quiet period control registers @@ -1758,7 +1771,7 @@ #define AR5K_CCK_FIL_CNT 0x8128 /* - * PHY Error Counters (?) + * PHY Error Counters (same masks as AR5K_PHY_ERR_FIL) */ #define AR5K_PHYERR_CNT1 0x812c #define AR5K_PHYERR_CNT1_MASK 0x8130 @@ -1766,6 +1779,9 @@ #define AR5K_PHYERR_CNT2 0x8134 #define AR5K_PHYERR_CNT2_MASK 0x8138 +/* if the PHY Error Counters reach this maximum, we get MIB interrupts */ +#define ATH5K_PHYERR_CNT_MAX 0x00c00000 + /* * TSF Threshold register (?) */ @@ -1974,7 +1990,7 @@ #define AR5K_PHY_SETTLING 0x9844 /* Register Address */ #define AR5K_PHY_SETTLING_AGC 0x0000007f /* AGC settling time */ #define AR5K_PHY_SETTLING_AGC_S 0 -#define AR5K_PHY_SETTLING_SWITCH 0x00003f80 /* Switch settlig time */ +#define AR5K_PHY_SETTLING_SWITCH 0x00003f80 /* Switch settling time */ #define AR5K_PHY_SETTLING_SWITCH_S 7 /* diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index cbf28e37984..307f80e83f9 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -19,8 +19,6 @@ * */ -#define _ATH5K_RESET - /*****************************\ Reset functions and helpers \*****************************/ @@ -34,6 +32,27 @@ #include "base.h" #include "debug.h" +/* + * Check if a register write has been completed + */ +int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, + bool is_set) +{ + int i; + u32 data; + + for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) { + data = ath5k_hw_reg_read(ah, reg); + if (is_set && (data & flag)) + break; + else if ((data & flag) == val) + break; + udelay(15); + } + + return (i <= 0) ? -EAGAIN : 0; +} + /** * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212 * @@ -221,8 +240,8 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) /* * Sleep control */ -int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, - bool set_chip, u16 sleep_duration) +static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, + bool set_chip, u16 sleep_duration) { unsigned int i; u32 staid, data; @@ -608,7 +627,6 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable) AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1); } - return; } /* TODO: Half/Quarter rate */ @@ -864,8 +882,6 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, /* Heavy clipping -disable for now */ if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1) ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE); - - return; } /* @@ -1017,11 +1033,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, if (ret) return ret; - /* - * Initialize operating mode - */ - ah->ah_op_mode = op_mode; - /* PHY access enable */ if (ah->ah_mac_srev >= AR5K_SREV_AR5211) ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); @@ -1192,7 +1203,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ath5k_hw_set_associd(ah); /* Set PCU config */ - ath5k_hw_set_opmode(ah); + ath5k_hw_set_opmode(ah, op_mode); /* Clear any pending interrupts * PISR/SISR Not available on 5210 */ @@ -1378,7 +1389,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, * external 32KHz crystal when sleeping if one * exists */ if (ah->ah_version == AR5K_AR5212 && - ah->ah_op_mode != NL80211_IFTYPE_AP) + op_mode != NL80211_IFTYPE_AP) ath5k_hw_set_sleep_clock(ah, true); /* @@ -1388,5 +1399,3 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ath5k_hw_reset_tsf(ah); return 0; } - -#undef _ATH5K_RESET diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 5774cea23a3..35f23bdc442 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -32,3 +32,24 @@ config ATH9K_DEBUGFS Also required for changing debug message flags at run time. +config ATH9K_HTC + tristate "Atheros HTC based wireless cards support" + depends on USB && MAC80211 + select ATH9K_HW + select MAC80211_LEDS + select LEDS_CLASS + select NEW_LEDS + select ATH9K_COMMON + ---help--- + Support for Atheros HTC based cards. + Chipsets supported: AR9271 + + For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc + + The built module will be ath9k_htc. + +config ATH9K_HTC_DEBUGFS + bool "Atheros ath9k_htc debugging" + depends on ATH9K_HTC && DEBUG_FS + ---help--- + Say Y, if you need access to ath9k_htc's statistics. diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 6b50d5eb9ec..dd112be218a 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -13,18 +13,38 @@ ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o obj-$(CONFIG_ATH9K) += ath9k.o -ath9k_hw-y:= hw.o \ +ath9k_hw-y:= \ + ar9002_hw.o \ + ar9003_hw.o \ + hw.o \ + ar9003_phy.o \ + ar9002_phy.o \ + ar5008_phy.o \ + ar9002_calib.o \ + ar9003_calib.o \ + calib.o \ eeprom.o \ eeprom_def.o \ eeprom_4k.o \ eeprom_9287.o \ - calib.o \ ani.o \ - phy.o \ btcoex.o \ mac.o \ + ar9002_mac.o \ + ar9003_mac.o \ + ar9003_eeprom.o obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o ath9k_common-y:= common.o + +ath9k_htc-y += htc_hst.o \ + hif_usb.o \ + wmi.o \ + htc_drv_txrx.o \ + htc_drv_main.o \ + htc_drv_beacon.o \ + htc_drv_init.o + +obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index ca4994f1315..85fdd26039c 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -47,6 +47,7 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) } static struct ath_bus_ops ath_ahb_bus_ops = { + .ath_bus_type = ATH_AHB, .read_cachesize = ath_ahb_read_cachesize, .eeprom_read = ath_ahb_eeprom_read, }; diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 2a0cd64c2bf..ba8b20f0159 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -15,6 +15,7 @@ */ #include "hw.h" +#include "hw-ops.h" static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, struct ath9k_channel *chan) @@ -37,190 +38,6 @@ static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, return 0; } -static bool ath9k_hw_ani_control(struct ath_hw *ah, - enum ath9k_ani_cmd cmd, int param) -{ - struct ar5416AniState *aniState = ah->curani; - struct ath_common *common = ath9k_hw_common(ah); - - switch (cmd & ah->ani_function) { - case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ - u32 level = param; - - if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { - ath_print(common, ATH_DBG_ANI, - "level out of range (%u > %u)\n", - level, - (unsigned)ARRAY_SIZE(ah->totalSizeDesired)); - return false; - } - - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_TOT_DES, - ah->totalSizeDesired[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_LOW, - ah->coarse_low[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_HIGH, - ah->coarse_high[level]); - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRPWR, - ah->firpwr[level]); - - if (level > aniState->noiseImmunityLevel) - ah->stats.ast_ani_niup++; - else if (level < aniState->noiseImmunityLevel) - ah->stats.ast_ani_nidown++; - aniState->noiseImmunityLevel = level; - break; - } - case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ - const int m1ThreshLow[] = { 127, 50 }; - const int m2ThreshLow[] = { 127, 40 }; - const int m1Thresh[] = { 127, 0x4d }; - const int m2Thresh[] = { 127, 0x40 }; - const int m2CountThr[] = { 31, 16 }; - const int m2CountThrLow[] = { 63, 48 }; - u32 on = param ? 1 : 0; - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2_THRESH, - m2Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2COUNT_THR, - m2CountThr[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, - m2CountThrLow[on]); - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH, - m2Thresh[on]); - - if (on) - REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - else - REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - - if (!on != aniState->ofdmWeakSigDetectOff) { - if (on) - ah->stats.ast_ani_ofdmon++; - else - ah->stats.ast_ani_ofdmoff++; - aniState->ofdmWeakSigDetectOff = !on; - } - break; - } - case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ - const int weakSigThrCck[] = { 8, 6 }; - u32 high = param ? 1 : 0; - - REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, - AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, - weakSigThrCck[high]); - if (high != aniState->cckWeakSigThreshold) { - if (high) - ah->stats.ast_ani_cckhigh++; - else - ah->stats.ast_ani_ccklow++; - aniState->cckWeakSigThreshold = high; - } - break; - } - case ATH9K_ANI_FIRSTEP_LEVEL:{ - const int firstep[] = { 0, 4, 8 }; - u32 level = param; - - if (level >= ARRAY_SIZE(firstep)) { - ath_print(common, ATH_DBG_ANI, - "level out of range (%u > %u)\n", - level, - (unsigned) ARRAY_SIZE(firstep)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRSTEP, - firstep[level]); - if (level > aniState->firstepLevel) - ah->stats.ast_ani_stepup++; - else if (level < aniState->firstepLevel) - ah->stats.ast_ani_stepdown++; - aniState->firstepLevel = level; - break; - } - case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ - const int cycpwrThr1[] = - { 2, 4, 6, 8, 10, 12, 14, 16 }; - u32 level = param; - - if (level >= ARRAY_SIZE(cycpwrThr1)) { - ath_print(common, ATH_DBG_ANI, - "level out of range (%u > %u)\n", - level, - (unsigned) ARRAY_SIZE(cycpwrThr1)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_TIMING5, - AR_PHY_TIMING5_CYCPWR_THR1, - cycpwrThr1[level]); - if (level > aniState->spurImmunityLevel) - ah->stats.ast_ani_spurup++; - else if (level < aniState->spurImmunityLevel) - ah->stats.ast_ani_spurdown++; - aniState->spurImmunityLevel = level; - break; - } - case ATH9K_ANI_PRESENT: - break; - default: - ath_print(common, ATH_DBG_ANI, - "invalid cmd %u\n", cmd); - return false; - } - - ath_print(common, ATH_DBG_ANI, "ANI parameters:\n"); - ath_print(common, ATH_DBG_ANI, - "noiseImmunityLevel=%d, spurImmunityLevel=%d, " - "ofdmWeakSigDetectOff=%d\n", - aniState->noiseImmunityLevel, - aniState->spurImmunityLevel, - !aniState->ofdmWeakSigDetectOff); - ath_print(common, ATH_DBG_ANI, - "cckWeakSigThreshold=%d, " - "firstepLevel=%d, listenTime=%d\n", - aniState->cckWeakSigThreshold, - aniState->firstepLevel, - aniState->listenTime); - ath_print(common, ATH_DBG_ANI, - "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", - aniState->cycleCount, - aniState->ofdmPhyErrCount, - aniState->cckPhyErrCount); - - return true; -} - static void ath9k_hw_update_mibstats(struct ath_hw *ah, struct ath9k_mib_stats *stats) { @@ -262,11 +79,17 @@ static void ath9k_ani_restart(struct ath_hw *ah) "Writing ofdmbase=%u cckbase=%u\n", aniState->ofdmPhyErrBase, aniState->cckPhyErrBase); + + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); aniState->ofdmPhyErrCount = 0; @@ -540,8 +363,14 @@ void ath9k_ani_reset(struct ath_hw *ah) ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & ~ATH9K_RX_FILTER_PHYERR); ath9k_ani_restart(ah); + + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); } void ath9k_hw_ani_monitor(struct ath_hw *ah, @@ -639,6 +468,8 @@ void ath9k_enable_mib_counters(struct ath_hw *ah) ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_FILT_OFDM, 0); REG_WRITE(ah, AR_FILT_CCK, 0); REG_WRITE(ah, AR_MIBC, @@ -646,6 +477,9 @@ void ath9k_enable_mib_counters(struct ath_hw *ah) & 0x0f); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); } /* Freeze the MIB counters, get the stats and then clear them */ @@ -809,20 +643,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", ah->ani[0].cckPhyErrBase); + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + ath9k_enable_mib_counters(ah); ah->aniperiod = ATH9K_ANI_PERIOD; if (ah->config.enable_ani) ah->proc_phyerr |= HAL_PROCESS_ANI; } - -void ath9k_hw_ani_disable(struct ath_hw *ah) -{ - ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n"); - - ath9k_hw_disable_mib_counters(ah); - REG_WRITE(ah, AR_PHY_ERR_1, 0); - REG_WRITE(ah, AR_PHY_ERR_2, 0); -} diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 4e1ab94a515..3356762ea38 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -118,6 +118,5 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt, void ath9k_hw_procmibevent(struct ath_hw *ah); void ath9k_hw_ani_setup(struct ath_hw *ah); void ath9k_hw_ani_init(struct ath_hw *ah); -void ath9k_hw_ani_disable(struct ath_hw *ah); #endif /* ANI_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h new file mode 100644 index 00000000000..025c31ac614 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h @@ -0,0 +1,742 @@ +/* + * Copyright (c) 2008-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. + */ + +#ifndef INITVALS_AR5008_H +#define INITVALS_AR5008_H + +static const u32 ar5416Modes[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, + { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 }, + { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 }, + { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de }, + { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, + { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e }, + { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 }, + { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 }, + { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b }, + { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, + { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, + { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, + { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 }, + { 0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 }, + { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, + { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, + { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, + { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, + { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, + { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, + { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, + { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, + { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, + { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, + { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, + { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, + { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, + { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const u32 ar5416Common[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00007010, 0x00000000 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0x88000010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x00008300, 0x00000000 }, + { 0x00008304, 0x00000000 }, + { 0x00008308, 0x00000000 }, + { 0x0000830c, 0x00000000 }, + { 0x00008310, 0x00000000 }, + { 0x00008314, 0x00000000 }, + { 0x00008318, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00070000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xad848e19 }, + { 0x00009810, 0x7d14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x00009840, 0x206a002e }, + { 0x0000984c, 0x1284233c }, + { 0x00009854, 0x00000859 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x05100000 }, + { 0x0000a920, 0x05100000 }, + { 0x0000b920, 0x05100000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280b212 }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5d50e188 }, + { 0x00009958, 0x00081fff }, + { 0x0000c95c, 0x004b6a8e }, + { 0x0000c968, 0x000003ce }, + { 0x00009970, 0x190fb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x001fff00 }, + { 0x000099ac, 0x00000000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000200 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x000000aa }, + { 0x000099fc, 0x00001042 }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009b9c, 0x00000033 }, + { 0x00009ba0, 0x00000034 }, + { 0x00009ba4, 0x00000035 }, + { 0x00009ba8, 0x00000035 }, + { 0x00009bac, 0x00000035 }, + { 0x00009bb0, 0x00000035 }, + { 0x00009bb4, 0x00000035 }, + { 0x00009bb8, 0x00000035 }, + { 0x00009bbc, 0x00000035 }, + { 0x00009bc0, 0x00000035 }, + { 0x00009bc4, 0x00000035 }, + { 0x00009bc8, 0x00000035 }, + { 0x00009bcc, 0x00000035 }, + { 0x00009bd0, 0x00000035 }, + { 0x00009bd4, 0x00000035 }, + { 0x00009bd8, 0x00000035 }, + { 0x00009bdc, 0x00000035 }, + { 0x00009be0, 0x00000035 }, + { 0x00009be4, 0x00000035 }, + { 0x00009be8, 0x00000035 }, + { 0x00009bec, 0x00000035 }, + { 0x00009bf0, 0x00000035 }, + { 0x00009bf4, 0x00000035 }, + { 0x00009bf8, 0x00000010 }, + { 0x00009bfc, 0x0000001a }, + { 0x0000a210, 0x40806333 }, + { 0x0000a214, 0x00106c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x018830c6 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x00000bb5 }, + { 0x0000a22c, 0x00000011 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0e79e5c6 }, + { 0x0000b26c, 0x0e79e5c6 }, + { 0x0000c26c, 0x0e79e5c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x051701ce }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa1f }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x08000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, +}; + +static const u32 ar5416Bank0[][2] = { + { 0x000098b0, 0x1e5795e5 }, + { 0x000098e0, 0x02008020 }, +}; + +static const u32 ar5416BB_RfGain[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000040, 0x00000040 }, + { 0x00009a08, 0x00000080, 0x00000080 }, + { 0x00009a0c, 0x000001a1, 0x00000141 }, + { 0x00009a10, 0x000001e1, 0x00000181 }, + { 0x00009a14, 0x00000021, 0x000001c1 }, + { 0x00009a18, 0x00000061, 0x00000001 }, + { 0x00009a1c, 0x00000168, 0x00000041 }, + { 0x00009a20, 0x000001a8, 0x000001a8 }, + { 0x00009a24, 0x000001e8, 0x000001e8 }, + { 0x00009a28, 0x00000028, 0x00000028 }, + { 0x00009a2c, 0x00000068, 0x00000068 }, + { 0x00009a30, 0x00000189, 0x000000a8 }, + { 0x00009a34, 0x000001c9, 0x00000169 }, + { 0x00009a38, 0x00000009, 0x000001a9 }, + { 0x00009a3c, 0x00000049, 0x000001e9 }, + { 0x00009a40, 0x00000089, 0x00000029 }, + { 0x00009a44, 0x00000170, 0x00000069 }, + { 0x00009a48, 0x000001b0, 0x00000190 }, + { 0x00009a4c, 0x000001f0, 0x000001d0 }, + { 0x00009a50, 0x00000030, 0x00000010 }, + { 0x00009a54, 0x00000070, 0x00000050 }, + { 0x00009a58, 0x00000191, 0x00000090 }, + { 0x00009a5c, 0x000001d1, 0x00000151 }, + { 0x00009a60, 0x00000011, 0x00000191 }, + { 0x00009a64, 0x00000051, 0x000001d1 }, + { 0x00009a68, 0x00000091, 0x00000011 }, + { 0x00009a6c, 0x000001b8, 0x00000051 }, + { 0x00009a70, 0x000001f8, 0x00000198 }, + { 0x00009a74, 0x00000038, 0x000001d8 }, + { 0x00009a78, 0x00000078, 0x00000018 }, + { 0x00009a7c, 0x00000199, 0x00000058 }, + { 0x00009a80, 0x000001d9, 0x00000098 }, + { 0x00009a84, 0x00000019, 0x00000159 }, + { 0x00009a88, 0x00000059, 0x00000199 }, + { 0x00009a8c, 0x00000099, 0x000001d9 }, + { 0x00009a90, 0x000000d9, 0x00000019 }, + { 0x00009a94, 0x000000f9, 0x00000059 }, + { 0x00009a98, 0x000000f9, 0x00000099 }, + { 0x00009a9c, 0x000000f9, 0x000000d9 }, + { 0x00009aa0, 0x000000f9, 0x000000f9 }, + { 0x00009aa4, 0x000000f9, 0x000000f9 }, + { 0x00009aa8, 0x000000f9, 0x000000f9 }, + { 0x00009aac, 0x000000f9, 0x000000f9 }, + { 0x00009ab0, 0x000000f9, 0x000000f9 }, + { 0x00009ab4, 0x000000f9, 0x000000f9 }, + { 0x00009ab8, 0x000000f9, 0x000000f9 }, + { 0x00009abc, 0x000000f9, 0x000000f9 }, + { 0x00009ac0, 0x000000f9, 0x000000f9 }, + { 0x00009ac4, 0x000000f9, 0x000000f9 }, + { 0x00009ac8, 0x000000f9, 0x000000f9 }, + { 0x00009acc, 0x000000f9, 0x000000f9 }, + { 0x00009ad0, 0x000000f9, 0x000000f9 }, + { 0x00009ad4, 0x000000f9, 0x000000f9 }, + { 0x00009ad8, 0x000000f9, 0x000000f9 }, + { 0x00009adc, 0x000000f9, 0x000000f9 }, + { 0x00009ae0, 0x000000f9, 0x000000f9 }, + { 0x00009ae4, 0x000000f9, 0x000000f9 }, + { 0x00009ae8, 0x000000f9, 0x000000f9 }, + { 0x00009aec, 0x000000f9, 0x000000f9 }, + { 0x00009af0, 0x000000f9, 0x000000f9 }, + { 0x00009af4, 0x000000f9, 0x000000f9 }, + { 0x00009af8, 0x000000f9, 0x000000f9 }, + { 0x00009afc, 0x000000f9, 0x000000f9 }, +}; + +static const u32 ar5416Bank1[][2] = { + { 0x000098b0, 0x02108421 }, + { 0x000098ec, 0x00000008 }, +}; + +static const u32 ar5416Bank2[][2] = { + { 0x000098b0, 0x0e73ff17 }, + { 0x000098e0, 0x00000420 }, +}; + +static const u32 ar5416Bank3[][3] = { + { 0x000098f0, 0x01400018, 0x01c00018 }, +}; + +static const u32 ar5416Bank6[][3] = { + + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x004210a2, 0x004210a2 }, + { 0x0000989c, 0x0014008f, 0x0014008f }, + { 0x0000989c, 0x00c40003, 0x00c40003 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000f1, 0x000000f1 }, + { 0x0000989c, 0x00002081, 0x00002081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const u32 ar5416Bank6TPC[][3] = { + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x00423022, 0x00423022 }, + { 0x0000989c, 0x201400df, 0x201400df }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000e1, 0x000000e1 }, + { 0x0000989c, 0x00007081, 0x00007081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const u32 ar5416Bank7[][2] = { + { 0x0000989c, 0x00000500 }, + { 0x0000989c, 0x00000800 }, + { 0x000098cc, 0x0000000e }, +}; + +static const u32 ar5416Addac[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000003 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x0000000c }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000030 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000060 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000058 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; + +static const u32 ar5416Modes_9100[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, + { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 }, + { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec86d2e, 0x7ec84d2e, 0x7ec82d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, + { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a11, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009940, 0x00754604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204 }, + { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, + { 0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e }, + { 0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff }, +#ifdef TB243 + { 0x00009960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x0000a960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x0000b960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00002210, 0x00002210, 0x00001120 }, +#else + { 0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, + { 0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, + { 0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, + { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, +#endif + { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00 }, + { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, + { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, + { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, + { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, + { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, + { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, + { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, + { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, + { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, + { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, + { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, + { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, + { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, + { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +#endif /* INITVALS_AR5008_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c new file mode 100644 index 00000000000..b2c17c98bb3 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -0,0 +1,1374 @@ +/* + * Copyright (c) 2008-2010 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 "hw.h" +#include "hw-ops.h" +#include "../regd.h" +#include "ar9002_phy.h" + +/* All code below is for non single-chip solutions */ + +/** + * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters + * @rfbuf: + * @reg32: + * @numBits: + * @firstBit: + * @column: + * + * Performs analog "swizzling" of parameters into their location. + * Used on external AR2133/AR5133 radios. + */ +static void ar5008_hw_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, + u32 numBits, u32 firstBit, + u32 column) +{ + u32 tmp32, mask, arrayEntry, lastBit; + int32_t bitPosition, bitsLeft; + + tmp32 = ath9k_hw_reverse_bits(reg32, numBits); + arrayEntry = (firstBit - 1) / 8; + bitPosition = (firstBit - 1) % 8; + bitsLeft = numBits; + while (bitsLeft > 0) { + lastBit = (bitPosition + bitsLeft > 8) ? + 8 : bitPosition + bitsLeft; + mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) << + (column * 8); + rfBuf[arrayEntry] &= ~mask; + rfBuf[arrayEntry] |= ((tmp32 << bitPosition) << + (column * 8)) & mask; + bitsLeft -= 8 - bitPosition; + tmp32 = tmp32 >> (8 - bitPosition); + bitPosition = 0; + arrayEntry++; + } +} + +/* + * Fix on 2.4 GHz band for orientation sensitivity issue by increasing + * rf_pwd_icsyndiv. + * + * Theoretical Rules: + * if 2 GHz band + * if forceBiasAuto + * if synth_freq < 2412 + * bias = 0 + * else if 2412 <= synth_freq <= 2422 + * bias = 1 + * else // synth_freq > 2422 + * bias = 2 + * else if forceBias > 0 + * bias = forceBias & 7 + * else + * no change, use value from ini file + * else + * no change, invalid band + * + * 1st Mod: + * 2422 also uses value of 2 + * <approved> + * + * 2nd Mod: + * Less than 2412 uses value of 0, 2412 and above uses value of 2 + */ +static void ar5008_hw_force_bias(struct ath_hw *ah, u16 synth_freq) +{ + struct ath_common *common = ath9k_hw_common(ah); + u32 tmp_reg; + int reg_writes = 0; + u32 new_bias = 0; + + if (!AR_SREV_5416(ah) || synth_freq >= 3000) + return; + + BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + + if (synth_freq < 2412) + new_bias = 0; + else if (synth_freq < 2422) + new_bias = 1; + else + new_bias = 2; + + /* pre-reverse this field */ + tmp_reg = ath9k_hw_reverse_bits(new_bias, 3); + + ath_print(common, ATH_DBG_CONFIG, + "Force rf_pwd_icsyndiv to %1d on %4d\n", + new_bias, synth_freq); + + /* swizzle rf_pwd_icsyndiv */ + ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data, tmp_reg, 3, 181, 3); + + /* write Bank 6 with new params */ + REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes); +} + +/** + * ar5008_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios + * @ah: atheros hardware stucture + * @chan: + * + * For the external AR2133/AR5133 radios, takes the MHz channel value and set + * the channel value. Assumes writes enabled to analog bus and bank6 register + * cache in ah->analogBank6Data. + */ +static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) +{ + struct ath_common *common = ath9k_hw_common(ah); + u32 channelSel = 0; + u32 bModeSynth = 0; + u32 aModeRefSel = 0; + u32 reg32 = 0; + u16 freq; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + if (freq < 4800) { + u32 txctl; + + if (((freq - 2192) % 5) == 0) { + channelSel = ((freq - 672) * 2 - 3040) / 10; + bModeSynth = 0; + } else if (((freq - 2224) % 5) == 0) { + channelSel = ((freq - 704) * 2 - 3040) / 10; + bModeSynth = 1; + } else { + ath_print(common, ATH_DBG_FATAL, + "Invalid channel %u MHz\n", freq); + return -EINVAL; + } + + channelSel = (channelSel << 2) & 0xff; + channelSel = ath9k_hw_reverse_bits(channelSel, 8); + + txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (freq == 2484) { + + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); + } + + } else if ((freq % 20) == 0 && freq >= 5120) { + channelSel = + ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8); + aModeRefSel = ath9k_hw_reverse_bits(1, 2); + } else if ((freq % 10) == 0) { + channelSel = + ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8); + if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) + aModeRefSel = ath9k_hw_reverse_bits(2, 2); + else + aModeRefSel = ath9k_hw_reverse_bits(1, 2); + } else if ((freq % 5) == 0) { + channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8); + aModeRefSel = ath9k_hw_reverse_bits(1, 2); + } else { + ath_print(common, ATH_DBG_FATAL, + "Invalid channel %u MHz\n", freq); + return -EINVAL; + } + + ar5008_hw_force_bias(ah, freq); + + reg32 = + (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | + (1 << 5) | 0x1; + + REG_WRITE(ah, AR_PHY(0x37), reg32); + + ah->curchan = chan; + ah->curchan_rad_index = -1; + + return 0; +} + +/** + * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios + * @ah: atheros hardware structure + * @chan: + * + * For non single-chip solutions. Converts to baseband spur frequency given the + * input channel frequency and compute register settings below. + */ +static void ar5008_hw_spur_mitigate(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + int bb_spur = AR_NO_SPUR; + int bin, cur_bin; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, new; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); + + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - (chan->channel * 10); + if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) + return; + + bin = bb_spur * 32; + + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); + + new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, new); + + spur_delta_phase = ((bb_spur * 524288) / 100) & + AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; + spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; + + new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, new); + + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + + /* workaround for gcc bug #37014 */ + volatile int tmp_v = abs(cur_vit_mask - bin); + + if (tmp_v < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); +} + +/** + * ar5008_hw_rf_alloc_ext_banks - allocates banks for external radio programming + * @ah: atheros hardware structure + * + * Only required for older devices with external AR2133/AR5133 radios. + */ +static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah) +{ +#define ATH_ALLOC_BANK(bank, size) do { \ + bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \ + if (!bank) { \ + ath_print(common, ATH_DBG_FATAL, \ + "Cannot allocate RF banks\n"); \ + return -ENOMEM; \ + } \ + } while (0); + + struct ath_common *common = ath9k_hw_common(ah); + + BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + + ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows); + ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows); + ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows); + ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows); + ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows); + ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows); + ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows); + ATH_ALLOC_BANK(ah->addac5416_21, + ah->iniAddac.ia_rows * ah->iniAddac.ia_columns); + ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows); + + return 0; +#undef ATH_ALLOC_BANK +} + + +/** + * ar5008_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers + * @ah: atheros hardware struture + * For the external AR2133/AR5133 radios banks. + */ +static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah) +{ +#define ATH_FREE_BANK(bank) do { \ + kfree(bank); \ + bank = NULL; \ + } while (0); + + BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); + + ATH_FREE_BANK(ah->analogBank0Data); + ATH_FREE_BANK(ah->analogBank1Data); + ATH_FREE_BANK(ah->analogBank2Data); + ATH_FREE_BANK(ah->analogBank3Data); + ATH_FREE_BANK(ah->analogBank6Data); + ATH_FREE_BANK(ah->analogBank6TPCData); + ATH_FREE_BANK(ah->analogBank7Data); + ATH_FREE_BANK(ah->addac5416_21); + ATH_FREE_BANK(ah->bank6Temp); + +#undef ATH_FREE_BANK +} + +/* * + * ar5008_hw_set_rf_regs - programs rf registers based on EEPROM + * @ah: atheros hardware structure + * @chan: + * @modesIndex: + * + * Used for the external AR2133/AR5133 radios. + * + * Reads the EEPROM header info from the device structure and programs + * all rf registers. This routine requires access to the analog + * rf device. This is not required for single-chip devices. + */ +static bool ar5008_hw_set_rf_regs(struct ath_hw *ah, + struct ath9k_channel *chan, + u16 modesIndex) +{ + u32 eepMinorRev; + u32 ob5GHz = 0, db5GHz = 0; + u32 ob2GHz = 0, db2GHz = 0; + int regWrites = 0; + + /* + * Software does not need to program bank data + * for single chip devices, that is AR9280 or anything + * after that. + */ + if (AR_SREV_9280_10_OR_LATER(ah)) + return true; + + /* Setup rf parameters */ + eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); + + /* Setup Bank 0 Write */ + RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); + + /* Setup Bank 1 Write */ + RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); + + /* Setup Bank 2 Write */ + RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); + + /* Setup Bank 6 Write */ + RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, + modesIndex); + { + int i; + for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) { + ah->analogBank6Data[i] = + INI_RA(&ah->iniBank6TPC, i, modesIndex); + } + } + + /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ + if (eepMinorRev >= 2) { + if (IS_CHAN_2GHZ(chan)) { + ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2); + db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2); + ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data, + ob2GHz, 3, 197, 0); + ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data, + db2GHz, 3, 194, 0); + } else { + ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5); + db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5); + ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data, + ob5GHz, 3, 203, 0); + ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data, + db5GHz, 3, 200, 0); + } + } + + /* Setup Bank 7 Setup */ + RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); + + /* Write Analog registers */ + REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, + regWrites); + REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data, + regWrites); + REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data, + regWrites); + REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data, + regWrites); + REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data, + regWrites); + REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data, + regWrites); + + return true; +} + +static void ar5008_hw_init_bb(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 synthDelay; + + synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_B(chan)) + synthDelay = (4 * synthDelay) / 22; + else + synthDelay /= 10; + + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + udelay(synthDelay + BASE_ACTIVATE_DELAY); +} + +static void ar5008_hw_init_chain_masks(struct ath_hw *ah) +{ + int rx_chainmask, tx_chainmask; + + rx_chainmask = ah->rxchainmask; + tx_chainmask = ah->txchainmask; + + ENABLE_REGWRITE_BUFFER(ah); + + switch (rx_chainmask) { + case 0x5: + DISABLE_REGWRITE_BUFFER(ah); + REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, + AR_PHY_SWAP_ALT_CHAIN); + ENABLE_REGWRITE_BUFFER(ah); + case 0x3: + if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) { + REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); + REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); + break; + } + case 0x1: + case 0x2: + case 0x7: + REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); + REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); + break; + default: + break; + } + + REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + + if (tx_chainmask == 0x5) { + REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, + AR_PHY_SWAP_ALT_CHAIN); + } + if (AR_SREV_9100(ah)) + REG_WRITE(ah, AR_PHY_ANALOG_SWAP, + REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001); +} + +static void ar5008_hw_override_ini(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 val; + + /* + * Set the RX_ABORT and RX_DIS and clear if off only after + * RXE is set for MAC. This prevents frames with corrupted + * descriptor status. + */ + REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + + if (AR_SREV_9280_10_OR_LATER(ah)) { + val = REG_READ(ah, AR_PCU_MISC_MODE2); + + if (!AR_SREV_9271(ah)) + val &= ~AR_PCU_MISC_MODE2_HWWAR1; + + if (AR_SREV_9287_10_OR_LATER(ah)) + val = val & (~AR_PCU_MISC_MODE2_HWWAR2); + + REG_WRITE(ah, AR_PCU_MISC_MODE2, val); + } + + if (!AR_SREV_5416_20_OR_LATER(ah) || + AR_SREV_9280_10_OR_LATER(ah)) + return; + /* + * Disable BB clock gating + * Necessary to avoid issues on AR5416 2.0 + */ + REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); + + /* + * Disable RIFS search on some chips to avoid baseband + * hang issues. + */ + if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) { + val = REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS); + val &= ~AR_PHY_RIFS_INIT_DELAY; + REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val); + } +} + +static void ar5008_hw_set_channel_regs(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 phymode; + u32 enableDacFifo = 0; + + if (AR_SREV_9285_10_OR_LATER(ah)) + enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) & + AR_PHY_FC_ENABLE_DAC_FIFO); + + phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 + | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo; + + if (IS_CHAN_HT40(chan)) { + phymode |= AR_PHY_FC_DYN2040_EN; + + if ((chan->chanmode == CHANNEL_A_HT40PLUS) || + (chan->chanmode == CHANNEL_G_HT40PLUS)) + phymode |= AR_PHY_FC_DYN2040_PRI_CH; + + } + REG_WRITE(ah, AR_PHY_TURBO, phymode); + + ath9k_hw_set11nmac2040(ah); + + ENABLE_REGWRITE_BUFFER(ah); + + REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); + REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); +} + + +static int ar5008_hw_process_ini(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + int i, regWrites = 0; + struct ieee80211_channel *channel = chan->chan; + u32 modesIndex, freqIndex; + + switch (chan->chanmode) { + case CHANNEL_A: + case CHANNEL_A_HT20: + modesIndex = 1; + freqIndex = 1; + break; + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + modesIndex = 2; + freqIndex = 1; + break; + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_B: + modesIndex = 4; + freqIndex = 2; + break; + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + modesIndex = 3; + freqIndex = 2; + break; + + default: + return -EINVAL; + } + + if (AR_SREV_9287_12_OR_LATER(ah)) { + /* Enable ASYNC FIFO */ + REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, + AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL); + REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO); + REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, + AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET); + REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, + AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET); + } + + /* + * Set correct baseband to analog shift setting to + * access analog chips. + */ + REG_WRITE(ah, AR_PHY(0), 0x00000007); + + /* Write ADDAC shifts */ + REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); + ah->eep_ops->set_addac(ah, chan); + + if (AR_SREV_5416_22_OR_LATER(ah)) { + REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites); + } else { + struct ar5416IniArray temp; + u32 addacSize = + sizeof(u32) * ah->iniAddac.ia_rows * + ah->iniAddac.ia_columns; + + /* For AR5416 2.0/2.1 */ + memcpy(ah->addac5416_21, + ah->iniAddac.ia_array, addacSize); + + /* override CLKDRV value at [row, column] = [31, 1] */ + (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0; + + temp.ia_array = ah->addac5416_21; + temp.ia_columns = ah->iniAddac.ia_columns; + temp.ia_rows = ah->iniAddac.ia_rows; + REG_WRITE_ARRAY(&temp, 1, regWrites); + } + + REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); + + ENABLE_REGWRITE_BUFFER(ah); + + for (i = 0; i < ah->iniModes.ia_rows; i++) { + u32 reg = INI_RA(&ah->iniModes, i, 0); + u32 val = INI_RA(&ah->iniModes, i, modesIndex); + + if (reg == AR_AN_TOP2 && ah->need_an_top2_fixup) + val &= ~AR_AN_TOP2_PWDCLKIND; + + REG_WRITE(ah, reg, val); + + if (reg >= 0x7800 && reg < 0x78a0 + && ah->config.analog_shiftreg) { + udelay(100); + } + + DO_DELAY(regWrites); + } + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + + if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah)) + REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); + + if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) || + AR_SREV_9287_10_OR_LATER(ah)) + REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); + + if (AR_SREV_9271_10(ah)) + REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only, + modesIndex, regWrites); + + ENABLE_REGWRITE_BUFFER(ah); + + /* Write common array parameters */ + for (i = 0; i < ah->iniCommon.ia_rows; i++) { + u32 reg = INI_RA(&ah->iniCommon, i, 0); + u32 val = INI_RA(&ah->iniCommon, i, 1); + + REG_WRITE(ah, reg, val); + + if (reg >= 0x7800 && reg < 0x78a0 + && ah->config.analog_shiftreg) { + udelay(100); + } + + DO_DELAY(regWrites); + } + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + + if (AR_SREV_9271(ah)) { + if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1) + REG_WRITE_ARRAY(&ah->iniModes_high_power_tx_gain_9271, + modesIndex, regWrites); + else + REG_WRITE_ARRAY(&ah->iniModes_normal_power_tx_gain_9271, + modesIndex, regWrites); + } + + REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); + + if (IS_CHAN_A_FAST_CLOCK(ah, chan)) { + REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, + regWrites); + } + + ar5008_hw_override_ini(ah, chan); + ar5008_hw_set_channel_regs(ah, chan); + ar5008_hw_init_chain_masks(ah); + ath9k_olc_init(ah); + + /* Set TX power */ + ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(regulatory, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) regulatory->power_limit)); + + /* Write analog registers */ + if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "ar5416SetRfRegs failed\n"); + return -EIO; + } + + return 0; +} + +static void ar5008_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan) +{ + u32 rfMode = 0; + + if (chan == NULL) + return; + + rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) + ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; + + if (!AR_SREV_9280_10_OR_LATER(ah)) + rfMode |= (IS_CHAN_5GHZ(chan)) ? + AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; + + if (IS_CHAN_A_FAST_CLOCK(ah, chan)) + rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); + + REG_WRITE(ah, AR_PHY_MODE, rfMode); +} + +static void ar5008_hw_mark_phy_inactive(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); +} + +static void ar5008_hw_set_delta_slope(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 coef_scaled, ds_coef_exp, ds_coef_man; + u32 clockMhzScaled = 0x64000000; + struct chan_centers centers; + + if (IS_CHAN_HALF_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 1; + else if (IS_CHAN_QUARTER_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 2; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + coef_scaled = clockMhzScaled / centers.synth_center; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); + + coef_scaled = (9 * coef_scaled) / 10; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); +} + +static bool ar5008_hw_rfbus_req(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); + return ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, + AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT); +} + +static void ar5008_hw_rfbus_done(struct ath_hw *ah) +{ + u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_B(ah->curchan)) + synthDelay = (4 * synthDelay) / 22; + else + synthDelay /= 10; + + udelay(synthDelay + BASE_ACTIVATE_DELAY); + + REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); +} + +static void ar5008_hw_enable_rfkill(struct ath_hw *ah) +{ + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); + + REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, + AR_GPIO_INPUT_MUX2_RFSILENT); + + ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio); + REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); +} + +static void ar5008_restore_chainmask(struct ath_hw *ah) +{ + int rx_chainmask = ah->rxchainmask; + + if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { + REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); + REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); + } +} + +static void ar5008_set_diversity(struct ath_hw *ah, bool value) +{ + u32 v = REG_READ(ah, AR_PHY_CCK_DETECT); + if (value) + v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + else + v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + REG_WRITE(ah, AR_PHY_CCK_DETECT, v); +} + +static u32 ar9100_hw_compute_pll_control(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + if (chan && IS_CHAN_5GHZ(chan)) + return 0x1450; + return 0x1458; +} + +static u32 ar9160_hw_compute_pll_control(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 pll; + + pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); + + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); + + if (chan && IS_CHAN_5GHZ(chan)) + pll |= SM(0x50, AR_RTC_9160_PLL_DIV); + else + pll |= SM(0x58, AR_RTC_9160_PLL_DIV); + + return pll; +} + +static u32 ar5008_hw_compute_pll_control(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 pll; + + pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; + + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_PLL_CLKSEL); + + if (chan && IS_CHAN_5GHZ(chan)) + pll |= SM(0xa, AR_RTC_PLL_DIV); + else + pll |= SM(0xb, AR_RTC_PLL_DIV); + + return pll; +} + +static bool ar5008_hw_ani_control(struct ath_hw *ah, + enum ath9k_ani_cmd cmd, int param) +{ + struct ar5416AniState *aniState = ah->curani; + struct ath_common *common = ath9k_hw_common(ah); + + switch (cmd & ah->ani_function) { + case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ + u32 level = param; + + if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { + ath_print(common, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned)ARRAY_SIZE(ah->totalSizeDesired)); + return false; + } + + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_TOT_DES, + ah->totalSizeDesired[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_LOW, + ah->coarse_low[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_HIGH, + ah->coarse_high[level]); + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRPWR, + ah->firpwr[level]); + + if (level > aniState->noiseImmunityLevel) + ah->stats.ast_ani_niup++; + else if (level < aniState->noiseImmunityLevel) + ah->stats.ast_ani_nidown++; + aniState->noiseImmunityLevel = level; + break; + } + case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ + const int m1ThreshLow[] = { 127, 50 }; + const int m2ThreshLow[] = { 127, 40 }; + const int m1Thresh[] = { 127, 0x4d }; + const int m2Thresh[] = { 127, 0x40 }; + const int m2CountThr[] = { 31, 16 }; + const int m2CountThrLow[] = { 63, 48 }; + u32 on = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M1_THRESH_LOW, + m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2_THRESH_LOW, + m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M1_THRESH, + m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2_THRESH, + m2Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2COUNT_THR, + m2CountThr[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, + m2CountThrLow[on]); + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH_LOW, + m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH_LOW, + m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH, + m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH, + m2Thresh[on]); + + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + else + REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + + if (!on != aniState->ofdmWeakSigDetectOff) { + if (on) + ah->stats.ast_ani_ofdmon++; + else + ah->stats.ast_ani_ofdmoff++; + aniState->ofdmWeakSigDetectOff = !on; + } + break; + } + case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ + const int weakSigThrCck[] = { 8, 6 }; + u32 high = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, + AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, + weakSigThrCck[high]); + if (high != aniState->cckWeakSigThreshold) { + if (high) + ah->stats.ast_ani_cckhigh++; + else + ah->stats.ast_ani_ccklow++; + aniState->cckWeakSigThreshold = high; + } + break; + } + case ATH9K_ANI_FIRSTEP_LEVEL:{ + const int firstep[] = { 0, 4, 8 }; + u32 level = param; + + if (level >= ARRAY_SIZE(firstep)) { + ath_print(common, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) ARRAY_SIZE(firstep)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRSTEP, + firstep[level]); + if (level > aniState->firstepLevel) + ah->stats.ast_ani_stepup++; + else if (level < aniState->firstepLevel) + ah->stats.ast_ani_stepdown++; + aniState->firstepLevel = level; + break; + } + case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ + const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; + u32 level = param; + + if (level >= ARRAY_SIZE(cycpwrThr1)) { + ath_print(common, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) ARRAY_SIZE(cycpwrThr1)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_TIMING5, + AR_PHY_TIMING5_CYCPWR_THR1, + cycpwrThr1[level]); + if (level > aniState->spurImmunityLevel) + ah->stats.ast_ani_spurup++; + else if (level < aniState->spurImmunityLevel) + ah->stats.ast_ani_spurdown++; + aniState->spurImmunityLevel = level; + break; + } + case ATH9K_ANI_PRESENT: + break; + default: + ath_print(common, ATH_DBG_ANI, + "invalid cmd %u\n", cmd); + return false; + } + + ath_print(common, ATH_DBG_ANI, "ANI parameters:\n"); + ath_print(common, ATH_DBG_ANI, + "noiseImmunityLevel=%d, spurImmunityLevel=%d, " + "ofdmWeakSigDetectOff=%d\n", + aniState->noiseImmunityLevel, + aniState->spurImmunityLevel, + !aniState->ofdmWeakSigDetectOff); + ath_print(common, ATH_DBG_ANI, + "cckWeakSigThreshold=%d, " + "firstepLevel=%d, listenTime=%d\n", + aniState->cckWeakSigThreshold, + aniState->firstepLevel, + aniState->listenTime); + ath_print(common, ATH_DBG_ANI, + "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", + aniState->cycleCount, + aniState->ofdmPhyErrCount, + aniState->cckPhyErrCount); + + return true; +} + +static void ar5008_hw_do_getnf(struct ath_hw *ah, + int16_t nfarray[NUM_NF_READINGS]) +{ + struct ath_common *common = ath9k_hw_common(ah); + int16_t nf; + + nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 0] is %d\n", nf); + nfarray[0] = nf; + + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 1] is %d\n", nf); + nfarray[1] = nf; + + nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 2] is %d\n", nf); + nfarray[2] = nf; + + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 0] is %d\n", nf); + nfarray[3] = nf; + + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 1] is %d\n", nf); + nfarray[4] = nf; + + nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 2] is %d\n", nf); + nfarray[5] = nf; +} + +static void ar5008_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) +{ + struct ath9k_nfcal_hist *h; + int i, j; + int32_t val; + const u32 ar5416_cca_regs[6] = { + AR_PHY_CCA, + AR_PHY_CH1_CCA, + AR_PHY_CH2_CCA, + AR_PHY_EXT_CCA, + AR_PHY_CH1_EXT_CCA, + AR_PHY_CH2_EXT_CCA + }; + u8 chainmask, rx_chain_status; + + rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK); + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + chainmask = 0x9; + else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) { + if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4)) + chainmask = 0x1B; + else + chainmask = 0x09; + } else { + if (rx_chain_status & 0x4) + chainmask = 0x3F; + else if (rx_chain_status & 0x2) + chainmask = 0x1B; + else + chainmask = 0x09; + } + + h = ah->nfCalHist; + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (h[i].privNF) << 1) & 0x1ff); + REG_WRITE(ah, ar5416_cca_regs[i], val); + } + } + + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_ENABLE_NF); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + + for (j = 0; j < 5; j++) { + if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & + AR_PHY_AGC_CONTROL_NF) == 0) + break; + udelay(50); + } + + ENABLE_REGWRITE_BUFFER(ah); + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (-50) << 1) & 0x1ff); + REG_WRITE(ah, ar5416_cca_regs[i], val); + } + } + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); +} + +void ar5008_hw_attach_phy_ops(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + + priv_ops->rf_set_freq = ar5008_hw_set_channel; + priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate; + + priv_ops->rf_alloc_ext_banks = ar5008_hw_rf_alloc_ext_banks; + priv_ops->rf_free_ext_banks = ar5008_hw_rf_free_ext_banks; + priv_ops->set_rf_regs = ar5008_hw_set_rf_regs; + priv_ops->set_channel_regs = ar5008_hw_set_channel_regs; + priv_ops->init_bb = ar5008_hw_init_bb; + priv_ops->process_ini = ar5008_hw_process_ini; + priv_ops->set_rfmode = ar5008_hw_set_rfmode; + priv_ops->mark_phy_inactive = ar5008_hw_mark_phy_inactive; + priv_ops->set_delta_slope = ar5008_hw_set_delta_slope; + priv_ops->rfbus_req = ar5008_hw_rfbus_req; + priv_ops->rfbus_done = ar5008_hw_rfbus_done; + priv_ops->enable_rfkill = ar5008_hw_enable_rfkill; + priv_ops->restore_chainmask = ar5008_restore_chainmask; + priv_ops->set_diversity = ar5008_set_diversity; + priv_ops->ani_control = ar5008_hw_ani_control; + priv_ops->do_getnf = ar5008_hw_do_getnf; + priv_ops->loadnf = ar5008_hw_loadnf; + + if (AR_SREV_9100(ah)) + priv_ops->compute_pll_control = ar9100_hw_compute_pll_control; + else if (AR_SREV_9160_10_OR_LATER(ah)) + priv_ops->compute_pll_control = ar9160_hw_compute_pll_control; + else + priv_ops->compute_pll_control = ar5008_hw_compute_pll_control; +} diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h new file mode 100644 index 00000000000..0b94bd385b0 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h @@ -0,0 +1,1254 @@ + +static const u32 ar5416Common_9100[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00020010, 0x00000003 }, + { 0x00020038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00004000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0x00000000 }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x00008300, 0x00000000 }, + { 0x00008304, 0x00000000 }, + { 0x00008308, 0x00000000 }, + { 0x0000830c, 0x00000000 }, + { 0x00008310, 0x00000000 }, + { 0x00008314, 0x00000000 }, + { 0x00008318, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00000000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xad848e19 }, + { 0x00009810, 0x7d14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x00009840, 0x206a01ae }, + { 0x0000984c, 0x1284233c }, + { 0x00009854, 0x00000859 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x05100000 }, + { 0x0000a920, 0x05100000 }, + { 0x0000b920, 0x05100000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280b212 }, + { 0x0000994c, 0x00020028 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x0000c968, 0x000003ce }, + { 0x00009970, 0x190fb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x006f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000200 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099fc, 0x00001042 }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009b9c, 0x00000033 }, + { 0x00009ba0, 0x00000034 }, + { 0x00009ba4, 0x00000035 }, + { 0x00009ba8, 0x00000035 }, + { 0x00009bac, 0x00000035 }, + { 0x00009bb0, 0x00000035 }, + { 0x00009bb4, 0x00000035 }, + { 0x00009bb8, 0x00000035 }, + { 0x00009bbc, 0x00000035 }, + { 0x00009bc0, 0x00000035 }, + { 0x00009bc4, 0x00000035 }, + { 0x00009bc8, 0x00000035 }, + { 0x00009bcc, 0x00000035 }, + { 0x00009bd0, 0x00000035 }, + { 0x00009bd4, 0x00000035 }, + { 0x00009bd8, 0x00000035 }, + { 0x00009bdc, 0x00000035 }, + { 0x00009be0, 0x00000035 }, + { 0x00009be4, 0x00000035 }, + { 0x00009be8, 0x00000035 }, + { 0x00009bec, 0x00000035 }, + { 0x00009bf0, 0x00000035 }, + { 0x00009bf4, 0x00000035 }, + { 0x00009bf8, 0x00000010 }, + { 0x00009bfc, 0x0000001a }, + { 0x0000a210, 0x40806333 }, + { 0x0000a214, 0x00106c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x018830c6 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x001a0bb5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889ae }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000a000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000001 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000c26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79a8aa33 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, +}; + +static const u32 ar5416Bank0_9100[][2] = { + { 0x000098b0, 0x1e5795e5 }, + { 0x000098e0, 0x02008020 }, +}; + +static const u32 ar5416BB_RfGain_9100[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000040, 0x00000040 }, + { 0x00009a08, 0x00000080, 0x00000080 }, + { 0x00009a0c, 0x000001a1, 0x00000141 }, + { 0x00009a10, 0x000001e1, 0x00000181 }, + { 0x00009a14, 0x00000021, 0x000001c1 }, + { 0x00009a18, 0x00000061, 0x00000001 }, + { 0x00009a1c, 0x00000168, 0x00000041 }, + { 0x00009a20, 0x000001a8, 0x000001a8 }, + { 0x00009a24, 0x000001e8, 0x000001e8 }, + { 0x00009a28, 0x00000028, 0x00000028 }, + { 0x00009a2c, 0x00000068, 0x00000068 }, + { 0x00009a30, 0x00000189, 0x000000a8 }, + { 0x00009a34, 0x000001c9, 0x00000169 }, + { 0x00009a38, 0x00000009, 0x000001a9 }, + { 0x00009a3c, 0x00000049, 0x000001e9 }, + { 0x00009a40, 0x00000089, 0x00000029 }, + { 0x00009a44, 0x00000170, 0x00000069 }, + { 0x00009a48, 0x000001b0, 0x00000190 }, + { 0x00009a4c, 0x000001f0, 0x000001d0 }, + { 0x00009a50, 0x00000030, 0x00000010 }, + { 0x00009a54, 0x00000070, 0x00000050 }, + { 0x00009a58, 0x00000191, 0x00000090 }, + { 0x00009a5c, 0x000001d1, 0x00000151 }, + { 0x00009a60, 0x00000011, 0x00000191 }, + { 0x00009a64, 0x00000051, 0x000001d1 }, + { 0x00009a68, 0x00000091, 0x00000011 }, + { 0x00009a6c, 0x000001b8, 0x00000051 }, + { 0x00009a70, 0x000001f8, 0x00000198 }, + { 0x00009a74, 0x00000038, 0x000001d8 }, + { 0x00009a78, 0x00000078, 0x00000018 }, + { 0x00009a7c, 0x00000199, 0x00000058 }, + { 0x00009a80, 0x000001d9, 0x00000098 }, + { 0x00009a84, 0x00000019, 0x00000159 }, + { 0x00009a88, 0x00000059, 0x00000199 }, + { 0x00009a8c, 0x00000099, 0x000001d9 }, + { 0x00009a90, 0x000000d9, 0x00000019 }, + { 0x00009a94, 0x000000f9, 0x00000059 }, + { 0x00009a98, 0x000000f9, 0x00000099 }, + { 0x00009a9c, 0x000000f9, 0x000000d9 }, + { 0x00009aa0, 0x000000f9, 0x000000f9 }, + { 0x00009aa4, 0x000000f9, 0x000000f9 }, + { 0x00009aa8, 0x000000f9, 0x000000f9 }, + { 0x00009aac, 0x000000f9, 0x000000f9 }, + { 0x00009ab0, 0x000000f9, 0x000000f9 }, + { 0x00009ab4, 0x000000f9, 0x000000f9 }, + { 0x00009ab8, 0x000000f9, 0x000000f9 }, + { 0x00009abc, 0x000000f9, 0x000000f9 }, + { 0x00009ac0, 0x000000f9, 0x000000f9 }, + { 0x00009ac4, 0x000000f9, 0x000000f9 }, + { 0x00009ac8, 0x000000f9, 0x000000f9 }, + { 0x00009acc, 0x000000f9, 0x000000f9 }, + { 0x00009ad0, 0x000000f9, 0x000000f9 }, + { 0x00009ad4, 0x000000f9, 0x000000f9 }, + { 0x00009ad8, 0x000000f9, 0x000000f9 }, + { 0x00009adc, 0x000000f9, 0x000000f9 }, + { 0x00009ae0, 0x000000f9, 0x000000f9 }, + { 0x00009ae4, 0x000000f9, 0x000000f9 }, + { 0x00009ae8, 0x000000f9, 0x000000f9 }, + { 0x00009aec, 0x000000f9, 0x000000f9 }, + { 0x00009af0, 0x000000f9, 0x000000f9 }, + { 0x00009af4, 0x000000f9, 0x000000f9 }, + { 0x00009af8, 0x000000f9, 0x000000f9 }, + { 0x00009afc, 0x000000f9, 0x000000f9 }, +}; + +static const u32 ar5416Bank1_9100[][2] = { + { 0x000098b0, 0x02108421}, + { 0x000098ec, 0x00000008}, +}; + +static const u32 ar5416Bank2_9100[][2] = { + { 0x000098b0, 0x0e73ff17}, + { 0x000098e0, 0x00000420}, +}; + +static const u32 ar5416Bank3_9100[][3] = { + { 0x000098f0, 0x01400018, 0x01c00018 }, +}; + +static const u32 ar5416Bank6_9100[][3] = { + + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x004210a2, 0x004210a2 }, + { 0x0000989c, 0x0014000f, 0x0014000f }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x000180d6, 0x000180d6 }, + { 0x0000989c, 0x0000c0aa, 0x0000c0aa }, + { 0x0000989c, 0x000000b1, 0x000000b1 }, + { 0x0000989c, 0x00002000, 0x00002000 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + + +static const u32 ar5416Bank6TPC_9100[][3] = { + + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x00423022, 0x00423022 }, + { 0x0000989c, 0x2014008f, 0x2014008f }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000e1, 0x000000e1 }, + { 0x0000989c, 0x00007080, 0x00007080 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const u32 ar5416Bank7_9100[][2] = { + { 0x0000989c, 0x00000500 }, + { 0x0000989c, 0x00000800 }, + { 0x000098cc, 0x0000000e }, +}; + +static const u32 ar5416Addac_9100[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000010 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000015 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; + +static const u32 ar5416Modes_9160[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, + { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, + { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 }, + { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, + { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, + { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, + { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, + { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, + { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, + { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce }, + { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 }, + { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, + { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, + { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, + { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, + { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, + { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, + { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, + { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, + { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, + { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, + { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, + { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, + { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, + { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, +}; + +static const u32 ar5416Common_9160[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020015 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00007010, 0x00000020 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x40000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x000080c0, 0x2a82301a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c4, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x00008300, 0x00000000 }, + { 0x00008304, 0x00000000 }, + { 0x00008308, 0x00000000 }, + { 0x0000830c, 0x00000000 }, + { 0x00008310, 0x00000000 }, + { 0x00008314, 0x00000000 }, + { 0x00008318, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000007 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x000107ff }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xad848e19 }, + { 0x00009810, 0x7d14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x00009840, 0x206a01ae }, + { 0x0000984c, 0x1284233c }, + { 0x00009854, 0x00000859 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x05100000 }, + { 0x0000a920, 0x05100000 }, + { 0x0000b920, 0x05100000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009948, 0x9280b212 }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009940, 0x00750604 }, + { 0x0000c95c, 0x004b6a8e }, + { 0x00009970, 0x190fb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x006f0000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000200 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099fc, 0x00001042 }, + { 0x00009b00, 0x00000000 }, + { 0x00009b04, 0x00000001 }, + { 0x00009b08, 0x00000002 }, + { 0x00009b0c, 0x00000003 }, + { 0x00009b10, 0x00000004 }, + { 0x00009b14, 0x00000005 }, + { 0x00009b18, 0x00000008 }, + { 0x00009b1c, 0x00000009 }, + { 0x00009b20, 0x0000000a }, + { 0x00009b24, 0x0000000b }, + { 0x00009b28, 0x0000000c }, + { 0x00009b2c, 0x0000000d }, + { 0x00009b30, 0x00000010 }, + { 0x00009b34, 0x00000011 }, + { 0x00009b38, 0x00000012 }, + { 0x00009b3c, 0x00000013 }, + { 0x00009b40, 0x00000014 }, + { 0x00009b44, 0x00000015 }, + { 0x00009b48, 0x00000018 }, + { 0x00009b4c, 0x00000019 }, + { 0x00009b50, 0x0000001a }, + { 0x00009b54, 0x0000001b }, + { 0x00009b58, 0x0000001c }, + { 0x00009b5c, 0x0000001d }, + { 0x00009b60, 0x00000020 }, + { 0x00009b64, 0x00000021 }, + { 0x00009b68, 0x00000022 }, + { 0x00009b6c, 0x00000023 }, + { 0x00009b70, 0x00000024 }, + { 0x00009b74, 0x00000025 }, + { 0x00009b78, 0x00000028 }, + { 0x00009b7c, 0x00000029 }, + { 0x00009b80, 0x0000002a }, + { 0x00009b84, 0x0000002b }, + { 0x00009b88, 0x0000002c }, + { 0x00009b8c, 0x0000002d }, + { 0x00009b90, 0x00000030 }, + { 0x00009b94, 0x00000031 }, + { 0x00009b98, 0x00000032 }, + { 0x00009b9c, 0x00000033 }, + { 0x00009ba0, 0x00000034 }, + { 0x00009ba4, 0x00000035 }, + { 0x00009ba8, 0x00000035 }, + { 0x00009bac, 0x00000035 }, + { 0x00009bb0, 0x00000035 }, + { 0x00009bb4, 0x00000035 }, + { 0x00009bb8, 0x00000035 }, + { 0x00009bbc, 0x00000035 }, + { 0x00009bc0, 0x00000035 }, + { 0x00009bc4, 0x00000035 }, + { 0x00009bc8, 0x00000035 }, + { 0x00009bcc, 0x00000035 }, + { 0x00009bd0, 0x00000035 }, + { 0x00009bd4, 0x00000035 }, + { 0x00009bd8, 0x00000035 }, + { 0x00009bdc, 0x00000035 }, + { 0x00009be0, 0x00000035 }, + { 0x00009be4, 0x00000035 }, + { 0x00009be8, 0x00000035 }, + { 0x00009bec, 0x00000035 }, + { 0x00009bf0, 0x00000035 }, + { 0x00009bf4, 0x00000035 }, + { 0x00009bf8, 0x00000010 }, + { 0x00009bfc, 0x0000001a }, + { 0x0000a210, 0x40806333 }, + { 0x0000a214, 0x00106c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x018830c6 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x001a0bb5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a23c, 0x13c889af }, + { 0x0000a240, 0x38490a20 }, + { 0x0000a244, 0x00007bb6 }, + { 0x0000a248, 0x0fff3ffc }, + { 0x0000a24c, 0x00000001 }, + { 0x0000a250, 0x0000e000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0cc75380 }, + { 0x0000a25c, 0x0f0f0f01 }, + { 0x0000a260, 0xdfa91f01 }, + { 0x0000a268, 0x00000001 }, + { 0x0000a26c, 0x0ebae9c6 }, + { 0x0000b26c, 0x0ebae9c6 }, + { 0x0000c26c, 0x0ebae9c6 }, + { 0x0000d270, 0x00820820 }, + { 0x0000a278, 0x1ce739ce }, + { 0x0000a27c, 0x050701ce }, + { 0x0000a338, 0x00000000 }, + { 0x0000a33c, 0x00000000 }, + { 0x0000a340, 0x00000000 }, + { 0x0000a344, 0x00000000 }, + { 0x0000a348, 0x3fffffff }, + { 0x0000a34c, 0x3fffffff }, + { 0x0000a350, 0x3fffffff }, + { 0x0000a354, 0x0003ffff }, + { 0x0000a358, 0x79bfaa03 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x1ce739ce }, + { 0x0000a398, 0x000001ce }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3c8, 0x00000246 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x1ce739ce }, + { 0x0000a3e0, 0x000001ce }, +}; + +static const u32 ar5416Bank0_9160[][2] = { + { 0x000098b0, 0x1e5795e5 }, + { 0x000098e0, 0x02008020 }, +}; + +static const u32 ar5416BB_RfGain_9160[][3] = { + { 0x00009a00, 0x00000000, 0x00000000 }, + { 0x00009a04, 0x00000040, 0x00000040 }, + { 0x00009a08, 0x00000080, 0x00000080 }, + { 0x00009a0c, 0x000001a1, 0x00000141 }, + { 0x00009a10, 0x000001e1, 0x00000181 }, + { 0x00009a14, 0x00000021, 0x000001c1 }, + { 0x00009a18, 0x00000061, 0x00000001 }, + { 0x00009a1c, 0x00000168, 0x00000041 }, + { 0x00009a20, 0x000001a8, 0x000001a8 }, + { 0x00009a24, 0x000001e8, 0x000001e8 }, + { 0x00009a28, 0x00000028, 0x00000028 }, + { 0x00009a2c, 0x00000068, 0x00000068 }, + { 0x00009a30, 0x00000189, 0x000000a8 }, + { 0x00009a34, 0x000001c9, 0x00000169 }, + { 0x00009a38, 0x00000009, 0x000001a9 }, + { 0x00009a3c, 0x00000049, 0x000001e9 }, + { 0x00009a40, 0x00000089, 0x00000029 }, + { 0x00009a44, 0x00000170, 0x00000069 }, + { 0x00009a48, 0x000001b0, 0x00000190 }, + { 0x00009a4c, 0x000001f0, 0x000001d0 }, + { 0x00009a50, 0x00000030, 0x00000010 }, + { 0x00009a54, 0x00000070, 0x00000050 }, + { 0x00009a58, 0x00000191, 0x00000090 }, + { 0x00009a5c, 0x000001d1, 0x00000151 }, + { 0x00009a60, 0x00000011, 0x00000191 }, + { 0x00009a64, 0x00000051, 0x000001d1 }, + { 0x00009a68, 0x00000091, 0x00000011 }, + { 0x00009a6c, 0x000001b8, 0x00000051 }, + { 0x00009a70, 0x000001f8, 0x00000198 }, + { 0x00009a74, 0x00000038, 0x000001d8 }, + { 0x00009a78, 0x00000078, 0x00000018 }, + { 0x00009a7c, 0x00000199, 0x00000058 }, + { 0x00009a80, 0x000001d9, 0x00000098 }, + { 0x00009a84, 0x00000019, 0x00000159 }, + { 0x00009a88, 0x00000059, 0x00000199 }, + { 0x00009a8c, 0x00000099, 0x000001d9 }, + { 0x00009a90, 0x000000d9, 0x00000019 }, + { 0x00009a94, 0x000000f9, 0x00000059 }, + { 0x00009a98, 0x000000f9, 0x00000099 }, + { 0x00009a9c, 0x000000f9, 0x000000d9 }, + { 0x00009aa0, 0x000000f9, 0x000000f9 }, + { 0x00009aa4, 0x000000f9, 0x000000f9 }, + { 0x00009aa8, 0x000000f9, 0x000000f9 }, + { 0x00009aac, 0x000000f9, 0x000000f9 }, + { 0x00009ab0, 0x000000f9, 0x000000f9 }, + { 0x00009ab4, 0x000000f9, 0x000000f9 }, + { 0x00009ab8, 0x000000f9, 0x000000f9 }, + { 0x00009abc, 0x000000f9, 0x000000f9 }, + { 0x00009ac0, 0x000000f9, 0x000000f9 }, + { 0x00009ac4, 0x000000f9, 0x000000f9 }, + { 0x00009ac8, 0x000000f9, 0x000000f9 }, + { 0x00009acc, 0x000000f9, 0x000000f9 }, + { 0x00009ad0, 0x000000f9, 0x000000f9 }, + { 0x00009ad4, 0x000000f9, 0x000000f9 }, + { 0x00009ad8, 0x000000f9, 0x000000f9 }, + { 0x00009adc, 0x000000f9, 0x000000f9 }, + { 0x00009ae0, 0x000000f9, 0x000000f9 }, + { 0x00009ae4, 0x000000f9, 0x000000f9 }, + { 0x00009ae8, 0x000000f9, 0x000000f9 }, + { 0x00009aec, 0x000000f9, 0x000000f9 }, + { 0x00009af0, 0x000000f9, 0x000000f9 }, + { 0x00009af4, 0x000000f9, 0x000000f9 }, + { 0x00009af8, 0x000000f9, 0x000000f9 }, + { 0x00009afc, 0x000000f9, 0x000000f9 }, +}; + +static const u32 ar5416Bank1_9160[][2] = { + { 0x000098b0, 0x02108421 }, + { 0x000098ec, 0x00000008 }, +}; + +static const u32 ar5416Bank2_9160[][2] = { + { 0x000098b0, 0x0e73ff17 }, + { 0x000098e0, 0x00000420 }, +}; + +static const u32 ar5416Bank3_9160[][3] = { + { 0x000098f0, 0x01400018, 0x01c00018 }, +}; + +static const u32 ar5416Bank6_9160[][3] = { + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x004210a2, 0x004210a2 }, + { 0x0000989c, 0x0014008f, 0x0014008f }, + { 0x0000989c, 0x00c40003, 0x00c40003 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000f1, 0x000000f1 }, + { 0x0000989c, 0x00002081, 0x00002081 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const u32 ar5416Bank6TPC_9160[][3] = { + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00000000, 0x00000000 }, + { 0x0000989c, 0x00e00000, 0x00e00000 }, + { 0x0000989c, 0x005e0000, 0x005e0000 }, + { 0x0000989c, 0x00120000, 0x00120000 }, + { 0x0000989c, 0x00620000, 0x00620000 }, + { 0x0000989c, 0x00020000, 0x00020000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x40ff0000, 0x40ff0000 }, + { 0x0000989c, 0x005f0000, 0x005f0000 }, + { 0x0000989c, 0x00870000, 0x00870000 }, + { 0x0000989c, 0x00f90000, 0x00f90000 }, + { 0x0000989c, 0x007b0000, 0x007b0000 }, + { 0x0000989c, 0x00ff0000, 0x00ff0000 }, + { 0x0000989c, 0x00f50000, 0x00f50000 }, + { 0x0000989c, 0x00dc0000, 0x00dc0000 }, + { 0x0000989c, 0x00110000, 0x00110000 }, + { 0x0000989c, 0x006100a8, 0x006100a8 }, + { 0x0000989c, 0x00423022, 0x00423022 }, + { 0x0000989c, 0x2014008f, 0x2014008f }, + { 0x0000989c, 0x00c40002, 0x00c40002 }, + { 0x0000989c, 0x003000f2, 0x003000f2 }, + { 0x0000989c, 0x00440016, 0x00440016 }, + { 0x0000989c, 0x00410040, 0x00410040 }, + { 0x0000989c, 0x0001805e, 0x0001805e }, + { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, + { 0x0000989c, 0x000000e1, 0x000000e1 }, + { 0x0000989c, 0x00007080, 0x00007080 }, + { 0x0000989c, 0x000000d4, 0x000000d4 }, + { 0x000098d0, 0x0000000f, 0x0010000f }, +}; + +static const u32 ar5416Bank7_9160[][2] = { + { 0x0000989c, 0x00000500 }, + { 0x0000989c, 0x00000800 }, + { 0x000098cc, 0x0000000e }, +}; + +static const u32 ar5416Addac_9160[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000018 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000019 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000003 }, + {0x0000989c, 0x00000008 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; + +static const u32 ar5416Addac_91601_1[][2] = { + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000018 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x000000c0 }, + {0x0000989c, 0x00000019 }, + {0x0000989c, 0x00000004 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x0000989c, 0x00000000 }, + {0x000098cc, 0x00000000 }, +}; + diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c new file mode 100644 index 00000000000..5fdbb53b47e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -0,0 +1,1000 @@ +/* + * Copyright (c) 2008-2010 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 "hw.h" +#include "hw-ops.h" +#include "ar9002_phy.h" + +#define AR9285_CLCAL_REDO_THRESH 1 + +static void ar9002_hw_setup_calibration(struct ath_hw *ah, + struct ath9k_cal_list *currCal) +{ + struct ath_common *common = ath9k_hw_common(ah); + + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, + currCal->calData->calCountMax); + + switch (currCal->calData->calType) { + case IQ_MISMATCH_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); + ath_print(common, ATH_DBG_CALIBRATE, + "starting IQ Mismatch Calibration\n"); + break; + case ADC_GAIN_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); + ath_print(common, ATH_DBG_CALIBRATE, + "starting ADC Gain Calibration\n"); + break; + case ADC_DC_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); + ath_print(common, ATH_DBG_CALIBRATE, + "starting ADC DC Calibration\n"); + break; + case ADC_DC_INIT_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); + ath_print(common, ATH_DBG_CALIBRATE, + "starting Init ADC DC Calibration\n"); + break; + case TEMP_COMP_CAL: + break; /* Not supported */ + } + + REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_DO_CAL); +} + +static bool ar9002_hw_per_calibration(struct ath_hw *ah, + struct ath9k_channel *ichan, + u8 rxchainmask, + struct ath9k_cal_list *currCal) +{ + bool iscaldone = false; + + if (currCal->calState == CAL_RUNNING) { + if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & + AR_PHY_TIMING_CTRL4_DO_CAL)) { + + currCal->calData->calCollect(ah); + ah->cal_samples++; + + if (ah->cal_samples >= + currCal->calData->calNumSamples) { + int i, numChains = 0; + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (rxchainmask & (1 << i)) + numChains++; + } + + currCal->calData->calPostProc(ah, numChains); + ichan->CalValid |= currCal->calData->calType; + currCal->calState = CAL_DONE; + iscaldone = true; + } else { + ar9002_hw_setup_calibration(ah, currCal); + } + } + } else if (!(ichan->CalValid & currCal->calData->calType)) { + ath9k_hw_reset_calibration(ah, currCal); + } + + return iscaldone; +} + +/* Assumes you are talking about the currently configured channel */ +static bool ar9002_hw_iscal_supported(struct ath_hw *ah, + enum ath9k_cal_types calType) +{ + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; + + switch (calType & ah->supp_cals) { + case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */ + return true; + case ADC_GAIN_CAL: + case ADC_DC_CAL: + if (!(conf->channel->band == IEEE80211_BAND_2GHZ && + conf_is_ht20(conf))) + return true; + break; + } + return false; +} + +static void ar9002_hw_iqcal_collect(struct ath_hw *ah) +{ + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ah->totalPowerMeasI[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ah->totalPowerMeasQ[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ah->totalIqCorrMeas[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + ah->cal_samples, i, ah->totalPowerMeasI[i], + ah->totalPowerMeasQ[i], + ah->totalIqCorrMeas[i]); + } +} + +static void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah) +{ + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ah->totalAdcIOddPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ah->totalAdcIEvenPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ah->totalAdcQOddPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ah->totalAdcQEvenPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ah->cal_samples, i, + ah->totalAdcIOddPhase[i], + ah->totalAdcIEvenPhase[i], + ah->totalAdcQOddPhase[i], + ah->totalAdcQEvenPhase[i]); + } +} + +static void ar9002_hw_adc_dccal_collect(struct ath_hw *ah) +{ + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ah->totalAdcDcOffsetIOddPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ah->totalAdcDcOffsetIEvenPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ah->totalAdcDcOffsetQOddPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ah->totalAdcDcOffsetQEvenPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ah->cal_samples, i, + ah->totalAdcDcOffsetIOddPhase[i], + ah->totalAdcDcOffsetIEvenPhase[i], + ah->totalAdcDcOffsetQOddPhase[i], + ah->totalAdcDcOffsetQEvenPhase[i]); + } +} + +static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) +{ + struct ath_common *common = ath9k_hw_common(ah); + u32 powerMeasQ, powerMeasI, iqCorrMeas; + u32 qCoffDenom, iCoffDenom; + int32_t qCoff, iCoff; + int iqCorrNeg, i; + + for (i = 0; i < numChains; i++) { + powerMeasI = ah->totalPowerMeasI[i]; + powerMeasQ = ah->totalPowerMeasQ[i]; + iqCorrMeas = ah->totalIqCorrMeas[i]; + + ath_print(common, ATH_DBG_CALIBRATE, + "Starting IQ Cal and Correction for Chain %d\n", + i); + + ath_print(common, ATH_DBG_CALIBRATE, + "Orignal: Chn %diq_corr_meas = 0x%08x\n", + i, ah->totalIqCorrMeas[i]); + + iqCorrNeg = 0; + + if (iqCorrMeas > 0x80000000) { + iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; + iqCorrNeg = 1; + } + + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); + ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", + iqCorrNeg); + + iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; + qCoffDenom = powerMeasQ / 64; + + if ((powerMeasQ != 0) && (iCoffDenom != 0) && + (qCoffDenom != 0)) { + iCoff = iqCorrMeas / iCoffDenom; + qCoff = powerMeasI / qCoffDenom - 64; + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d iCoff = 0x%08x\n", i, iCoff); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d qCoff = 0x%08x\n", i, qCoff); + + iCoff = iCoff & 0x3f; + ath_print(common, ATH_DBG_CALIBRATE, + "New: Chn %d iCoff = 0x%08x\n", i, iCoff); + if (iqCorrNeg == 0x0) + iCoff = 0x40 - iCoff; + + if (qCoff > 15) + qCoff = 15; + else if (qCoff <= -16) + qCoff = 16; + + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", + i, iCoff, qCoff); + + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, + iCoff); + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, + qCoff); + ath_print(common, ATH_DBG_CALIBRATE, + "IQ Cal and Correction done for Chain %d\n", + i); + } + } + + REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); +} + +static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) +{ + struct ath_common *common = ath9k_hw_common(ah); + u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; + u32 qGainMismatch, iGainMismatch, val, i; + + for (i = 0; i < numChains; i++) { + iOddMeasOffset = ah->totalAdcIOddPhase[i]; + iEvenMeasOffset = ah->totalAdcIEvenPhase[i]; + qOddMeasOffset = ah->totalAdcQOddPhase[i]; + qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; + + ath_print(common, ATH_DBG_CALIBRATE, + "Starting ADC Gain Cal for Chain %d\n", i); + + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = 0x%08x\n", i, + iOddMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = 0x%08x\n", i, + iEvenMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = 0x%08x\n", i, + qOddMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = 0x%08x\n", i, + qEvenMeasOffset); + + if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { + iGainMismatch = + ((iEvenMeasOffset * 32) / + iOddMeasOffset) & 0x3f; + qGainMismatch = + ((qOddMeasOffset * 32) / + qEvenMeasOffset) & 0x3f; + + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_i = 0x%08x\n", i, + iGainMismatch); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_q = 0x%08x\n", i, + qGainMismatch); + + val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xfffff000; + val |= (qGainMismatch) | (iGainMismatch << 6); + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + ath_print(common, ATH_DBG_CALIBRATE, + "ADC Gain Cal done for Chain %d\n", i); + } + } + + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | + AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); +} + +static void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) +{ + struct ath_common *common = ath9k_hw_common(ah); + u32 iOddMeasOffset, iEvenMeasOffset, val, i; + int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; + const struct ath9k_percal_data *calData = + ah->cal_list_curr->calData; + u32 numSamples = + (1 << (calData->calCountMax + 5)) * calData->calNumSamples; + + for (i = 0; i < numChains; i++) { + iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i]; + iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i]; + qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; + qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; + + ath_print(common, ATH_DBG_CALIBRATE, + "Starting ADC DC Offset Cal for Chain %d\n", i); + + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = %d\n", i, + iOddMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = %d\n", i, + iEvenMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = %d\n", i, + qOddMeasOffset); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = %d\n", i, + qEvenMeasOffset); + + iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / + numSamples) & 0x1ff; + qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / + numSamples) & 0x1ff; + + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, + iDcMismatch); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, + qDcMismatch); + + val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xc0000fff; + val |= (qDcMismatch << 12) | (iDcMismatch << 21); + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + ath_print(common, ATH_DBG_CALIBRATE, + "ADC DC Offset Cal done for Chain %d\n", i); + } + + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | + AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); +} + +static void ar9287_hw_olc_temp_compensation(struct ath_hw *ah) +{ + u32 rddata; + int32_t delta, currPDADC, slope; + + rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); + currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); + + if (ah->initPDADC == 0 || currPDADC == 0) { + /* + * Zero value indicates that no frames have been transmitted + * yet, can't do temperature compensation until frames are + * transmitted. + */ + return; + } else { + slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE); + + if (slope == 0) { /* to avoid divide by zero case */ + delta = 0; + } else { + delta = ((currPDADC - ah->initPDADC)*4) / slope; + } + REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, + AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); + REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, + AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); + } +} + +static void ar9280_hw_olc_temp_compensation(struct ath_hw *ah) +{ + u32 rddata, i; + int delta, currPDADC, regval; + + rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); + currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); + + if (ah->initPDADC == 0 || currPDADC == 0) + return; + + if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) + delta = (currPDADC - ah->initPDADC + 4) / 8; + else + delta = (currPDADC - ah->initPDADC + 5) / 10; + + if (delta != ah->PDADCdelta) { + ah->PDADCdelta = delta; + for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { + regval = ah->originalGain[i] - delta; + if (regval < 0) + regval = 0; + + REG_RMW_FIELD(ah, + AR_PHY_TX_GAIN_TBL1 + i * 4, + AR_PHY_TX_GAIN, regval); + } + } +} + +static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) +{ + u32 regVal; + unsigned int i; + u32 regList[][2] = { + { 0x786c, 0 }, + { 0x7854, 0 }, + { 0x7820, 0 }, + { 0x7824, 0 }, + { 0x7868, 0 }, + { 0x783c, 0 }, + { 0x7838, 0 } , + { 0x7828, 0 } , + }; + + for (i = 0; i < ARRAY_SIZE(regList); i++) + regList[i][1] = REG_READ(ah, regList[i][0]); + + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1)); + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal |= (0x1 << 27); + REG_WRITE(ah, 0x9808, regVal); + + /* 786c,b23,1, pwddac=1 */ + REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); + /* 7854, b5,1, pdrxtxbb=1 */ + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); + /* 7854, b7,1, pdv2i=1 */ + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); + /* 7854, b8,1, pddacinterface=1 */ + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); + /* 7824,b12,0, offcal=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); + /* 7838, b1,0, pwddb=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); + /* 7820,b11,0, enpacal=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); + /* 7820,b25,1, pdpadrv1=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); + /* 7820,b24,0, pdpadrv2=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); + /* 7820,b23,0, pdpaout=0 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); + /* 783c,b14-16,7, padrvgn2tab_0=7 */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); + /* + * 7838,b29-31,0, padrvgn1tab_0=0 + * does not matter since we turn it off + */ + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); + + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff); + + /* Set: + * localmode=1,bmode=1,bmoderxtx=1,synthon=1, + * txon=1,paon=1,oscon=1,synthon_force=1 + */ + REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); + udelay(30); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0); + + /* find off_6_1; */ + for (i = 6; i > 0; i--) { + regVal = REG_READ(ah, 0x7834); + regVal |= (1 << (20 + i)); + REG_WRITE(ah, 0x7834, regVal); + udelay(1); + /* regVal = REG_READ(ah, 0x7834); */ + regVal &= (~(0x1 << (20 + i))); + regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9) + << (20 + i)); + REG_WRITE(ah, 0x7834, regVal); + } + + regVal = (regVal >> 20) & 0x7f; + + /* Update PA cal info */ + if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) { + if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) + ah->pacal_info.max_skipcount = + 2 * ah->pacal_info.max_skipcount; + ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; + } else { + ah->pacal_info.max_skipcount = 1; + ah->pacal_info.skipcount = 0; + ah->pacal_info.prev_offset = regVal; + } + + ENABLE_REGWRITE_BUFFER(ah); + + regVal = REG_READ(ah, 0x7834); + regVal |= 0x1; + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal &= (~(0x1 << 27)); + REG_WRITE(ah, 0x9808, regVal); + + for (i = 0; i < ARRAY_SIZE(regList); i++) + REG_WRITE(ah, regList[i][0], regList[i][1]); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); +} + +static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset) +{ + struct ath_common *common = ath9k_hw_common(ah); + u32 regVal; + int i, offset, offs_6_1, offs_0; + u32 ccomp_org, reg_field; + u32 regList[][2] = { + { 0x786c, 0 }, + { 0x7854, 0 }, + { 0x7820, 0 }, + { 0x7824, 0 }, + { 0x7868, 0 }, + { 0x783c, 0 }, + { 0x7838, 0 }, + }; + + ath_print(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); + + /* PA CAL is not needed for high power solution */ + if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == + AR5416_EEP_TXGAIN_HIGH_POWER) + return; + + if (AR_SREV_9285_11(ah)) { + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); + udelay(10); + } + + for (i = 0; i < ARRAY_SIZE(regList); i++) + regList[i][1] = REG_READ(ah, regList[i][0]); + + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1)); + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal |= (0x1 << 27); + REG_WRITE(ah, 0x9808, regVal); + + REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); + ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf); + + REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); + udelay(30); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); + + for (i = 6; i > 0; i--) { + regVal = REG_READ(ah, 0x7834); + regVal |= (1 << (19 + i)); + REG_WRITE(ah, 0x7834, regVal); + udelay(1); + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1 << (19 + i))); + reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); + regVal |= (reg_field << (19 + i)); + REG_WRITE(ah, 0x7834, regVal); + } + + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); + udelay(1); + reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); + offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); + offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); + + offset = (offs_6_1<<1) | offs_0; + offset = offset - 0; + offs_6_1 = offset>>1; + offs_0 = offset & 1; + + if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) { + if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) + ah->pacal_info.max_skipcount = + 2 * ah->pacal_info.max_skipcount; + ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; + } else { + ah->pacal_info.max_skipcount = 1; + ah->pacal_info.skipcount = 0; + ah->pacal_info.prev_offset = offset; + } + + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); + + regVal = REG_READ(ah, 0x7834); + regVal |= 0x1; + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal &= (~(0x1 << 27)); + REG_WRITE(ah, 0x9808, regVal); + + for (i = 0; i < ARRAY_SIZE(regList); i++) + REG_WRITE(ah, regList[i][0], regList[i][1]); + + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + +} + +static void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset) +{ + if (AR_SREV_9271(ah)) { + if (is_reset || !ah->pacal_info.skipcount) + ar9271_hw_pa_cal(ah, is_reset); + else + ah->pacal_info.skipcount--; + } else if (AR_SREV_9285_11_OR_LATER(ah)) { + if (is_reset || !ah->pacal_info.skipcount) + ar9285_hw_pa_cal(ah, is_reset); + else + ah->pacal_info.skipcount--; + } +} + +static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah) +{ + if (OLC_FOR_AR9287_10_LATER) + ar9287_hw_olc_temp_compensation(ah); + else if (OLC_FOR_AR9280_20_LATER) + ar9280_hw_olc_temp_compensation(ah); +} + +static bool ar9002_hw_calibrate(struct ath_hw *ah, + struct ath9k_channel *chan, + u8 rxchainmask, + bool longcal) +{ + bool iscaldone = true; + struct ath9k_cal_list *currCal = ah->cal_list_curr; + + if (currCal && + (currCal->calState == CAL_RUNNING || + currCal->calState == CAL_WAITING)) { + iscaldone = ar9002_hw_per_calibration(ah, chan, + rxchainmask, currCal); + if (iscaldone) { + ah->cal_list_curr = currCal = currCal->calNext; + + if (currCal->calState == CAL_WAITING) { + iscaldone = false; + ath9k_hw_reset_calibration(ah, currCal); + } + } + } + + /* Do NF cal only at longer intervals */ + if (longcal) { + /* Do periodic PAOffset Cal */ + ar9002_hw_pa_cal(ah, false); + ar9002_hw_olc_temp_compensation(ah); + + /* + * Get the value from the previous NF cal and update + * history buffer. + */ + ath9k_hw_getnf(ah, chan); + + /* + * Load the NF from history buffer of the current channel. + * NF is slow time-variant, so it is OK to use a historical + * value. + */ + ath9k_hw_loadnf(ah, ah->curchan); + + ath9k_hw_start_nfcal(ah); + } + + return iscaldone; +} + +/* Carrier leakage Calibration fix */ +static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan) +{ + struct ath_common *common = ath9k_hw_common(ah); + + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + if (IS_CHAN_HT20(chan)) { + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { + ath_print(common, ATH_DBG_CALIBRATE, "offset " + "calibration failed to complete in " + "1ms; noisy ??\n"); + return false; + } + REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + } + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT)) { + ath_print(common, ATH_DBG_CALIBRATE, "offset calibration " + "failed to complete in 1ms; noisy ??\n"); + return false; + } + + REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + + return true; +} + +static bool ar9285_hw_clc(struct ath_hw *ah, struct ath9k_channel *chan) +{ + int i; + u_int32_t txgain_max; + u_int32_t clc_gain, gain_mask = 0, clc_num = 0; + u_int32_t reg_clc_I0, reg_clc_Q0; + u_int32_t i0_num = 0; + u_int32_t q0_num = 0; + u_int32_t total_num = 0; + u_int32_t reg_rf2g5_org; + bool retv = true; + + if (!(ar9285_hw_cl_cal(ah, chan))) + return false; + + txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7), + AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX); + + for (i = 0; i < (txgain_max+1); i++) { + clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) & + AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S; + if (!(gain_mask & (1 << clc_gain))) { + gain_mask |= (1 << clc_gain); + clc_num++; + } + } + + for (i = 0; i < clc_num; i++) { + reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) + & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S; + reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) + & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S; + if (reg_clc_I0 == 0) + i0_num++; + + if (reg_clc_Q0 == 0) + q0_num++; + } + total_num = i0_num + q0_num; + if (total_num > AR9285_CLCAL_REDO_THRESH) { + reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5); + if (AR_SREV_9285E_20(ah)) { + REG_WRITE(ah, AR9285_RF2G5, + (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | + AR9285_RF2G5_IC50TX_XE_SET); + } else { + REG_WRITE(ah, AR9285_RF2G5, + (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | + AR9285_RF2G5_IC50TX_SET); + } + retv = ar9285_hw_cl_cal(ah, chan); + REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org); + } + return retv; +} + +static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) { + if (!ar9285_hw_clc(ah, chan)) + return false; + } else { + if (AR_SREV_9280_10_OR_LATER(ah)) { + if (!AR_SREV_9287_10_OR_LATER(ah)) + REG_CLR_BIT(ah, AR_PHY_ADC_CTL, + AR_PHY_ADC_CTL_OFF_PWDADC); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); + } + + /* Calibrate the AGC */ + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); + + /* Poll for offset calibration complete */ + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT)) { + ath_print(common, ATH_DBG_CALIBRATE, + "offset calibration failed to " + "complete in 1ms; noisy environment?\n"); + return false; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + if (!AR_SREV_9287_10_OR_LATER(ah)) + REG_SET_BIT(ah, AR_PHY_ADC_CTL, + AR_PHY_ADC_CTL_OFF_PWDADC); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); + } + } + + /* Do PA Calibration */ + ar9002_hw_pa_cal(ah, true); + + /* Do NF Calibration after DC offset and other calibrations */ + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); + + ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; + + /* Enable IQ, ADC Gain and ADC DC offset CALs */ + if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { + if (ar9002_hw_iscal_supported(ah, ADC_GAIN_CAL)) { + INIT_CAL(&ah->adcgain_caldata); + INSERT_CAL(ah, &ah->adcgain_caldata); + ath_print(common, ATH_DBG_CALIBRATE, + "enabling ADC Gain Calibration.\n"); + } + if (ar9002_hw_iscal_supported(ah, ADC_DC_CAL)) { + INIT_CAL(&ah->adcdc_caldata); + INSERT_CAL(ah, &ah->adcdc_caldata); + ath_print(common, ATH_DBG_CALIBRATE, + "enabling ADC DC Calibration.\n"); + } + if (ar9002_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); + ath_print(common, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); + } + + ah->cal_list_curr = ah->cal_list; + + if (ah->cal_list_curr) + ath9k_hw_reset_calibration(ah, ah->cal_list_curr); + } + + chan->CalValid = 0; + + return true; +} + +static const struct ath9k_percal_data iq_cal_multi_sample = { + IQ_MISMATCH_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ar9002_hw_iqcal_collect, + ar9002_hw_iqcalibrate +}; +static const struct ath9k_percal_data iq_cal_single_sample = { + IQ_MISMATCH_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ar9002_hw_iqcal_collect, + ar9002_hw_iqcalibrate +}; +static const struct ath9k_percal_data adc_gain_cal_multi_sample = { + ADC_GAIN_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ar9002_hw_adc_gaincal_collect, + ar9002_hw_adc_gaincal_calibrate +}; +static const struct ath9k_percal_data adc_gain_cal_single_sample = { + ADC_GAIN_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ar9002_hw_adc_gaincal_collect, + ar9002_hw_adc_gaincal_calibrate +}; +static const struct ath9k_percal_data adc_dc_cal_multi_sample = { + ADC_DC_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ar9002_hw_adc_dccal_collect, + ar9002_hw_adc_dccal_calibrate +}; +static const struct ath9k_percal_data adc_dc_cal_single_sample = { + ADC_DC_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ar9002_hw_adc_dccal_collect, + ar9002_hw_adc_dccal_calibrate +}; +static const struct ath9k_percal_data adc_init_dc_cal = { + ADC_DC_INIT_CAL, + MIN_CAL_SAMPLES, + INIT_LOG_COUNT, + ar9002_hw_adc_dccal_collect, + ar9002_hw_adc_dccal_calibrate +}; + +static void ar9002_hw_init_cal_settings(struct ath_hw *ah) +{ + if (AR_SREV_9100(ah)) { + ah->iq_caldata.calData = &iq_cal_multi_sample; + ah->supp_cals = IQ_MISMATCH_CAL; + return; + } + + if (AR_SREV_9160_10_OR_LATER(ah)) { + if (AR_SREV_9280_10_OR_LATER(ah)) { + ah->iq_caldata.calData = &iq_cal_single_sample; + ah->adcgain_caldata.calData = + &adc_gain_cal_single_sample; + ah->adcdc_caldata.calData = + &adc_dc_cal_single_sample; + ah->adcdc_calinitdata.calData = + &adc_init_dc_cal; + } else { + ah->iq_caldata.calData = &iq_cal_multi_sample; + ah->adcgain_caldata.calData = + &adc_gain_cal_multi_sample; + ah->adcdc_caldata.calData = + &adc_dc_cal_multi_sample; + ah->adcdc_calinitdata.calData = + &adc_init_dc_cal; + } + ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; + } +} + +void ar9002_hw_attach_calib_ops(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + struct ath_hw_ops *ops = ath9k_hw_ops(ah); + + priv_ops->init_cal_settings = ar9002_hw_init_cal_settings; + priv_ops->init_cal = ar9002_hw_init_cal; + priv_ops->setup_calibration = ar9002_hw_setup_calibration; + priv_ops->iscal_supported = ar9002_hw_iscal_supported; + + ops->calibrate = ar9002_hw_calibrate; +} diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c new file mode 100644 index 00000000000..a8a8cdc04af --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -0,0 +1,598 @@ +/* + * Copyright (c) 2008-2010 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 "hw.h" +#include "ar5008_initvals.h" +#include "ar9001_initvals.h" +#include "ar9002_initvals.h" + +/* General hardware code for the A5008/AR9001/AR9002 hadware families */ + +static bool ar9002_hw_macversion_supported(u32 macversion) +{ + switch (macversion) { + case AR_SREV_VERSION_5416_PCI: + case AR_SREV_VERSION_5416_PCIE: + case AR_SREV_VERSION_9160: + case AR_SREV_VERSION_9100: + case AR_SREV_VERSION_9280: + case AR_SREV_VERSION_9285: + case AR_SREV_VERSION_9287: + case AR_SREV_VERSION_9271: + return true; + default: + break; + } + return false; +} + +static void ar9002_hw_init_mode_regs(struct ath_hw *ah) +{ + if (AR_SREV_9271(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271, + ARRAY_SIZE(ar9271Modes_9271), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271, + ARRAY_SIZE(ar9271Common_9271), 2); + INIT_INI_ARRAY(&ah->iniCommon_normal_cck_fir_coeff_9271, + ar9271Common_normal_cck_fir_coeff_9271, + ARRAY_SIZE(ar9271Common_normal_cck_fir_coeff_9271), 2); + INIT_INI_ARRAY(&ah->iniCommon_japan_2484_cck_fir_coeff_9271, + ar9271Common_japan_2484_cck_fir_coeff_9271, + ARRAY_SIZE(ar9271Common_japan_2484_cck_fir_coeff_9271), 2); + INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only, + ar9271Modes_9271_1_0_only, + ARRAY_SIZE(ar9271Modes_9271_1_0_only), 6); + INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg, + ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 6); + INIT_INI_ARRAY(&ah->iniModes_high_power_tx_gain_9271, + ar9271Modes_high_power_tx_gain_9271, + ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 6); + INIT_INI_ARRAY(&ah->iniModes_normal_power_tx_gain_9271, + ar9271Modes_normal_power_tx_gain_9271, + ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 6); + return; + } + + if (AR_SREV_9287_11_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, + ARRAY_SIZE(ar9287Modes_9287_1_1), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1, + ARRAY_SIZE(ar9287Common_9287_1_1), 2); + if (ah->config.pcie_clock_req) + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_off_L1_9287_1_1, + ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2); + else + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_always_on_L1_9287_1_1, + ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1), + 2); + } else if (AR_SREV_9287_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0, + ARRAY_SIZE(ar9287Modes_9287_1_0), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0, + ARRAY_SIZE(ar9287Common_9287_1_0), 2); + + if (ah->config.pcie_clock_req) + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_off_L1_9287_1_0, + ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2); + else + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9287PciePhy_clkreq_always_on_L1_9287_1_0, + ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0), + 2); + } else if (AR_SREV_9285_12_OR_LATER(ah)) { + + + INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, + ARRAY_SIZE(ar9285Modes_9285_1_2), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2, + ARRAY_SIZE(ar9285Common_9285_1_2), 2); + + if (ah->config.pcie_clock_req) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9285PciePhy_clkreq_off_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2); + } else { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9285PciePhy_clkreq_always_on_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2), + 2); + } + } else if (AR_SREV_9285_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285, + ARRAY_SIZE(ar9285Modes_9285), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285, + ARRAY_SIZE(ar9285Common_9285), 2); + + if (ah->config.pcie_clock_req) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9285PciePhy_clkreq_off_L1_9285, + ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2); + } else { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9285PciePhy_clkreq_always_on_L1_9285, + ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2); + } + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2, + ARRAY_SIZE(ar9280Modes_9280_2), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2, + ARRAY_SIZE(ar9280Common_9280_2), 2); + + if (ah->config.pcie_clock_req) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9280PciePhy_clkreq_off_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2); + } else { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9280PciePhy_clkreq_always_on_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); + } + INIT_INI_ARRAY(&ah->iniModesAdditional, + ar9280Modes_fast_clock_9280_2, + ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); + } else if (AR_SREV_9280_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280, + ARRAY_SIZE(ar9280Modes_9280), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280, + ARRAY_SIZE(ar9280Common_9280), 2); + } else if (AR_SREV_9160_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160, + ARRAY_SIZE(ar5416Modes_9160), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160, + ARRAY_SIZE(ar5416Common_9160), 2); + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160, + ARRAY_SIZE(ar5416Bank0_9160), 2); + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160, + ARRAY_SIZE(ar5416BB_RfGain_9160), 3); + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160, + ARRAY_SIZE(ar5416Bank1_9160), 2); + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160, + ARRAY_SIZE(ar5416Bank2_9160), 2); + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160, + ARRAY_SIZE(ar5416Bank3_9160), 3); + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160, + ARRAY_SIZE(ar5416Bank6_9160), 3); + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160, + ARRAY_SIZE(ar5416Bank6TPC_9160), 3); + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160, + ARRAY_SIZE(ar5416Bank7_9160), 2); + if (AR_SREV_9160_11(ah)) { + INIT_INI_ARRAY(&ah->iniAddac, + ar5416Addac_91601_1, + ARRAY_SIZE(ar5416Addac_91601_1), 2); + } else { + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160, + ARRAY_SIZE(ar5416Addac_9160), 2); + } + } else if (AR_SREV_9100_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100, + ARRAY_SIZE(ar5416Modes_9100), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100, + ARRAY_SIZE(ar5416Common_9100), 2); + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100, + ARRAY_SIZE(ar5416Bank0_9100), 2); + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100, + ARRAY_SIZE(ar5416BB_RfGain_9100), 3); + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100, + ARRAY_SIZE(ar5416Bank1_9100), 2); + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100, + ARRAY_SIZE(ar5416Bank2_9100), 2); + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100, + ARRAY_SIZE(ar5416Bank3_9100), 3); + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100, + ARRAY_SIZE(ar5416Bank6_9100), 3); + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100, + ARRAY_SIZE(ar5416Bank6TPC_9100), 3); + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100, + ARRAY_SIZE(ar5416Bank7_9100), 2); + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100, + ARRAY_SIZE(ar5416Addac_9100), 2); + } else { + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes, + ARRAY_SIZE(ar5416Modes), 6); + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common, + ARRAY_SIZE(ar5416Common), 2); + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0, + ARRAY_SIZE(ar5416Bank0), 2); + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain, + ARRAY_SIZE(ar5416BB_RfGain), 3); + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1, + ARRAY_SIZE(ar5416Bank1), 2); + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2, + ARRAY_SIZE(ar5416Bank2), 2); + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3, + ARRAY_SIZE(ar5416Bank3), 3); + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6, + ARRAY_SIZE(ar5416Bank6), 3); + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC, + ARRAY_SIZE(ar5416Bank6TPC), 3); + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7, + ARRAY_SIZE(ar5416Bank7), 2); + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, + ARRAY_SIZE(ar5416Addac), 2); + } +} + +/* Support for Japan ch.14 (2484) spread */ +void ar9002_hw_cck_chan14_spread(struct ath_hw *ah) +{ + if (AR_SREV_9287_11_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniCckfirNormal, + ar9287Common_normal_cck_fir_coeff_92871_1, + ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_92871_1), + 2); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9287Common_japan_2484_cck_fir_coeff_92871_1, + ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_92871_1), + 2); + } +} + +static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah) +{ + u32 rxgain_type; + + if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= + AR5416_EEP_MINOR_VER_17) { + rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE); + + if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9280Modes_backoff_13db_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6); + else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9280Modes_backoff_23db_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6); + else + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9280Modes_original_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); + } else { + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9280Modes_original_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); + } +} + +static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah) +{ + u32 txgain_type; + + if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= + AR5416_EEP_MINOR_VER_19) { + txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); + + if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9280Modes_high_power_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9280Modes_original_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); + } else { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9280Modes_original_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); + } +} + +static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) +{ + if (AR_SREV_9287_11_OR_LATER(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9287Modes_rx_gain_9287_1_1, + ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6); + else if (AR_SREV_9287_10(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9287Modes_rx_gain_9287_1_0, + ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6); + else if (AR_SREV_9280_20(ah)) + ar9280_20_hw_init_rxgain_ini(ah); + + if (AR_SREV_9287_11_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9287Modes_tx_gain_9287_1_1, + ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6); + } else if (AR_SREV_9287_10(ah)) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9287Modes_tx_gain_9287_1_0, + ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6); + } else if (AR_SREV_9280_20(ah)) { + ar9280_20_hw_init_txgain_ini(ah); + } else if (AR_SREV_9285_12_OR_LATER(ah)) { + u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); + + /* txgain table */ + if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) { + if (AR_SREV_9285E_20(ah)) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_XE2_0_high_power, + ARRAY_SIZE( + ar9285Modes_XE2_0_high_power), 6); + } else { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_high_power_tx_gain_9285_1_2, + ARRAY_SIZE( + ar9285Modes_high_power_tx_gain_9285_1_2), 6); + } + } else { + if (AR_SREV_9285E_20(ah)) { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_XE2_0_normal_power, + ARRAY_SIZE( + ar9285Modes_XE2_0_normal_power), 6); + } else { + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9285Modes_original_tx_gain_9285_1_2, + ARRAY_SIZE( + ar9285Modes_original_tx_gain_9285_1_2), 6); + } + } + } +} + +/* + * Helper for ASPM support. + * + * Disable PLL when in L0s as well as receiver clock when in L1. + * This power saving option must be enabled through the SerDes. + * + * Programming the SerDes must go through the same 288 bit serial shift + * register as the other analog registers. Hence the 9 writes. + */ +static void ar9002_hw_configpcipowersave(struct ath_hw *ah, + int restore, + int power_off) +{ + u8 i; + u32 val; + + if (ah->is_pciexpress != true) + return; + + /* Do not touch SerDes registers */ + if (ah->config.pcie_powersave_enable == 2) + return; + + /* Nothing to do on restore for 11N */ + if (!restore) { + if (AR_SREV_9280_20_OR_LATER(ah)) { + /* + * AR9280 2.0 or later chips use SerDes values from the + * initvals.h initialized depending on chipset during + * __ath9k_hw_init() + */ + for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) { + REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0), + INI_RA(&ah->iniPcieSerdes, i, 1)); + } + } else if (AR_SREV_9280(ah) && + (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) { + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + + /* RX shut off when elecidle is asserted */ + REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); + REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); + REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); + + /* Shut off CLKREQ active in L1 */ + if (ah->config.pcie_clock_req) + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); + else + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); + + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); + + /* Load the new settings */ + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); + + } else { + ENABLE_REGWRITE_BUFFER(ah); + + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + + /* RX shut off when elecidle is asserted */ + REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); + REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); + REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); + + /* + * Ignore ah->ah_config.pcie_clock_req setting for + * pre-AR9280 11n + */ + REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); + + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); + + /* Load the new settings */ + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + } + + udelay(1000); + + /* set bit 19 to allow forcing of pcie core into L1 state */ + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); + + /* Several PCIe massages to ensure proper behaviour */ + if (ah->config.pcie_waen) { + val = ah->config.pcie_waen; + if (!power_off) + val &= (~AR_WA_D3_L1_DISABLE); + } else { + if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || + AR_SREV_9287(ah)) { + val = AR9285_WA_DEFAULT; + if (!power_off) + val &= (~AR_WA_D3_L1_DISABLE); + } else if (AR_SREV_9280(ah)) { + /* + * On AR9280 chips bit 22 of 0x4004 needs to be + * set otherwise card may disappear. + */ + val = AR9280_WA_DEFAULT; + if (!power_off) + val &= (~AR_WA_D3_L1_DISABLE); + } else + val = AR_WA_DEFAULT; + } + + REG_WRITE(ah, AR_WA, val); + } + + if (power_off) { + /* + * Set PCIe workaround bits + * bit 14 in WA register (disable L1) should only + * be set when device enters D3 and be cleared + * when device comes back to D0. + */ + if (ah->config.pcie_waen) { + if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE) + REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE); + } else { + if (((AR_SREV_9285(ah) || AR_SREV_9271(ah) || + AR_SREV_9287(ah)) && + (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) || + (AR_SREV_9280(ah) && + (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) { + REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE); + } + } + } +} + +static int ar9002_hw_get_radiorev(struct ath_hw *ah) +{ + u32 val; + int i; + + ENABLE_REGWRITE_BUFFER(ah); + + REG_WRITE(ah, AR_PHY(0x36), 0x00007058); + for (i = 0; i < 8; i++) + REG_WRITE(ah, AR_PHY(0x20), 0x00010000); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + + val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; + val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); + + return ath9k_hw_reverse_bits(val, 8); +} + +int ar9002_hw_rf_claim(struct ath_hw *ah) +{ + u32 val; + + REG_WRITE(ah, AR_PHY(0), 0x00000007); + + val = ar9002_hw_get_radiorev(ah); + switch (val & AR_RADIO_SREV_MAJOR) { + case 0: + val = AR_RAD5133_SREV_MAJOR; + break; + case AR_RAD5133_SREV_MAJOR: + case AR_RAD5122_SREV_MAJOR: + case AR_RAD2133_SREV_MAJOR: + case AR_RAD2122_SREV_MAJOR: + break; + default: + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "Radio Chip Rev 0x%02X not supported\n", + val & AR_RADIO_SREV_MAJOR); + return -EOPNOTSUPP; + } + + ah->hw_version.analog5GhzRev = val; + + return 0; +} + +/* + * Enable ASYNC FIFO + * + * If Async FIFO is enabled, the following counters change as MAC now runs + * at 117 Mhz instead of 88/44MHz when async FIFO is disabled. + * + * The values below tested for ht40 2 chain. + * Overwrite the delay/timeouts initialized in process ini. + */ +void ar9002_hw_enable_async_fifo(struct ath_hw *ah) +{ + if (AR_SREV_9287_12_OR_LATER(ah)) { + REG_WRITE(ah, AR_D_GBL_IFS_SIFS, + AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR); + REG_WRITE(ah, AR_D_GBL_IFS_SLOT, + AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR); + REG_WRITE(ah, AR_D_GBL_IFS_EIFS, + AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR); + + REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR); + REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR); + + REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER, + AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768); + REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN, + AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL); + } +} + +/* + * We don't enable WEP aggregation on mac80211 but we keep this + * around for HAL unification purposes. + */ +void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah) +{ + if (AR_SREV_9287_12_OR_LATER(ah)) { + REG_SET_BIT(ah, AR_PCU_MISC_MODE2, + AR_PCU_MISC_MODE2_ENABLE_AGGWEP); + } +} + +/* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */ +void ar9002_hw_attach_ops(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + struct ath_hw_ops *ops = ath9k_hw_ops(ah); + + priv_ops->init_mode_regs = ar9002_hw_init_mode_regs; + priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs; + priv_ops->macversion_supported = ar9002_hw_macversion_supported; + + ops->config_pci_powersave = ar9002_hw_configpcipowersave; + + ar5008_hw_attach_phy_ops(ah); + if (AR_SREV_9280_10_OR_LATER(ah)) + ar9002_hw_attach_phy_ops(ah); + + ar9002_hw_attach_calib_ops(ah); + ar9002_hw_attach_mac_ops(ah); +} diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h index 8a3bf3ab998..dae7f3304eb 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2009 Atheros Communications Inc. + * Copyright (c) 2010 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 @@ -14,1982 +14,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -static const u32 ar5416Modes[][6] = { - { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, - { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, - { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, - { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, - { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, - { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, - { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 }, - { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a }, - { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, - { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, - { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 }, - { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de }, - { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e }, - { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 }, - { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, - { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, - { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, - { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 }, - { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b }, - { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, - { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, - { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, - { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, - { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 }, - { 0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 }, - { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, - { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c }, - { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, - { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, - { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, - { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, - { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, - { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, - { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, - { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, - { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, - { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, - { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, - { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, - { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, - { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, - { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, - { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, - { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, -}; - -static const u32 ar5416Common[][2] = { - { 0x0000000c, 0x00000000 }, - { 0x00000030, 0x00020015 }, - { 0x00000034, 0x00000005 }, - { 0x00000040, 0x00000000 }, - { 0x00000044, 0x00000008 }, - { 0x00000048, 0x00000008 }, - { 0x0000004c, 0x00000010 }, - { 0x00000050, 0x00000000 }, - { 0x00000054, 0x0000001f }, - { 0x00000800, 0x00000000 }, - { 0x00000804, 0x00000000 }, - { 0x00000808, 0x00000000 }, - { 0x0000080c, 0x00000000 }, - { 0x00000810, 0x00000000 }, - { 0x00000814, 0x00000000 }, - { 0x00000818, 0x00000000 }, - { 0x0000081c, 0x00000000 }, - { 0x00000820, 0x00000000 }, - { 0x00000824, 0x00000000 }, - { 0x00001040, 0x002ffc0f }, - { 0x00001044, 0x002ffc0f }, - { 0x00001048, 0x002ffc0f }, - { 0x0000104c, 0x002ffc0f }, - { 0x00001050, 0x002ffc0f }, - { 0x00001054, 0x002ffc0f }, - { 0x00001058, 0x002ffc0f }, - { 0x0000105c, 0x002ffc0f }, - { 0x00001060, 0x002ffc0f }, - { 0x00001064, 0x002ffc0f }, - { 0x00001230, 0x00000000 }, - { 0x00001270, 0x00000000 }, - { 0x00001038, 0x00000000 }, - { 0x00001078, 0x00000000 }, - { 0x000010b8, 0x00000000 }, - { 0x000010f8, 0x00000000 }, - { 0x00001138, 0x00000000 }, - { 0x00001178, 0x00000000 }, - { 0x000011b8, 0x00000000 }, - { 0x000011f8, 0x00000000 }, - { 0x00001238, 0x00000000 }, - { 0x00001278, 0x00000000 }, - { 0x000012b8, 0x00000000 }, - { 0x000012f8, 0x00000000 }, - { 0x00001338, 0x00000000 }, - { 0x00001378, 0x00000000 }, - { 0x000013b8, 0x00000000 }, - { 0x000013f8, 0x00000000 }, - { 0x00001438, 0x00000000 }, - { 0x00001478, 0x00000000 }, - { 0x000014b8, 0x00000000 }, - { 0x000014f8, 0x00000000 }, - { 0x00001538, 0x00000000 }, - { 0x00001578, 0x00000000 }, - { 0x000015b8, 0x00000000 }, - { 0x000015f8, 0x00000000 }, - { 0x00001638, 0x00000000 }, - { 0x00001678, 0x00000000 }, - { 0x000016b8, 0x00000000 }, - { 0x000016f8, 0x00000000 }, - { 0x00001738, 0x00000000 }, - { 0x00001778, 0x00000000 }, - { 0x000017b8, 0x00000000 }, - { 0x000017f8, 0x00000000 }, - { 0x0000103c, 0x00000000 }, - { 0x0000107c, 0x00000000 }, - { 0x000010bc, 0x00000000 }, - { 0x000010fc, 0x00000000 }, - { 0x0000113c, 0x00000000 }, - { 0x0000117c, 0x00000000 }, - { 0x000011bc, 0x00000000 }, - { 0x000011fc, 0x00000000 }, - { 0x0000123c, 0x00000000 }, - { 0x0000127c, 0x00000000 }, - { 0x000012bc, 0x00000000 }, - { 0x000012fc, 0x00000000 }, - { 0x0000133c, 0x00000000 }, - { 0x0000137c, 0x00000000 }, - { 0x000013bc, 0x00000000 }, - { 0x000013fc, 0x00000000 }, - { 0x0000143c, 0x00000000 }, - { 0x0000147c, 0x00000000 }, - { 0x00004030, 0x00000002 }, - { 0x0000403c, 0x00000002 }, - { 0x00007010, 0x00000000 }, - { 0x00007038, 0x000004c2 }, - { 0x00008004, 0x00000000 }, - { 0x00008008, 0x00000000 }, - { 0x0000800c, 0x00000000 }, - { 0x00008018, 0x00000700 }, - { 0x00008020, 0x00000000 }, - { 0x00008038, 0x00000000 }, - { 0x0000803c, 0x00000000 }, - { 0x00008048, 0x40000000 }, - { 0x00008054, 0x00000000 }, - { 0x00008058, 0x00000000 }, - { 0x0000805c, 0x000fc78f }, - { 0x00008060, 0x0000000f }, - { 0x00008064, 0x00000000 }, - { 0x000080c0, 0x2a82301a }, - { 0x000080c4, 0x05dc01e0 }, - { 0x000080c8, 0x1f402710 }, - { 0x000080cc, 0x01f40000 }, - { 0x000080d0, 0x00001e00 }, - { 0x000080d4, 0x00000000 }, - { 0x000080d8, 0x00400000 }, - { 0x000080e0, 0xffffffff }, - { 0x000080e4, 0x0000ffff }, - { 0x000080e8, 0x003f3f3f }, - { 0x000080ec, 0x00000000 }, - { 0x000080f0, 0x00000000 }, - { 0x000080f4, 0x00000000 }, - { 0x000080f8, 0x00000000 }, - { 0x000080fc, 0x00020000 }, - { 0x00008100, 0x00020000 }, - { 0x00008104, 0x00000001 }, - { 0x00008108, 0x00000052 }, - { 0x0000810c, 0x00000000 }, - { 0x00008110, 0x00000168 }, - { 0x00008118, 0x000100aa }, - { 0x0000811c, 0x00003210 }, - { 0x00008124, 0x00000000 }, - { 0x00008128, 0x00000000 }, - { 0x0000812c, 0x00000000 }, - { 0x00008130, 0x00000000 }, - { 0x00008134, 0x00000000 }, - { 0x00008138, 0x00000000 }, - { 0x0000813c, 0x00000000 }, - { 0x00008144, 0xffffffff }, - { 0x00008168, 0x00000000 }, - { 0x0000816c, 0x00000000 }, - { 0x00008170, 0x32143320 }, - { 0x00008174, 0xfaa4fa50 }, - { 0x00008178, 0x00000100 }, - { 0x0000817c, 0x00000000 }, - { 0x000081c4, 0x00000000 }, - { 0x000081ec, 0x00000000 }, - { 0x000081f0, 0x00000000 }, - { 0x000081f4, 0x00000000 }, - { 0x000081f8, 0x00000000 }, - { 0x000081fc, 0x00000000 }, - { 0x00008200, 0x00000000 }, - { 0x00008204, 0x00000000 }, - { 0x00008208, 0x00000000 }, - { 0x0000820c, 0x00000000 }, - { 0x00008210, 0x00000000 }, - { 0x00008214, 0x00000000 }, - { 0x00008218, 0x00000000 }, - { 0x0000821c, 0x00000000 }, - { 0x00008220, 0x00000000 }, - { 0x00008224, 0x00000000 }, - { 0x00008228, 0x00000000 }, - { 0x0000822c, 0x00000000 }, - { 0x00008230, 0x00000000 }, - { 0x00008234, 0x00000000 }, - { 0x00008238, 0x00000000 }, - { 0x0000823c, 0x00000000 }, - { 0x00008240, 0x00100000 }, - { 0x00008244, 0x0010f400 }, - { 0x00008248, 0x00000100 }, - { 0x0000824c, 0x0001e800 }, - { 0x00008250, 0x00000000 }, - { 0x00008254, 0x00000000 }, - { 0x00008258, 0x00000000 }, - { 0x0000825c, 0x400000ff }, - { 0x00008260, 0x00080922 }, - { 0x00008264, 0xa8000010 }, - { 0x00008270, 0x00000000 }, - { 0x00008274, 0x40000000 }, - { 0x00008278, 0x003e4180 }, - { 0x0000827c, 0x00000000 }, - { 0x00008284, 0x0000002c }, - { 0x00008288, 0x0000002c }, - { 0x0000828c, 0x00000000 }, - { 0x00008294, 0x00000000 }, - { 0x00008298, 0x00000000 }, - { 0x00008300, 0x00000000 }, - { 0x00008304, 0x00000000 }, - { 0x00008308, 0x00000000 }, - { 0x0000830c, 0x00000000 }, - { 0x00008310, 0x00000000 }, - { 0x00008314, 0x00000000 }, - { 0x00008318, 0x00000000 }, - { 0x00008328, 0x00000000 }, - { 0x0000832c, 0x00000007 }, - { 0x00008330, 0x00000302 }, - { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00070000 }, - { 0x0000833c, 0x00000000 }, - { 0x00008340, 0x000107ff }, - { 0x00009808, 0x00000000 }, - { 0x0000980c, 0xad848e19 }, - { 0x00009810, 0x7d14e000 }, - { 0x00009814, 0x9c0a9f6b }, - { 0x0000981c, 0x00000000 }, - { 0x0000982c, 0x0000a000 }, - { 0x00009830, 0x00000000 }, - { 0x0000983c, 0x00200400 }, - { 0x00009840, 0x206a002e }, - { 0x0000984c, 0x1284233c }, - { 0x00009854, 0x00000859 }, - { 0x00009900, 0x00000000 }, - { 0x00009904, 0x00000000 }, - { 0x00009908, 0x00000000 }, - { 0x0000990c, 0x00000000 }, - { 0x0000991c, 0x10000fff }, - { 0x00009920, 0x05100000 }, - { 0x0000a920, 0x05100000 }, - { 0x0000b920, 0x05100000 }, - { 0x00009928, 0x00000001 }, - { 0x0000992c, 0x00000004 }, - { 0x00009934, 0x1e1f2022 }, - { 0x00009938, 0x0a0b0c0d }, - { 0x0000993c, 0x00000000 }, - { 0x00009948, 0x9280b212 }, - { 0x0000994c, 0x00020028 }, - { 0x00009954, 0x5d50e188 }, - { 0x00009958, 0x00081fff }, - { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, - { 0x00009970, 0x190fb515 }, - { 0x00009974, 0x00000000 }, - { 0x00009978, 0x00000001 }, - { 0x0000997c, 0x00000000 }, - { 0x00009980, 0x00000000 }, - { 0x00009984, 0x00000000 }, - { 0x00009988, 0x00000000 }, - { 0x0000998c, 0x00000000 }, - { 0x00009990, 0x00000000 }, - { 0x00009994, 0x00000000 }, - { 0x00009998, 0x00000000 }, - { 0x0000999c, 0x00000000 }, - { 0x000099a0, 0x00000000 }, - { 0x000099a4, 0x00000001 }, - { 0x000099a8, 0x001fff00 }, - { 0x000099ac, 0x00000000 }, - { 0x000099b0, 0x03051000 }, - { 0x000099dc, 0x00000000 }, - { 0x000099e0, 0x00000200 }, - { 0x000099e4, 0xaaaaaaaa }, - { 0x000099e8, 0x3c466478 }, - { 0x000099ec, 0x000000aa }, - { 0x000099fc, 0x00001042 }, - { 0x00009b00, 0x00000000 }, - { 0x00009b04, 0x00000001 }, - { 0x00009b08, 0x00000002 }, - { 0x00009b0c, 0x00000003 }, - { 0x00009b10, 0x00000004 }, - { 0x00009b14, 0x00000005 }, - { 0x00009b18, 0x00000008 }, - { 0x00009b1c, 0x00000009 }, - { 0x00009b20, 0x0000000a }, - { 0x00009b24, 0x0000000b }, - { 0x00009b28, 0x0000000c }, - { 0x00009b2c, 0x0000000d }, - { 0x00009b30, 0x00000010 }, - { 0x00009b34, 0x00000011 }, - { 0x00009b38, 0x00000012 }, - { 0x00009b3c, 0x00000013 }, - { 0x00009b40, 0x00000014 }, - { 0x00009b44, 0x00000015 }, - { 0x00009b48, 0x00000018 }, - { 0x00009b4c, 0x00000019 }, - { 0x00009b50, 0x0000001a }, - { 0x00009b54, 0x0000001b }, - { 0x00009b58, 0x0000001c }, - { 0x00009b5c, 0x0000001d }, - { 0x00009b60, 0x00000020 }, - { 0x00009b64, 0x00000021 }, - { 0x00009b68, 0x00000022 }, - { 0x00009b6c, 0x00000023 }, - { 0x00009b70, 0x00000024 }, - { 0x00009b74, 0x00000025 }, - { 0x00009b78, 0x00000028 }, - { 0x00009b7c, 0x00000029 }, - { 0x00009b80, 0x0000002a }, - { 0x00009b84, 0x0000002b }, - { 0x00009b88, 0x0000002c }, - { 0x00009b8c, 0x0000002d }, - { 0x00009b90, 0x00000030 }, - { 0x00009b94, 0x00000031 }, - { 0x00009b98, 0x00000032 }, - { 0x00009b9c, 0x00000033 }, - { 0x00009ba0, 0x00000034 }, - { 0x00009ba4, 0x00000035 }, - { 0x00009ba8, 0x00000035 }, - { 0x00009bac, 0x00000035 }, - { 0x00009bb0, 0x00000035 }, - { 0x00009bb4, 0x00000035 }, - { 0x00009bb8, 0x00000035 }, - { 0x00009bbc, 0x00000035 }, - { 0x00009bc0, 0x00000035 }, - { 0x00009bc4, 0x00000035 }, - { 0x00009bc8, 0x00000035 }, - { 0x00009bcc, 0x00000035 }, - { 0x00009bd0, 0x00000035 }, - { 0x00009bd4, 0x00000035 }, - { 0x00009bd8, 0x00000035 }, - { 0x00009bdc, 0x00000035 }, - { 0x00009be0, 0x00000035 }, - { 0x00009be4, 0x00000035 }, - { 0x00009be8, 0x00000035 }, - { 0x00009bec, 0x00000035 }, - { 0x00009bf0, 0x00000035 }, - { 0x00009bf4, 0x00000035 }, - { 0x00009bf8, 0x00000010 }, - { 0x00009bfc, 0x0000001a }, - { 0x0000a210, 0x40806333 }, - { 0x0000a214, 0x00106c10 }, - { 0x0000a218, 0x009c4060 }, - { 0x0000a220, 0x018830c6 }, - { 0x0000a224, 0x00000400 }, - { 0x0000a228, 0x00000bb5 }, - { 0x0000a22c, 0x00000011 }, - { 0x0000a234, 0x20202020 }, - { 0x0000a238, 0x20202020 }, - { 0x0000a23c, 0x13c889af }, - { 0x0000a240, 0x38490a20 }, - { 0x0000a244, 0x00007bb6 }, - { 0x0000a248, 0x0fff3ffc }, - { 0x0000a24c, 0x00000001 }, - { 0x0000a250, 0x0000a000 }, - { 0x0000a254, 0x00000000 }, - { 0x0000a258, 0x0cc75380 }, - { 0x0000a25c, 0x0f0f0f01 }, - { 0x0000a260, 0xdfa91f01 }, - { 0x0000a268, 0x00000000 }, - { 0x0000a26c, 0x0e79e5c6 }, - { 0x0000b26c, 0x0e79e5c6 }, - { 0x0000c26c, 0x0e79e5c6 }, - { 0x0000d270, 0x00820820 }, - { 0x0000a278, 0x1ce739ce }, - { 0x0000a27c, 0x051701ce }, - { 0x0000a338, 0x00000000 }, - { 0x0000a33c, 0x00000000 }, - { 0x0000a340, 0x00000000 }, - { 0x0000a344, 0x00000000 }, - { 0x0000a348, 0x3fffffff }, - { 0x0000a34c, 0x3fffffff }, - { 0x0000a350, 0x3fffffff }, - { 0x0000a354, 0x0003ffff }, - { 0x0000a358, 0x79a8aa1f }, - { 0x0000d35c, 0x07ffffef }, - { 0x0000d360, 0x0fffffe7 }, - { 0x0000d364, 0x17ffffe5 }, - { 0x0000d368, 0x1fffffe4 }, - { 0x0000d36c, 0x37ffffe3 }, - { 0x0000d370, 0x3fffffe3 }, - { 0x0000d374, 0x57ffffe3 }, - { 0x0000d378, 0x5fffffe2 }, - { 0x0000d37c, 0x7fffffe2 }, - { 0x0000d380, 0x7f3c7bba }, - { 0x0000d384, 0xf3307ff0 }, - { 0x0000a388, 0x08000000 }, - { 0x0000a38c, 0x20202020 }, - { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x1ce739ce }, - { 0x0000a398, 0x000001ce }, - { 0x0000a39c, 0x00000001 }, - { 0x0000a3a0, 0x00000000 }, - { 0x0000a3a4, 0x00000000 }, - { 0x0000a3a8, 0x00000000 }, - { 0x0000a3ac, 0x00000000 }, - { 0x0000a3b0, 0x00000000 }, - { 0x0000a3b4, 0x00000000 }, - { 0x0000a3b8, 0x00000000 }, - { 0x0000a3bc, 0x00000000 }, - { 0x0000a3c0, 0x00000000 }, - { 0x0000a3c4, 0x00000000 }, - { 0x0000a3c8, 0x00000246 }, - { 0x0000a3cc, 0x20202020 }, - { 0x0000a3d0, 0x20202020 }, - { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce }, -}; - -static const u32 ar5416Bank0[][2] = { - { 0x000098b0, 0x1e5795e5 }, - { 0x000098e0, 0x02008020 }, -}; - -static const u32 ar5416BB_RfGain[][3] = { - { 0x00009a00, 0x00000000, 0x00000000 }, - { 0x00009a04, 0x00000040, 0x00000040 }, - { 0x00009a08, 0x00000080, 0x00000080 }, - { 0x00009a0c, 0x000001a1, 0x00000141 }, - { 0x00009a10, 0x000001e1, 0x00000181 }, - { 0x00009a14, 0x00000021, 0x000001c1 }, - { 0x00009a18, 0x00000061, 0x00000001 }, - { 0x00009a1c, 0x00000168, 0x00000041 }, - { 0x00009a20, 0x000001a8, 0x000001a8 }, - { 0x00009a24, 0x000001e8, 0x000001e8 }, - { 0x00009a28, 0x00000028, 0x00000028 }, - { 0x00009a2c, 0x00000068, 0x00000068 }, - { 0x00009a30, 0x00000189, 0x000000a8 }, - { 0x00009a34, 0x000001c9, 0x00000169 }, - { 0x00009a38, 0x00000009, 0x000001a9 }, - { 0x00009a3c, 0x00000049, 0x000001e9 }, - { 0x00009a40, 0x00000089, 0x00000029 }, - { 0x00009a44, 0x00000170, 0x00000069 }, - { 0x00009a48, 0x000001b0, 0x00000190 }, - { 0x00009a4c, 0x000001f0, 0x000001d0 }, - { 0x00009a50, 0x00000030, 0x00000010 }, - { 0x00009a54, 0x00000070, 0x00000050 }, - { 0x00009a58, 0x00000191, 0x00000090 }, - { 0x00009a5c, 0x000001d1, 0x00000151 }, - { 0x00009a60, 0x00000011, 0x00000191 }, - { 0x00009a64, 0x00000051, 0x000001d1 }, - { 0x00009a68, 0x00000091, 0x00000011 }, - { 0x00009a6c, 0x000001b8, 0x00000051 }, - { 0x00009a70, 0x000001f8, 0x00000198 }, - { 0x00009a74, 0x00000038, 0x000001d8 }, - { 0x00009a78, 0x00000078, 0x00000018 }, - { 0x00009a7c, 0x00000199, 0x00000058 }, - { 0x00009a80, 0x000001d9, 0x00000098 }, - { 0x00009a84, 0x00000019, 0x00000159 }, - { 0x00009a88, 0x00000059, 0x00000199 }, - { 0x00009a8c, 0x00000099, 0x000001d9 }, - { 0x00009a90, 0x000000d9, 0x00000019 }, - { 0x00009a94, 0x000000f9, 0x00000059 }, - { 0x00009a98, 0x000000f9, 0x00000099 }, - { 0x00009a9c, 0x000000f9, 0x000000d9 }, - { 0x00009aa0, 0x000000f9, 0x000000f9 }, - { 0x00009aa4, 0x000000f9, 0x000000f9 }, - { 0x00009aa8, 0x000000f9, 0x000000f9 }, - { 0x00009aac, 0x000000f9, 0x000000f9 }, - { 0x00009ab0, 0x000000f9, 0x000000f9 }, - { 0x00009ab4, 0x000000f9, 0x000000f9 }, - { 0x00009ab8, 0x000000f9, 0x000000f9 }, - { 0x00009abc, 0x000000f9, 0x000000f9 }, - { 0x00009ac0, 0x000000f9, 0x000000f9 }, - { 0x00009ac4, 0x000000f9, 0x000000f9 }, - { 0x00009ac8, 0x000000f9, 0x000000f9 }, - { 0x00009acc, 0x000000f9, 0x000000f9 }, - { 0x00009ad0, 0x000000f9, 0x000000f9 }, - { 0x00009ad4, 0x000000f9, 0x000000f9 }, - { 0x00009ad8, 0x000000f9, 0x000000f9 }, - { 0x00009adc, 0x000000f9, 0x000000f9 }, - { 0x00009ae0, 0x000000f9, 0x000000f9 }, - { 0x00009ae4, 0x000000f9, 0x000000f9 }, - { 0x00009ae8, 0x000000f9, 0x000000f9 }, - { 0x00009aec, 0x000000f9, 0x000000f9 }, - { 0x00009af0, 0x000000f9, 0x000000f9 }, - { 0x00009af4, 0x000000f9, 0x000000f9 }, - { 0x00009af8, 0x000000f9, 0x000000f9 }, - { 0x00009afc, 0x000000f9, 0x000000f9 }, -}; - -static const u32 ar5416Bank1[][2] = { - { 0x000098b0, 0x02108421 }, - { 0x000098ec, 0x00000008 }, -}; - -static const u32 ar5416Bank2[][2] = { - { 0x000098b0, 0x0e73ff17 }, - { 0x000098e0, 0x00000420 }, -}; - -static const u32 ar5416Bank3[][3] = { - { 0x000098f0, 0x01400018, 0x01c00018 }, -}; - -static const u32 ar5416Bank6[][3] = { - - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x40ff0000, 0x40ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x004210a2, 0x004210a2 }, - { 0x0000989c, 0x0014008f, 0x0014008f }, - { 0x0000989c, 0x00c40003, 0x00c40003 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x0001805e, 0x0001805e }, - { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, - { 0x0000989c, 0x000000f1, 0x000000f1 }, - { 0x0000989c, 0x00002081, 0x00002081 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - -static const u32 ar5416Bank6TPC[][3] = { - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x40ff0000, 0x40ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x00423022, 0x00423022 }, - { 0x0000989c, 0x201400df, 0x201400df }, - { 0x0000989c, 0x00c40002, 0x00c40002 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x0001805e, 0x0001805e }, - { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, - { 0x0000989c, 0x000000e1, 0x000000e1 }, - { 0x0000989c, 0x00007081, 0x00007081 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - -static const u32 ar5416Bank7[][2] = { - { 0x0000989c, 0x00000500 }, - { 0x0000989c, 0x00000800 }, - { 0x000098cc, 0x0000000e }, -}; - -static const u32 ar5416Addac[][2] = { - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000003 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x0000000c }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000030 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000060 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000058 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x000098cc, 0x00000000 }, -}; - -static const u32 ar5416Modes_9100[][6] = { - { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, - { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, - { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, - { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, - { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, - { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, - { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, - { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, - { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, - { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 }, - { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec86d2e, 0x7ec84d2e, 0x7ec82d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, - { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, - { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, - { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, - { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, - { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, - { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a11, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009940, 0x00754604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204 }, - { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, - { 0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e }, - { 0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff }, -#ifdef TB243 - { 0x00009960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, - { 0x0000a960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, - { 0x0000b960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 }, - { 0x00009964, 0x00000000, 0x00000000, 0x00002210, 0x00002210, 0x00001120 }, -#else - { 0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, - { 0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, - { 0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 }, - { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, -#endif - { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00 }, - { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, - { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, - { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, - { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, - { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, - { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, - { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, - { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, - { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, - { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, - { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, - { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, - { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, - { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, - { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, - { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, - { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, - { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, - { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, -}; - -static const u32 ar5416Common_9100[][2] = { - { 0x0000000c, 0x00000000 }, - { 0x00000030, 0x00020015 }, - { 0x00000034, 0x00000005 }, - { 0x00000040, 0x00000000 }, - { 0x00000044, 0x00000008 }, - { 0x00000048, 0x00000008 }, - { 0x0000004c, 0x00000010 }, - { 0x00000050, 0x00000000 }, - { 0x00000054, 0x0000001f }, - { 0x00000800, 0x00000000 }, - { 0x00000804, 0x00000000 }, - { 0x00000808, 0x00000000 }, - { 0x0000080c, 0x00000000 }, - { 0x00000810, 0x00000000 }, - { 0x00000814, 0x00000000 }, - { 0x00000818, 0x00000000 }, - { 0x0000081c, 0x00000000 }, - { 0x00000820, 0x00000000 }, - { 0x00000824, 0x00000000 }, - { 0x00001040, 0x002ffc0f }, - { 0x00001044, 0x002ffc0f }, - { 0x00001048, 0x002ffc0f }, - { 0x0000104c, 0x002ffc0f }, - { 0x00001050, 0x002ffc0f }, - { 0x00001054, 0x002ffc0f }, - { 0x00001058, 0x002ffc0f }, - { 0x0000105c, 0x002ffc0f }, - { 0x00001060, 0x002ffc0f }, - { 0x00001064, 0x002ffc0f }, - { 0x00001230, 0x00000000 }, - { 0x00001270, 0x00000000 }, - { 0x00001038, 0x00000000 }, - { 0x00001078, 0x00000000 }, - { 0x000010b8, 0x00000000 }, - { 0x000010f8, 0x00000000 }, - { 0x00001138, 0x00000000 }, - { 0x00001178, 0x00000000 }, - { 0x000011b8, 0x00000000 }, - { 0x000011f8, 0x00000000 }, - { 0x00001238, 0x00000000 }, - { 0x00001278, 0x00000000 }, - { 0x000012b8, 0x00000000 }, - { 0x000012f8, 0x00000000 }, - { 0x00001338, 0x00000000 }, - { 0x00001378, 0x00000000 }, - { 0x000013b8, 0x00000000 }, - { 0x000013f8, 0x00000000 }, - { 0x00001438, 0x00000000 }, - { 0x00001478, 0x00000000 }, - { 0x000014b8, 0x00000000 }, - { 0x000014f8, 0x00000000 }, - { 0x00001538, 0x00000000 }, - { 0x00001578, 0x00000000 }, - { 0x000015b8, 0x00000000 }, - { 0x000015f8, 0x00000000 }, - { 0x00001638, 0x00000000 }, - { 0x00001678, 0x00000000 }, - { 0x000016b8, 0x00000000 }, - { 0x000016f8, 0x00000000 }, - { 0x00001738, 0x00000000 }, - { 0x00001778, 0x00000000 }, - { 0x000017b8, 0x00000000 }, - { 0x000017f8, 0x00000000 }, - { 0x0000103c, 0x00000000 }, - { 0x0000107c, 0x00000000 }, - { 0x000010bc, 0x00000000 }, - { 0x000010fc, 0x00000000 }, - { 0x0000113c, 0x00000000 }, - { 0x0000117c, 0x00000000 }, - { 0x000011bc, 0x00000000 }, - { 0x000011fc, 0x00000000 }, - { 0x0000123c, 0x00000000 }, - { 0x0000127c, 0x00000000 }, - { 0x000012bc, 0x00000000 }, - { 0x000012fc, 0x00000000 }, - { 0x0000133c, 0x00000000 }, - { 0x0000137c, 0x00000000 }, - { 0x000013bc, 0x00000000 }, - { 0x000013fc, 0x00000000 }, - { 0x0000143c, 0x00000000 }, - { 0x0000147c, 0x00000000 }, - { 0x00020010, 0x00000003 }, - { 0x00020038, 0x000004c2 }, - { 0x00008004, 0x00000000 }, - { 0x00008008, 0x00000000 }, - { 0x0000800c, 0x00000000 }, - { 0x00008018, 0x00000700 }, - { 0x00008020, 0x00000000 }, - { 0x00008038, 0x00000000 }, - { 0x0000803c, 0x00000000 }, - { 0x00008048, 0x40000000 }, - { 0x00008054, 0x00004000 }, - { 0x00008058, 0x00000000 }, - { 0x0000805c, 0x000fc78f }, - { 0x00008060, 0x0000000f }, - { 0x00008064, 0x00000000 }, - { 0x000080c0, 0x2a82301a }, - { 0x000080c4, 0x05dc01e0 }, - { 0x000080c8, 0x1f402710 }, - { 0x000080cc, 0x01f40000 }, - { 0x000080d0, 0x00001e00 }, - { 0x000080d4, 0x00000000 }, - { 0x000080d8, 0x00400000 }, - { 0x000080e0, 0xffffffff }, - { 0x000080e4, 0x0000ffff }, - { 0x000080e8, 0x003f3f3f }, - { 0x000080ec, 0x00000000 }, - { 0x000080f0, 0x00000000 }, - { 0x000080f4, 0x00000000 }, - { 0x000080f8, 0x00000000 }, - { 0x000080fc, 0x00020000 }, - { 0x00008100, 0x00020000 }, - { 0x00008104, 0x00000001 }, - { 0x00008108, 0x00000052 }, - { 0x0000810c, 0x00000000 }, - { 0x00008110, 0x00000168 }, - { 0x00008118, 0x000100aa }, - { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04800 }, - { 0x00008124, 0x00000000 }, - { 0x00008128, 0x00000000 }, - { 0x0000812c, 0x00000000 }, - { 0x00008130, 0x00000000 }, - { 0x00008134, 0x00000000 }, - { 0x00008138, 0x00000000 }, - { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, - { 0x00008168, 0x00000000 }, - { 0x0000816c, 0x00000000 }, - { 0x00008170, 0x32143320 }, - { 0x00008174, 0xfaa4fa50 }, - { 0x00008178, 0x00000100 }, - { 0x0000817c, 0x00000000 }, - { 0x000081c4, 0x00000000 }, - { 0x000081d0, 0x00003210 }, - { 0x000081ec, 0x00000000 }, - { 0x000081f0, 0x00000000 }, - { 0x000081f4, 0x00000000 }, - { 0x000081f8, 0x00000000 }, - { 0x000081fc, 0x00000000 }, - { 0x00008200, 0x00000000 }, - { 0x00008204, 0x00000000 }, - { 0x00008208, 0x00000000 }, - { 0x0000820c, 0x00000000 }, - { 0x00008210, 0x00000000 }, - { 0x00008214, 0x00000000 }, - { 0x00008218, 0x00000000 }, - { 0x0000821c, 0x00000000 }, - { 0x00008220, 0x00000000 }, - { 0x00008224, 0x00000000 }, - { 0x00008228, 0x00000000 }, - { 0x0000822c, 0x00000000 }, - { 0x00008230, 0x00000000 }, - { 0x00008234, 0x00000000 }, - { 0x00008238, 0x00000000 }, - { 0x0000823c, 0x00000000 }, - { 0x00008240, 0x00100000 }, - { 0x00008244, 0x0010f400 }, - { 0x00008248, 0x00000100 }, - { 0x0000824c, 0x0001e800 }, - { 0x00008250, 0x00000000 }, - { 0x00008254, 0x00000000 }, - { 0x00008258, 0x00000000 }, - { 0x0000825c, 0x400000ff }, - { 0x00008260, 0x00080922 }, - { 0x00008270, 0x00000000 }, - { 0x00008274, 0x40000000 }, - { 0x00008278, 0x003e4180 }, - { 0x0000827c, 0x00000000 }, - { 0x00008284, 0x0000002c }, - { 0x00008288, 0x0000002c }, - { 0x0000828c, 0x00000000 }, - { 0x00008294, 0x00000000 }, - { 0x00008298, 0x00000000 }, - { 0x00008300, 0x00000000 }, - { 0x00008304, 0x00000000 }, - { 0x00008308, 0x00000000 }, - { 0x0000830c, 0x00000000 }, - { 0x00008310, 0x00000000 }, - { 0x00008314, 0x00000000 }, - { 0x00008318, 0x00000000 }, - { 0x00008328, 0x00000000 }, - { 0x0000832c, 0x00000007 }, - { 0x00008330, 0x00000302 }, - { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, - { 0x0000833c, 0x00000000 }, - { 0x00008340, 0x000107ff }, - { 0x00009808, 0x00000000 }, - { 0x0000980c, 0xad848e19 }, - { 0x00009810, 0x7d14e000 }, - { 0x00009814, 0x9c0a9f6b }, - { 0x0000981c, 0x00000000 }, - { 0x0000982c, 0x0000a000 }, - { 0x00009830, 0x00000000 }, - { 0x0000983c, 0x00200400 }, - { 0x00009840, 0x206a01ae }, - { 0x0000984c, 0x1284233c }, - { 0x00009854, 0x00000859 }, - { 0x00009900, 0x00000000 }, - { 0x00009904, 0x00000000 }, - { 0x00009908, 0x00000000 }, - { 0x0000990c, 0x00000000 }, - { 0x0000991c, 0x10000fff }, - { 0x00009920, 0x05100000 }, - { 0x0000a920, 0x05100000 }, - { 0x0000b920, 0x05100000 }, - { 0x00009928, 0x00000001 }, - { 0x0000992c, 0x00000004 }, - { 0x00009934, 0x1e1f2022 }, - { 0x00009938, 0x0a0b0c0d }, - { 0x0000993c, 0x00000000 }, - { 0x00009948, 0x9280b212 }, - { 0x0000994c, 0x00020028 }, - { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, - { 0x00009970, 0x190fb515 }, - { 0x00009974, 0x00000000 }, - { 0x00009978, 0x00000001 }, - { 0x0000997c, 0x00000000 }, - { 0x00009980, 0x00000000 }, - { 0x00009984, 0x00000000 }, - { 0x00009988, 0x00000000 }, - { 0x0000998c, 0x00000000 }, - { 0x00009990, 0x00000000 }, - { 0x00009994, 0x00000000 }, - { 0x00009998, 0x00000000 }, - { 0x0000999c, 0x00000000 }, - { 0x000099a0, 0x00000000 }, - { 0x000099a4, 0x00000001 }, - { 0x000099a8, 0x201fff00 }, - { 0x000099ac, 0x006f0000 }, - { 0x000099b0, 0x03051000 }, - { 0x000099dc, 0x00000000 }, - { 0x000099e0, 0x00000200 }, - { 0x000099e4, 0xaaaaaaaa }, - { 0x000099e8, 0x3c466478 }, - { 0x000099ec, 0x0cc80caa }, - { 0x000099fc, 0x00001042 }, - { 0x00009b00, 0x00000000 }, - { 0x00009b04, 0x00000001 }, - { 0x00009b08, 0x00000002 }, - { 0x00009b0c, 0x00000003 }, - { 0x00009b10, 0x00000004 }, - { 0x00009b14, 0x00000005 }, - { 0x00009b18, 0x00000008 }, - { 0x00009b1c, 0x00000009 }, - { 0x00009b20, 0x0000000a }, - { 0x00009b24, 0x0000000b }, - { 0x00009b28, 0x0000000c }, - { 0x00009b2c, 0x0000000d }, - { 0x00009b30, 0x00000010 }, - { 0x00009b34, 0x00000011 }, - { 0x00009b38, 0x00000012 }, - { 0x00009b3c, 0x00000013 }, - { 0x00009b40, 0x00000014 }, - { 0x00009b44, 0x00000015 }, - { 0x00009b48, 0x00000018 }, - { 0x00009b4c, 0x00000019 }, - { 0x00009b50, 0x0000001a }, - { 0x00009b54, 0x0000001b }, - { 0x00009b58, 0x0000001c }, - { 0x00009b5c, 0x0000001d }, - { 0x00009b60, 0x00000020 }, - { 0x00009b64, 0x00000021 }, - { 0x00009b68, 0x00000022 }, - { 0x00009b6c, 0x00000023 }, - { 0x00009b70, 0x00000024 }, - { 0x00009b74, 0x00000025 }, - { 0x00009b78, 0x00000028 }, - { 0x00009b7c, 0x00000029 }, - { 0x00009b80, 0x0000002a }, - { 0x00009b84, 0x0000002b }, - { 0x00009b88, 0x0000002c }, - { 0x00009b8c, 0x0000002d }, - { 0x00009b90, 0x00000030 }, - { 0x00009b94, 0x00000031 }, - { 0x00009b98, 0x00000032 }, - { 0x00009b9c, 0x00000033 }, - { 0x00009ba0, 0x00000034 }, - { 0x00009ba4, 0x00000035 }, - { 0x00009ba8, 0x00000035 }, - { 0x00009bac, 0x00000035 }, - { 0x00009bb0, 0x00000035 }, - { 0x00009bb4, 0x00000035 }, - { 0x00009bb8, 0x00000035 }, - { 0x00009bbc, 0x00000035 }, - { 0x00009bc0, 0x00000035 }, - { 0x00009bc4, 0x00000035 }, - { 0x00009bc8, 0x00000035 }, - { 0x00009bcc, 0x00000035 }, - { 0x00009bd0, 0x00000035 }, - { 0x00009bd4, 0x00000035 }, - { 0x00009bd8, 0x00000035 }, - { 0x00009bdc, 0x00000035 }, - { 0x00009be0, 0x00000035 }, - { 0x00009be4, 0x00000035 }, - { 0x00009be8, 0x00000035 }, - { 0x00009bec, 0x00000035 }, - { 0x00009bf0, 0x00000035 }, - { 0x00009bf4, 0x00000035 }, - { 0x00009bf8, 0x00000010 }, - { 0x00009bfc, 0x0000001a }, - { 0x0000a210, 0x40806333 }, - { 0x0000a214, 0x00106c10 }, - { 0x0000a218, 0x009c4060 }, - { 0x0000a220, 0x018830c6 }, - { 0x0000a224, 0x00000400 }, - { 0x0000a228, 0x001a0bb5 }, - { 0x0000a22c, 0x00000000 }, - { 0x0000a234, 0x20202020 }, - { 0x0000a238, 0x20202020 }, - { 0x0000a23c, 0x13c889ae }, - { 0x0000a240, 0x38490a20 }, - { 0x0000a244, 0x00007bb6 }, - { 0x0000a248, 0x0fff3ffc }, - { 0x0000a24c, 0x00000001 }, - { 0x0000a250, 0x0000a000 }, - { 0x0000a254, 0x00000000 }, - { 0x0000a258, 0x0cc75380 }, - { 0x0000a25c, 0x0f0f0f01 }, - { 0x0000a260, 0xdfa91f01 }, - { 0x0000a268, 0x00000001 }, - { 0x0000a26c, 0x0ebae9c6 }, - { 0x0000b26c, 0x0ebae9c6 }, - { 0x0000c26c, 0x0ebae9c6 }, - { 0x0000d270, 0x00820820 }, - { 0x0000a278, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce }, - { 0x0000a338, 0x00000000 }, - { 0x0000a33c, 0x00000000 }, - { 0x0000a340, 0x00000000 }, - { 0x0000a344, 0x00000000 }, - { 0x0000a348, 0x3fffffff }, - { 0x0000a34c, 0x3fffffff }, - { 0x0000a350, 0x3fffffff }, - { 0x0000a354, 0x0003ffff }, - { 0x0000a358, 0x79a8aa33 }, - { 0x0000d35c, 0x07ffffef }, - { 0x0000d360, 0x0fffffe7 }, - { 0x0000d364, 0x17ffffe5 }, - { 0x0000d368, 0x1fffffe4 }, - { 0x0000d36c, 0x37ffffe3 }, - { 0x0000d370, 0x3fffffe3 }, - { 0x0000d374, 0x57ffffe3 }, - { 0x0000d378, 0x5fffffe2 }, - { 0x0000d37c, 0x7fffffe2 }, - { 0x0000d380, 0x7f3c7bba }, - { 0x0000d384, 0xf3307ff0 }, - { 0x0000a388, 0x0c000000 }, - { 0x0000a38c, 0x20202020 }, - { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x1ce739ce }, - { 0x0000a398, 0x000001ce }, - { 0x0000a39c, 0x00000001 }, - { 0x0000a3a0, 0x00000000 }, - { 0x0000a3a4, 0x00000000 }, - { 0x0000a3a8, 0x00000000 }, - { 0x0000a3ac, 0x00000000 }, - { 0x0000a3b0, 0x00000000 }, - { 0x0000a3b4, 0x00000000 }, - { 0x0000a3b8, 0x00000000 }, - { 0x0000a3bc, 0x00000000 }, - { 0x0000a3c0, 0x00000000 }, - { 0x0000a3c4, 0x00000000 }, - { 0x0000a3c8, 0x00000246 }, - { 0x0000a3cc, 0x20202020 }, - { 0x0000a3d0, 0x20202020 }, - { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce }, -}; - -static const u32 ar5416Bank0_9100[][2] = { - { 0x000098b0, 0x1e5795e5 }, - { 0x000098e0, 0x02008020 }, -}; - -static const u32 ar5416BB_RfGain_9100[][3] = { - { 0x00009a00, 0x00000000, 0x00000000 }, - { 0x00009a04, 0x00000040, 0x00000040 }, - { 0x00009a08, 0x00000080, 0x00000080 }, - { 0x00009a0c, 0x000001a1, 0x00000141 }, - { 0x00009a10, 0x000001e1, 0x00000181 }, - { 0x00009a14, 0x00000021, 0x000001c1 }, - { 0x00009a18, 0x00000061, 0x00000001 }, - { 0x00009a1c, 0x00000168, 0x00000041 }, - { 0x00009a20, 0x000001a8, 0x000001a8 }, - { 0x00009a24, 0x000001e8, 0x000001e8 }, - { 0x00009a28, 0x00000028, 0x00000028 }, - { 0x00009a2c, 0x00000068, 0x00000068 }, - { 0x00009a30, 0x00000189, 0x000000a8 }, - { 0x00009a34, 0x000001c9, 0x00000169 }, - { 0x00009a38, 0x00000009, 0x000001a9 }, - { 0x00009a3c, 0x00000049, 0x000001e9 }, - { 0x00009a40, 0x00000089, 0x00000029 }, - { 0x00009a44, 0x00000170, 0x00000069 }, - { 0x00009a48, 0x000001b0, 0x00000190 }, - { 0x00009a4c, 0x000001f0, 0x000001d0 }, - { 0x00009a50, 0x00000030, 0x00000010 }, - { 0x00009a54, 0x00000070, 0x00000050 }, - { 0x00009a58, 0x00000191, 0x00000090 }, - { 0x00009a5c, 0x000001d1, 0x00000151 }, - { 0x00009a60, 0x00000011, 0x00000191 }, - { 0x00009a64, 0x00000051, 0x000001d1 }, - { 0x00009a68, 0x00000091, 0x00000011 }, - { 0x00009a6c, 0x000001b8, 0x00000051 }, - { 0x00009a70, 0x000001f8, 0x00000198 }, - { 0x00009a74, 0x00000038, 0x000001d8 }, - { 0x00009a78, 0x00000078, 0x00000018 }, - { 0x00009a7c, 0x00000199, 0x00000058 }, - { 0x00009a80, 0x000001d9, 0x00000098 }, - { 0x00009a84, 0x00000019, 0x00000159 }, - { 0x00009a88, 0x00000059, 0x00000199 }, - { 0x00009a8c, 0x00000099, 0x000001d9 }, - { 0x00009a90, 0x000000d9, 0x00000019 }, - { 0x00009a94, 0x000000f9, 0x00000059 }, - { 0x00009a98, 0x000000f9, 0x00000099 }, - { 0x00009a9c, 0x000000f9, 0x000000d9 }, - { 0x00009aa0, 0x000000f9, 0x000000f9 }, - { 0x00009aa4, 0x000000f9, 0x000000f9 }, - { 0x00009aa8, 0x000000f9, 0x000000f9 }, - { 0x00009aac, 0x000000f9, 0x000000f9 }, - { 0x00009ab0, 0x000000f9, 0x000000f9 }, - { 0x00009ab4, 0x000000f9, 0x000000f9 }, - { 0x00009ab8, 0x000000f9, 0x000000f9 }, - { 0x00009abc, 0x000000f9, 0x000000f9 }, - { 0x00009ac0, 0x000000f9, 0x000000f9 }, - { 0x00009ac4, 0x000000f9, 0x000000f9 }, - { 0x00009ac8, 0x000000f9, 0x000000f9 }, - { 0x00009acc, 0x000000f9, 0x000000f9 }, - { 0x00009ad0, 0x000000f9, 0x000000f9 }, - { 0x00009ad4, 0x000000f9, 0x000000f9 }, - { 0x00009ad8, 0x000000f9, 0x000000f9 }, - { 0x00009adc, 0x000000f9, 0x000000f9 }, - { 0x00009ae0, 0x000000f9, 0x000000f9 }, - { 0x00009ae4, 0x000000f9, 0x000000f9 }, - { 0x00009ae8, 0x000000f9, 0x000000f9 }, - { 0x00009aec, 0x000000f9, 0x000000f9 }, - { 0x00009af0, 0x000000f9, 0x000000f9 }, - { 0x00009af4, 0x000000f9, 0x000000f9 }, - { 0x00009af8, 0x000000f9, 0x000000f9 }, - { 0x00009afc, 0x000000f9, 0x000000f9 }, -}; - -static const u32 ar5416Bank1_9100[][2] = { - { 0x000098b0, 0x02108421}, - { 0x000098ec, 0x00000008}, -}; - -static const u32 ar5416Bank2_9100[][2] = { - { 0x000098b0, 0x0e73ff17}, - { 0x000098e0, 0x00000420}, -}; - -static const u32 ar5416Bank3_9100[][3] = { - { 0x000098f0, 0x01400018, 0x01c00018 }, -}; - -static const u32 ar5416Bank6_9100[][3] = { - - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x004210a2, 0x004210a2 }, - { 0x0000989c, 0x0014000f, 0x0014000f }, - { 0x0000989c, 0x00c40002, 0x00c40002 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x000180d6, 0x000180d6 }, - { 0x0000989c, 0x0000c0aa, 0x0000c0aa }, - { 0x0000989c, 0x000000b1, 0x000000b1 }, - { 0x0000989c, 0x00002000, 0x00002000 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - - -static const u32 ar5416Bank6TPC_9100[][3] = { - - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x40ff0000, 0x40ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x00423022, 0x00423022 }, - { 0x0000989c, 0x2014008f, 0x2014008f }, - { 0x0000989c, 0x00c40002, 0x00c40002 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x0001805e, 0x0001805e }, - { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, - { 0x0000989c, 0x000000e1, 0x000000e1 }, - { 0x0000989c, 0x00007080, 0x00007080 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - -static const u32 ar5416Bank7_9100[][2] = { - { 0x0000989c, 0x00000500 }, - { 0x0000989c, 0x00000800 }, - { 0x000098cc, 0x0000000e }, -}; - -static const u32 ar5416Addac_9100[][2] = { - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000010 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x000000c0 }, - {0x0000989c, 0x00000015 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x000098cc, 0x00000000 }, -}; - -static const u32 ar5416Modes_9160[][6] = { - { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, - { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, - { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, - { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 }, - { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, - { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf }, - { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, - { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, - { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, - { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, - { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, - { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 }, - { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, - { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, - { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, - { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, - { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, - { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, - { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, - { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, - { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, - { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, - { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, - { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce }, - { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 }, - { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, - { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, - { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, - { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, - { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, - { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 }, - { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 }, - { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 }, - { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, - { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa }, - { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 }, - { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 }, - { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 }, - { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b }, - { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b }, - { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a }, - { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf }, - { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f }, - { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f }, - { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f }, - { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, -}; - -static const u32 ar5416Common_9160[][2] = { - { 0x0000000c, 0x00000000 }, - { 0x00000030, 0x00020015 }, - { 0x00000034, 0x00000005 }, - { 0x00000040, 0x00000000 }, - { 0x00000044, 0x00000008 }, - { 0x00000048, 0x00000008 }, - { 0x0000004c, 0x00000010 }, - { 0x00000050, 0x00000000 }, - { 0x00000054, 0x0000001f }, - { 0x00000800, 0x00000000 }, - { 0x00000804, 0x00000000 }, - { 0x00000808, 0x00000000 }, - { 0x0000080c, 0x00000000 }, - { 0x00000810, 0x00000000 }, - { 0x00000814, 0x00000000 }, - { 0x00000818, 0x00000000 }, - { 0x0000081c, 0x00000000 }, - { 0x00000820, 0x00000000 }, - { 0x00000824, 0x00000000 }, - { 0x00001040, 0x002ffc0f }, - { 0x00001044, 0x002ffc0f }, - { 0x00001048, 0x002ffc0f }, - { 0x0000104c, 0x002ffc0f }, - { 0x00001050, 0x002ffc0f }, - { 0x00001054, 0x002ffc0f }, - { 0x00001058, 0x002ffc0f }, - { 0x0000105c, 0x002ffc0f }, - { 0x00001060, 0x002ffc0f }, - { 0x00001064, 0x002ffc0f }, - { 0x00001230, 0x00000000 }, - { 0x00001270, 0x00000000 }, - { 0x00001038, 0x00000000 }, - { 0x00001078, 0x00000000 }, - { 0x000010b8, 0x00000000 }, - { 0x000010f8, 0x00000000 }, - { 0x00001138, 0x00000000 }, - { 0x00001178, 0x00000000 }, - { 0x000011b8, 0x00000000 }, - { 0x000011f8, 0x00000000 }, - { 0x00001238, 0x00000000 }, - { 0x00001278, 0x00000000 }, - { 0x000012b8, 0x00000000 }, - { 0x000012f8, 0x00000000 }, - { 0x00001338, 0x00000000 }, - { 0x00001378, 0x00000000 }, - { 0x000013b8, 0x00000000 }, - { 0x000013f8, 0x00000000 }, - { 0x00001438, 0x00000000 }, - { 0x00001478, 0x00000000 }, - { 0x000014b8, 0x00000000 }, - { 0x000014f8, 0x00000000 }, - { 0x00001538, 0x00000000 }, - { 0x00001578, 0x00000000 }, - { 0x000015b8, 0x00000000 }, - { 0x000015f8, 0x00000000 }, - { 0x00001638, 0x00000000 }, - { 0x00001678, 0x00000000 }, - { 0x000016b8, 0x00000000 }, - { 0x000016f8, 0x00000000 }, - { 0x00001738, 0x00000000 }, - { 0x00001778, 0x00000000 }, - { 0x000017b8, 0x00000000 }, - { 0x000017f8, 0x00000000 }, - { 0x0000103c, 0x00000000 }, - { 0x0000107c, 0x00000000 }, - { 0x000010bc, 0x00000000 }, - { 0x000010fc, 0x00000000 }, - { 0x0000113c, 0x00000000 }, - { 0x0000117c, 0x00000000 }, - { 0x000011bc, 0x00000000 }, - { 0x000011fc, 0x00000000 }, - { 0x0000123c, 0x00000000 }, - { 0x0000127c, 0x00000000 }, - { 0x000012bc, 0x00000000 }, - { 0x000012fc, 0x00000000 }, - { 0x0000133c, 0x00000000 }, - { 0x0000137c, 0x00000000 }, - { 0x000013bc, 0x00000000 }, - { 0x000013fc, 0x00000000 }, - { 0x0000143c, 0x00000000 }, - { 0x0000147c, 0x00000000 }, - { 0x00004030, 0x00000002 }, - { 0x0000403c, 0x00000002 }, - { 0x00007010, 0x00000020 }, - { 0x00007038, 0x000004c2 }, - { 0x00008004, 0x00000000 }, - { 0x00008008, 0x00000000 }, - { 0x0000800c, 0x00000000 }, - { 0x00008018, 0x00000700 }, - { 0x00008020, 0x00000000 }, - { 0x00008038, 0x00000000 }, - { 0x0000803c, 0x00000000 }, - { 0x00008048, 0x40000000 }, - { 0x00008054, 0x00000000 }, - { 0x00008058, 0x00000000 }, - { 0x0000805c, 0x000fc78f }, - { 0x00008060, 0x0000000f }, - { 0x00008064, 0x00000000 }, - { 0x000080c0, 0x2a82301a }, - { 0x000080c4, 0x05dc01e0 }, - { 0x000080c8, 0x1f402710 }, - { 0x000080cc, 0x01f40000 }, - { 0x000080d0, 0x00001e00 }, - { 0x000080d4, 0x00000000 }, - { 0x000080d8, 0x00400000 }, - { 0x000080e0, 0xffffffff }, - { 0x000080e4, 0x0000ffff }, - { 0x000080e8, 0x003f3f3f }, - { 0x000080ec, 0x00000000 }, - { 0x000080f0, 0x00000000 }, - { 0x000080f4, 0x00000000 }, - { 0x000080f8, 0x00000000 }, - { 0x000080fc, 0x00020000 }, - { 0x00008100, 0x00020000 }, - { 0x00008104, 0x00000001 }, - { 0x00008108, 0x00000052 }, - { 0x0000810c, 0x00000000 }, - { 0x00008110, 0x00000168 }, - { 0x00008118, 0x000100aa }, - { 0x0000811c, 0x00003210 }, - { 0x00008120, 0x08f04800 }, - { 0x00008124, 0x00000000 }, - { 0x00008128, 0x00000000 }, - { 0x0000812c, 0x00000000 }, - { 0x00008130, 0x00000000 }, - { 0x00008134, 0x00000000 }, - { 0x00008138, 0x00000000 }, - { 0x0000813c, 0x00000000 }, - { 0x00008144, 0xffffffff }, - { 0x00008168, 0x00000000 }, - { 0x0000816c, 0x00000000 }, - { 0x00008170, 0x32143320 }, - { 0x00008174, 0xfaa4fa50 }, - { 0x00008178, 0x00000100 }, - { 0x0000817c, 0x00000000 }, - { 0x000081c4, 0x00000000 }, - { 0x000081d0, 0x00003210 }, - { 0x000081ec, 0x00000000 }, - { 0x000081f0, 0x00000000 }, - { 0x000081f4, 0x00000000 }, - { 0x000081f8, 0x00000000 }, - { 0x000081fc, 0x00000000 }, - { 0x00008200, 0x00000000 }, - { 0x00008204, 0x00000000 }, - { 0x00008208, 0x00000000 }, - { 0x0000820c, 0x00000000 }, - { 0x00008210, 0x00000000 }, - { 0x00008214, 0x00000000 }, - { 0x00008218, 0x00000000 }, - { 0x0000821c, 0x00000000 }, - { 0x00008220, 0x00000000 }, - { 0x00008224, 0x00000000 }, - { 0x00008228, 0x00000000 }, - { 0x0000822c, 0x00000000 }, - { 0x00008230, 0x00000000 }, - { 0x00008234, 0x00000000 }, - { 0x00008238, 0x00000000 }, - { 0x0000823c, 0x00000000 }, - { 0x00008240, 0x00100000 }, - { 0x00008244, 0x0010f400 }, - { 0x00008248, 0x00000100 }, - { 0x0000824c, 0x0001e800 }, - { 0x00008250, 0x00000000 }, - { 0x00008254, 0x00000000 }, - { 0x00008258, 0x00000000 }, - { 0x0000825c, 0x400000ff }, - { 0x00008260, 0x00080922 }, - { 0x00008270, 0x00000000 }, - { 0x00008274, 0x40000000 }, - { 0x00008278, 0x003e4180 }, - { 0x0000827c, 0x00000000 }, - { 0x00008284, 0x0000002c }, - { 0x00008288, 0x0000002c }, - { 0x0000828c, 0x00000000 }, - { 0x00008294, 0x00000000 }, - { 0x00008298, 0x00000000 }, - { 0x00008300, 0x00000000 }, - { 0x00008304, 0x00000000 }, - { 0x00008308, 0x00000000 }, - { 0x0000830c, 0x00000000 }, - { 0x00008310, 0x00000000 }, - { 0x00008314, 0x00000000 }, - { 0x00008318, 0x00000000 }, - { 0x00008328, 0x00000000 }, - { 0x0000832c, 0x00000007 }, - { 0x00008330, 0x00000302 }, - { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00ff0000 }, - { 0x0000833c, 0x00000000 }, - { 0x00008340, 0x000107ff }, - { 0x00009808, 0x00000000 }, - { 0x0000980c, 0xad848e19 }, - { 0x00009810, 0x7d14e000 }, - { 0x00009814, 0x9c0a9f6b }, - { 0x0000981c, 0x00000000 }, - { 0x0000982c, 0x0000a000 }, - { 0x00009830, 0x00000000 }, - { 0x0000983c, 0x00200400 }, - { 0x00009840, 0x206a01ae }, - { 0x0000984c, 0x1284233c }, - { 0x00009854, 0x00000859 }, - { 0x00009900, 0x00000000 }, - { 0x00009904, 0x00000000 }, - { 0x00009908, 0x00000000 }, - { 0x0000990c, 0x00000000 }, - { 0x0000991c, 0x10000fff }, - { 0x00009920, 0x05100000 }, - { 0x0000a920, 0x05100000 }, - { 0x0000b920, 0x05100000 }, - { 0x00009928, 0x00000001 }, - { 0x0000992c, 0x00000004 }, - { 0x00009934, 0x1e1f2022 }, - { 0x00009938, 0x0a0b0c0d }, - { 0x0000993c, 0x00000000 }, - { 0x00009948, 0x9280b212 }, - { 0x0000994c, 0x00020028 }, - { 0x00009954, 0x5f3ca3de }, - { 0x00009958, 0x2108ecff }, - { 0x00009940, 0x00750604 }, - { 0x0000c95c, 0x004b6a8e }, - { 0x00009970, 0x190fb515 }, - { 0x00009974, 0x00000000 }, - { 0x00009978, 0x00000001 }, - { 0x0000997c, 0x00000000 }, - { 0x00009980, 0x00000000 }, - { 0x00009984, 0x00000000 }, - { 0x00009988, 0x00000000 }, - { 0x0000998c, 0x00000000 }, - { 0x00009990, 0x00000000 }, - { 0x00009994, 0x00000000 }, - { 0x00009998, 0x00000000 }, - { 0x0000999c, 0x00000000 }, - { 0x000099a0, 0x00000000 }, - { 0x000099a4, 0x00000001 }, - { 0x000099a8, 0x201fff00 }, - { 0x000099ac, 0x006f0000 }, - { 0x000099b0, 0x03051000 }, - { 0x000099dc, 0x00000000 }, - { 0x000099e0, 0x00000200 }, - { 0x000099e4, 0xaaaaaaaa }, - { 0x000099e8, 0x3c466478 }, - { 0x000099ec, 0x0cc80caa }, - { 0x000099fc, 0x00001042 }, - { 0x00009b00, 0x00000000 }, - { 0x00009b04, 0x00000001 }, - { 0x00009b08, 0x00000002 }, - { 0x00009b0c, 0x00000003 }, - { 0x00009b10, 0x00000004 }, - { 0x00009b14, 0x00000005 }, - { 0x00009b18, 0x00000008 }, - { 0x00009b1c, 0x00000009 }, - { 0x00009b20, 0x0000000a }, - { 0x00009b24, 0x0000000b }, - { 0x00009b28, 0x0000000c }, - { 0x00009b2c, 0x0000000d }, - { 0x00009b30, 0x00000010 }, - { 0x00009b34, 0x00000011 }, - { 0x00009b38, 0x00000012 }, - { 0x00009b3c, 0x00000013 }, - { 0x00009b40, 0x00000014 }, - { 0x00009b44, 0x00000015 }, - { 0x00009b48, 0x00000018 }, - { 0x00009b4c, 0x00000019 }, - { 0x00009b50, 0x0000001a }, - { 0x00009b54, 0x0000001b }, - { 0x00009b58, 0x0000001c }, - { 0x00009b5c, 0x0000001d }, - { 0x00009b60, 0x00000020 }, - { 0x00009b64, 0x00000021 }, - { 0x00009b68, 0x00000022 }, - { 0x00009b6c, 0x00000023 }, - { 0x00009b70, 0x00000024 }, - { 0x00009b74, 0x00000025 }, - { 0x00009b78, 0x00000028 }, - { 0x00009b7c, 0x00000029 }, - { 0x00009b80, 0x0000002a }, - { 0x00009b84, 0x0000002b }, - { 0x00009b88, 0x0000002c }, - { 0x00009b8c, 0x0000002d }, - { 0x00009b90, 0x00000030 }, - { 0x00009b94, 0x00000031 }, - { 0x00009b98, 0x00000032 }, - { 0x00009b9c, 0x00000033 }, - { 0x00009ba0, 0x00000034 }, - { 0x00009ba4, 0x00000035 }, - { 0x00009ba8, 0x00000035 }, - { 0x00009bac, 0x00000035 }, - { 0x00009bb0, 0x00000035 }, - { 0x00009bb4, 0x00000035 }, - { 0x00009bb8, 0x00000035 }, - { 0x00009bbc, 0x00000035 }, - { 0x00009bc0, 0x00000035 }, - { 0x00009bc4, 0x00000035 }, - { 0x00009bc8, 0x00000035 }, - { 0x00009bcc, 0x00000035 }, - { 0x00009bd0, 0x00000035 }, - { 0x00009bd4, 0x00000035 }, - { 0x00009bd8, 0x00000035 }, - { 0x00009bdc, 0x00000035 }, - { 0x00009be0, 0x00000035 }, - { 0x00009be4, 0x00000035 }, - { 0x00009be8, 0x00000035 }, - { 0x00009bec, 0x00000035 }, - { 0x00009bf0, 0x00000035 }, - { 0x00009bf4, 0x00000035 }, - { 0x00009bf8, 0x00000010 }, - { 0x00009bfc, 0x0000001a }, - { 0x0000a210, 0x40806333 }, - { 0x0000a214, 0x00106c10 }, - { 0x0000a218, 0x009c4060 }, - { 0x0000a220, 0x018830c6 }, - { 0x0000a224, 0x00000400 }, - { 0x0000a228, 0x001a0bb5 }, - { 0x0000a22c, 0x00000000 }, - { 0x0000a234, 0x20202020 }, - { 0x0000a238, 0x20202020 }, - { 0x0000a23c, 0x13c889af }, - { 0x0000a240, 0x38490a20 }, - { 0x0000a244, 0x00007bb6 }, - { 0x0000a248, 0x0fff3ffc }, - { 0x0000a24c, 0x00000001 }, - { 0x0000a250, 0x0000e000 }, - { 0x0000a254, 0x00000000 }, - { 0x0000a258, 0x0cc75380 }, - { 0x0000a25c, 0x0f0f0f01 }, - { 0x0000a260, 0xdfa91f01 }, - { 0x0000a268, 0x00000001 }, - { 0x0000a26c, 0x0ebae9c6 }, - { 0x0000b26c, 0x0ebae9c6 }, - { 0x0000c26c, 0x0ebae9c6 }, - { 0x0000d270, 0x00820820 }, - { 0x0000a278, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce }, - { 0x0000a338, 0x00000000 }, - { 0x0000a33c, 0x00000000 }, - { 0x0000a340, 0x00000000 }, - { 0x0000a344, 0x00000000 }, - { 0x0000a348, 0x3fffffff }, - { 0x0000a34c, 0x3fffffff }, - { 0x0000a350, 0x3fffffff }, - { 0x0000a354, 0x0003ffff }, - { 0x0000a358, 0x79bfaa03 }, - { 0x0000d35c, 0x07ffffef }, - { 0x0000d360, 0x0fffffe7 }, - { 0x0000d364, 0x17ffffe5 }, - { 0x0000d368, 0x1fffffe4 }, - { 0x0000d36c, 0x37ffffe3 }, - { 0x0000d370, 0x3fffffe3 }, - { 0x0000d374, 0x57ffffe3 }, - { 0x0000d378, 0x5fffffe2 }, - { 0x0000d37c, 0x7fffffe2 }, - { 0x0000d380, 0x7f3c7bba }, - { 0x0000d384, 0xf3307ff0 }, - { 0x0000a388, 0x0c000000 }, - { 0x0000a38c, 0x20202020 }, - { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x1ce739ce }, - { 0x0000a398, 0x000001ce }, - { 0x0000a39c, 0x00000001 }, - { 0x0000a3a0, 0x00000000 }, - { 0x0000a3a4, 0x00000000 }, - { 0x0000a3a8, 0x00000000 }, - { 0x0000a3ac, 0x00000000 }, - { 0x0000a3b0, 0x00000000 }, - { 0x0000a3b4, 0x00000000 }, - { 0x0000a3b8, 0x00000000 }, - { 0x0000a3bc, 0x00000000 }, - { 0x0000a3c0, 0x00000000 }, - { 0x0000a3c4, 0x00000000 }, - { 0x0000a3c8, 0x00000246 }, - { 0x0000a3cc, 0x20202020 }, - { 0x0000a3d0, 0x20202020 }, - { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x1ce739ce }, - { 0x0000a3e0, 0x000001ce }, -}; - -static const u32 ar5416Bank0_9160[][2] = { - { 0x000098b0, 0x1e5795e5 }, - { 0x000098e0, 0x02008020 }, -}; - -static const u32 ar5416BB_RfGain_9160[][3] = { - { 0x00009a00, 0x00000000, 0x00000000 }, - { 0x00009a04, 0x00000040, 0x00000040 }, - { 0x00009a08, 0x00000080, 0x00000080 }, - { 0x00009a0c, 0x000001a1, 0x00000141 }, - { 0x00009a10, 0x000001e1, 0x00000181 }, - { 0x00009a14, 0x00000021, 0x000001c1 }, - { 0x00009a18, 0x00000061, 0x00000001 }, - { 0x00009a1c, 0x00000168, 0x00000041 }, - { 0x00009a20, 0x000001a8, 0x000001a8 }, - { 0x00009a24, 0x000001e8, 0x000001e8 }, - { 0x00009a28, 0x00000028, 0x00000028 }, - { 0x00009a2c, 0x00000068, 0x00000068 }, - { 0x00009a30, 0x00000189, 0x000000a8 }, - { 0x00009a34, 0x000001c9, 0x00000169 }, - { 0x00009a38, 0x00000009, 0x000001a9 }, - { 0x00009a3c, 0x00000049, 0x000001e9 }, - { 0x00009a40, 0x00000089, 0x00000029 }, - { 0x00009a44, 0x00000170, 0x00000069 }, - { 0x00009a48, 0x000001b0, 0x00000190 }, - { 0x00009a4c, 0x000001f0, 0x000001d0 }, - { 0x00009a50, 0x00000030, 0x00000010 }, - { 0x00009a54, 0x00000070, 0x00000050 }, - { 0x00009a58, 0x00000191, 0x00000090 }, - { 0x00009a5c, 0x000001d1, 0x00000151 }, - { 0x00009a60, 0x00000011, 0x00000191 }, - { 0x00009a64, 0x00000051, 0x000001d1 }, - { 0x00009a68, 0x00000091, 0x00000011 }, - { 0x00009a6c, 0x000001b8, 0x00000051 }, - { 0x00009a70, 0x000001f8, 0x00000198 }, - { 0x00009a74, 0x00000038, 0x000001d8 }, - { 0x00009a78, 0x00000078, 0x00000018 }, - { 0x00009a7c, 0x00000199, 0x00000058 }, - { 0x00009a80, 0x000001d9, 0x00000098 }, - { 0x00009a84, 0x00000019, 0x00000159 }, - { 0x00009a88, 0x00000059, 0x00000199 }, - { 0x00009a8c, 0x00000099, 0x000001d9 }, - { 0x00009a90, 0x000000d9, 0x00000019 }, - { 0x00009a94, 0x000000f9, 0x00000059 }, - { 0x00009a98, 0x000000f9, 0x00000099 }, - { 0x00009a9c, 0x000000f9, 0x000000d9 }, - { 0x00009aa0, 0x000000f9, 0x000000f9 }, - { 0x00009aa4, 0x000000f9, 0x000000f9 }, - { 0x00009aa8, 0x000000f9, 0x000000f9 }, - { 0x00009aac, 0x000000f9, 0x000000f9 }, - { 0x00009ab0, 0x000000f9, 0x000000f9 }, - { 0x00009ab4, 0x000000f9, 0x000000f9 }, - { 0x00009ab8, 0x000000f9, 0x000000f9 }, - { 0x00009abc, 0x000000f9, 0x000000f9 }, - { 0x00009ac0, 0x000000f9, 0x000000f9 }, - { 0x00009ac4, 0x000000f9, 0x000000f9 }, - { 0x00009ac8, 0x000000f9, 0x000000f9 }, - { 0x00009acc, 0x000000f9, 0x000000f9 }, - { 0x00009ad0, 0x000000f9, 0x000000f9 }, - { 0x00009ad4, 0x000000f9, 0x000000f9 }, - { 0x00009ad8, 0x000000f9, 0x000000f9 }, - { 0x00009adc, 0x000000f9, 0x000000f9 }, - { 0x00009ae0, 0x000000f9, 0x000000f9 }, - { 0x00009ae4, 0x000000f9, 0x000000f9 }, - { 0x00009ae8, 0x000000f9, 0x000000f9 }, - { 0x00009aec, 0x000000f9, 0x000000f9 }, - { 0x00009af0, 0x000000f9, 0x000000f9 }, - { 0x00009af4, 0x000000f9, 0x000000f9 }, - { 0x00009af8, 0x000000f9, 0x000000f9 }, - { 0x00009afc, 0x000000f9, 0x000000f9 }, -}; - -static const u32 ar5416Bank1_9160[][2] = { - { 0x000098b0, 0x02108421 }, - { 0x000098ec, 0x00000008 }, -}; - -static const u32 ar5416Bank2_9160[][2] = { - { 0x000098b0, 0x0e73ff17 }, - { 0x000098e0, 0x00000420 }, -}; - -static const u32 ar5416Bank3_9160[][3] = { - { 0x000098f0, 0x01400018, 0x01c00018 }, -}; - -static const u32 ar5416Bank6_9160[][3] = { - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x40ff0000, 0x40ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x004210a2, 0x004210a2 }, - { 0x0000989c, 0x0014008f, 0x0014008f }, - { 0x0000989c, 0x00c40003, 0x00c40003 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x0001805e, 0x0001805e }, - { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, - { 0x0000989c, 0x000000f1, 0x000000f1 }, - { 0x0000989c, 0x00002081, 0x00002081 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - -static const u32 ar5416Bank6TPC_9160[][3] = { - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00000000, 0x00000000 }, - { 0x0000989c, 0x00e00000, 0x00e00000 }, - { 0x0000989c, 0x005e0000, 0x005e0000 }, - { 0x0000989c, 0x00120000, 0x00120000 }, - { 0x0000989c, 0x00620000, 0x00620000 }, - { 0x0000989c, 0x00020000, 0x00020000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x40ff0000, 0x40ff0000 }, - { 0x0000989c, 0x005f0000, 0x005f0000 }, - { 0x0000989c, 0x00870000, 0x00870000 }, - { 0x0000989c, 0x00f90000, 0x00f90000 }, - { 0x0000989c, 0x007b0000, 0x007b0000 }, - { 0x0000989c, 0x00ff0000, 0x00ff0000 }, - { 0x0000989c, 0x00f50000, 0x00f50000 }, - { 0x0000989c, 0x00dc0000, 0x00dc0000 }, - { 0x0000989c, 0x00110000, 0x00110000 }, - { 0x0000989c, 0x006100a8, 0x006100a8 }, - { 0x0000989c, 0x00423022, 0x00423022 }, - { 0x0000989c, 0x2014008f, 0x2014008f }, - { 0x0000989c, 0x00c40002, 0x00c40002 }, - { 0x0000989c, 0x003000f2, 0x003000f2 }, - { 0x0000989c, 0x00440016, 0x00440016 }, - { 0x0000989c, 0x00410040, 0x00410040 }, - { 0x0000989c, 0x0001805e, 0x0001805e }, - { 0x0000989c, 0x0000c0ab, 0x0000c0ab }, - { 0x0000989c, 0x000000e1, 0x000000e1 }, - { 0x0000989c, 0x00007080, 0x00007080 }, - { 0x0000989c, 0x000000d4, 0x000000d4 }, - { 0x000098d0, 0x0000000f, 0x0010000f }, -}; - -static const u32 ar5416Bank7_9160[][2] = { - { 0x0000989c, 0x00000500 }, - { 0x0000989c, 0x00000800 }, - { 0x000098cc, 0x0000000e }, -}; +#ifndef INITVALS_9002_10_H +#define INITVALS_9002_10_H -static u32 ar5416Addac_9160[][2] = { - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x000000c0 }, - {0x0000989c, 0x00000018 }, - {0x0000989c, 0x00000004 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x000000c0 }, - {0x0000989c, 0x00000019 }, - {0x0000989c, 0x00000004 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000004 }, - {0x0000989c, 0x00000003 }, - {0x0000989c, 0x00000008 }, - {0x0000989c, 0x00000000 }, - {0x000098cc, 0x00000000 }, -}; - -static u32 ar5416Addac_91601_1[][2] = { - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x000000c0 }, - {0x0000989c, 0x00000018 }, - {0x0000989c, 0x00000004 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x000000c0 }, - {0x0000989c, 0x00000019 }, - {0x0000989c, 0x00000004 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x0000989c, 0x00000000 }, - {0x000098cc, 0x00000000 }, -}; - -/* XXX 9280 1 */ static const u32 ar9280Modes_9280[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -2766,7 +793,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008258, 0x00000000 }, { 0x0000825c, 0x400000ff }, { 0x00008260, 0x00080922 }, - { 0x00008264, 0xa8a00010 }, + { 0x00008264, 0x88a00010 }, { 0x00008270, 0x00000000 }, { 0x00008274, 0x40000000 }, { 0x00008278, 0x003e4180 }, @@ -3441,7 +1468,7 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { }; /* AR9285 Revsion 10*/ -static const u_int32_t ar9285Modes_9285[][6] = { +static const u32 ar9285Modes_9285[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, @@ -3763,7 +1790,7 @@ static const u_int32_t ar9285Modes_9285[][6] = { { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, }; -static const u_int32_t ar9285Common_9285[][2] = { +static const u32 ar9285Common_9285[][2] = { { 0x0000000c, 0x00000000 }, { 0x00000030, 0x00020045 }, { 0x00000034, 0x00000005 }, @@ -3936,7 +1963,7 @@ static const u_int32_t ar9285Common_9285[][2] = { { 0x00008258, 0x00000000 }, { 0x0000825c, 0x400000ff }, { 0x00008260, 0x00080922 }, - { 0x00008264, 0xa8a00010 }, + { 0x00008264, 0x88a00010 }, { 0x00008270, 0x00000000 }, { 0x00008274, 0x40000000 }, { 0x00008278, 0x003e4180 }, @@ -4096,7 +2123,7 @@ static const u_int32_t ar9285Common_9285[][2] = { { 0x00007870, 0x10142c00 }, }; -static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285[][2] = { +static const u32 ar9285PciePhy_clkreq_always_on_L1_9285[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, @@ -4109,7 +2136,7 @@ static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285[][2] = { {0x00004044, 0x00000000 }, }; -static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = { +static const u32 ar9285PciePhy_clkreq_off_L1_9285[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, @@ -4123,7 +2150,7 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = { }; /* AR9285 v1_2 PCI Register Writes. Created: 04/13/09 */ -static const u_int32_t ar9285Modes_9285_1_2[][6] = { +static const u32 ar9285Modes_9285_1_2[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -4184,7 +2211,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, - { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 }, { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, @@ -4198,8 +2225,8 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, - { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, - { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, @@ -4312,7 +2339,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, - { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 }, { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, @@ -4326,8 +2353,8 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, - { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, - { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, @@ -4429,7 +2456,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = { { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, }; -static const u_int32_t ar9285Common_9285_1_2[][2] = { +static const u32 ar9285Common_9285_1_2[][2] = { { 0x0000000c, 0x00000000 }, { 0x00000030, 0x00020045 }, { 0x00000034, 0x00000005 }, @@ -4731,17 +2758,12 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00007808, 0x54214514 }, { 0x0000780c, 0x02025830 }, { 0x00007810, 0x71c0d388 }, - { 0x00007814, 0x924934a8 }, { 0x0000781c, 0x00000000 }, { 0x00007824, 0x00d86fff }, - { 0x00007828, 0x26d2491b }, { 0x0000782c, 0x6e36d97b }, - { 0x00007830, 0xedb6d96e }, { 0x00007834, 0x71400087 }, - { 0x0000783c, 0x0001fffe }, - { 0x00007840, 0xffeb1a20 }, { 0x00007844, 0x000c0db6 }, - { 0x00007848, 0x6db61b6f }, + { 0x00007848, 0x6db6246f }, { 0x0000784c, 0x6d9b66db }, { 0x00007850, 0x6d8c6dba }, { 0x00007854, 0x00040000 }, @@ -4753,7 +2775,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = { { 0x00007870, 0x10142c00 }, }; -static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { +static const u32 ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 }, @@ -4777,7 +2799,12 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 }, + { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b }, + { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e }, { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 }, + { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe }, + { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 }, { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe }, { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 }, @@ -4789,7 +2816,7 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 }, }; -static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = { +static const u32 ar9285Modes_original_tx_gain_9285_1_2[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, @@ -4813,7 +2840,52 @@ static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = { { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 }, + { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b }, + { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e }, { 0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801 }, + { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe }, + { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 }, + { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 }, + { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 }, + { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, + { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c }, + { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, + { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c }, + { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, +}; + +static const u32 ar9285Modes_XE2_0_normal_power[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 }, + { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b }, + { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6dbae }, + { 0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441 }, + { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe }, + { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c }, { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 }, { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 }, { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, @@ -4825,7 +2897,47 @@ static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = { { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c }, }; -static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { +static const u32 ar9285Modes_XE2_0_high_power[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 }, + { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b }, + { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e }, + { 0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443 }, + { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe }, + { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c }, + { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe }, + { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 }, + { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 }, + { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 }, + { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 }, +}; + +static const u32 ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, @@ -4838,7 +2950,7 @@ static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { {0x00004044, 0x00000000 }, }; -static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { +static const u32 ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, @@ -4852,7 +2964,7 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { }; /* AR9287 Revision 10 */ -static const u_int32_t ar9287Modes_9287_1_0[][6] = { +static const u32 ar9287Modes_9287_1_0[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -4899,7 +3011,7 @@ static const u_int32_t ar9287Modes_9287_1_0[][6] = { { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, }; -static const u_int32_t ar9287Common_9287_1_0[][2] = { +static const u32 ar9287Common_9287_1_0[][2] = { { 0x0000000c, 0x00000000 }, { 0x00000030, 0x00020015 }, { 0x00000034, 0x00000005 }, @@ -5073,7 +3185,7 @@ static const u_int32_t ar9287Common_9287_1_0[][2] = { { 0x00008258, 0x00000000 }, { 0x0000825c, 0x400000ff }, { 0x00008260, 0x00080922 }, - { 0x00008264, 0xa8a00010 }, + { 0x00008264, 0x88a00010 }, { 0x00008270, 0x00000000 }, { 0x00008274, 0x40000000 }, { 0x00008278, 0x003e4180 }, @@ -5270,7 +3382,7 @@ static const u_int32_t ar9287Common_9287_1_0[][2] = { { 0x000078b8, 0x2a850160 }, }; -static const u_int32_t ar9287Modes_tx_gain_9287_1_0[][6] = { +static const u32 ar9287Modes_tx_gain_9287_1_0[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 }, @@ -5320,7 +3432,7 @@ static const u_int32_t ar9287Modes_tx_gain_9287_1_0[][6] = { }; -static const u_int32_t ar9287Modes_rx_gain_9287_1_0[][6] = { +static const u32 ar9287Modes_rx_gain_9287_1_0[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 }, { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 }, @@ -5582,7 +3694,7 @@ static const u_int32_t ar9287Modes_rx_gain_9287_1_0[][6] = { { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 }, }; -static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = { +static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, @@ -5595,7 +3707,7 @@ static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = { {0x00004044, 0x00000000 }, }; -static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = { +static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, @@ -5610,7 +3722,7 @@ static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = { /* AR9287 Revision 11 */ -static const u_int32_t ar9287Modes_9287_1_1[][6] = { +static const u32 ar9287Modes_9287_1_1[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -5657,7 +3769,7 @@ static const u_int32_t ar9287Modes_9287_1_1[][6] = { { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, }; -static const u_int32_t ar9287Common_9287_1_1[][2] = { +static const u32 ar9287Common_9287_1_1[][2] = { { 0x0000000c, 0x00000000 }, { 0x00000030, 0x00020015 }, { 0x00000034, 0x00000005 }, @@ -6027,21 +4139,22 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = { /* * For Japanese regulatory requirements, 2484 MHz requires the following three - * registers be programmed differently from the channel between 2412 and 2472 MHz. + * registers be programmed differently from the channel between 2412 and + * 2472 MHz. */ -static const u_int32_t ar9287Common_normal_cck_fir_coeff_92871_1[][2] = { +static const u32 ar9287Common_normal_cck_fir_coeff_92871_1[][2] = { { 0x0000a1f4, 0x00fffeff }, { 0x0000a1f8, 0x00f5f9ff }, { 0x0000a1fc, 0xb79f6427 }, }; -static const u_int32_t ar9287Common_japan_2484_cck_fir_coeff_92871_1[][2] = { +static const u32 ar9287Common_japan_2484_cck_fir_coeff_92871_1[][2] = { { 0x0000a1f4, 0x00000000 }, { 0x0000a1f8, 0xefff0301 }, { 0x0000a1fc, 0xca9228ee }, }; -static const u_int32_t ar9287Modes_tx_gain_9287_1_1[][6] = { +static const u32 ar9287Modes_tx_gain_9287_1_1[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 }, @@ -6090,7 +4203,7 @@ static const u_int32_t ar9287Modes_tx_gain_9287_1_1[][6] = { { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 }, }; -static const u_int32_t ar9287Modes_rx_gain_9287_1_1[][6] = { +static const u32 ar9287Modes_rx_gain_9287_1_1[][6] = { /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 }, { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 }, @@ -6352,7 +4465,7 @@ static const u_int32_t ar9287Modes_rx_gain_9287_1_1[][6] = { { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 }, }; -static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = { +static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, @@ -6365,7 +4478,7 @@ static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = { {0x00004044, 0x00000000 }, }; -static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = { +static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, @@ -6380,7 +4493,7 @@ static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = { /* AR9271 initialization values automaticaly created: 06/04/09 */ -static const u_int32_t ar9271Modes_9271[][6] = { +static const u32 ar9271Modes_9271[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, @@ -6441,7 +4554,7 @@ static const u_int32_t ar9271Modes_9271[][6] = { { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, - { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 }, { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, @@ -6455,8 +4568,8 @@ static const u_int32_t ar9271Modes_9271[][6] = { { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, - { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, - { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, @@ -6569,7 +4682,7 @@ static const u_int32_t ar9271Modes_9271[][6] = { { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, - { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 }, { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, @@ -6583,8 +4696,8 @@ static const u_int32_t ar9271Modes_9271[][6] = { { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, - { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, - { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, @@ -6683,29 +4796,10 @@ static const u_int32_t ar9271Modes_9271[][6] = { { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, - { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 }, - { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, - { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 }, - { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 }, - { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 }, - { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 }, - { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 }, - { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 }, - { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 }, - { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 }, - { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 }, - { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 }, - { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 }, - { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 }, - { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, - { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, - { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, - { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, }; -static const u_int32_t ar9271Common_9271[][2] = { +static const u32 ar9271Common_9271[][2] = { { 0x0000000c, 0x00000000 }, { 0x00000030, 0x00020045 }, { 0x00000034, 0x00000005 }, @@ -6910,13 +5004,10 @@ static const u_int32_t ar9271Common_9271[][2] = { { 0x00007810, 0x71c0d388 }, { 0x00007814, 0x924934a8 }, { 0x0000781c, 0x00000000 }, - { 0x00007820, 0x00000c04 }, - { 0x00007824, 0x00d8abff }, { 0x00007828, 0x66964300 }, { 0x0000782c, 0x8db6d961 }, { 0x00007830, 0x8db6d96c }, { 0x00007834, 0x6140008b }, - { 0x00007838, 0x00000029 }, { 0x0000783c, 0x72ee0a72 }, { 0x00007840, 0xbbfffffc }, { 0x00007844, 0x000c0db6 }, @@ -6929,7 +5020,6 @@ static const u_int32_t ar9271Common_9271[][2] = { { 0x00007860, 0x21084210 }, { 0x00007864, 0xf7d7ffde }, { 0x00007868, 0xc2034080 }, - { 0x0000786c, 0x48609eb4 }, { 0x00007870, 0x10142c00 }, { 0x00009808, 0x00000000 }, { 0x0000980c, 0xafe68e30 }, @@ -6982,9 +5072,6 @@ static const u_int32_t ar9271Common_9271[][2] = { { 0x000099e8, 0x3c466478 }, { 0x000099ec, 0x0cc80caa }, { 0x000099f0, 0x00000000 }, - { 0x0000a1f4, 0x00000000 }, - { 0x0000a1f8, 0x71733d01 }, - { 0x0000a1fc, 0xd0ad5c12 }, { 0x0000a208, 0x803e68c8 }, { 0x0000a210, 0x4080a333 }, { 0x0000a214, 0x00206c10 }, @@ -7004,13 +5091,9 @@ static const u_int32_t ar9271Common_9271[][2] = { { 0x0000a260, 0xdfa90f01 }, { 0x0000a268, 0x00000000 }, { 0x0000a26c, 0x0ebae9e6 }, - { 0x0000a278, 0x3bdef7bd }, - { 0x0000a27c, 0x050e83bd }, { 0x0000a388, 0x0c000000 }, { 0x0000a38c, 0x20202020 }, { 0x0000a390, 0x20202020 }, - { 0x0000a394, 0x3bdef7bd }, - { 0x0000a398, 0x000003bd }, { 0x0000a39c, 0x00000001 }, { 0x0000a3a0, 0x00000000 }, { 0x0000a3a4, 0x00000000 }, @@ -7025,8 +5108,6 @@ static const u_int32_t ar9271Common_9271[][2] = { { 0x0000a3cc, 0x20202020 }, { 0x0000a3d0, 0x20202020 }, { 0x0000a3d4, 0x20202020 }, - { 0x0000a3dc, 0x3bdef7bd }, - { 0x0000a3e0, 0x000003bd }, { 0x0000a3e4, 0x00000000 }, { 0x0000a3e8, 0x18c43433 }, { 0x0000a3ec, 0x00f70081 }, @@ -7046,7 +5127,104 @@ static const u_int32_t ar9271Common_9271[][2] = { { 0x0000d384, 0xf3307ff0 }, }; -static const u_int32_t ar9271Modes_9271_1_0_only[][6] = { +static const u32 ar9271Common_normal_cck_fir_coeff_9271[][2] = { + { 0x0000a1f4, 0x00fffeff }, + { 0x0000a1f8, 0x00f5f9ff }, + { 0x0000a1fc, 0xb79f6427 }, +}; + +static const u32 ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = { + { 0x0000a1f4, 0x00000000 }, + { 0x0000a1f8, 0xefff0301 }, + { 0x0000a1fc, 0xca9228ee }, +}; + +static const u32 ar9271Modes_9271_1_0_only[][6] = { { 0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311 }, { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, }; + +static const u32 ar9271Modes_9271_ANI_reg[][6] = { + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e }, + { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8 }, + { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, +}; + +static const u32 ar9271Modes_normal_power_tx_gain_9271[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 }, + { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029, 0x00000029 }, + { 0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff }, + { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 }, + { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 }, + { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 }, + { 0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd }, + { 0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd }, + { 0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd }, + { 0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd }, + { 0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd }, + { 0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd }, +}; + +static const u32 ar9271Modes_high_power_tx_gain_9271[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80, 0x00000000 }, + { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 }, + { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b }, + { 0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff }, + { 0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba, 0x08609eb6 }, + { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a212652, 0x0a212652, 0x0a22a652 }, + { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, + { 0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063, 0x05018063 }, + { 0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63 }, + { 0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063 }, + { 0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63 }, + { 0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063 }, +}; + +#endif /* INITVALS_9002_10_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c new file mode 100644 index 00000000000..2be20d2070c --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2008-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 "hw.h" + +#define AR_BufLen 0x00000fff + +static void ar9002_hw_rx_enable(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_CR, AR_CR_RXE); +} + +static void ar9002_hw_set_desc_link(void *ds, u32 ds_link) +{ + ((struct ath_desc*) ds)->ds_link = ds_link; +} + +static void ar9002_hw_get_desc_link(void *ds, u32 **ds_link) +{ + *ds_link = &((struct ath_desc *)ds)->ds_link; +} + +static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) +{ + u32 isr = 0; + u32 mask2 = 0; + struct ath9k_hw_capabilities *pCap = &ah->caps; + u32 sync_cause = 0; + bool fatal_int = false; + struct ath_common *common = ath9k_hw_common(ah); + + if (!AR_SREV_9100(ah)) { + if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { + if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) + == AR_RTC_STATUS_ON) { + isr = REG_READ(ah, AR_ISR); + } + } + + sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & + AR_INTR_SYNC_DEFAULT; + + *masked = 0; + + if (!isr && !sync_cause) + return false; + } else { + *masked = 0; + isr = REG_READ(ah, AR_ISR); + } + + if (isr) { + if (isr & AR_ISR_BCNMISC) { + u32 isr2; + isr2 = REG_READ(ah, AR_ISR_S2); + if (isr2 & AR_ISR_S2_TIM) + mask2 |= ATH9K_INT_TIM; + if (isr2 & AR_ISR_S2_DTIM) + mask2 |= ATH9K_INT_DTIM; + if (isr2 & AR_ISR_S2_DTIMSYNC) + mask2 |= ATH9K_INT_DTIMSYNC; + if (isr2 & (AR_ISR_S2_CABEND)) + mask2 |= ATH9K_INT_CABEND; + if (isr2 & AR_ISR_S2_GTT) + mask2 |= ATH9K_INT_GTT; + if (isr2 & AR_ISR_S2_CST) + mask2 |= ATH9K_INT_CST; + if (isr2 & AR_ISR_S2_TSFOOR) + mask2 |= ATH9K_INT_TSFOOR; + } + + isr = REG_READ(ah, AR_ISR_RAC); + if (isr == 0xffffffff) { + *masked = 0; + return false; + } + + *masked = isr & ATH9K_INT_COMMON; + + if (ah->config.rx_intr_mitigation) { + if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) + *masked |= ATH9K_INT_RX; + } + + if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) + *masked |= ATH9K_INT_RX; + if (isr & + (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | + AR_ISR_TXEOL)) { + u32 s0_s, s1_s; + + *masked |= ATH9K_INT_TX; + + s0_s = REG_READ(ah, AR_ISR_S0_S); + ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK); + ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); + + s1_s = REG_READ(ah, AR_ISR_S1_S); + ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR); + ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL); + } + + if (isr & AR_ISR_RXORN) { + ath_print(common, ATH_DBG_INTERRUPT, + "receive FIFO overrun interrupt\n"); + } + + if (!AR_SREV_9100(ah)) { + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + u32 isr5 = REG_READ(ah, AR_ISR_S5_S); + if (isr5 & AR_ISR_S5_TIM_TIMER) + *masked |= ATH9K_INT_TIM_TIMER; + } + } + + *masked |= mask2; + } + + if (AR_SREV_9100(ah)) + return true; + + if (isr & AR_ISR_GENTMR) { + u32 s5_s; + + s5_s = REG_READ(ah, AR_ISR_S5_S); + if (isr & AR_ISR_GENTMR) { + ah->intr_gen_timer_trigger = + MS(s5_s, AR_ISR_S5_GENTIMER_TRIG); + + ah->intr_gen_timer_thresh = + MS(s5_s, AR_ISR_S5_GENTIMER_THRESH); + + if (ah->intr_gen_timer_trigger) + *masked |= ATH9K_INT_GENTIMER; + + } + } + + if (sync_cause) { + fatal_int = + (sync_cause & + (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) + ? true : false; + + if (fatal_int) { + if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { + ath_print(common, ATH_DBG_ANY, + "received PCI FATAL interrupt\n"); + } + if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { + ath_print(common, ATH_DBG_ANY, + "received PCI PERR interrupt\n"); + } + *masked |= ATH9K_INT_FATAL; + } + if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { + ath_print(common, ATH_DBG_INTERRUPT, + "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); + REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); + REG_WRITE(ah, AR_RC, 0); + *masked |= ATH9K_INT_FATAL; + } + if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { + ath_print(common, ATH_DBG_INTERRUPT, + "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); + } + + REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); + (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); + } + + return true; +} + +static void ar9002_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen, + bool is_firstseg, bool is_lastseg, + const void *ds0, dma_addr_t buf_addr, + unsigned int qcu) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_data = buf_addr; + + if (is_firstseg) { + ads->ds_ctl1 |= seglen | (is_lastseg ? 0 : AR_TxMore); + } else if (is_lastseg) { + ads->ds_ctl0 = 0; + ads->ds_ctl1 = seglen; + ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; + ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; + } else { + ads->ds_ctl0 = 0; + ads->ds_ctl1 = seglen | AR_TxMore; + ads->ds_ctl2 = 0; + ads->ds_ctl3 = 0; + } + ads->ds_txstatus0 = ads->ds_txstatus1 = 0; + ads->ds_txstatus2 = ads->ds_txstatus3 = 0; + ads->ds_txstatus4 = ads->ds_txstatus5 = 0; + ads->ds_txstatus6 = ads->ds_txstatus7 = 0; + ads->ds_txstatus8 = ads->ds_txstatus9 = 0; +} + +static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, + struct ath_tx_status *ts) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if ((ads->ds_txstatus9 & AR_TxDone) == 0) + return -EINPROGRESS; + + ts->ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); + ts->ts_tstamp = ads->AR_SendTimestamp; + ts->ts_status = 0; + ts->ts_flags = 0; + + if (ads->ds_txstatus1 & AR_FrmXmitOK) + ts->ts_status |= ATH9K_TX_ACKED; + if (ads->ds_txstatus1 & AR_ExcessiveRetries) + ts->ts_status |= ATH9K_TXERR_XRETRY; + if (ads->ds_txstatus1 & AR_Filtered) + ts->ts_status |= ATH9K_TXERR_FILT; + if (ads->ds_txstatus1 & AR_FIFOUnderrun) { + ts->ts_status |= ATH9K_TXERR_FIFO; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus9 & AR_TxOpExceeded) + ts->ts_status |= ATH9K_TXERR_XTXOP; + if (ads->ds_txstatus1 & AR_TxTimerExpired) + ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED; + + if (ads->ds_txstatus1 & AR_DescCfgErr) + ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR; + if (ads->ds_txstatus1 & AR_TxDataUnderrun) { + ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { + ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus0 & AR_TxBaStatus) { + ts->ts_flags |= ATH9K_TX_BA; + ts->ba_low = ads->AR_BaBitmapLow; + ts->ba_high = ads->AR_BaBitmapHigh; + } + + ts->ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); + switch (ts->ts_rateindex) { + case 0: + ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); + break; + case 1: + ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); + break; + case 2: + ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); + break; + case 3: + ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); + break; + } + + ts->ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); + ts->ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); + ts->ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); + ts->ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); + ts->ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); + ts->ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); + ts->ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); + ts->evm0 = ads->AR_TxEVM0; + ts->evm1 = ads->AR_TxEVM1; + ts->evm2 = ads->AR_TxEVM2; + ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); + ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); + ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); + ts->ts_antenna = 0; + + return 0; +} + +static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds, + u32 pktLen, enum ath9k_pkt_type type, + u32 txPower, u32 keyIx, + enum ath9k_key_type keyType, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + txPower += ah->txpower_indexoffset; + if (txPower > 63) + txPower = 63; + + ads->ds_ctl0 = (pktLen & AR_FrameLen) + | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) + | SM(txPower, AR_XmitPower) + | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) + | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) + | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) + | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); + + ads->ds_ctl1 = + (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) + | SM(type, AR_FrameType) + | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) + | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) + | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); + + ads->ds_ctl6 = SM(keyType, AR_EncrType); + + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) { + ads->ds_ctl8 = 0; + ads->ds_ctl9 = 0; + ads->ds_ctl10 = 0; + ads->ds_ctl11 = 0; + } +} + +static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, + void *lastds, + u32 durUpdateEn, u32 rtsctsRate, + u32 rtsctsDuration, + struct ath9k_11n_rate_series series[], + u32 nseries, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ar5416_desc *last_ads = AR5416DESC(lastds); + u32 ds_ctl0; + + if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { + ds_ctl0 = ads->ds_ctl0; + + if (flags & ATH9K_TXDESC_RTSENA) { + ds_ctl0 &= ~AR_CTSEnable; + ds_ctl0 |= AR_RTSEnable; + } else { + ds_ctl0 &= ~AR_RTSEnable; + ds_ctl0 |= AR_CTSEnable; + } + + ads->ds_ctl0 = ds_ctl0; + } else { + ads->ds_ctl0 = + (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); + } + + ads->ds_ctl2 = set11nTries(series, 0) + | set11nTries(series, 1) + | set11nTries(series, 2) + | set11nTries(series, 3) + | (durUpdateEn ? AR_DurUpdateEna : 0) + | SM(0, AR_BurstDur); + + ads->ds_ctl3 = set11nRate(series, 0) + | set11nRate(series, 1) + | set11nRate(series, 2) + | set11nRate(series, 3); + + ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) + | set11nPktDurRTSCTS(series, 1); + + ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) + | set11nPktDurRTSCTS(series, 3); + + ads->ds_ctl7 = set11nRateFlags(series, 0) + | set11nRateFlags(series, 1) + | set11nRateFlags(series, 2) + | set11nRateFlags(series, 3) + | SM(rtsctsRate, AR_RTSCTSRate); + last_ads->ds_ctl2 = ads->ds_ctl2; + last_ads->ds_ctl3 = ads->ds_ctl3; +} + +static void ar9002_hw_set11n_aggr_first(struct ath_hw *ah, void *ds, + u32 aggrLen) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + ads->ds_ctl6 &= ~AR_AggrLen; + ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); +} + +static void ar9002_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds, + u32 numDelims) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + unsigned int ctl6; + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + + ctl6 = ads->ds_ctl6; + ctl6 &= ~AR_PadDelim; + ctl6 |= SM(numDelims, AR_PadDelim); + ads->ds_ctl6 = ctl6; +} + +static void ar9002_hw_set11n_aggr_last(struct ath_hw *ah, void *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 |= AR_IsAggr; + ads->ds_ctl1 &= ~AR_MoreAggr; + ads->ds_ctl6 &= ~AR_PadDelim; +} + +static void ar9002_hw_clr11n_aggr(struct ath_hw *ah, void *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); +} + +static void ar9002_hw_set11n_burstduration(struct ath_hw *ah, void *ds, + u32 burstDuration) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl2 &= ~AR_BurstDur; + ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); +} + +static void ar9002_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, + u32 vmf) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if (vmf) + ads->ds_ctl0 |= AR_VirtMoreFrag; + else + ads->ds_ctl0 &= ~AR_VirtMoreFrag; +} + +void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, + u32 size, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ath9k_hw_capabilities *pCap = &ah->caps; + + ads->ds_ctl1 = size & AR_BufLen; + if (flags & ATH9K_RXDESC_INTREQ) + ads->ds_ctl1 |= AR_RxIntrReq; + + ads->ds_rxstatus8 &= ~AR_RxDone; + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) + memset(&(ads->u), 0, sizeof(ads->u)); +} +EXPORT_SYMBOL(ath9k_hw_setuprxdesc); + +void ar9002_hw_attach_mac_ops(struct ath_hw *ah) +{ + struct ath_hw_ops *ops = ath9k_hw_ops(ah); + + ops->rx_enable = ar9002_hw_rx_enable; + ops->set_desc_link = ar9002_hw_set_desc_link; + ops->get_desc_link = ar9002_hw_get_desc_link; + ops->get_isr = ar9002_hw_get_isr; + ops->fill_txdesc = ar9002_hw_fill_txdesc; + ops->proc_txdesc = ar9002_hw_proc_txdesc; + ops->set11n_txdesc = ar9002_hw_set11n_txdesc; + ops->set11n_ratescenario = ar9002_hw_set11n_ratescenario; + ops->set11n_aggr_first = ar9002_hw_set11n_aggr_first; + ops->set11n_aggr_middle = ar9002_hw_set11n_aggr_middle; + ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; + ops->clr11n_aggr = ar9002_hw_clr11n_aggr; + ops->set11n_burstduration = ar9002_hw_set11n_burstduration; + ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag; +} diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c new file mode 100644 index 00000000000..ed314e89bfe --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2008-2010 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. + */ + +/** + * DOC: Programming Atheros 802.11n analog front end radios + * + * AR5416 MAC based PCI devices and AR518 MAC based PCI-Express + * devices have either an external AR2133 analog front end radio for single + * band 2.4 GHz communication or an AR5133 analog front end radio for dual + * band 2.4 GHz / 5 GHz communication. + * + * All devices after the AR5416 and AR5418 family starting with the AR9280 + * have their analog front radios, MAC/BB and host PCIe/USB interface embedded + * into a single-chip and require less programming. + * + * The following single-chips exist with a respective embedded radio: + * + * AR9280 - 11n dual-band 2x2 MIMO for PCIe + * AR9281 - 11n single-band 1x2 MIMO for PCIe + * AR9285 - 11n single-band 1x1 for PCIe + * AR9287 - 11n single-band 2x2 MIMO for PCIe + * + * AR9220 - 11n dual-band 2x2 MIMO for PCI + * AR9223 - 11n single-band 2x2 MIMO for PCI + * + * AR9287 - 11n single-band 1x1 MIMO for USB + */ + +#include "hw.h" +#include "ar9002_phy.h" + +/** + * ar9002_hw_set_channel - set channel on single-chip device + * @ah: atheros hardware structure + * @chan: + * + * This is the function to change channel on single-chip devices, that is + * all devices after ar9280. + * + * This function takes the channel value in MHz and sets + * hardware channel value. Assumes writes have been enabled to analog bus. + * + * Actual Expression, + * + * For 2GHz channel, + * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17) + * (freq_ref = 40MHz) + * + * For 5GHz channel, + * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10) + * (freq_ref = 40MHz/(24>>amodeRefSel)) + */ +static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) +{ + u16 bMode, fracMode, aModeRefSel = 0; + u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0; + struct chan_centers centers; + u32 refDivA = 24; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL); + reg32 &= 0xc0000000; + + if (freq < 4800) { /* 2 GHz, fractional mode */ + u32 txctl; + int regWrites = 0; + + bMode = 1; + fracMode = 1; + aModeRefSel = 0; + channelSel = CHANSEL_2G(freq); + + if (AR_SREV_9287_11_OR_LATER(ah)) { + if (freq == 2484) { + /* Enable channel spreading for channel 14 */ + REG_WRITE_ARRAY(&ah->iniCckfirJapan2484, + 1, regWrites); + } else { + REG_WRITE_ARRAY(&ah->iniCckfirNormal, + 1, regWrites); + } + } else { + txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); + if (freq == 2484) { + /* Enable channel spreading for channel 14 */ + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl | AR_PHY_CCK_TX_CTRL_JAPAN); + } else { + REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, + txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); + } + } + } else { + bMode = 0; + fracMode = 0; + + switch (ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) { + case 0: + if ((freq % 20) == 0) + aModeRefSel = 3; + else if ((freq % 10) == 0) + aModeRefSel = 2; + if (aModeRefSel) + break; + case 1: + default: + aModeRefSel = 0; + /* + * Enable 2G (fractional) mode for channels + * which are 5MHz spaced. + */ + fracMode = 1; + refDivA = 1; + channelSel = CHANSEL_5G(freq); + + /* RefDivA setting */ + REG_RMW_FIELD(ah, AR_AN_SYNTH9, + AR_AN_SYNTH9_REFDIVA, refDivA); + + } + + if (!fracMode) { + ndiv = (freq * (refDivA >> aModeRefSel)) / 60; + channelSel = ndiv & 0x1ff; + channelFrac = (ndiv & 0xfffffe00) * 2; + channelSel = (channelSel << 17) | channelFrac; + } + } + + reg32 = reg32 | + (bMode << 29) | + (fracMode << 28) | (aModeRefSel << 26) | (channelSel); + + REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); + + ah->curchan = chan; + ah->curchan_rad_index = -1; + + return 0; +} + +/** + * ar9002_hw_spur_mitigate - convert baseband spur frequency + * @ah: atheros hardware structure + * @chan: + * + * For single-chip solutions. Converts to baseband spur frequency given the + * input channel frequency and compute register settings below. + */ +static void ar9002_hw_spur_mitigate(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + int bb_spur = AR_NO_SPUR; + int freq; + int bin, cur_bin; + int bb_spur_off, spur_subchannel_sd; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, newVal; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; + struct chan_centers centers; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); + + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + ah->config.spurmode = SPUR_ENABLE_EEPROM; + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); + + if (is2GHz) + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; + else + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; + + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - freq; + + if (IS_CHAN_HT40(chan)) { + if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { + bb_spur = cur_bb_spur; + break; + } + } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + return; + } else { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + } + + bin = bb_spur * 320; + + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + + ENABLE_REGWRITE_BUFFER(ah); + + newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); + + newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); + + if (IS_CHAN_HT40(chan)) { + if (bb_spur < 0) { + spur_subchannel_sd = 1; + bb_spur_off = bb_spur + 10; + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur - 10; + } + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur; + } + + if (IS_CHAN_HT40(chan)) + spur_delta_phase = + ((bb_spur * 262144) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + else + spur_delta_phase = + ((bb_spur * 524288) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; + spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; + + newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, newVal); + + newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; + REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); + + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + + /* workaround for gcc bug #37014 */ + volatile int tmp_v = abs(cur_vit_mask - bin); + + if (tmp_v < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); +} + +static void ar9002_olc_init(struct ath_hw *ah) +{ + u32 i; + + if (!OLC_FOR_AR9280_20_LATER) + return; + + if (OLC_FOR_AR9287_10_LATER) { + REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9, + AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL); + ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TXPC0, + AR9287_AN_TXPC0_TXPCMODE, + AR9287_AN_TXPC0_TXPCMODE_S, + AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE); + udelay(100); + } else { + for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) + ah->originalGain[i] = + MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), + AR_PHY_TX_GAIN); + ah->PDADCdelta = 0; + } +} + +static u32 ar9002_hw_compute_pll_control(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 pll; + + pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); + + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); + + if (chan && IS_CHAN_5GHZ(chan)) { + if (IS_CHAN_A_FAST_CLOCK(ah, chan)) + pll = 0x142c; + else if (AR_SREV_9280_20(ah)) + pll = 0x2850; + else + pll |= SM(0x28, AR_RTC_9160_PLL_DIV); + } else { + pll |= SM(0x2c, AR_RTC_9160_PLL_DIV); + } + + return pll; +} + +static void ar9002_hw_do_getnf(struct ath_hw *ah, + int16_t nfarray[NUM_NF_READINGS]) +{ + struct ath_common *common = ath9k_hw_common(ah); + int16_t nf; + + nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 0] is %d\n", nf); + + if (AR_SREV_9271(ah) && (nf >= -114)) + nf = -116; + + nfarray[0] = nf; + + if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), + AR9280_PHY_CH1_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 1] is %d\n", nf); + nfarray[1] = nf; + } + + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR9280_PHY_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 0] is %d\n", nf); + + if (AR_SREV_9271(ah) && (nf >= -114)) + nf = -116; + + nfarray[3] = nf; + + if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), + AR9280_PHY_CH1_EXT_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 1] is %d\n", nf); + nfarray[4] = nf; + } +} + +void ar9002_hw_attach_phy_ops(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + + priv_ops->set_rf_regs = NULL; + priv_ops->rf_alloc_ext_banks = NULL; + priv_ops->rf_free_ext_banks = NULL; + priv_ops->rf_set_freq = ar9002_hw_set_channel; + priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate; + priv_ops->olc_init = ar9002_olc_init; + priv_ops->compute_pll_control = ar9002_hw_compute_pll_control; + priv_ops->do_getnf = ar9002_hw_do_getnf; +} diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h new file mode 100644 index 00000000000..81bf6e5840e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2008-2010 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. + */ +#ifndef AR9002_PHY_H +#define AR9002_PHY_H + +#define AR_PHY_TEST 0x9800 +#define PHY_AGC_CLR 0x10000000 +#define RFSILENT_BB 0x00002000 + +#define AR_PHY_TURBO 0x9804 +#define AR_PHY_FC_TURBO_MODE 0x00000001 +#define AR_PHY_FC_TURBO_SHORT 0x00000002 +#define AR_PHY_FC_DYN2040_EN 0x00000004 +#define AR_PHY_FC_DYN2040_PRI_ONLY 0x00000008 +#define AR_PHY_FC_DYN2040_PRI_CH 0x00000010 +/* For 25 MHz channel spacing -- not used but supported by hw */ +#define AR_PHY_FC_DYN2040_EXT_CH 0x00000020 +#define AR_PHY_FC_HT_EN 0x00000040 +#define AR_PHY_FC_SHORT_GI_40 0x00000080 +#define AR_PHY_FC_WALSH 0x00000100 +#define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200 +#define AR_PHY_FC_ENABLE_DAC_FIFO 0x00000800 + +#define AR_PHY_TEST2 0x9808 + +#define AR_PHY_TIMING2 0x9810 +#define AR_PHY_TIMING3 0x9814 +#define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 +#define AR_PHY_TIMING3_DSC_MAN_S 17 +#define AR_PHY_TIMING3_DSC_EXP 0x0001E000 +#define AR_PHY_TIMING3_DSC_EXP_S 13 + +#define AR_PHY_CHIP_ID_REV_0 0x80 +#define AR_PHY_CHIP_ID_REV_1 0x81 +#define AR_PHY_CHIP_ID_9160_REV_0 0xb0 + +#define AR_PHY_ACTIVE 0x981C +#define AR_PHY_ACTIVE_EN 0x00000001 +#define AR_PHY_ACTIVE_DIS 0x00000000 + +#define AR_PHY_RF_CTL2 0x9824 +#define AR_PHY_TX_END_DATA_START 0x000000FF +#define AR_PHY_TX_END_DATA_START_S 0 +#define AR_PHY_TX_END_PA_ON 0x0000FF00 +#define AR_PHY_TX_END_PA_ON_S 8 + +#define AR_PHY_RF_CTL3 0x9828 +#define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000 +#define AR_PHY_TX_END_TO_A2_RX_ON_S 16 + +#define AR_PHY_ADC_CTL 0x982C +#define AR_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003 +#define AR_PHY_ADC_CTL_OFF_INBUFGAIN_S 0 +#define AR_PHY_ADC_CTL_OFF_PWDDAC 0x00002000 +#define AR_PHY_ADC_CTL_OFF_PWDBANDGAP 0x00004000 +#define AR_PHY_ADC_CTL_OFF_PWDADC 0x00008000 +#define AR_PHY_ADC_CTL_ON_INBUFGAIN 0x00030000 +#define AR_PHY_ADC_CTL_ON_INBUFGAIN_S 16 + +#define AR_PHY_ADC_SERIAL_CTL 0x9830 +#define AR_PHY_SEL_INTERNAL_ADDAC 0x00000000 +#define AR_PHY_SEL_EXTERNAL_RADIO 0x00000001 + +#define AR_PHY_RF_CTL4 0x9834 +#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF 0xFF000000 +#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF_S 24 +#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF 0x00FF0000 +#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF_S 16 +#define AR_PHY_RF_CTL4_FRAME_XPAB_ON 0x0000FF00 +#define AR_PHY_RF_CTL4_FRAME_XPAB_ON_S 8 +#define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF +#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0 + +#define AR_PHY_TSTDAC_CONST 0x983c + +#define AR_PHY_SETTLING 0x9844 +#define AR_PHY_SETTLING_SWITCH 0x00003F80 +#define AR_PHY_SETTLING_SWITCH_S 7 + +#define AR_PHY_RXGAIN 0x9848 +#define AR_PHY_RXGAIN_TXRX_ATTEN 0x0003F000 +#define AR_PHY_RXGAIN_TXRX_ATTEN_S 12 +#define AR_PHY_RXGAIN_TXRX_RF_MAX 0x007C0000 +#define AR_PHY_RXGAIN_TXRX_RF_MAX_S 18 +#define AR9280_PHY_RXGAIN_TXRX_ATTEN 0x00003F80 +#define AR9280_PHY_RXGAIN_TXRX_ATTEN_S 7 +#define AR9280_PHY_RXGAIN_TXRX_MARGIN 0x001FC000 +#define AR9280_PHY_RXGAIN_TXRX_MARGIN_S 14 + +#define AR_PHY_DESIRED_SZ 0x9850 +#define AR_PHY_DESIRED_SZ_ADC 0x000000FF +#define AR_PHY_DESIRED_SZ_ADC_S 0 +#define AR_PHY_DESIRED_SZ_PGA 0x0000FF00 +#define AR_PHY_DESIRED_SZ_PGA_S 8 +#define AR_PHY_DESIRED_SZ_TOT_DES 0x0FF00000 +#define AR_PHY_DESIRED_SZ_TOT_DES_S 20 + +#define AR_PHY_FIND_SIG 0x9858 +#define AR_PHY_FIND_SIG_FIRSTEP 0x0003F000 +#define AR_PHY_FIND_SIG_FIRSTEP_S 12 +#define AR_PHY_FIND_SIG_FIRPWR 0x03FC0000 +#define AR_PHY_FIND_SIG_FIRPWR_S 18 + +#define AR_PHY_AGC_CTL1 0x985C +#define AR_PHY_AGC_CTL1_COARSE_LOW 0x00007F80 +#define AR_PHY_AGC_CTL1_COARSE_LOW_S 7 +#define AR_PHY_AGC_CTL1_COARSE_HIGH 0x003F8000 +#define AR_PHY_AGC_CTL1_COARSE_HIGH_S 15 + +#define AR_PHY_CCA 0x9864 +#define AR_PHY_MINCCA_PWR 0x0FF80000 +#define AR_PHY_MINCCA_PWR_S 19 +#define AR_PHY_CCA_THRESH62 0x0007F000 +#define AR_PHY_CCA_THRESH62_S 12 +#define AR9280_PHY_MINCCA_PWR 0x1FF00000 +#define AR9280_PHY_MINCCA_PWR_S 20 +#define AR9280_PHY_CCA_THRESH62 0x000FF000 +#define AR9280_PHY_CCA_THRESH62_S 12 + +#define AR_PHY_SFCORR_LOW 0x986C +#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW 0x00000001 +#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW 0x00003F00 +#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S 8 +#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW 0x001FC000 +#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S 14 +#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW 0x0FE00000 +#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S 21 + +#define AR_PHY_SFCORR 0x9868 +#define AR_PHY_SFCORR_M2COUNT_THR 0x0000001F +#define AR_PHY_SFCORR_M2COUNT_THR_S 0 +#define AR_PHY_SFCORR_M1_THRESH 0x00FE0000 +#define AR_PHY_SFCORR_M1_THRESH_S 17 +#define AR_PHY_SFCORR_M2_THRESH 0x7F000000 +#define AR_PHY_SFCORR_M2_THRESH_S 24 + +#define AR_PHY_SLEEP_CTR_CONTROL 0x9870 +#define AR_PHY_SLEEP_CTR_LIMIT 0x9874 +#define AR_PHY_SYNTH_CONTROL 0x9874 +#define AR_PHY_SLEEP_SCAL 0x9878 + +#define AR_PHY_PLL_CTL 0x987c +#define AR_PHY_PLL_CTL_40 0xaa +#define AR_PHY_PLL_CTL_40_5413 0x04 +#define AR_PHY_PLL_CTL_44 0xab +#define AR_PHY_PLL_CTL_44_2133 0xeb +#define AR_PHY_PLL_CTL_40_2133 0xea + +#define AR_PHY_SPECTRAL_SCAN 0x9910 /* AR9280 spectral scan configuration register */ +#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x1 +#define AR_PHY_SPECTRAL_SCAN_ENA 0x00000001 /* Enable spectral scan, reg 68, bit 0 */ +#define AR_PHY_SPECTRAL_SCAN_ENA_S 0 /* Enable spectral scan, reg 68, bit 0 */ +#define AR_PHY_SPECTRAL_SCAN_ACTIVE 0x00000002 /* Activate spectral scan reg 68, bit 1*/ +#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S 1 /* Activate spectral scan reg 68, bit 1*/ +#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD 0x000000F0 /* Interval for FFT reports, reg 68, bits 4-7*/ +#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S 4 +#define AR_PHY_SPECTRAL_SCAN_PERIOD 0x0000FF00 /* Interval for FFT reports, reg 68, bits 8-15*/ +#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8 +#define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 /* Number of reports, reg 68, bits 16-23*/ +#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16 +#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 /* Short repeat, reg 68, bit 24*/ +#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 /* Short repeat, reg 68, bit 24*/ + +#define AR_PHY_RX_DELAY 0x9914 +#define AR_PHY_SEARCH_START_DELAY 0x9918 +#define AR_PHY_RX_DELAY_DELAY 0x00003FFF + +#define AR_PHY_TIMING_CTRL4(_i) (0x9920 + ((_i) << 12)) +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01F +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S 0 +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7E0 +#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5 +#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x800 +#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xF000 +#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12 +#define AR_PHY_TIMING_CTRL4_DO_CAL 0x10000 + +#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI 0x80000000 +#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER 0x40000000 +#define AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK 0x20000000 +#define AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK 0x10000000 + +#define AR_PHY_TIMING5 0x9924 +#define AR_PHY_TIMING5_CYCPWR_THR1 0x000000FE +#define AR_PHY_TIMING5_CYCPWR_THR1_S 1 + +#define AR_PHY_POWER_TX_RATE1 0x9934 +#define AR_PHY_POWER_TX_RATE2 0x9938 +#define AR_PHY_POWER_TX_RATE_MAX 0x993c +#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040 + +#define AR_PHY_FRAME_CTL 0x9944 +#define AR_PHY_FRAME_CTL_TX_CLIP 0x00000038 +#define AR_PHY_FRAME_CTL_TX_CLIP_S 3 + +#define AR_PHY_TXPWRADJ 0x994C +#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA 0x00000FC0 +#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA_S 6 +#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX 0x00FC0000 +#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX_S 18 + +#define AR_PHY_RADAR_EXT 0x9940 +#define AR_PHY_RADAR_EXT_ENA 0x00004000 + +#define AR_PHY_RADAR_0 0x9954 +#define AR_PHY_RADAR_0_ENA 0x00000001 +#define AR_PHY_RADAR_0_FFT_ENA 0x80000000 +#define AR_PHY_RADAR_0_INBAND 0x0000003e +#define AR_PHY_RADAR_0_INBAND_S 1 +#define AR_PHY_RADAR_0_PRSSI 0x00000FC0 +#define AR_PHY_RADAR_0_PRSSI_S 6 +#define AR_PHY_RADAR_0_HEIGHT 0x0003F000 +#define AR_PHY_RADAR_0_HEIGHT_S 12 +#define AR_PHY_RADAR_0_RRSSI 0x00FC0000 +#define AR_PHY_RADAR_0_RRSSI_S 18 +#define AR_PHY_RADAR_0_FIRPWR 0x7F000000 +#define AR_PHY_RADAR_0_FIRPWR_S 24 + +#define AR_PHY_RADAR_1 0x9958 +#define AR_PHY_RADAR_1_RELPWR_ENA 0x00800000 +#define AR_PHY_RADAR_1_USE_FIR128 0x00400000 +#define AR_PHY_RADAR_1_RELPWR_THRESH 0x003F0000 +#define AR_PHY_RADAR_1_RELPWR_THRESH_S 16 +#define AR_PHY_RADAR_1_BLOCK_CHECK 0x00008000 +#define AR_PHY_RADAR_1_MAX_RRSSI 0x00004000 +#define AR_PHY_RADAR_1_RELSTEP_CHECK 0x00002000 +#define AR_PHY_RADAR_1_RELSTEP_THRESH 0x00001F00 +#define AR_PHY_RADAR_1_RELSTEP_THRESH_S 8 +#define AR_PHY_RADAR_1_MAXLEN 0x000000FF +#define AR_PHY_RADAR_1_MAXLEN_S 0 + +#define AR_PHY_SWITCH_CHAIN_0 0x9960 +#define AR_PHY_SWITCH_COM 0x9964 + +#define AR_PHY_SIGMA_DELTA 0x996C +#define AR_PHY_SIGMA_DELTA_ADC_SEL 0x00000003 +#define AR_PHY_SIGMA_DELTA_ADC_SEL_S 0 +#define AR_PHY_SIGMA_DELTA_FILT2 0x000000F8 +#define AR_PHY_SIGMA_DELTA_FILT2_S 3 +#define AR_PHY_SIGMA_DELTA_FILT1 0x00001F00 +#define AR_PHY_SIGMA_DELTA_FILT1_S 8 +#define AR_PHY_SIGMA_DELTA_ADC_CLIP 0x01FFE000 +#define AR_PHY_SIGMA_DELTA_ADC_CLIP_S 13 + +#define AR_PHY_RESTART 0x9970 +#define AR_PHY_RESTART_DIV_GC 0x001C0000 +#define AR_PHY_RESTART_DIV_GC_S 18 + +#define AR_PHY_RFBUS_REQ 0x997C +#define AR_PHY_RFBUS_REQ_EN 0x00000001 + +#define AR_PHY_TIMING7 0x9980 +#define AR_PHY_TIMING8 0x9984 +#define AR_PHY_TIMING8_PILOT_MASK_2 0x000FFFFF +#define AR_PHY_TIMING8_PILOT_MASK_2_S 0 + +#define AR_PHY_BIN_MASK2_1 0x9988 +#define AR_PHY_BIN_MASK2_2 0x998c +#define AR_PHY_BIN_MASK2_3 0x9990 +#define AR_PHY_BIN_MASK2_4 0x9994 + +#define AR_PHY_BIN_MASK_1 0x9900 +#define AR_PHY_BIN_MASK_2 0x9904 +#define AR_PHY_BIN_MASK_3 0x9908 + +#define AR_PHY_MASK_CTL 0x990c + +#define AR_PHY_BIN_MASK2_4_MASK_4 0x00003FFF +#define AR_PHY_BIN_MASK2_4_MASK_4_S 0 + +#define AR_PHY_TIMING9 0x9998 +#define AR_PHY_TIMING10 0x999c +#define AR_PHY_TIMING10_PILOT_MASK_2 0x000FFFFF +#define AR_PHY_TIMING10_PILOT_MASK_2_S 0 + +#define AR_PHY_TIMING11 0x99a0 +#define AR_PHY_TIMING11_SPUR_DELTA_PHASE 0x000FFFFF +#define AR_PHY_TIMING11_SPUR_DELTA_PHASE_S 0 +#define AR_PHY_TIMING11_USE_SPUR_IN_AGC 0x40000000 +#define AR_PHY_TIMING11_USE_SPUR_IN_SELFCOR 0x80000000 + +#define AR_PHY_RX_CHAINMASK 0x99a4 +#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12)) +#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000 +#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000 + +#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac +#define AR_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000 +#define AR_PHY_9285_ANT_DIV_CTL 0x01000000 +#define AR_PHY_9285_ANT_DIV_CTL_S 24 +#define AR_PHY_9285_ANT_DIV_ALT_LNACONF 0x06000000 +#define AR_PHY_9285_ANT_DIV_ALT_LNACONF_S 25 +#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF 0x18000000 +#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S 27 +#define AR_PHY_9285_ANT_DIV_ALT_GAINTB 0x20000000 +#define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S 29 +#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000 +#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30 +#define AR_PHY_9285_ANT_DIV_LNA1 2 +#define AR_PHY_9285_ANT_DIV_LNA2 1 +#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3 +#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0 +#define AR_PHY_9285_ANT_DIV_GAINTB_0 0 +#define AR_PHY_9285_ANT_DIV_GAINTB_1 1 + +#define AR_PHY_EXT_CCA0 0x99b8 +#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF +#define AR_PHY_EXT_CCA0_THRESH62_S 0 + +#define AR_PHY_EXT_CCA 0x99bc +#define AR_PHY_EXT_CCA_CYCPWR_THR1 0x0000FE00 +#define AR_PHY_EXT_CCA_CYCPWR_THR1_S 9 +#define AR_PHY_EXT_CCA_THRESH62 0x007F0000 +#define AR_PHY_EXT_CCA_THRESH62_S 16 +#define AR_PHY_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_EXT_MINCCA_PWR_S 23 +#define AR9280_PHY_EXT_MINCCA_PWR 0x01FF0000 +#define AR9280_PHY_EXT_MINCCA_PWR_S 16 + +#define AR_PHY_SFCORR_EXT 0x99c0 +#define AR_PHY_SFCORR_EXT_M1_THRESH 0x0000007F +#define AR_PHY_SFCORR_EXT_M1_THRESH_S 0 +#define AR_PHY_SFCORR_EXT_M2_THRESH 0x00003F80 +#define AR_PHY_SFCORR_EXT_M2_THRESH_S 7 +#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW 0x001FC000 +#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14 +#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW 0x0FE00000 +#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21 +#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28 + +#define AR_PHY_HALFGI 0x99D0 +#define AR_PHY_HALFGI_DSC_MAN 0x0007FFF0 +#define AR_PHY_HALFGI_DSC_MAN_S 4 +#define AR_PHY_HALFGI_DSC_EXP 0x0000000F +#define AR_PHY_HALFGI_DSC_EXP_S 0 + +#define AR_PHY_CHAN_INFO_MEMORY 0x99DC +#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001 + +#define AR_PHY_HEAVY_CLIP_ENABLE 0x99E0 + +#define AR_PHY_HEAVY_CLIP_FACTOR_RIFS 0x99EC +#define AR_PHY_RIFS_INIT_DELAY 0x03ff0000 + +#define AR_PHY_M_SLEEP 0x99f0 +#define AR_PHY_REFCLKDLY 0x99f4 +#define AR_PHY_REFCLKPD 0x99f8 + +#define AR_PHY_CALMODE 0x99f0 + +#define AR_PHY_CALMODE_IQ 0x00000000 +#define AR_PHY_CALMODE_ADC_GAIN 0x00000001 +#define AR_PHY_CALMODE_ADC_DC_PER 0x00000002 +#define AR_PHY_CALMODE_ADC_DC_INIT 0x00000003 + +#define AR_PHY_CAL_MEAS_0(_i) (0x9c10 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_1(_i) (0x9c14 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_2(_i) (0x9c18 + ((_i) << 12)) +#define AR_PHY_CAL_MEAS_3(_i) (0x9c1c + ((_i) << 12)) + +#define AR_PHY_CURRENT_RSSI 0x9c1c +#define AR9280_PHY_CURRENT_RSSI 0x9c3c + +#define AR_PHY_RFBUS_GRANT 0x9C20 +#define AR_PHY_RFBUS_GRANT_EN 0x00000001 + +#define AR_PHY_CHAN_INFO_GAIN_DIFF 0x9CF4 +#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320 + +#define AR_PHY_CHAN_INFO_GAIN 0x9CFC + +#define AR_PHY_MODE 0xA200 +#define AR_PHY_MODE_ASYNCFIFO 0x80 +#define AR_PHY_MODE_AR2133 0x08 +#define AR_PHY_MODE_AR5111 0x00 +#define AR_PHY_MODE_AR5112 0x08 +#define AR_PHY_MODE_DYNAMIC 0x04 +#define AR_PHY_MODE_RF2GHZ 0x02 +#define AR_PHY_MODE_RF5GHZ 0x00 +#define AR_PHY_MODE_CCK 0x01 +#define AR_PHY_MODE_OFDM 0x00 +#define AR_PHY_MODE_DYN_CCK_DISABLE 0x100 + +#define AR_PHY_CCK_TX_CTRL 0xA204 +#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010 +#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK 0x0000000C +#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S 2 + +#define AR_PHY_CCK_DETECT 0xA208 +#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F +#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0 +/* [12:6] settling time for antenna switch */ +#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0 +#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6 +#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 +#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S 13 + +#define AR_PHY_GAIN_2GHZ 0xA20C +#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000 +#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN_S 18 +#define AR_PHY_GAIN_2GHZ_BSW_MARGIN 0x00003C00 +#define AR_PHY_GAIN_2GHZ_BSW_MARGIN_S 10 +#define AR_PHY_GAIN_2GHZ_BSW_ATTEN 0x0000001F +#define AR_PHY_GAIN_2GHZ_BSW_ATTEN_S 0 + +#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN 0x003E0000 +#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN_S 17 +#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN 0x0001F000 +#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN_S 12 +#define AR_PHY_GAIN_2GHZ_XATTEN2_DB 0x00000FC0 +#define AR_PHY_GAIN_2GHZ_XATTEN2_DB_S 6 +#define AR_PHY_GAIN_2GHZ_XATTEN1_DB 0x0000003F +#define AR_PHY_GAIN_2GHZ_XATTEN1_DB_S 0 + +#define AR_PHY_CCK_RXCTRL4 0xA21C +#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT 0x01F80000 +#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19 + +#define AR_PHY_DAG_CTRLCCK 0xA228 +#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR 0x00000200 +#define AR_PHY_DAG_CTRLCCK_RSSI_THR 0x0001FC00 +#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S 10 + +#define AR_PHY_FORCE_CLKEN_CCK 0xA22C +#define AR_PHY_FORCE_CLKEN_CCK_MRC_MUX 0x00000040 + +#define AR_PHY_POWER_TX_RATE3 0xA234 +#define AR_PHY_POWER_TX_RATE4 0xA238 + +#define AR_PHY_SCRM_SEQ_XR 0xA23C +#define AR_PHY_HEADER_DETECT_XR 0xA240 +#define AR_PHY_CHIRP_DETECTED_XR 0xA244 +#define AR_PHY_BLUETOOTH 0xA254 + +#define AR_PHY_TPCRG1 0xA258 +#define AR_PHY_TPCRG1_NUM_PD_GAIN 0x0000c000 +#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14 + +#define AR_PHY_TPCRG1_PD_GAIN_1 0x00030000 +#define AR_PHY_TPCRG1_PD_GAIN_1_S 16 +#define AR_PHY_TPCRG1_PD_GAIN_2 0x000C0000 +#define AR_PHY_TPCRG1_PD_GAIN_2_S 18 +#define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000 +#define AR_PHY_TPCRG1_PD_GAIN_3_S 20 + +#define AR_PHY_TPCRG1_PD_CAL_ENABLE 0x00400000 +#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22 + +#define AR_PHY_TX_PWRCTRL4 0xa264 +#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID 0x00000001 +#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID_S 0 +#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT 0x000001FE +#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT_S 1 + +#define AR_PHY_TX_PWRCTRL6_0 0xa270 +#define AR_PHY_TX_PWRCTRL6_1 0xb270 +#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE 0x03000000 +#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S 24 + +#define AR_PHY_TX_PWRCTRL7 0xa274 +#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000 +#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19 + +#define AR_PHY_TX_PWRCTRL9 0xa27C +#define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 +#define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 +#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000 +#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31 + +#define AR_PHY_TX_GAIN_TBL1 0xa300 +#define AR_PHY_TX_GAIN 0x0007F000 +#define AR_PHY_TX_GAIN_S 12 + +#define AR_PHY_CH0_TX_PWRCTRL11 0xa398 +#define AR_PHY_CH1_TX_PWRCTRL11 0xb398 +#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00 +#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10 + +#define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 +#define AR_PHY_MASK2_M_31_45 0xa3a4 +#define AR_PHY_MASK2_M_16_30 0xa3a8 +#define AR_PHY_MASK2_M_00_15 0xa3ac +#define AR_PHY_MASK2_P_15_01 0xa3b8 +#define AR_PHY_MASK2_P_30_16 0xa3bc +#define AR_PHY_MASK2_P_45_31 0xa3c0 +#define AR_PHY_MASK2_P_61_45 0xa3c4 +#define AR_PHY_SPUR_REG 0x994c + +#define AR_PHY_SPUR_REG_MASK_RATE_CNTL (0xFF << 18) +#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S 18 + +#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM 0x20000 +#define AR_PHY_SPUR_REG_MASK_RATE_SELECT (0xFF << 9) +#define AR_PHY_SPUR_REG_MASK_RATE_SELECT_S 9 +#define AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100 +#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH 0x7F +#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S 0 + +#define AR_PHY_PILOT_MASK_01_30 0xa3b0 +#define AR_PHY_PILOT_MASK_31_60 0xa3b4 + +#define AR_PHY_CHANNEL_MASK_01_30 0x99d4 +#define AR_PHY_CHANNEL_MASK_31_60 0x99d8 + +#define AR_PHY_ANALOG_SWAP 0xa268 +#define AR_PHY_SWAP_ALT_CHAIN 0x00000040 + +#define AR_PHY_TPCRG5 0xA26C +#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP 0x0000000F +#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S 0 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1 0x000003F0 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S 4 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2 0x0000FC00 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S 10 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3 0x003F0000 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S 16 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0FC00000 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22 + +/* Carrier leak calibration control, do it after AGC calibration */ +#define AR_PHY_CL_CAL_CTL 0xA358 +#define AR_PHY_CL_CAL_ENABLE 0x00000002 +#define AR_PHY_PARALLEL_CAL_ENABLE 0x00000001 + +#define AR_PHY_POWER_TX_RATE5 0xA38C +#define AR_PHY_POWER_TX_RATE6 0xA390 + +#define AR_PHY_CAL_CHAINMASK 0xA39C + +#define AR_PHY_POWER_TX_SUB 0xA3C8 +#define AR_PHY_POWER_TX_RATE7 0xA3CC +#define AR_PHY_POWER_TX_RATE8 0xA3D0 +#define AR_PHY_POWER_TX_RATE9 0xA3D4 + +#define AR_PHY_XPA_CFG 0xA3D8 +#define AR_PHY_FORCE_XPA_CFG 0x000000001 +#define AR_PHY_FORCE_XPA_CFG_S 0 + +#define AR_PHY_CH1_CCA 0xa864 +#define AR_PHY_CH1_MINCCA_PWR 0x0FF80000 +#define AR_PHY_CH1_MINCCA_PWR_S 19 +#define AR9280_PHY_CH1_MINCCA_PWR 0x1FF00000 +#define AR9280_PHY_CH1_MINCCA_PWR_S 20 + +#define AR_PHY_CH2_CCA 0xb864 +#define AR_PHY_CH2_MINCCA_PWR 0x0FF80000 +#define AR_PHY_CH2_MINCCA_PWR_S 19 + +#define AR_PHY_CH1_EXT_CCA 0xa9bc +#define AR_PHY_CH1_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23 +#define AR9280_PHY_CH1_EXT_MINCCA_PWR 0x01FF0000 +#define AR9280_PHY_CH1_EXT_MINCCA_PWR_S 16 + +#define AR_PHY_CH2_EXT_CCA 0xb9bc +#define AR_PHY_CH2_EXT_MINCCA_PWR 0xFF800000 +#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23 + +#endif diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c new file mode 100644 index 00000000000..56a9e5fa6d6 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -0,0 +1,802 @@ +/* + * Copyright (c) 2010 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 "hw.h" +#include "hw-ops.h" +#include "ar9003_phy.h" + +static void ar9003_hw_setup_calibration(struct ath_hw *ah, + struct ath9k_cal_list *currCal) +{ + struct ath_common *common = ath9k_hw_common(ah); + + /* Select calibration to run */ + switch (currCal->calData->calType) { + case IQ_MISMATCH_CAL: + /* + * Start calibration with + * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples + */ + REG_RMW_FIELD(ah, AR_PHY_TIMING4, + AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX, + currCal->calData->calCountMax); + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); + + ath_print(common, ATH_DBG_CALIBRATE, + "starting IQ Mismatch Calibration\n"); + + /* Kick-off cal */ + REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); + break; + case TEMP_COMP_CAL: + REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, + AR_PHY_65NM_CH0_THERM_LOCAL, 1); + REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, + AR_PHY_65NM_CH0_THERM_START, 1); + + ath_print(common, ATH_DBG_CALIBRATE, + "starting Temperature Compensation Calibration\n"); + break; + case ADC_DC_INIT_CAL: + case ADC_GAIN_CAL: + case ADC_DC_CAL: + /* Not yet */ + break; + } +} + +/* + * Generic calibration routine. + * Recalibrate the lower PHY chips to account for temperature/environment + * changes. + */ +static bool ar9003_hw_per_calibration(struct ath_hw *ah, + struct ath9k_channel *ichan, + u8 rxchainmask, + struct ath9k_cal_list *currCal) +{ + /* Cal is assumed not done until explicitly set below */ + bool iscaldone = false; + + /* Calibration in progress. */ + if (currCal->calState == CAL_RUNNING) { + /* Check to see if it has finished. */ + if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) { + /* + * Accumulate cal measures for active chains + */ + currCal->calData->calCollect(ah); + ah->cal_samples++; + + if (ah->cal_samples >= + currCal->calData->calNumSamples) { + unsigned int i, numChains = 0; + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (rxchainmask & (1 << i)) + numChains++; + } + + /* + * Process accumulated data + */ + currCal->calData->calPostProc(ah, numChains); + + /* Calibration has finished. */ + ichan->CalValid |= currCal->calData->calType; + currCal->calState = CAL_DONE; + iscaldone = true; + } else { + /* + * Set-up collection of another sub-sample until we + * get desired number + */ + ar9003_hw_setup_calibration(ah, currCal); + } + } + } else if (!(ichan->CalValid & currCal->calData->calType)) { + /* If current cal is marked invalid in channel, kick it off */ + ath9k_hw_reset_calibration(ah, currCal); + } + + return iscaldone; +} + +static bool ar9003_hw_calibrate(struct ath_hw *ah, + struct ath9k_channel *chan, + u8 rxchainmask, + bool longcal) +{ + bool iscaldone = true; + struct ath9k_cal_list *currCal = ah->cal_list_curr; + + /* + * For given calibration: + * 1. Call generic cal routine + * 2. When this cal is done (isCalDone) if we have more cals waiting + * (eg after reset), mask this to upper layers by not propagating + * isCalDone if it is set to TRUE. + * Instead, change isCalDone to FALSE and setup the waiting cal(s) + * to be run. + */ + if (currCal && + (currCal->calState == CAL_RUNNING || + currCal->calState == CAL_WAITING)) { + iscaldone = ar9003_hw_per_calibration(ah, chan, + rxchainmask, currCal); + if (iscaldone) { + ah->cal_list_curr = currCal = currCal->calNext; + + if (currCal->calState == CAL_WAITING) { + iscaldone = false; + ath9k_hw_reset_calibration(ah, currCal); + } + } + } + + /* Do NF cal only at longer intervals */ + if (longcal) { + /* + * Load the NF from history buffer of the current channel. + * NF is slow time-variant, so it is OK to use a historical + * value. + */ + ath9k_hw_loadnf(ah, ah->curchan); + + /* start NF calibration, without updating BB NF register */ + ath9k_hw_start_nfcal(ah); + } + + return iscaldone; +} + +static void ar9003_hw_iqcal_collect(struct ath_hw *ah) +{ + int i; + + /* Accumulate IQ cal measures for active chains */ + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ah->totalPowerMeasI[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ah->totalPowerMeasQ[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ah->totalIqCorrMeas[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + ah->cal_samples, i, ah->totalPowerMeasI[i], + ah->totalPowerMeasQ[i], + ah->totalIqCorrMeas[i]); + } +} + +static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) +{ + struct ath_common *common = ath9k_hw_common(ah); + u32 powerMeasQ, powerMeasI, iqCorrMeas; + u32 qCoffDenom, iCoffDenom; + int32_t qCoff, iCoff; + int iqCorrNeg, i; + const u_int32_t offset_array[3] = { + AR_PHY_RX_IQCAL_CORR_B0, + AR_PHY_RX_IQCAL_CORR_B1, + AR_PHY_RX_IQCAL_CORR_B2, + }; + + for (i = 0; i < numChains; i++) { + powerMeasI = ah->totalPowerMeasI[i]; + powerMeasQ = ah->totalPowerMeasQ[i]; + iqCorrMeas = ah->totalIqCorrMeas[i]; + + ath_print(common, ATH_DBG_CALIBRATE, + "Starting IQ Cal and Correction for Chain %d\n", + i); + + ath_print(common, ATH_DBG_CALIBRATE, + "Orignal: Chn %diq_corr_meas = 0x%08x\n", + i, ah->totalIqCorrMeas[i]); + + iqCorrNeg = 0; + + if (iqCorrMeas > 0x80000000) { + iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; + iqCorrNeg = 1; + } + + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); + ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", + iqCorrNeg); + + iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256; + qCoffDenom = powerMeasQ / 64; + + if ((iCoffDenom != 0) && (qCoffDenom != 0)) { + iCoff = iqCorrMeas / iCoffDenom; + qCoff = powerMeasI / qCoffDenom - 64; + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d iCoff = 0x%08x\n", i, iCoff); + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d qCoff = 0x%08x\n", i, qCoff); + + /* Force bounds on iCoff */ + if (iCoff >= 63) + iCoff = 63; + else if (iCoff <= -63) + iCoff = -63; + + /* Negate iCoff if iqCorrNeg == 0 */ + if (iqCorrNeg == 0x0) + iCoff = -iCoff; + + /* Force bounds on qCoff */ + if (qCoff >= 63) + qCoff = 63; + else if (qCoff <= -63) + qCoff = -63; + + iCoff = iCoff & 0x7f; + qCoff = qCoff & 0x7f; + + ath_print(common, ATH_DBG_CALIBRATE, + "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", + i, iCoff, qCoff); + ath_print(common, ATH_DBG_CALIBRATE, + "Register offset (0x%04x) " + "before update = 0x%x\n", + offset_array[i], + REG_READ(ah, offset_array[i])); + + REG_RMW_FIELD(ah, offset_array[i], + AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, + iCoff); + REG_RMW_FIELD(ah, offset_array[i], + AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, + qCoff); + ath_print(common, ATH_DBG_CALIBRATE, + "Register offset (0x%04x) QI COFF " + "(bitfields 0x%08x) after update = 0x%x\n", + offset_array[i], + AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, + REG_READ(ah, offset_array[i])); + ath_print(common, ATH_DBG_CALIBRATE, + "Register offset (0x%04x) QQ COFF " + "(bitfields 0x%08x) after update = 0x%x\n", + offset_array[i], + AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, + REG_READ(ah, offset_array[i])); + + ath_print(common, ATH_DBG_CALIBRATE, + "IQ Cal and Correction done for Chain %d\n", + i); + } + } + + REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0, + AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); + ath_print(common, ATH_DBG_CALIBRATE, + "IQ Cal and Correction (offset 0x%04x) enabled " + "(bit position 0x%08x). New Value 0x%08x\n", + (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), + AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, + REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); +} + +static const struct ath9k_percal_data iq_cal_single_sample = { + IQ_MISMATCH_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ar9003_hw_iqcal_collect, + ar9003_hw_iqcalibrate +}; + +static void ar9003_hw_init_cal_settings(struct ath_hw *ah) +{ + ah->iq_caldata.calData = &iq_cal_single_sample; + ah->supp_cals = IQ_MISMATCH_CAL; +} + +static bool ar9003_hw_iscal_supported(struct ath_hw *ah, + enum ath9k_cal_types calType) +{ + switch (calType & ah->supp_cals) { + case IQ_MISMATCH_CAL: + /* + * XXX: Run IQ Mismatch for non-CCK only + * Note that CHANNEL_B is never set though. + */ + return true; + case ADC_GAIN_CAL: + case ADC_DC_CAL: + return false; + case TEMP_COMP_CAL: + return true; + } + + return false; +} + +/* + * solve 4x4 linear equation used in loopback iq cal. + */ +static bool ar9003_hw_solve_iq_cal(struct ath_hw *ah, + s32 sin_2phi_1, + s32 cos_2phi_1, + s32 sin_2phi_2, + s32 cos_2phi_2, + s32 mag_a0_d0, + s32 phs_a0_d0, + s32 mag_a1_d0, + s32 phs_a1_d0, + s32 solved_eq[]) +{ + s32 f1 = cos_2phi_1 - cos_2phi_2, + f3 = sin_2phi_1 - sin_2phi_2, + f2; + s32 mag_tx, phs_tx, mag_rx, phs_rx; + const s32 result_shift = 1 << 15; + struct ath_common *common = ath9k_hw_common(ah); + + f2 = (f1 * f1 + f3 * f3) / result_shift; + + if (!f2) { + ath_print(common, ATH_DBG_CALIBRATE, "Divide by 0\n"); + return false; + } + + /* mag mismatch, tx */ + mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0); + /* phs mismatch, tx */ + phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0); + + mag_tx = (mag_tx / f2); + phs_tx = (phs_tx / f2); + + /* mag mismatch, rx */ + mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) / + result_shift; + /* phs mismatch, rx */ + phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) / + result_shift; + + solved_eq[0] = mag_tx; + solved_eq[1] = phs_tx; + solved_eq[2] = mag_rx; + solved_eq[3] = phs_rx; + + return true; +} + +static s32 ar9003_hw_find_mag_approx(struct ath_hw *ah, s32 in_re, s32 in_im) +{ + s32 abs_i = abs(in_re), + abs_q = abs(in_im), + max_abs, min_abs; + + if (abs_i > abs_q) { + max_abs = abs_i; + min_abs = abs_q; + } else { + max_abs = abs_q; + min_abs = abs_i; + } + + return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4); +} + +#define DELPT 32 + +static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, + s32 chain_idx, + const s32 iq_res[], + s32 iqc_coeff[]) +{ + s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0, + i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1, + i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0, + i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1; + s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1, + phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1, + sin_2phi_1, cos_2phi_1, + sin_2phi_2, cos_2phi_2; + s32 mag_tx, phs_tx, mag_rx, phs_rx; + s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx, + q_q_coff, q_i_coff; + const s32 res_scale = 1 << 15; + const s32 delpt_shift = 1 << 8; + s32 mag1, mag2; + struct ath_common *common = ath9k_hw_common(ah); + + i2_m_q2_a0_d0 = iq_res[0] & 0xfff; + i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff; + iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8); + + if (i2_m_q2_a0_d0 > 0x800) + i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1); + + if (i2_p_q2_a0_d0 > 0x800) + i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1); + + if (iq_corr_a0_d0 > 0x800) + iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1); + + i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff; + i2_p_q2_a0_d1 = (iq_res[2] & 0xfff); + iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff; + + if (i2_m_q2_a0_d1 > 0x800) + i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); + + if (i2_p_q2_a0_d1 > 0x800) + i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1); + + if (iq_corr_a0_d1 > 0x800) + iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); + + i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8); + i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff; + iq_corr_a1_d0 = iq_res[4] & 0xfff; + + if (i2_m_q2_a1_d0 > 0x800) + i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1); + + if (i2_p_q2_a1_d0 > 0x800) + i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1); + + if (iq_corr_a1_d0 > 0x800) + iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1); + + i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff; + i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8); + iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff; + + if (i2_m_q2_a1_d1 > 0x800) + i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1); + + if (i2_p_q2_a1_d1 > 0x800) + i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1); + + if (iq_corr_a1_d1 > 0x800) + iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1); + + if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) || + (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) { + ath_print(common, ATH_DBG_CALIBRATE, + "Divide by 0:\na0_d0=%d\n" + "a0_d1=%d\na2_d0=%d\na1_d1=%d\n", + i2_p_q2_a0_d0, i2_p_q2_a0_d1, + i2_p_q2_a1_d0, i2_p_q2_a1_d1); + return false; + } + + mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0; + phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0; + + mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1; + phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1; + + mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0; + phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0; + + mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1; + phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1; + + /* w/o analog phase shift */ + sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT); + /* w/o analog phase shift */ + cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT); + /* w/ analog phase shift */ + sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT); + /* w/ analog phase shift */ + cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT); + + /* + * force sin^2 + cos^2 = 1; + * find magnitude by approximation + */ + mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1); + mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2); + + if ((mag1 == 0) || (mag2 == 0)) { + ath_print(common, ATH_DBG_CALIBRATE, + "Divide by 0: mag1=%d, mag2=%d\n", + mag1, mag2); + return false; + } + + /* normalization sin and cos by mag */ + sin_2phi_1 = (sin_2phi_1 * res_scale / mag1); + cos_2phi_1 = (cos_2phi_1 * res_scale / mag1); + sin_2phi_2 = (sin_2phi_2 * res_scale / mag2); + cos_2phi_2 = (cos_2phi_2 * res_scale / mag2); + + /* calculate IQ mismatch */ + if (!ar9003_hw_solve_iq_cal(ah, + sin_2phi_1, cos_2phi_1, + sin_2phi_2, cos_2phi_2, + mag_a0_d0, phs_a0_d0, + mag_a1_d0, + phs_a1_d0, solved_eq)) { + ath_print(common, ATH_DBG_CALIBRATE, + "Call to ar9003_hw_solve_iq_cal() failed.\n"); + return false; + } + + mag_tx = solved_eq[0]; + phs_tx = solved_eq[1]; + mag_rx = solved_eq[2]; + phs_rx = solved_eq[3]; + + ath_print(common, ATH_DBG_CALIBRATE, + "chain %d: mag mismatch=%d phase mismatch=%d\n", + chain_idx, mag_tx/res_scale, phs_tx/res_scale); + + if (res_scale == mag_tx) { + ath_print(common, ATH_DBG_CALIBRATE, + "Divide by 0: mag_tx=%d, res_scale=%d\n", + mag_tx, res_scale); + return false; + } + + /* calculate and quantize Tx IQ correction factor */ + mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx); + phs_corr_tx = -phs_tx; + + q_q_coff = (mag_corr_tx * 128 / res_scale); + q_i_coff = (phs_corr_tx * 256 / res_scale); + + ath_print(common, ATH_DBG_CALIBRATE, + "tx chain %d: mag corr=%d phase corr=%d\n", + chain_idx, q_q_coff, q_i_coff); + + if (q_i_coff < -63) + q_i_coff = -63; + if (q_i_coff > 63) + q_i_coff = 63; + if (q_q_coff < -63) + q_q_coff = -63; + if (q_q_coff > 63) + q_q_coff = 63; + + iqc_coeff[0] = (q_q_coff * 128) + q_i_coff; + + ath_print(common, ATH_DBG_CALIBRATE, + "tx chain %d: iq corr coeff=%x\n", + chain_idx, iqc_coeff[0]); + + if (-mag_rx == res_scale) { + ath_print(common, ATH_DBG_CALIBRATE, + "Divide by 0: mag_rx=%d, res_scale=%d\n", + mag_rx, res_scale); + return false; + } + + /* calculate and quantize Rx IQ correction factors */ + mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx); + phs_corr_rx = -phs_rx; + + q_q_coff = (mag_corr_rx * 128 / res_scale); + q_i_coff = (phs_corr_rx * 256 / res_scale); + + ath_print(common, ATH_DBG_CALIBRATE, + "rx chain %d: mag corr=%d phase corr=%d\n", + chain_idx, q_q_coff, q_i_coff); + + if (q_i_coff < -63) + q_i_coff = -63; + if (q_i_coff > 63) + q_i_coff = 63; + if (q_q_coff < -63) + q_q_coff = -63; + if (q_q_coff > 63) + q_q_coff = 63; + + iqc_coeff[1] = (q_q_coff * 128) + q_i_coff; + + ath_print(common, ATH_DBG_CALIBRATE, + "rx chain %d: iq corr coeff=%x\n", + chain_idx, iqc_coeff[1]); + + return true; +} + +static void ar9003_hw_tx_iq_cal(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + const u32 txiqcal_status[AR9300_MAX_CHAINS] = { + AR_PHY_TX_IQCAL_STATUS_B0, + AR_PHY_TX_IQCAL_STATUS_B1, + AR_PHY_TX_IQCAL_STATUS_B2, + }; + const u32 tx_corr_coeff[AR9300_MAX_CHAINS] = { + AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, + AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, + AR_PHY_TX_IQCAL_CORR_COEFF_01_B2, + }; + const u32 rx_corr[AR9300_MAX_CHAINS] = { + AR_PHY_RX_IQCAL_CORR_B0, + AR_PHY_RX_IQCAL_CORR_B1, + AR_PHY_RX_IQCAL_CORR_B2, + }; + const u_int32_t chan_info_tab[] = { + AR_PHY_CHAN_INFO_TAB_0, + AR_PHY_CHAN_INFO_TAB_1, + AR_PHY_CHAN_INFO_TAB_2, + }; + s32 iq_res[6]; + s32 iqc_coeff[2]; + s32 i, j; + u32 num_chains = 0; + + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (ah->txchainmask & (1 << i)) + num_chains++; + } + + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, + AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, + DELPT); + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, + AR_PHY_TX_IQCAL_START_DO_CAL, + AR_PHY_TX_IQCAL_START_DO_CAL); + + if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, + AR_PHY_TX_IQCAL_START_DO_CAL, + 0, AH_WAIT_TIMEOUT)) { + ath_print(common, ATH_DBG_CALIBRATE, + "Tx IQ Cal not complete.\n"); + goto TX_IQ_CAL_FAILED; + } + + for (i = 0; i < num_chains; i++) { + ath_print(common, ATH_DBG_CALIBRATE, + "Doing Tx IQ Cal for chain %d.\n", i); + + if (REG_READ(ah, txiqcal_status[i]) & + AR_PHY_TX_IQCAL_STATUS_FAILED) { + ath_print(common, ATH_DBG_CALIBRATE, + "Tx IQ Cal failed for chain %d.\n", i); + goto TX_IQ_CAL_FAILED; + } + + for (j = 0; j < 3; j++) { + u_int8_t idx = 2 * j, + offset = 4 * j; + + REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, + AR_PHY_CHAN_INFO_TAB_S2_READ, 0); + + /* 32 bits */ + iq_res[idx] = REG_READ(ah, chan_info_tab[i] + offset); + + REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, + AR_PHY_CHAN_INFO_TAB_S2_READ, 1); + + /* 16 bits */ + iq_res[idx+1] = 0xffff & REG_READ(ah, + chan_info_tab[i] + + offset); + + ath_print(common, ATH_DBG_CALIBRATE, + "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", + idx, iq_res[idx], idx+1, iq_res[idx+1]); + } + + if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, iqc_coeff)) { + ath_print(common, ATH_DBG_CALIBRATE, + "Failed in calculation of IQ correction.\n"); + goto TX_IQ_CAL_FAILED; + } + + ath_print(common, ATH_DBG_CALIBRATE, + "IQ_COEFF[0] = 0x%x IQ_COEFF[1] = 0x%x\n", + iqc_coeff[0], iqc_coeff[1]); + + REG_RMW_FIELD(ah, tx_corr_coeff[i], + AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, + iqc_coeff[0]); + REG_RMW_FIELD(ah, rx_corr[i], + AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_Q_COFF, + iqc_coeff[1] >> 7); + REG_RMW_FIELD(ah, rx_corr[i], + AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_I_COFF, + iqc_coeff[1]); + } + + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, + AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); + REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, + AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); + + return; + +TX_IQ_CAL_FAILED: + ath_print(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); +} + +static bool ar9003_hw_init_cal(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ath_common *common = ath9k_hw_common(ah); + + /* + * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain mode before + * running AGC/TxIQ cals + */ + ar9003_hw_set_chain_masks(ah, 0x7, 0x7); + + /* Calibrate the AGC */ + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); + + /* Poll for offset calibration complete */ + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT)) { + ath_print(common, ATH_DBG_CALIBRATE, + "offset calibration failed to " + "complete in 1ms; noisy environment?\n"); + return false; + } + + /* Do Tx IQ Calibration */ + if (ah->config.tx_iq_calibration) + ar9003_hw_tx_iq_cal(ah); + + /* Revert chainmasks to their original values before NF cal */ + ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); + + /* Initialize list pointers */ + ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; + + if (ar9003_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); + ath_print(common, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); + } + + if (ar9003_hw_iscal_supported(ah, TEMP_COMP_CAL)) { + INIT_CAL(&ah->tempCompCalData); + INSERT_CAL(ah, &ah->tempCompCalData); + ath_print(common, ATH_DBG_CALIBRATE, + "enabling Temperature Compensation Calibration.\n"); + } + + /* Initialize current pointer to first element in list */ + ah->cal_list_curr = ah->cal_list; + + if (ah->cal_list_curr) + ath9k_hw_reset_calibration(ah, ah->cal_list_curr); + + chan->CalValid = 0; + + return true; +} + +void ar9003_hw_attach_calib_ops(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + struct ath_hw_ops *ops = ath9k_hw_ops(ah); + + priv_ops->init_cal_settings = ar9003_hw_init_cal_settings; + priv_ops->init_cal = ar9003_hw_init_cal; + priv_ops->setup_calibration = ar9003_hw_setup_calibration; + priv_ops->iscal_supported = ar9003_hw_iscal_supported; + + ops->calibrate = ar9003_hw_calibrate; +} diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c new file mode 100644 index 00000000000..23eb60ea545 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -0,0 +1,1838 @@ +/* + * Copyright (c) 2010 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 "hw.h" +#include "ar9003_phy.h" +#include "ar9003_eeprom.h" + +#define COMP_HDR_LEN 4 +#define COMP_CKSUM_LEN 2 + +#define AR_CH0_TOP (0x00016288) +#define AR_CH0_TOP_XPABIASLVL (0x3) +#define AR_CH0_TOP_XPABIASLVL_S (8) + +#define AR_CH0_THERM (0x00016290) +#define AR_CH0_THERM_SPARE (0x3f) +#define AR_CH0_THERM_SPARE_S (0) + +#define AR_SWITCH_TABLE_COM_ALL (0xffff) +#define AR_SWITCH_TABLE_COM_ALL_S (0) + +#define AR_SWITCH_TABLE_COM2_ALL (0xffffff) +#define AR_SWITCH_TABLE_COM2_ALL_S (0) + +#define AR_SWITCH_TABLE_ALL (0xfff) +#define AR_SWITCH_TABLE_ALL_S (0) + +#define LE16(x) __constant_cpu_to_le16(x) +#define LE32(x) __constant_cpu_to_le32(x) + +static const struct ar9300_eeprom ar9300_default = { + .eepromVersion = 2, + .templateVersion = 2, + .macAddr = {1, 2, 3, 4, 5, 6}, + .custData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + .baseEepHeader = { + .regDmn = { LE16(0), LE16(0x1f) }, + .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */ + .opCapFlags = { + .opFlags = AR9300_OPFLAGS_11G | AR9300_OPFLAGS_11A, + .eepMisc = 0, + }, + .rfSilent = 0, + .blueToothOptions = 0, + .deviceCap = 0, + .deviceType = 5, /* takes lower byte in eeprom location */ + .pwrTableOffset = AR9300_PWR_TABLE_OFFSET, + .params_for_tuning_caps = {0, 0}, + .featureEnable = 0x0c, + /* + * bit0 - enable tx temp comp - disabled + * bit1 - enable tx volt comp - disabled + * bit2 - enable fastClock - enabled + * bit3 - enable doubling - enabled + * bit4 - enable internal regulator - disabled + */ + .miscConfiguration = 0, /* bit0 - turn down drivestrength */ + .eepromWriteEnableGpio = 3, + .wlanDisableGpio = 0, + .wlanLedGpio = 8, + .rxBandSelectGpio = 0xff, + .txrxgain = 0, + .swreg = 0, + }, + .modalHeader2G = { + /* ar9300_modal_eep_header 2g */ + /* 4 idle,t1,t2,b(4 bits per setting) */ + .antCtrlCommon = LE32(0x110), + /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */ + .antCtrlCommon2 = LE32(0x22222), + + /* + * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r, + * rx1, rx12, b (2 bits each) + */ + .antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) }, + + /* + * xatten1DB[AR9300_MAX_CHAINS]; 3 xatten1_db + * for ar9280 (0xa20c/b20c 5:0) + */ + .xatten1DB = {0, 0, 0}, + + /* + * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin + * for ar9280 (0xa20c/b20c 16:12 + */ + .xatten1Margin = {0, 0, 0}, + .tempSlope = 36, + .voltSlope = 0, + + /* + * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur + * channels in usual fbin coding format + */ + .spurChans = {0, 0, 0, 0, 0}, + + /* + * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check + * if the register is per chain + */ + .noiseFloorThreshCh = {-1, 0, 0}, + .ob = {1, 1, 1},/* 3 chain */ + .db_stage2 = {1, 1, 1}, /* 3 chain */ + .db_stage3 = {0, 0, 0}, + .db_stage4 = {0, 0, 0}, + .xpaBiasLvl = 0, + .txFrameToDataStart = 0x0e, + .txFrameToPaOn = 0x0e, + .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ + .antennaGain = 0, + .switchSettling = 0x2c, + .adcDesiredSize = -30, + .txEndToXpaOff = 0, + .txEndToRxOn = 0x2, + .txFrameToXpaOn = 0xe, + .thresh62 = 28, + .futureModal = { /* [32] */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + }, + .calFreqPier2G = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1), + }, + /* ar9300_cal_data_per_freq_op_loop 2g */ + .calPierData2G = { + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} }, + }, + .calTarget_freqbin_Cck = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2484, 1), + }, + .calTarget_freqbin_2G = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTarget_freqbin_2GHT20 = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTarget_freqbin_2GHT40 = { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2437, 1), + FREQ2FBIN(2472, 1) + }, + .calTargetPowerCck = { + /* 1L-5L,5S,11L,11S */ + { {36, 36, 36, 36} }, + { {36, 36, 36, 36} }, + }, + .calTargetPower2G = { + /* 6-24,36,48,54 */ + { {32, 32, 28, 24} }, + { {32, 32, 28, 24} }, + { {32, 32, 28, 24} }, + }, + .calTargetPower2GHT20 = { + { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} }, + { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} }, + { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} }, + }, + .calTargetPower2GHT40 = { + { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} }, + { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} }, + { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} }, + }, + .ctlIndex_2G = { + 0x11, 0x12, 0x15, 0x17, 0x41, 0x42, + 0x45, 0x47, 0x31, 0x32, 0x35, 0x37, + }, + .ctl_freqbin_2G = { + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2457, 1), + FREQ2FBIN(2462, 1) + }, + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2462, 1), + 0xFF, + }, + + { + FREQ2FBIN(2412, 1), + FREQ2FBIN(2417, 1), + FREQ2FBIN(2462, 1), + 0xFF, + }, + { + FREQ2FBIN(2422, 1), + FREQ2FBIN(2427, 1), + FREQ2FBIN(2447, 1), + FREQ2FBIN(2452, 1) + }, + + { + /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1), + }, + + { + /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0, + }, + + { + /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + FREQ2FBIN(2472, 1), + 0, + }, + + { + /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1), + /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1), + /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1), + /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1), + }, + + { + /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + }, + + { + /* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0 + }, + + { + /* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1), + /* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1), + /* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1), + 0 + }, + + { + /* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1), + /* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1), + /* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1), + /* Data[11].ctlEdges[3].bChannel */ + FREQ2FBIN(2462, 1), + } + }, + .ctlPowerData_2G = { + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } }, + + { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + + { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + + { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } }, + { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } }, + }, + .modalHeader5G = { + /* 4 idle,t1,t2,b (4 bits per setting) */ + .antCtrlCommon = LE32(0x110), + /* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */ + .antCtrlCommon2 = LE32(0x22222), + /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */ + .antCtrlChain = { + LE16(0x000), LE16(0x000), LE16(0x000), + }, + /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */ + .xatten1DB = {0, 0, 0}, + + /* + * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin + * for merlin (0xa20c/b20c 16:12 + */ + .xatten1Margin = {0, 0, 0}, + .tempSlope = 68, + .voltSlope = 0, + /* spurChans spur channels in usual fbin coding format */ + .spurChans = {0, 0, 0, 0, 0}, + /* noiseFloorThreshCh Check if the register is per chain */ + .noiseFloorThreshCh = {-1, 0, 0}, + .ob = {3, 3, 3}, /* 3 chain */ + .db_stage2 = {3, 3, 3}, /* 3 chain */ + .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */ + .db_stage4 = {3, 3, 3}, /* don't exist for 2G */ + .xpaBiasLvl = 0, + .txFrameToDataStart = 0x0e, + .txFrameToPaOn = 0x0e, + .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */ + .antennaGain = 0, + .switchSettling = 0x2d, + .adcDesiredSize = -30, + .txEndToXpaOff = 0, + .txEndToRxOn = 0x2, + .txFrameToXpaOn = 0xe, + .thresh62 = 28, + .futureModal = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + }, + .calFreqPier5G = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5220, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5725, 0), + FREQ2FBIN(5825, 0) + }, + .calPierData5G = { + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + }, + + }, + .calTarget_freqbin_5G = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5220, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5400, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5600, 0), + FREQ2FBIN(5725, 0), + FREQ2FBIN(5825, 0) + }, + .calTarget_freqbin_5GHT20 = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5240, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5745, 0), + FREQ2FBIN(5725, 0), + FREQ2FBIN(5825, 0) + }, + .calTarget_freqbin_5GHT40 = { + FREQ2FBIN(5180, 0), + FREQ2FBIN(5240, 0), + FREQ2FBIN(5320, 0), + FREQ2FBIN(5500, 0), + FREQ2FBIN(5700, 0), + FREQ2FBIN(5745, 0), + FREQ2FBIN(5725, 0), + FREQ2FBIN(5825, 0) + }, + .calTargetPower5G = { + /* 6-24,36,48,54 */ + { {20, 20, 20, 10} }, + { {20, 20, 20, 10} }, + { {20, 20, 20, 10} }, + { {20, 20, 20, 10} }, + { {20, 20, 20, 10} }, + { {20, 20, 20, 10} }, + { {20, 20, 20, 10} }, + { {20, 20, 20, 10} }, + }, + .calTargetPower5GHT20 = { + /* + * 0_8_16,1-3_9-11_17-19, + * 4,5,6,7,12,13,14,15,20,21,22,23 + */ + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + }, + .calTargetPower5GHT40 = { + /* + * 0_8_16,1-3_9-11_17-19, + * 4,5,6,7,12,13,14,15,20,21,22,23 + */ + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} }, + }, + .ctlIndex_5G = { + 0x10, 0x16, 0x18, 0x40, 0x46, + 0x48, 0x30, 0x36, 0x38 + }, + .ctl_freqbin_5G = { + { + /* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0), + /* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0), + /* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + { + /* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0), + /* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0), + /* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + + { + /* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0), + /* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0), + /* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0), + /* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0), + /* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0), + /* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0), + /* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0) + }, + + { + /* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0), + /* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0), + /* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0), + /* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0), + /* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[3].ctlEdges[6].bChannel */ 0xFF, + /* Data[3].ctlEdges[7].bChannel */ 0xFF, + }, + + { + /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0), + /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0), + /* Data[4].ctlEdges[4].bChannel */ 0xFF, + /* Data[4].ctlEdges[5].bChannel */ 0xFF, + /* Data[4].ctlEdges[6].bChannel */ 0xFF, + /* Data[4].ctlEdges[7].bChannel */ 0xFF, + }, + + { + /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0), + /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0), + /* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0), + /* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0), + /* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0), + /* Data[5].ctlEdges[6].bChannel */ 0xFF, + /* Data[5].ctlEdges[7].bChannel */ 0xFF + }, + + { + /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0), + /* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0), + /* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0), + /* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0), + /* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0), + /* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0), + /* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0) + }, + + { + /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0), + /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0), + /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0), + /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0), + /* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0), + /* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0), + /* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0), + /* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0) + }, + + { + /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0), + /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0), + /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0), + /* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0), + /* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0), + /* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0), + /* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0), + /* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0) + } + }, + .ctlPowerData_5G = { + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 0}, {60, 1}, {60, 0}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + } + }, + { + { + {60, 0}, {60, 1}, {60, 1}, {60, 0}, + {60, 1}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + {60, 0}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 0}, {60, 0}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 1}, + } + }, + { + { + {60, 1}, {60, 1}, {60, 0}, {60, 1}, + {60, 1}, {60, 1}, {60, 1}, {60, 0}, + } + }, + { + { + {60, 1}, {60, 0}, {60, 1}, {60, 1}, + {60, 1}, {60, 1}, {60, 0}, {60, 1}, + } + }, + } +}; + +static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah) +{ + return 0; +} + +static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, + enum eeprom_param param) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct ar9300_base_eep_hdr *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_MAC_LSW: + return eep->macAddr[0] << 8 | eep->macAddr[1]; + case EEP_MAC_MID: + return eep->macAddr[2] << 8 | eep->macAddr[3]; + case EEP_MAC_MSW: + return eep->macAddr[4] << 8 | eep->macAddr[5]; + case EEP_REG_0: + return le16_to_cpu(pBase->regDmn[0]); + case EEP_REG_1: + return le16_to_cpu(pBase->regDmn[1]); + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags.opFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_TX_MASK: + return (pBase->txrxMask >> 4) & 0xf; + case EEP_RX_MASK: + return pBase->txrxMask & 0xf; + case EEP_DRIVE_STRENGTH: +#define AR9300_EEP_BASE_DRIV_STRENGTH 0x1 + return pBase->miscConfiguration & AR9300_EEP_BASE_DRIV_STRENGTH; + case EEP_INTERNAL_REGULATOR: + /* Bit 4 is internal regulator flag */ + return (pBase->featureEnable & 0x10) >> 4; + case EEP_SWREG: + return le32_to_cpu(pBase->swreg); + default: + return 0; + } +} + +static bool ar9300_eeprom_read_byte(struct ath_common *common, int address, + u8 *buffer) +{ + u16 val; + + if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val))) + return false; + + *buffer = (val >> (8 * (address % 2))) & 0xff; + return true; +} + +static bool ar9300_eeprom_read_word(struct ath_common *common, int address, + u8 *buffer) +{ + u16 val; + + if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val))) + return false; + + buffer[0] = val >> 8; + buffer[1] = val & 0xff; + + return true; +} + +static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer, + int count) +{ + struct ath_common *common = ath9k_hw_common(ah); + int i; + + if ((address < 0) || ((address + count) / 2 > AR9300_EEPROM_SIZE - 1)) { + ath_print(common, ATH_DBG_EEPROM, + "eeprom address not in range\n"); + return false; + } + + /* + * Since we're reading the bytes in reverse order from a little-endian + * word stream, an even address means we only use the lower half of + * the 16-bit word at that address + */ + if (address % 2 == 0) { + if (!ar9300_eeprom_read_byte(common, address--, buffer++)) + goto error; + + count--; + } + + for (i = 0; i < count / 2; i++) { + if (!ar9300_eeprom_read_word(common, address, buffer)) + goto error; + + address -= 2; + buffer += 2; + } + + if (count % 2) + if (!ar9300_eeprom_read_byte(common, address, buffer)) + goto error; + + return true; + +error: + ath_print(common, ATH_DBG_EEPROM, + "unable to read eeprom region at offset %d\n", address); + return false; +} + +static void ar9300_comp_hdr_unpack(u8 *best, int *code, int *reference, + int *length, int *major, int *minor) +{ + unsigned long value[4]; + + value[0] = best[0]; + value[1] = best[1]; + value[2] = best[2]; + value[3] = best[3]; + *code = ((value[0] >> 5) & 0x0007); + *reference = (value[0] & 0x001f) | ((value[1] >> 2) & 0x0020); + *length = ((value[1] << 4) & 0x07f0) | ((value[2] >> 4) & 0x000f); + *major = (value[2] & 0x000f); + *minor = (value[3] & 0x00ff); +} + +static u16 ar9300_comp_cksum(u8 *data, int dsize) +{ + int it, checksum = 0; + + for (it = 0; it < dsize; it++) { + checksum += data[it]; + checksum &= 0xffff; + } + + return checksum; +} + +static bool ar9300_uncompress_block(struct ath_hw *ah, + u8 *mptr, + int mdataSize, + u8 *block, + int size) +{ + int it; + int spot; + int offset; + int length; + struct ath_common *common = ath9k_hw_common(ah); + + spot = 0; + + for (it = 0; it < size; it += (length+2)) { + offset = block[it]; + offset &= 0xff; + spot += offset; + length = block[it+1]; + length &= 0xff; + + if (length > 0 && spot >= 0 && spot+length < mdataSize) { + ath_print(common, ATH_DBG_EEPROM, + "Restore at %d: spot=%d " + "offset=%d length=%d\n", + it, spot, offset, length); + memcpy(&mptr[spot], &block[it+2], length); + spot += length; + } else if (length > 0) { + ath_print(common, ATH_DBG_EEPROM, + "Bad restore at %d: spot=%d " + "offset=%d length=%d\n", + it, spot, offset, length); + return false; + } + } + return true; +} + +static int ar9300_compress_decision(struct ath_hw *ah, + int it, + int code, + int reference, + u8 *mptr, + u8 *word, int length, int mdata_size) +{ + struct ath_common *common = ath9k_hw_common(ah); + u8 *dptr; + + switch (code) { + case _CompressNone: + if (length != mdata_size) { + ath_print(common, ATH_DBG_EEPROM, + "EEPROM structure size mismatch" + "memory=%d eeprom=%d\n", mdata_size, length); + return -1; + } + memcpy(mptr, (u8 *) (word + COMP_HDR_LEN), length); + ath_print(common, ATH_DBG_EEPROM, "restored eeprom %d:" + " uncompressed, length %d\n", it, length); + break; + case _CompressBlock: + if (reference == 0) { + dptr = mptr; + } else { + if (reference != 2) { + ath_print(common, ATH_DBG_EEPROM, + "cant find reference eeprom" + "struct %d\n", reference); + return -1; + } + memcpy(mptr, &ar9300_default, mdata_size); + } + ath_print(common, ATH_DBG_EEPROM, + "restore eeprom %d: block, reference %d," + " length %d\n", it, reference, length); + ar9300_uncompress_block(ah, mptr, mdata_size, + (u8 *) (word + COMP_HDR_LEN), length); + break; + default: + ath_print(common, ATH_DBG_EEPROM, "unknown compression" + " code %d\n", code); + return -1; + } + return 0; +} + +/* + * Read the configuration data from the eeprom. + * The data can be put in any specified memory buffer. + * + * Returns -1 on error. + * Returns address of next memory location on success. + */ +static int ar9300_eeprom_restore_internal(struct ath_hw *ah, + u8 *mptr, int mdata_size) +{ +#define MDEFAULT 15 +#define MSTATE 100 + int cptr; + u8 *word; + int code; + int reference, length, major, minor; + int osize; + int it; + u16 checksum, mchecksum; + struct ath_common *common = ath9k_hw_common(ah); + + word = kzalloc(2048, GFP_KERNEL); + if (!word) + return -1; + + memcpy(mptr, &ar9300_default, mdata_size); + + cptr = AR9300_BASE_ADDR; + for (it = 0; it < MSTATE; it++) { + if (!ar9300_read_eeprom(ah, cptr, word, COMP_HDR_LEN)) + goto fail; + + if ((word[0] == 0 && word[1] == 0 && word[2] == 0 && + word[3] == 0) || (word[0] == 0xff && word[1] == 0xff + && word[2] == 0xff && word[3] == 0xff)) + break; + + ar9300_comp_hdr_unpack(word, &code, &reference, + &length, &major, &minor); + ath_print(common, ATH_DBG_EEPROM, + "Found block at %x: code=%d ref=%d" + "length=%d major=%d minor=%d\n", cptr, code, + reference, length, major, minor); + if (length >= 1024) { + ath_print(common, ATH_DBG_EEPROM, + "Skipping bad header\n"); + cptr -= COMP_HDR_LEN; + continue; + } + + osize = length; + ar9300_read_eeprom(ah, cptr, word, + COMP_HDR_LEN + osize + COMP_CKSUM_LEN); + checksum = ar9300_comp_cksum(&word[COMP_HDR_LEN], length); + mchecksum = word[COMP_HDR_LEN + osize] | + (word[COMP_HDR_LEN + osize + 1] << 8); + ath_print(common, ATH_DBG_EEPROM, + "checksum %x %x\n", checksum, mchecksum); + if (checksum == mchecksum) { + ar9300_compress_decision(ah, it, code, reference, mptr, + word, length, mdata_size); + } else { + ath_print(common, ATH_DBG_EEPROM, + "skipping block with bad checksum\n"); + } + cptr -= (COMP_HDR_LEN + osize + COMP_CKSUM_LEN); + } + + kfree(word); + return cptr; + +fail: + kfree(word); + return -1; +} + +/* + * Restore the configuration structure by reading the eeprom. + * This function destroys any existing in-memory structure + * content. + */ +static bool ath9k_hw_ar9300_fill_eeprom(struct ath_hw *ah) +{ + u8 *mptr = (u8 *) &ah->eeprom.ar9300_eep; + + if (ar9300_eeprom_restore_internal(ah, mptr, + sizeof(struct ar9300_eeprom)) < 0) + return false; + + return true; +} + +/* XXX: review hardware docs */ +static int ath9k_hw_ar9300_get_eeprom_ver(struct ath_hw *ah) +{ + return ah->eeprom.ar9300_eep.eepromVersion; +} + +/* XXX: could be read from the eepromVersion, not sure yet */ +static int ath9k_hw_ar9300_get_eeprom_rev(struct ath_hw *ah) +{ + return 0; +} + +static u8 ath9k_hw_ar9300_get_num_ant_config(struct ath_hw *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + +static u16 ath9k_hw_ar9300_get_eeprom_antenna_cfg(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return -EINVAL; +} + +static s32 ar9003_hw_xpa_bias_level_get(struct ath_hw *ah, bool is2ghz) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + + if (is2ghz) + return eep->modalHeader2G.xpaBiasLvl; + else + return eep->modalHeader5G.xpaBiasLvl; +} + +static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) +{ + int bias = ar9003_hw_xpa_bias_level_get(ah, is2ghz); + REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, (bias & 0x3)); + REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_SPARE, + ((bias >> 2) & 0x3)); +} + +static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + __le32 val; + + if (is2ghz) + val = eep->modalHeader2G.antCtrlCommon; + else + val = eep->modalHeader5G.antCtrlCommon; + return le32_to_cpu(val); +} + +static u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + __le32 val; + + if (is2ghz) + val = eep->modalHeader2G.antCtrlCommon2; + else + val = eep->modalHeader5G.antCtrlCommon2; + return le32_to_cpu(val); +} + +static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, + int chain, + bool is2ghz) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + __le16 val = 0; + + if (chain >= 0 && chain < AR9300_MAX_CHAINS) { + if (is2ghz) + val = eep->modalHeader2G.antCtrlChain[chain]; + else + val = eep->modalHeader5G.antCtrlChain[chain]; + } + + return le16_to_cpu(val); +} + +static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) +{ + u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz); + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value); + + value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz); + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); + + value = ar9003_hw_ant_ctrl_chain_get(ah, 0, is2ghz); + REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value); + + value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz); + REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL, value); + + value = ar9003_hw_ant_ctrl_chain_get(ah, 2, is2ghz); + REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL, value); +} + +static void ar9003_hw_drive_strength_apply(struct ath_hw *ah) +{ + int drive_strength; + unsigned long reg; + + drive_strength = ath9k_hw_ar9300_get_eeprom(ah, EEP_DRIVE_STRENGTH); + + if (!drive_strength) + return; + + reg = REG_READ(ah, AR_PHY_65NM_CH0_BIAS1); + reg &= ~0x00ffffc0; + reg |= 0x5 << 21; + reg |= 0x5 << 18; + reg |= 0x5 << 15; + reg |= 0x5 << 12; + reg |= 0x5 << 9; + reg |= 0x5 << 6; + REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS1, reg); + + reg = REG_READ(ah, AR_PHY_65NM_CH0_BIAS2); + reg &= ~0xffffffe0; + reg |= 0x5 << 29; + reg |= 0x5 << 26; + reg |= 0x5 << 23; + reg |= 0x5 << 20; + reg |= 0x5 << 17; + reg |= 0x5 << 14; + reg |= 0x5 << 11; + reg |= 0x5 << 8; + reg |= 0x5 << 5; + REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS2, reg); + + reg = REG_READ(ah, AR_PHY_65NM_CH0_BIAS4); + reg &= ~0xff800000; + reg |= 0x5 << 29; + reg |= 0x5 << 26; + reg |= 0x5 << 23; + REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS4, reg); +} + +static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) +{ + int internal_regulator = + ath9k_hw_ar9300_get_eeprom(ah, EEP_INTERNAL_REGULATOR); + + if (internal_regulator) { + /* Internal regulator is ON. Write swreg register. */ + int swreg = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG); + REG_WRITE(ah, AR_RTC_REG_CONTROL1, + REG_READ(ah, AR_RTC_REG_CONTROL1) & + (~AR_RTC_REG_CONTROL1_SWREG_PROGRAM)); + REG_WRITE(ah, AR_RTC_REG_CONTROL0, swreg); + /* Set REG_CONTROL1.SWREG_PROGRAM */ + REG_WRITE(ah, AR_RTC_REG_CONTROL1, + REG_READ(ah, + AR_RTC_REG_CONTROL1) | + AR_RTC_REG_CONTROL1_SWREG_PROGRAM); + } else { + REG_WRITE(ah, AR_RTC_SLEEP_CLK, + (REG_READ(ah, + AR_RTC_SLEEP_CLK) | + AR_RTC_FORCE_SWREG_PRD)); + } +} + +static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + ar9003_hw_xpa_bias_level_apply(ah, IS_CHAN_2GHZ(chan)); + ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan)); + ar9003_hw_drive_strength_apply(ah); + ar9003_hw_internal_regulator_apply(ah); +} + +static void ath9k_hw_ar9300_set_addac(struct ath_hw *ah, + struct ath9k_channel *chan) +{ +} + +/* + * Returns the interpolated y value corresponding to the specified x value + * from the np ordered pairs of data (px,py). + * The pairs do not have to be in any order. + * If the specified x value is less than any of the px, + * the returned y value is equal to the py for the lowest px. + * If the specified x value is greater than any of the px, + * the returned y value is equal to the py for the highest px. + */ +static int ar9003_hw_power_interpolate(int32_t x, + int32_t *px, int32_t *py, u_int16_t np) +{ + int ip = 0; + int lx = 0, ly = 0, lhave = 0; + int hx = 0, hy = 0, hhave = 0; + int dx = 0; + int y = 0; + + lhave = 0; + hhave = 0; + + /* identify best lower and higher x calibration measurement */ + for (ip = 0; ip < np; ip++) { + dx = x - px[ip]; + + /* this measurement is higher than our desired x */ + if (dx <= 0) { + if (!hhave || dx > (x - hx)) { + /* new best higher x measurement */ + hx = px[ip]; + hy = py[ip]; + hhave = 1; + } + } + /* this measurement is lower than our desired x */ + if (dx >= 0) { + if (!lhave || dx < (x - lx)) { + /* new best lower x measurement */ + lx = px[ip]; + ly = py[ip]; + lhave = 1; + } + } + } + + /* the low x is good */ + if (lhave) { + /* so is the high x */ + if (hhave) { + /* they're the same, so just pick one */ + if (hx == lx) + y = ly; + else /* interpolate */ + y = ly + (((x - lx) * (hy - ly)) / (hx - lx)); + } else /* only low is good, use it */ + y = ly; + } else if (hhave) /* only high is good, use it */ + y = hy; + else /* nothing is good,this should never happen unless np=0, ???? */ + y = -(1 << 30); + return y; +} + +static u8 ar9003_hw_eeprom_get_tgt_pwr(struct ath_hw *ah, + u16 rateIndex, u16 freq, bool is2GHz) +{ + u16 numPiers, i; + s32 targetPowerArray[AR9300_NUM_5G_20_TARGET_POWERS]; + s32 freqArray[AR9300_NUM_5G_20_TARGET_POWERS]; + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct cal_tgt_pow_legacy *pEepromTargetPwr; + u8 *pFreqBin; + + if (is2GHz) { + numPiers = AR9300_NUM_2G_20_TARGET_POWERS; + pEepromTargetPwr = eep->calTargetPower2G; + pFreqBin = eep->calTarget_freqbin_2G; + } else { + numPiers = AR9300_NUM_5G_20_TARGET_POWERS; + pEepromTargetPwr = eep->calTargetPower5G; + pFreqBin = eep->calTarget_freqbin_5G; + } + + /* + * create array of channels and targetpower from + * targetpower piers stored on eeprom + */ + for (i = 0; i < numPiers; i++) { + freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz); + targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; + } + + /* interpolate to get target power for given frequency */ + return (u8) ar9003_hw_power_interpolate((s32) freq, + freqArray, + targetPowerArray, numPiers); +} + +static u8 ar9003_hw_eeprom_get_ht20_tgt_pwr(struct ath_hw *ah, + u16 rateIndex, + u16 freq, bool is2GHz) +{ + u16 numPiers, i; + s32 targetPowerArray[AR9300_NUM_5G_20_TARGET_POWERS]; + s32 freqArray[AR9300_NUM_5G_20_TARGET_POWERS]; + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct cal_tgt_pow_ht *pEepromTargetPwr; + u8 *pFreqBin; + + if (is2GHz) { + numPiers = AR9300_NUM_2G_20_TARGET_POWERS; + pEepromTargetPwr = eep->calTargetPower2GHT20; + pFreqBin = eep->calTarget_freqbin_2GHT20; + } else { + numPiers = AR9300_NUM_5G_20_TARGET_POWERS; + pEepromTargetPwr = eep->calTargetPower5GHT20; + pFreqBin = eep->calTarget_freqbin_5GHT20; + } + + /* + * create array of channels and targetpower + * from targetpower piers stored on eeprom + */ + for (i = 0; i < numPiers; i++) { + freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz); + targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; + } + + /* interpolate to get target power for given frequency */ + return (u8) ar9003_hw_power_interpolate((s32) freq, + freqArray, + targetPowerArray, numPiers); +} + +static u8 ar9003_hw_eeprom_get_ht40_tgt_pwr(struct ath_hw *ah, + u16 rateIndex, + u16 freq, bool is2GHz) +{ + u16 numPiers, i; + s32 targetPowerArray[AR9300_NUM_5G_40_TARGET_POWERS]; + s32 freqArray[AR9300_NUM_5G_40_TARGET_POWERS]; + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct cal_tgt_pow_ht *pEepromTargetPwr; + u8 *pFreqBin; + + if (is2GHz) { + numPiers = AR9300_NUM_2G_40_TARGET_POWERS; + pEepromTargetPwr = eep->calTargetPower2GHT40; + pFreqBin = eep->calTarget_freqbin_2GHT40; + } else { + numPiers = AR9300_NUM_5G_40_TARGET_POWERS; + pEepromTargetPwr = eep->calTargetPower5GHT40; + pFreqBin = eep->calTarget_freqbin_5GHT40; + } + + /* + * create array of channels and targetpower from + * targetpower piers stored on eeprom + */ + for (i = 0; i < numPiers; i++) { + freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz); + targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; + } + + /* interpolate to get target power for given frequency */ + return (u8) ar9003_hw_power_interpolate((s32) freq, + freqArray, + targetPowerArray, numPiers); +} + +static u8 ar9003_hw_eeprom_get_cck_tgt_pwr(struct ath_hw *ah, + u16 rateIndex, u16 freq) +{ + u16 numPiers = AR9300_NUM_2G_CCK_TARGET_POWERS, i; + s32 targetPowerArray[AR9300_NUM_2G_CCK_TARGET_POWERS]; + s32 freqArray[AR9300_NUM_2G_CCK_TARGET_POWERS]; + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct cal_tgt_pow_legacy *pEepromTargetPwr = eep->calTargetPowerCck; + u8 *pFreqBin = eep->calTarget_freqbin_Cck; + + /* + * create array of channels and targetpower from + * targetpower piers stored on eeprom + */ + for (i = 0; i < numPiers; i++) { + freqArray[i] = FBIN2FREQ(pFreqBin[i], 1); + targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex]; + } + + /* interpolate to get target power for given frequency */ + return (u8) ar9003_hw_power_interpolate((s32) freq, + freqArray, + targetPowerArray, numPiers); +} + +/* Set tx power registers to array of values passed in */ +static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) +{ +#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) + /* make sure forced gain is not set */ + REG_WRITE(ah, 0xa458, 0); + + /* Write the OFDM power per rate set */ + + /* 6 (LSB), 9, 12, 18 (MSB) */ + REG_WRITE(ah, 0xa3c0, + POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 16) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 0)); + + /* 24 (LSB), 36, 48, 54 (MSB) */ + REG_WRITE(ah, 0xa3c4, + POW_SM(pPwrArray[ALL_TARGET_LEGACY_54], 24) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_48], 16) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_36], 8) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 0)); + + /* Write the CCK power per rate set */ + + /* 1L (LSB), reserved, 2L, 2S (MSB) */ + REG_WRITE(ah, 0xa3c8, + POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 24) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) | + /* POW_SM(txPowerTimes2, 8) | this is reserved for AR9003 */ + POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0)); + + /* 5.5L (LSB), 5.5S, 11L, 11S (MSB) */ + REG_WRITE(ah, 0xa3cc, + POW_SM(pPwrArray[ALL_TARGET_LEGACY_11S], 24) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_11L], 16) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_5S], 8) | + POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0) + ); + + /* Write the HT20 power per rate set */ + + /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */ + REG_WRITE(ah, 0xa3d0, + POW_SM(pPwrArray[ALL_TARGET_HT20_5], 24) | + POW_SM(pPwrArray[ALL_TARGET_HT20_4], 16) | + POW_SM(pPwrArray[ALL_TARGET_HT20_1_3_9_11_17_19], 8) | + POW_SM(pPwrArray[ALL_TARGET_HT20_0_8_16], 0) + ); + + /* 6 (LSB), 7, 12, 13 (MSB) */ + REG_WRITE(ah, 0xa3d4, + POW_SM(pPwrArray[ALL_TARGET_HT20_13], 24) | + POW_SM(pPwrArray[ALL_TARGET_HT20_12], 16) | + POW_SM(pPwrArray[ALL_TARGET_HT20_7], 8) | + POW_SM(pPwrArray[ALL_TARGET_HT20_6], 0) + ); + + /* 14 (LSB), 15, 20, 21 */ + REG_WRITE(ah, 0xa3e4, + POW_SM(pPwrArray[ALL_TARGET_HT20_21], 24) | + POW_SM(pPwrArray[ALL_TARGET_HT20_20], 16) | + POW_SM(pPwrArray[ALL_TARGET_HT20_15], 8) | + POW_SM(pPwrArray[ALL_TARGET_HT20_14], 0) + ); + + /* Mixed HT20 and HT40 rates */ + + /* HT20 22 (LSB), HT20 23, HT40 22, HT40 23 (MSB) */ + REG_WRITE(ah, 0xa3e8, + POW_SM(pPwrArray[ALL_TARGET_HT40_23], 24) | + POW_SM(pPwrArray[ALL_TARGET_HT40_22], 16) | + POW_SM(pPwrArray[ALL_TARGET_HT20_23], 8) | + POW_SM(pPwrArray[ALL_TARGET_HT20_22], 0) + ); + + /* + * Write the HT40 power per rate set + * correct PAR difference between HT40 and HT20/LEGACY + * 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) + */ + REG_WRITE(ah, 0xa3d8, + POW_SM(pPwrArray[ALL_TARGET_HT40_5], 24) | + POW_SM(pPwrArray[ALL_TARGET_HT40_4], 16) | + POW_SM(pPwrArray[ALL_TARGET_HT40_1_3_9_11_17_19], 8) | + POW_SM(pPwrArray[ALL_TARGET_HT40_0_8_16], 0) + ); + + /* 6 (LSB), 7, 12, 13 (MSB) */ + REG_WRITE(ah, 0xa3dc, + POW_SM(pPwrArray[ALL_TARGET_HT40_13], 24) | + POW_SM(pPwrArray[ALL_TARGET_HT40_12], 16) | + POW_SM(pPwrArray[ALL_TARGET_HT40_7], 8) | + POW_SM(pPwrArray[ALL_TARGET_HT40_6], 0) + ); + + /* 14 (LSB), 15, 20, 21 */ + REG_WRITE(ah, 0xa3ec, + POW_SM(pPwrArray[ALL_TARGET_HT40_21], 24) | + POW_SM(pPwrArray[ALL_TARGET_HT40_20], 16) | + POW_SM(pPwrArray[ALL_TARGET_HT40_15], 8) | + POW_SM(pPwrArray[ALL_TARGET_HT40_14], 0) + ); + + return 0; +#undef POW_SM +} + +static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq) +{ + u8 targetPowerValT2[ar9300RateSize]; + /* XXX: hard code for now, need to get from eeprom struct */ + u8 ht40PowerIncForPdadc = 0; + bool is2GHz = false; + unsigned int i = 0; + struct ath_common *common = ath9k_hw_common(ah); + + if (freq < 4000) + is2GHz = true; + + targetPowerValT2[ALL_TARGET_LEGACY_6_24] = + ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_6_24, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_LEGACY_36] = + ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_36, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_LEGACY_48] = + ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_48, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_LEGACY_54] = + ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_54, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_LEGACY_1L_5L] = + ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_1L_5L, + freq); + targetPowerValT2[ALL_TARGET_LEGACY_5S] = + ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_5S, freq); + targetPowerValT2[ALL_TARGET_LEGACY_11L] = + ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_11L, freq); + targetPowerValT2[ALL_TARGET_LEGACY_11S] = + ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_11S, freq); + targetPowerValT2[ALL_TARGET_HT20_0_8_16] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_0_8_16, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_1_3_9_11_17_19] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_1_3_9_11_17_19, + freq, is2GHz); + targetPowerValT2[ALL_TARGET_HT20_4] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_4, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_5] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_5, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_6] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_6, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_7] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_7, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_12] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_12, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_13] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_13, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_14] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_14, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_15] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_15, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_20] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_20, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_21] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_21, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_22] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_22, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT20_23] = + ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_23, freq, + is2GHz); + targetPowerValT2[ALL_TARGET_HT40_0_8_16] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_0_8_16, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_1_3_9_11_17_19] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_1_3_9_11_17_19, + freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_4] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_4, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_5] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_5, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_6] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_6, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_7] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_7, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_12] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_12, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_13] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_13, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_14] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_14, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_15] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_15, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_20] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_20, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_21] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_21, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_22] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_22, freq, + is2GHz) + ht40PowerIncForPdadc; + targetPowerValT2[ALL_TARGET_HT40_23] = + ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_23, freq, + is2GHz) + ht40PowerIncForPdadc; + + while (i < ar9300RateSize) { + ath_print(common, ATH_DBG_EEPROM, + "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]); + i++; + + ath_print(common, ATH_DBG_EEPROM, + "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]); + i++; + + ath_print(common, ATH_DBG_EEPROM, + "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]); + i++; + + ath_print(common, ATH_DBG_EEPROM, + "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]); + i++; + } + + /* Write target power array to registers */ + ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); +} + +static int ar9003_hw_cal_pier_get(struct ath_hw *ah, + int mode, + int ipier, + int ichain, + int *pfrequency, + int *pcorrection, + int *ptemperature, int *pvoltage) +{ + u8 *pCalPier; + struct ar9300_cal_data_per_freq_op_loop *pCalPierStruct; + int is2GHz; + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct ath_common *common = ath9k_hw_common(ah); + + if (ichain >= AR9300_MAX_CHAINS) { + ath_print(common, ATH_DBG_EEPROM, + "Invalid chain index, must be less than %d\n", + AR9300_MAX_CHAINS); + return -1; + } + + if (mode) { /* 5GHz */ + if (ipier >= AR9300_NUM_5G_CAL_PIERS) { + ath_print(common, ATH_DBG_EEPROM, + "Invalid 5GHz cal pier index, must " + "be less than %d\n", + AR9300_NUM_5G_CAL_PIERS); + return -1; + } + pCalPier = &(eep->calFreqPier5G[ipier]); + pCalPierStruct = &(eep->calPierData5G[ichain][ipier]); + is2GHz = 0; + } else { + if (ipier >= AR9300_NUM_2G_CAL_PIERS) { + ath_print(common, ATH_DBG_EEPROM, + "Invalid 2GHz cal pier index, must " + "be less than %d\n", AR9300_NUM_2G_CAL_PIERS); + return -1; + } + + pCalPier = &(eep->calFreqPier2G[ipier]); + pCalPierStruct = &(eep->calPierData2G[ichain][ipier]); + is2GHz = 1; + } + + *pfrequency = FBIN2FREQ(*pCalPier, is2GHz); + *pcorrection = pCalPierStruct->refPower; + *ptemperature = pCalPierStruct->tempMeas; + *pvoltage = pCalPierStruct->voltMeas; + + return 0; +} + +static int ar9003_hw_power_control_override(struct ath_hw *ah, + int frequency, + int *correction, + int *voltage, int *temperature) +{ + int tempSlope = 0; + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + + REG_RMW(ah, AR_PHY_TPC_11_B0, + (correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), + AR_PHY_TPC_OLPC_GAIN_DELTA); + REG_RMW(ah, AR_PHY_TPC_11_B1, + (correction[1] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), + AR_PHY_TPC_OLPC_GAIN_DELTA); + REG_RMW(ah, AR_PHY_TPC_11_B2, + (correction[2] << AR_PHY_TPC_OLPC_GAIN_DELTA_S), + AR_PHY_TPC_OLPC_GAIN_DELTA); + + /* enable open loop power control on chip */ + REG_RMW(ah, AR_PHY_TPC_6_B0, + (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), + AR_PHY_TPC_6_ERROR_EST_MODE); + REG_RMW(ah, AR_PHY_TPC_6_B1, + (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), + AR_PHY_TPC_6_ERROR_EST_MODE); + REG_RMW(ah, AR_PHY_TPC_6_B2, + (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S), + AR_PHY_TPC_6_ERROR_EST_MODE); + + /* + * enable temperature compensation + * Need to use register names + */ + if (frequency < 4000) + tempSlope = eep->modalHeader2G.tempSlope; + else + tempSlope = eep->modalHeader5G.tempSlope; + + REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope); + REG_RMW_FIELD(ah, AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE, + temperature[0]); + + return 0; +} + +/* Apply the recorded correction values. */ +static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) +{ + int ichain, ipier, npier; + int mode; + int lfrequency[AR9300_MAX_CHAINS], + lcorrection[AR9300_MAX_CHAINS], + ltemperature[AR9300_MAX_CHAINS], lvoltage[AR9300_MAX_CHAINS]; + int hfrequency[AR9300_MAX_CHAINS], + hcorrection[AR9300_MAX_CHAINS], + htemperature[AR9300_MAX_CHAINS], hvoltage[AR9300_MAX_CHAINS]; + int fdiff; + int correction[AR9300_MAX_CHAINS], + voltage[AR9300_MAX_CHAINS], temperature[AR9300_MAX_CHAINS]; + int pfrequency, pcorrection, ptemperature, pvoltage; + struct ath_common *common = ath9k_hw_common(ah); + + mode = (frequency >= 4000); + if (mode) + npier = AR9300_NUM_5G_CAL_PIERS; + else + npier = AR9300_NUM_2G_CAL_PIERS; + + for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { + lfrequency[ichain] = 0; + hfrequency[ichain] = 100000; + } + /* identify best lower and higher frequency calibration measurement */ + for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { + for (ipier = 0; ipier < npier; ipier++) { + if (!ar9003_hw_cal_pier_get(ah, mode, ipier, ichain, + &pfrequency, &pcorrection, + &ptemperature, &pvoltage)) { + fdiff = frequency - pfrequency; + + /* + * this measurement is higher than + * our desired frequency + */ + if (fdiff <= 0) { + if (hfrequency[ichain] <= 0 || + hfrequency[ichain] >= 100000 || + fdiff > + (frequency - hfrequency[ichain])) { + /* + * new best higher + * frequency measurement + */ + hfrequency[ichain] = pfrequency; + hcorrection[ichain] = + pcorrection; + htemperature[ichain] = + ptemperature; + hvoltage[ichain] = pvoltage; + } + } + if (fdiff >= 0) { + if (lfrequency[ichain] <= 0 + || fdiff < + (frequency - lfrequency[ichain])) { + /* + * new best lower + * frequency measurement + */ + lfrequency[ichain] = pfrequency; + lcorrection[ichain] = + pcorrection; + ltemperature[ichain] = + ptemperature; + lvoltage[ichain] = pvoltage; + } + } + } + } + } + + /* interpolate */ + for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { + ath_print(common, ATH_DBG_EEPROM, + "ch=%d f=%d low=%d %d h=%d %d\n", + ichain, frequency, lfrequency[ichain], + lcorrection[ichain], hfrequency[ichain], + hcorrection[ichain]); + /* they're the same, so just pick one */ + if (hfrequency[ichain] == lfrequency[ichain]) { + correction[ichain] = lcorrection[ichain]; + voltage[ichain] = lvoltage[ichain]; + temperature[ichain] = ltemperature[ichain]; + } + /* the low frequency is good */ + else if (frequency - lfrequency[ichain] < 1000) { + /* so is the high frequency, interpolate */ + if (hfrequency[ichain] - frequency < 1000) { + + correction[ichain] = lcorrection[ichain] + + (((frequency - lfrequency[ichain]) * + (hcorrection[ichain] - + lcorrection[ichain])) / + (hfrequency[ichain] - lfrequency[ichain])); + + temperature[ichain] = ltemperature[ichain] + + (((frequency - lfrequency[ichain]) * + (htemperature[ichain] - + ltemperature[ichain])) / + (hfrequency[ichain] - lfrequency[ichain])); + + voltage[ichain] = + lvoltage[ichain] + + (((frequency - + lfrequency[ichain]) * (hvoltage[ichain] - + lvoltage[ichain])) + / (hfrequency[ichain] - + lfrequency[ichain])); + } + /* only low is good, use it */ + else { + correction[ichain] = lcorrection[ichain]; + temperature[ichain] = ltemperature[ichain]; + voltage[ichain] = lvoltage[ichain]; + } + } + /* only high is good, use it */ + else if (hfrequency[ichain] - frequency < 1000) { + correction[ichain] = hcorrection[ichain]; + temperature[ichain] = htemperature[ichain]; + voltage[ichain] = hvoltage[ichain]; + } else { /* nothing is good, presume 0???? */ + correction[ichain] = 0; + temperature[ichain] = 0; + voltage[ichain] = 0; + } + } + + ar9003_hw_power_control_override(ah, frequency, correction, voltage, + temperature); + + ath_print(common, ATH_DBG_EEPROM, + "for frequency=%d, calibration correction = %d %d %d\n", + frequency, correction[0], correction[1], correction[2]); + + return 0; +} + +static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + ah->txpower_limit = powerLimit; + ar9003_hw_set_target_power_eeprom(ah, chan->channel); + ar9003_hw_calibration_apply(ah, chan->channel); +} + +static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah, + u16 i, bool is2GHz) +{ + return AR_NO_SPUR; +} + +s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + + return (eep->baseEepHeader.txrxgain >> 4) & 0xf; /* bits 7:4 */ +} + +s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + + return (eep->baseEepHeader.txrxgain) & 0xf; /* bits 3:0 */ +} + +const struct eeprom_ops eep_ar9300_ops = { + .check_eeprom = ath9k_hw_ar9300_check_eeprom, + .get_eeprom = ath9k_hw_ar9300_get_eeprom, + .fill_eeprom = ath9k_hw_ar9300_fill_eeprom, + .get_eeprom_ver = ath9k_hw_ar9300_get_eeprom_ver, + .get_eeprom_rev = ath9k_hw_ar9300_get_eeprom_rev, + .get_num_ant_config = ath9k_hw_ar9300_get_num_ant_config, + .get_eeprom_antenna_cfg = ath9k_hw_ar9300_get_eeprom_antenna_cfg, + .set_board_values = ath9k_hw_ar9300_set_board_values, + .set_addac = ath9k_hw_ar9300_set_addac, + .set_txpower = ath9k_hw_ar9300_set_txpower, + .get_spur_channel = ath9k_hw_ar9300_get_spur_channel +}; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h new file mode 100644 index 00000000000..23fb353c3bb --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -0,0 +1,323 @@ +#ifndef AR9003_EEPROM_H +#define AR9003_EEPROM_H + +#include <linux/types.h> + +#define AR9300_EEP_VER 0xD000 +#define AR9300_EEP_VER_MINOR_MASK 0xFFF +#define AR9300_EEP_MINOR_VER_1 0x1 +#define AR9300_EEP_MINOR_VER AR9300_EEP_MINOR_VER_1 + +/* 16-bit offset location start of calibration struct */ +#define AR9300_EEP_START_LOC 256 +#define AR9300_NUM_5G_CAL_PIERS 8 +#define AR9300_NUM_2G_CAL_PIERS 3 +#define AR9300_NUM_5G_20_TARGET_POWERS 8 +#define AR9300_NUM_5G_40_TARGET_POWERS 8 +#define AR9300_NUM_2G_CCK_TARGET_POWERS 2 +#define AR9300_NUM_2G_20_TARGET_POWERS 3 +#define AR9300_NUM_2G_40_TARGET_POWERS 3 +/* #define AR9300_NUM_CTLS 21 */ +#define AR9300_NUM_CTLS_5G 9 +#define AR9300_NUM_CTLS_2G 12 +#define AR9300_CTL_MODE_M 0xF +#define AR9300_NUM_BAND_EDGES_5G 8 +#define AR9300_NUM_BAND_EDGES_2G 4 +#define AR9300_NUM_PD_GAINS 4 +#define AR9300_PD_GAINS_IN_MASK 4 +#define AR9300_PD_GAIN_ICEPTS 5 +#define AR9300_EEPROM_MODAL_SPURS 5 +#define AR9300_MAX_RATE_POWER 63 +#define AR9300_NUM_PDADC_VALUES 128 +#define AR9300_NUM_RATES 16 +#define AR9300_BCHAN_UNUSED 0xFF +#define AR9300_MAX_PWR_RANGE_IN_HALF_DB 64 +#define AR9300_OPFLAGS_11A 0x01 +#define AR9300_OPFLAGS_11G 0x02 +#define AR9300_OPFLAGS_5G_HT40 0x04 +#define AR9300_OPFLAGS_2G_HT40 0x08 +#define AR9300_OPFLAGS_5G_HT20 0x10 +#define AR9300_OPFLAGS_2G_HT20 0x20 +#define AR9300_EEPMISC_BIG_ENDIAN 0x01 +#define AR9300_EEPMISC_WOW 0x02 +#define AR9300_CUSTOMER_DATA_SIZE 20 + +#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) +#define FBIN2FREQ(x, y) ((y) ? (2300 + x) : (4800 + 5 * x)) +#define AR9300_MAX_CHAINS 3 +#define AR9300_ANT_16S 25 +#define AR9300_FUTURE_MODAL_SZ 6 + +#define AR9300_NUM_ANT_CHAIN_FIELDS 7 +#define AR9300_NUM_ANT_COMMON_FIELDS 4 +#define AR9300_SIZE_ANT_CHAIN_FIELD 3 +#define AR9300_SIZE_ANT_COMMON_FIELD 4 +#define AR9300_ANT_CHAIN_MASK 0x7 +#define AR9300_ANT_COMMON_MASK 0xf +#define AR9300_CHAIN_0_IDX 0 +#define AR9300_CHAIN_1_IDX 1 +#define AR9300_CHAIN_2_IDX 2 + +#define AR928X_NUM_ANT_CHAIN_FIELDS 6 +#define AR928X_SIZE_ANT_CHAIN_FIELD 2 +#define AR928X_ANT_CHAIN_MASK 0x3 + +/* Delta from which to start power to pdadc table */ +/* This offset is used in both open loop and closed loop power control + * schemes. In open loop power control, it is not really needed, but for + * the "sake of consistency" it was kept. For certain AP designs, this + * value is overwritten by the value in the flag "pwrTableOffset" just + * before writing the pdadc vs pwr into the chip registers. + */ +#define AR9300_PWR_TABLE_OFFSET 0 + +/* enable flags for voltage and temp compensation */ +#define ENABLE_TEMP_COMPENSATION 0x01 +#define ENABLE_VOLT_COMPENSATION 0x02 +/* byte addressable */ +#define AR9300_EEPROM_SIZE (16*1024) +#define FIXED_CCA_THRESHOLD 15 + +#define AR9300_BASE_ADDR 0x3ff + +enum targetPowerHTRates { + HT_TARGET_RATE_0_8_16, + HT_TARGET_RATE_1_3_9_11_17_19, + HT_TARGET_RATE_4, + HT_TARGET_RATE_5, + HT_TARGET_RATE_6, + HT_TARGET_RATE_7, + HT_TARGET_RATE_12, + HT_TARGET_RATE_13, + HT_TARGET_RATE_14, + HT_TARGET_RATE_15, + HT_TARGET_RATE_20, + HT_TARGET_RATE_21, + HT_TARGET_RATE_22, + HT_TARGET_RATE_23 +}; + +enum targetPowerLegacyRates { + LEGACY_TARGET_RATE_6_24, + LEGACY_TARGET_RATE_36, + LEGACY_TARGET_RATE_48, + LEGACY_TARGET_RATE_54 +}; + +enum targetPowerCckRates { + LEGACY_TARGET_RATE_1L_5L, + LEGACY_TARGET_RATE_5S, + LEGACY_TARGET_RATE_11L, + LEGACY_TARGET_RATE_11S +}; + +enum ar9300_Rates { + ALL_TARGET_LEGACY_6_24, + ALL_TARGET_LEGACY_36, + ALL_TARGET_LEGACY_48, + ALL_TARGET_LEGACY_54, + ALL_TARGET_LEGACY_1L_5L, + ALL_TARGET_LEGACY_5S, + ALL_TARGET_LEGACY_11L, + ALL_TARGET_LEGACY_11S, + ALL_TARGET_HT20_0_8_16, + ALL_TARGET_HT20_1_3_9_11_17_19, + ALL_TARGET_HT20_4, + ALL_TARGET_HT20_5, + ALL_TARGET_HT20_6, + ALL_TARGET_HT20_7, + ALL_TARGET_HT20_12, + ALL_TARGET_HT20_13, + ALL_TARGET_HT20_14, + ALL_TARGET_HT20_15, + ALL_TARGET_HT20_20, + ALL_TARGET_HT20_21, + ALL_TARGET_HT20_22, + ALL_TARGET_HT20_23, + ALL_TARGET_HT40_0_8_16, + ALL_TARGET_HT40_1_3_9_11_17_19, + ALL_TARGET_HT40_4, + ALL_TARGET_HT40_5, + ALL_TARGET_HT40_6, + ALL_TARGET_HT40_7, + ALL_TARGET_HT40_12, + ALL_TARGET_HT40_13, + ALL_TARGET_HT40_14, + ALL_TARGET_HT40_15, + ALL_TARGET_HT40_20, + ALL_TARGET_HT40_21, + ALL_TARGET_HT40_22, + ALL_TARGET_HT40_23, + ar9300RateSize, +}; + + +struct eepFlags { + u8 opFlags; + u8 eepMisc; +} __packed; + +enum CompressAlgorithm { + _CompressNone = 0, + _CompressLzma, + _CompressPairs, + _CompressBlock, + _Compress4, + _Compress5, + _Compress6, + _Compress7, +}; + +struct ar9300_base_eep_hdr { + __le16 regDmn[2]; + /* 4 bits tx and 4 bits rx */ + u8 txrxMask; + struct eepFlags opCapFlags; + u8 rfSilent; + u8 blueToothOptions; + u8 deviceCap; + /* takes lower byte in eeprom location */ + u8 deviceType; + /* offset in dB to be added to beginning + * of pdadc table in calibration + */ + int8_t pwrTableOffset; + u8 params_for_tuning_caps[2]; + /* + * bit0 - enable tx temp comp + * bit1 - enable tx volt comp + * bit2 - enable fastClock - default to 1 + * bit3 - enable doubling - default to 1 + * bit4 - enable internal regulator - default to 1 + */ + u8 featureEnable; + /* misc flags: bit0 - turn down drivestrength */ + u8 miscConfiguration; + u8 eepromWriteEnableGpio; + u8 wlanDisableGpio; + u8 wlanLedGpio; + u8 rxBandSelectGpio; + u8 txrxgain; + /* SW controlled internal regulator fields */ + __le32 swreg; +} __packed; + +struct ar9300_modal_eep_header { + /* 4 idle, t1, t2, b (4 bits per setting) */ + __le32 antCtrlCommon; + /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */ + __le32 antCtrlCommon2; + /* 6 idle, t, r, rx1, rx12, b (2 bits each) */ + __le16 antCtrlChain[AR9300_MAX_CHAINS]; + /* 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */ + u8 xatten1DB[AR9300_MAX_CHAINS]; + /* 3 xatten1_margin for merlin (0xa20c/b20c 16:12 */ + u8 xatten1Margin[AR9300_MAX_CHAINS]; + int8_t tempSlope; + int8_t voltSlope; + /* spur channels in usual fbin coding format */ + u8 spurChans[AR9300_EEPROM_MODAL_SPURS]; + /* 3 Check if the register is per chain */ + int8_t noiseFloorThreshCh[AR9300_MAX_CHAINS]; + u8 ob[AR9300_MAX_CHAINS]; + u8 db_stage2[AR9300_MAX_CHAINS]; + u8 db_stage3[AR9300_MAX_CHAINS]; + u8 db_stage4[AR9300_MAX_CHAINS]; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 txClip; + int8_t antennaGain; + u8 switchSettling; + int8_t adcDesiredSize; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + u8 futureModal[32]; +} __packed; + +struct ar9300_cal_data_per_freq_op_loop { + int8_t refPower; + /* pdadc voltage at power measurement */ + u8 voltMeas; + /* pcdac used for power measurement */ + u8 tempMeas; + /* range is -60 to -127 create a mapping equation 1db resolution */ + int8_t rxNoisefloorCal; + /*range is same as noisefloor */ + int8_t rxNoisefloorPower; + /* temp measured when noisefloor cal was performed */ + u8 rxTempMeas; +} __packed; + +struct cal_tgt_pow_legacy { + u8 tPow2x[4]; +} __packed; + +struct cal_tgt_pow_ht { + u8 tPow2x[14]; +} __packed; + +struct cal_ctl_edge_pwr { + u8 tPower:6, + flag:2; +} __packed; + +struct cal_ctl_data_2g { + struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_2G]; +} __packed; + +struct cal_ctl_data_5g { + struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_5G]; +} __packed; + +struct ar9300_eeprom { + u8 eepromVersion; + u8 templateVersion; + u8 macAddr[6]; + u8 custData[AR9300_CUSTOMER_DATA_SIZE]; + + struct ar9300_base_eep_hdr baseEepHeader; + + struct ar9300_modal_eep_header modalHeader2G; + u8 calFreqPier2G[AR9300_NUM_2G_CAL_PIERS]; + struct ar9300_cal_data_per_freq_op_loop + calPierData2G[AR9300_MAX_CHAINS][AR9300_NUM_2G_CAL_PIERS]; + u8 calTarget_freqbin_Cck[AR9300_NUM_2G_CCK_TARGET_POWERS]; + u8 calTarget_freqbin_2G[AR9300_NUM_2G_20_TARGET_POWERS]; + u8 calTarget_freqbin_2GHT20[AR9300_NUM_2G_20_TARGET_POWERS]; + u8 calTarget_freqbin_2GHT40[AR9300_NUM_2G_40_TARGET_POWERS]; + struct cal_tgt_pow_legacy + calTargetPowerCck[AR9300_NUM_2G_CCK_TARGET_POWERS]; + struct cal_tgt_pow_legacy + calTargetPower2G[AR9300_NUM_2G_20_TARGET_POWERS]; + struct cal_tgt_pow_ht + calTargetPower2GHT20[AR9300_NUM_2G_20_TARGET_POWERS]; + struct cal_tgt_pow_ht + calTargetPower2GHT40[AR9300_NUM_2G_40_TARGET_POWERS]; + u8 ctlIndex_2G[AR9300_NUM_CTLS_2G]; + u8 ctl_freqbin_2G[AR9300_NUM_CTLS_2G][AR9300_NUM_BAND_EDGES_2G]; + struct cal_ctl_data_2g ctlPowerData_2G[AR9300_NUM_CTLS_2G]; + struct ar9300_modal_eep_header modalHeader5G; + u8 calFreqPier5G[AR9300_NUM_5G_CAL_PIERS]; + struct ar9300_cal_data_per_freq_op_loop + calPierData5G[AR9300_MAX_CHAINS][AR9300_NUM_5G_CAL_PIERS]; + u8 calTarget_freqbin_5G[AR9300_NUM_5G_20_TARGET_POWERS]; + u8 calTarget_freqbin_5GHT20[AR9300_NUM_5G_20_TARGET_POWERS]; + u8 calTarget_freqbin_5GHT40[AR9300_NUM_5G_40_TARGET_POWERS]; + struct cal_tgt_pow_legacy + calTargetPower5G[AR9300_NUM_5G_20_TARGET_POWERS]; + struct cal_tgt_pow_ht + calTargetPower5GHT20[AR9300_NUM_5G_20_TARGET_POWERS]; + struct cal_tgt_pow_ht + calTargetPower5GHT40[AR9300_NUM_5G_40_TARGET_POWERS]; + u8 ctlIndex_5G[AR9300_NUM_CTLS_5G]; + u8 ctl_freqbin_5G[AR9300_NUM_CTLS_5G][AR9300_NUM_BAND_EDGES_5G]; + struct cal_ctl_data_5g ctlPowerData_5G[AR9300_NUM_CTLS_5G]; +} __packed; + +s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah); +s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah); + +#endif diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c new file mode 100644 index 00000000000..b15309caf1d --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2008-2010 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 "hw.h" +#include "ar9003_mac.h" +#include "ar9003_initvals.h" + +/* General hardware code for the AR9003 hadware family */ + +static bool ar9003_hw_macversion_supported(u32 macversion) +{ + switch (macversion) { + case AR_SREV_VERSION_9300: + return true; + default: + break; + } + return false; +} + +/* AR9003 2.0 - new INI format (pre, core, post arrays per subsystem) */ +/* + * XXX: move TX/RX gain INI to its own init_mode_gain_regs after + * ensuring it does not affect hardware bring up + */ +static void ar9003_hw_init_mode_regs(struct ath_hw *ah) +{ + /* mac */ + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + ar9300_2p0_mac_core, + ARRAY_SIZE(ar9300_2p0_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + ar9300_2p0_mac_postamble, + ARRAY_SIZE(ar9300_2p0_mac_postamble), 5); + + /* bb */ + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + ar9300_2p0_baseband_core, + ARRAY_SIZE(ar9300_2p0_baseband_core), 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + ar9300_2p0_baseband_postamble, + ARRAY_SIZE(ar9300_2p0_baseband_postamble), 5); + + /* radio */ + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + ar9300_2p0_radio_core, + ARRAY_SIZE(ar9300_2p0_radio_core), 2); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + ar9300_2p0_radio_postamble, + ARRAY_SIZE(ar9300_2p0_radio_postamble), 5); + + /* soc */ + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + ar9300_2p0_soc_preamble, + ARRAY_SIZE(ar9300_2p0_soc_preamble), 2); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + ar9300_2p0_soc_postamble, + ARRAY_SIZE(ar9300_2p0_soc_postamble), 5); + + /* rx/tx gain */ + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9300Common_rx_gain_table_2p0, + ARRAY_SIZE(ar9300Common_rx_gain_table_2p0), 2); + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_lowest_ob_db_tx_gain_table_2p0, + ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0), + 5); + + /* Load PCIE SERDES settings from INI */ + + /* Awake Setting */ + + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9300PciePhy_pll_on_clkreq_disable_L1_2p0, + ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p0), + 2); + + /* Sleep Setting */ + + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9300PciePhy_clkreq_enable_L1_2p0, + ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p0), + 2); + + /* Fast clock modal settings */ + INIT_INI_ARRAY(&ah->iniModesAdditional, + ar9300Modes_fast_clock_2p0, + ARRAY_SIZE(ar9300Modes_fast_clock_2p0), + 3); +} + +static void ar9003_tx_gain_table_apply(struct ath_hw *ah) +{ + switch (ar9003_hw_get_tx_gain_idx(ah)) { + case 0: + default: + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_lowest_ob_db_tx_gain_table_2p0, + ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0), + 5); + break; + case 1: + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_high_ob_db_tx_gain_table_2p0, + ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p0), + 5); + break; + case 2: + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_low_ob_db_tx_gain_table_2p0, + ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p0), + 5); + break; + } +} + +static void ar9003_rx_gain_table_apply(struct ath_hw *ah) +{ + switch (ar9003_hw_get_rx_gain_idx(ah)) { + case 0: + default: + INIT_INI_ARRAY(&ah->iniModesRxGain, ar9300Common_rx_gain_table_2p0, + ARRAY_SIZE(ar9300Common_rx_gain_table_2p0), + 2); + break; + case 1: + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9300Common_wo_xlna_rx_gain_table_2p0, + ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p0), + 2); + break; + } +} + +/* set gain table pointers according to values read from the eeprom */ +static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah) +{ + ar9003_tx_gain_table_apply(ah); + ar9003_rx_gain_table_apply(ah); +} + +/* + * Helper for ASPM support. + * + * Disable PLL when in L0s as well as receiver clock when in L1. + * This power saving option must be enabled through the SerDes. + * + * Programming the SerDes must go through the same 288 bit serial shift + * register as the other analog registers. Hence the 9 writes. + */ +static void ar9003_hw_configpcipowersave(struct ath_hw *ah, + int restore, + int power_off) +{ + if (ah->is_pciexpress != true) + return; + + /* Do not touch SerDes registers */ + if (ah->config.pcie_powersave_enable == 2) + return; + + /* Nothing to do on restore for 11N */ + if (!restore) { + /* set bit 19 to allow forcing of pcie core into L1 state */ + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); + + /* Several PCIe massages to ensure proper behaviour */ + if (ah->config.pcie_waen) + REG_WRITE(ah, AR_WA, ah->config.pcie_waen); + } +} + +/* Sets up the AR9003 hardware familiy callbacks */ +void ar9003_hw_attach_ops(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + struct ath_hw_ops *ops = ath9k_hw_ops(ah); + + priv_ops->init_mode_regs = ar9003_hw_init_mode_regs; + priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs; + priv_ops->macversion_supported = ar9003_hw_macversion_supported; + + ops->config_pci_powersave = ar9003_hw_configpcipowersave; + + ar9003_hw_attach_phy_ops(ah); + ar9003_hw_attach_calib_ops(ah); + ar9003_hw_attach_mac_ops(ah); +} diff --git a/drivers/net/wireless/ath/ath9k/ar9003_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_initvals.h new file mode 100644 index 00000000000..db019dd220b --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_initvals.h @@ -0,0 +1,1784 @@ +/* + * Copyright (c) 2010 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. + */ + +#ifndef INITVALS_9003_H +#define INITVALS_9003_H + +/* AR9003 2.0 */ + +static const u32 ar9300_2p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31}, + {0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800}, + {0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20}, + {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, + {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, + {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, +}; + +static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016448, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016848, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + +static const u32 ar9300Modes_fast_clock_2p0[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x00001030, 0x00000268, 0x000004d0}, + {0x00001070, 0x0000018c, 0x00000318}, + {0x000010b0, 0x00000fd0, 0x00001fa0}, + {0x00008014, 0x044c044c, 0x08980898}, + {0x0000801c, 0x148ec02b, 0x148ec057}, + {0x00008318, 0x000044c0, 0x00008980}, + {0x00009e00, 0x03721821, 0x03721821}, + {0x0000a230, 0x0000000b, 0x00000016}, + {0x0000a254, 0x00000898, 0x00001130}, +}; + +static const u32 ar9300_2p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x7f80fff8}, + {0x0001604c, 0x76d005b5}, + {0x00016050, 0x556cf031}, + {0x00016054, 0x13449440}, + {0x00016058, 0x0c51c92c}, + {0x0001605c, 0x3db7fffc}, + {0x00016060, 0xfffffffc}, + {0x00016064, 0x000f0278}, + {0x0001606c, 0x6db60000}, + {0x00016080, 0x00000000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x54214514}, + {0x0001608c, 0x119f481e}, + {0x00016090, 0x24926490}, + {0x00016098, 0xd2888888}, + {0x000160a0, 0x0a108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160b4, 0x92480080}, + {0x000160c0, 0x00adb6d0}, + {0x000160c4, 0x6db6db60}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x01e6c000}, + {0x00016100, 0x3fffbe01}, + {0x00016104, 0xfff80000}, + {0x00016108, 0x00080010}, + {0x00016144, 0x02084080}, + {0x00016148, 0x00000000}, + {0x00016280, 0x058a0001}, + {0x00016284, 0x3d840208}, + {0x00016288, 0x05a20408}, + {0x0001628c, 0x00038c07}, + {0x00016290, 0x40000004}, + {0x00016294, 0x458aa14f}, + {0x00016380, 0x00000000}, + {0x00016384, 0x00000000}, + {0x00016388, 0x00800700}, + {0x0001638c, 0x00800700}, + {0x00016390, 0x00800700}, + {0x00016394, 0x00000000}, + {0x00016398, 0x00000000}, + {0x0001639c, 0x00000000}, + {0x000163a0, 0x00000001}, + {0x000163a4, 0x00000001}, + {0x000163a8, 0x00000000}, + {0x000163ac, 0x00000000}, + {0x000163b0, 0x00000000}, + {0x000163b4, 0x00000000}, + {0x000163b8, 0x00000000}, + {0x000163bc, 0x00000000}, + {0x000163c0, 0x000000a0}, + {0x000163c4, 0x000c0000}, + {0x000163c8, 0x14021402}, + {0x000163cc, 0x00001402}, + {0x000163d0, 0x00000000}, + {0x000163d4, 0x00000000}, + {0x00016400, 0x36db6db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016440, 0x7f80fff8}, + {0x0001644c, 0x76d005b5}, + {0x00016450, 0x556cf031}, + {0x00016454, 0x13449440}, + {0x00016458, 0x0c51c92c}, + {0x0001645c, 0x3db7fffc}, + {0x00016460, 0xfffffffc}, + {0x00016464, 0x000f0278}, + {0x0001646c, 0x6db60000}, + {0x00016500, 0x3fffbe01}, + {0x00016504, 0xfff80000}, + {0x00016508, 0x00080010}, + {0x00016544, 0x02084080}, + {0x00016548, 0x00000000}, + {0x00016780, 0x00000000}, + {0x00016784, 0x00000000}, + {0x00016788, 0x00800700}, + {0x0001678c, 0x00800700}, + {0x00016790, 0x00800700}, + {0x00016794, 0x00000000}, + {0x00016798, 0x00000000}, + {0x0001679c, 0x00000000}, + {0x000167a0, 0x00000001}, + {0x000167a4, 0x00000001}, + {0x000167a8, 0x00000000}, + {0x000167ac, 0x00000000}, + {0x000167b0, 0x00000000}, + {0x000167b4, 0x00000000}, + {0x000167b8, 0x00000000}, + {0x000167bc, 0x00000000}, + {0x000167c0, 0x000000a0}, + {0x000167c4, 0x000c0000}, + {0x000167c8, 0x14021402}, + {0x000167cc, 0x00001402}, + {0x000167d0, 0x00000000}, + {0x000167d4, 0x00000000}, + {0x00016800, 0x36db6db6}, + {0x00016804, 0x6db6db40}, + {0x00016808, 0x73f00000}, + {0x0001680c, 0x00000000}, + {0x00016840, 0x7f80fff8}, + {0x0001684c, 0x76d005b5}, + {0x00016850, 0x556cf031}, + {0x00016854, 0x13449440}, + {0x00016858, 0x0c51c92c}, + {0x0001685c, 0x3db7fffc}, + {0x00016860, 0xfffffffc}, + {0x00016864, 0x000f0278}, + {0x0001686c, 0x6db60000}, + {0x00016900, 0x3fffbe01}, + {0x00016904, 0xfff80000}, + {0x00016908, 0x00080010}, + {0x00016944, 0x02084080}, + {0x00016948, 0x00000000}, + {0x00016b80, 0x00000000}, + {0x00016b84, 0x00000000}, + {0x00016b88, 0x00800700}, + {0x00016b8c, 0x00800700}, + {0x00016b90, 0x00800700}, + {0x00016b94, 0x00000000}, + {0x00016b98, 0x00000000}, + {0x00016b9c, 0x00000000}, + {0x00016ba0, 0x00000001}, + {0x00016ba4, 0x00000001}, + {0x00016ba8, 0x00000000}, + {0x00016bac, 0x00000000}, + {0x00016bb0, 0x00000000}, + {0x00016bb4, 0x00000000}, + {0x00016bb8, 0x00000000}, + {0x00016bbc, 0x00000000}, + {0x00016bc0, 0x000000a0}, + {0x00016bc4, 0x000c0000}, + {0x00016bc8, 0x14021402}, + {0x00016bcc, 0x00001402}, + {0x00016bd0, 0x00000000}, + {0x00016bd4, 0x00000000}, +}; + +static const u32 ar9300Common_rx_gain_table_merlin_2p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x02000101}, + {0x0000a004, 0x02000102}, + {0x0000a008, 0x02000103}, + {0x0000a00c, 0x02000104}, + {0x0000a010, 0x02000200}, + {0x0000a014, 0x02000201}, + {0x0000a018, 0x02000202}, + {0x0000a01c, 0x02000203}, + {0x0000a020, 0x02000204}, + {0x0000a024, 0x02000205}, + {0x0000a028, 0x02000208}, + {0x0000a02c, 0x02000302}, + {0x0000a030, 0x02000303}, + {0x0000a034, 0x02000304}, + {0x0000a038, 0x02000400}, + {0x0000a03c, 0x02010300}, + {0x0000a040, 0x02010301}, + {0x0000a044, 0x02010302}, + {0x0000a048, 0x02000500}, + {0x0000a04c, 0x02010400}, + {0x0000a050, 0x02020300}, + {0x0000a054, 0x02020301}, + {0x0000a058, 0x02020302}, + {0x0000a05c, 0x02020303}, + {0x0000a060, 0x02020400}, + {0x0000a064, 0x02030300}, + {0x0000a068, 0x02030301}, + {0x0000a06c, 0x02030302}, + {0x0000a070, 0x02030303}, + {0x0000a074, 0x02030400}, + {0x0000a078, 0x02040300}, + {0x0000a07c, 0x02040301}, + {0x0000a080, 0x02040302}, + {0x0000a084, 0x02040303}, + {0x0000a088, 0x02030500}, + {0x0000a08c, 0x02040400}, + {0x0000a090, 0x02050203}, + {0x0000a094, 0x02050204}, + {0x0000a098, 0x02050205}, + {0x0000a09c, 0x02040500}, + {0x0000a0a0, 0x02050301}, + {0x0000a0a4, 0x02050302}, + {0x0000a0a8, 0x02050303}, + {0x0000a0ac, 0x02050400}, + {0x0000a0b0, 0x02050401}, + {0x0000a0b4, 0x02050402}, + {0x0000a0b8, 0x02050403}, + {0x0000a0bc, 0x02050500}, + {0x0000a0c0, 0x02050501}, + {0x0000a0c4, 0x02050502}, + {0x0000a0c8, 0x02050503}, + {0x0000a0cc, 0x02050504}, + {0x0000a0d0, 0x02050600}, + {0x0000a0d4, 0x02050601}, + {0x0000a0d8, 0x02050602}, + {0x0000a0dc, 0x02050603}, + {0x0000a0e0, 0x02050604}, + {0x0000a0e4, 0x02050700}, + {0x0000a0e8, 0x02050701}, + {0x0000a0ec, 0x02050702}, + {0x0000a0f0, 0x02050703}, + {0x0000a0f4, 0x02050704}, + {0x0000a0f8, 0x02050705}, + {0x0000a0fc, 0x02050708}, + {0x0000a100, 0x02050709}, + {0x0000a104, 0x0205070a}, + {0x0000a108, 0x0205070b}, + {0x0000a10c, 0x0205070c}, + {0x0000a110, 0x0205070d}, + {0x0000a114, 0x02050710}, + {0x0000a118, 0x02050711}, + {0x0000a11c, 0x02050712}, + {0x0000a120, 0x02050713}, + {0x0000a124, 0x02050714}, + {0x0000a128, 0x02050715}, + {0x0000a12c, 0x02050730}, + {0x0000a130, 0x02050731}, + {0x0000a134, 0x02050732}, + {0x0000a138, 0x02050733}, + {0x0000a13c, 0x02050734}, + {0x0000a140, 0x02050735}, + {0x0000a144, 0x02050750}, + {0x0000a148, 0x02050751}, + {0x0000a14c, 0x02050752}, + {0x0000a150, 0x02050753}, + {0x0000a154, 0x02050754}, + {0x0000a158, 0x02050755}, + {0x0000a15c, 0x02050770}, + {0x0000a160, 0x02050771}, + {0x0000a164, 0x02050772}, + {0x0000a168, 0x02050773}, + {0x0000a16c, 0x02050774}, + {0x0000a170, 0x02050775}, + {0x0000a174, 0x00000776}, + {0x0000a178, 0x00000776}, + {0x0000a17c, 0x00000776}, + {0x0000a180, 0x00000776}, + {0x0000a184, 0x00000776}, + {0x0000a188, 0x00000776}, + {0x0000a18c, 0x00000776}, + {0x0000a190, 0x00000776}, + {0x0000a194, 0x00000776}, + {0x0000a198, 0x00000776}, + {0x0000a19c, 0x00000776}, + {0x0000a1a0, 0x00000776}, + {0x0000a1a4, 0x00000776}, + {0x0000a1a8, 0x00000776}, + {0x0000a1ac, 0x00000776}, + {0x0000a1b0, 0x00000776}, + {0x0000a1b4, 0x00000776}, + {0x0000a1b8, 0x00000776}, + {0x0000a1bc, 0x00000776}, + {0x0000a1c0, 0x00000776}, + {0x0000a1c4, 0x00000776}, + {0x0000a1c8, 0x00000776}, + {0x0000a1cc, 0x00000776}, + {0x0000a1d0, 0x00000776}, + {0x0000a1d4, 0x00000776}, + {0x0000a1d8, 0x00000776}, + {0x0000a1dc, 0x00000776}, + {0x0000a1e0, 0x00000776}, + {0x0000a1e4, 0x00000776}, + {0x0000a1e8, 0x00000776}, + {0x0000a1ec, 0x00000776}, + {0x0000a1f0, 0x00000776}, + {0x0000a1f4, 0x00000776}, + {0x0000a1f8, 0x00000776}, + {0x0000a1fc, 0x00000776}, + {0x0000b000, 0x02000101}, + {0x0000b004, 0x02000102}, + {0x0000b008, 0x02000103}, + {0x0000b00c, 0x02000104}, + {0x0000b010, 0x02000200}, + {0x0000b014, 0x02000201}, + {0x0000b018, 0x02000202}, + {0x0000b01c, 0x02000203}, + {0x0000b020, 0x02000204}, + {0x0000b024, 0x02000205}, + {0x0000b028, 0x02000208}, + {0x0000b02c, 0x02000302}, + {0x0000b030, 0x02000303}, + {0x0000b034, 0x02000304}, + {0x0000b038, 0x02000400}, + {0x0000b03c, 0x02010300}, + {0x0000b040, 0x02010301}, + {0x0000b044, 0x02010302}, + {0x0000b048, 0x02000500}, + {0x0000b04c, 0x02010400}, + {0x0000b050, 0x02020300}, + {0x0000b054, 0x02020301}, + {0x0000b058, 0x02020302}, + {0x0000b05c, 0x02020303}, + {0x0000b060, 0x02020400}, + {0x0000b064, 0x02030300}, + {0x0000b068, 0x02030301}, + {0x0000b06c, 0x02030302}, + {0x0000b070, 0x02030303}, + {0x0000b074, 0x02030400}, + {0x0000b078, 0x02040300}, + {0x0000b07c, 0x02040301}, + {0x0000b080, 0x02040302}, + {0x0000b084, 0x02040303}, + {0x0000b088, 0x02030500}, + {0x0000b08c, 0x02040400}, + {0x0000b090, 0x02050203}, + {0x0000b094, 0x02050204}, + {0x0000b098, 0x02050205}, + {0x0000b09c, 0x02040500}, + {0x0000b0a0, 0x02050301}, + {0x0000b0a4, 0x02050302}, + {0x0000b0a8, 0x02050303}, + {0x0000b0ac, 0x02050400}, + {0x0000b0b0, 0x02050401}, + {0x0000b0b4, 0x02050402}, + {0x0000b0b8, 0x02050403}, + {0x0000b0bc, 0x02050500}, + {0x0000b0c0, 0x02050501}, + {0x0000b0c4, 0x02050502}, + {0x0000b0c8, 0x02050503}, + {0x0000b0cc, 0x02050504}, + {0x0000b0d0, 0x02050600}, + {0x0000b0d4, 0x02050601}, + {0x0000b0d8, 0x02050602}, + {0x0000b0dc, 0x02050603}, + {0x0000b0e0, 0x02050604}, + {0x0000b0e4, 0x02050700}, + {0x0000b0e8, 0x02050701}, + {0x0000b0ec, 0x02050702}, + {0x0000b0f0, 0x02050703}, + {0x0000b0f4, 0x02050704}, + {0x0000b0f8, 0x02050705}, + {0x0000b0fc, 0x02050708}, + {0x0000b100, 0x02050709}, + {0x0000b104, 0x0205070a}, + {0x0000b108, 0x0205070b}, + {0x0000b10c, 0x0205070c}, + {0x0000b110, 0x0205070d}, + {0x0000b114, 0x02050710}, + {0x0000b118, 0x02050711}, + {0x0000b11c, 0x02050712}, + {0x0000b120, 0x02050713}, + {0x0000b124, 0x02050714}, + {0x0000b128, 0x02050715}, + {0x0000b12c, 0x02050730}, + {0x0000b130, 0x02050731}, + {0x0000b134, 0x02050732}, + {0x0000b138, 0x02050733}, + {0x0000b13c, 0x02050734}, + {0x0000b140, 0x02050735}, + {0x0000b144, 0x02050750}, + {0x0000b148, 0x02050751}, + {0x0000b14c, 0x02050752}, + {0x0000b150, 0x02050753}, + {0x0000b154, 0x02050754}, + {0x0000b158, 0x02050755}, + {0x0000b15c, 0x02050770}, + {0x0000b160, 0x02050771}, + {0x0000b164, 0x02050772}, + {0x0000b168, 0x02050773}, + {0x0000b16c, 0x02050774}, + {0x0000b170, 0x02050775}, + {0x0000b174, 0x00000776}, + {0x0000b178, 0x00000776}, + {0x0000b17c, 0x00000776}, + {0x0000b180, 0x00000776}, + {0x0000b184, 0x00000776}, + {0x0000b188, 0x00000776}, + {0x0000b18c, 0x00000776}, + {0x0000b190, 0x00000776}, + {0x0000b194, 0x00000776}, + {0x0000b198, 0x00000776}, + {0x0000b19c, 0x00000776}, + {0x0000b1a0, 0x00000776}, + {0x0000b1a4, 0x00000776}, + {0x0000b1a8, 0x00000776}, + {0x0000b1ac, 0x00000776}, + {0x0000b1b0, 0x00000776}, + {0x0000b1b4, 0x00000776}, + {0x0000b1b8, 0x00000776}, + {0x0000b1bc, 0x00000776}, + {0x0000b1c0, 0x00000776}, + {0x0000b1c4, 0x00000776}, + {0x0000b1c8, 0x00000776}, + {0x0000b1cc, 0x00000776}, + {0x0000b1d0, 0x00000776}, + {0x0000b1d4, 0x00000776}, + {0x0000b1d8, 0x00000776}, + {0x0000b1dc, 0x00000776}, + {0x0000b1e0, 0x00000776}, + {0x0000b1e4, 0x00000776}, + {0x0000b1e8, 0x00000776}, + {0x0000b1ec, 0x00000776}, + {0x0000b1f0, 0x00000776}, + {0x0000b1f4, 0x00000776}, + {0x0000b1f8, 0x00000776}, + {0x0000b1fc, 0x00000776}, +}; + +static const u32 ar9300_2p0_mac_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, + {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, + {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, + {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, +}; + +static const u32 ar9300_2p0_soc_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, +}; + +static const u32 ar9200_merlin_2p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00007800, 0x00040000}, + {0x00007804, 0xdb005012}, + {0x00007808, 0x04924914}, + {0x0000780c, 0x21084210}, + {0x00007810, 0x6d801300}, + {0x00007814, 0x0019beff}, + {0x00007818, 0x07e41000}, + {0x0000781c, 0x00392000}, + {0x00007820, 0x92592480}, + {0x00007824, 0x00040000}, + {0x00007828, 0xdb005012}, + {0x0000782c, 0x04924914}, + {0x00007830, 0x21084210}, + {0x00007834, 0x6d801300}, + {0x00007838, 0x0019beff}, + {0x0000783c, 0x07e40000}, + {0x00007840, 0x00392000}, + {0x00007844, 0x92592480}, + {0x00007848, 0x00100000}, + {0x0000784c, 0x773f0567}, + {0x00007850, 0x54214514}, + {0x00007854, 0x12035828}, + {0x00007858, 0x92592692}, + {0x0000785c, 0x00000000}, + {0x00007860, 0x56400000}, + {0x00007864, 0x0a8e370e}, + {0x00007868, 0xc0102850}, + {0x0000786c, 0x812d4000}, + {0x00007870, 0x807ec400}, + {0x00007874, 0x001b6db0}, + {0x00007878, 0x00376b63}, + {0x0000787c, 0x06db6db6}, + {0x00007880, 0x006d8000}, + {0x00007884, 0xffeffffe}, + {0x00007888, 0xffeffffe}, + {0x0000788c, 0x00010000}, + {0x00007890, 0x02060aeb}, + {0x00007894, 0x5a108000}, +}; + +static const u32 ar9300_2p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044}, + {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, + {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, + {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, + {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be04, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000c284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, +}; + +static const u32 ar9300_2p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0x9280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x5f3ca3de}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14750600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x52440bbe}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x01834061}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb515}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e3c, 0xcf946222}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009e54, 0x00000000}, + {0x00009fc0, 0x803e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x01193b93}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a22c, 0x01036a1e}, + {0x0000a234, 0x10000fff}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a2a0, 0x00000001}, + {0x0000a2c0, 0x00000001}, + {0x0000a2c8, 0x00000000}, + {0x0000a2cc, 0x18c43433}, + {0x0000a2d4, 0x00000000}, + {0x0000a2dc, 0x00000000}, + {0x0000a2e0, 0x00000000}, + {0x0000a2e4, 0x00000000}, + {0x0000a2e8, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x00000000}, + {0x0000a3a8, 0xaaaaaaaa}, + {0x0000a3ac, 0x3c466478}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000246}, + {0x0000a3f8, 0x0cdbd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739ce}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00000000}, + {0x0000a440, 0x00000000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x04000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00000000}, + {0x0000a610, 0x00000000}, + {0x0000a614, 0x00000000}, + {0x0000a618, 0x00000000}, + {0x0000a61c, 0x00000000}, + {0x0000a620, 0x00000000}, + {0x0000a624, 0x00000000}, + {0x0000a628, 0x00000000}, + {0x0000a62c, 0x00000000}, + {0x0000a630, 0x00000000}, + {0x0000a634, 0x00000000}, + {0x0000a638, 0x00000000}, + {0x0000a63c, 0x00000000}, + {0x0000a640, 0x00000000}, + {0x0000a644, 0x3fad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00000637}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x00000838}, + {0x0000a7c0, 0x00000000}, + {0x0000a7c4, 0xfffffffc}, + {0x0000a7c8, 0x00000000}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000001}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2dc, 0x00000000}, + {0x0000b2e0, 0x00000000}, + {0x0000b2e4, 0x00000000}, + {0x0000b2e8, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, + {0x0000b8d0, 0x004b6a8e}, + {0x0000b8d4, 0x00000820}, + {0x0000b8dc, 0x00000000}, + {0x0000b8f0, 0x00000000}, + {0x0000b8f4, 0x00000000}, + {0x0000c2d0, 0x00000080}, + {0x0000c2d4, 0x00000000}, + {0x0000c2dc, 0x00000000}, + {0x0000c2e0, 0x00000000}, + {0x0000c2e4, 0x00000000}, + {0x0000c2e8, 0x00000000}, + {0x0000c2ec, 0x00000000}, + {0x0000c2f0, 0x00000000}, + {0x0000c2f4, 0x00000000}, + {0x0000c2f8, 0x00000000}, + {0x0000c408, 0x0e79e5c0}, + {0x0000c40c, 0x00820820}, + {0x0000c420, 0x00000000}, +}; + +static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400}, + {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402}, + {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404}, + {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640}, + {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400}, + {0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402}, + {0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, + {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, + {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, + {0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, + {0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, + {0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, + {0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, + {0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, + {0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, +}; + +static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400}, + {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402}, + {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404}, + {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640}, + {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400}, + {0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402}, + {0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec}, + {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, + {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, + {0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, + {0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + +static const u32 ar9300Common_rx_gain_table_2p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x01910190}, + {0x0000a030, 0x01930192}, + {0x0000a034, 0x01950194}, + {0x0000a038, 0x038a0196}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x22222229}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x171d1d1d}, + {0x0000a094, 0x11111717}, + {0x0000a098, 0x00030311}, + {0x0000a09c, 0x00000000}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x64000001, 0x64000001, 0x64000001, 0x64000001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016448, 0x64000001, 0x64000001, 0x64000001, 0x64000001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016848, 0x64000001, 0x64000001, 0x64000001, 0x64000001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + +static const u32 ar9300_2p0_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, + {0x00000030, 0x00020085}, + {0x00000034, 0x00000005}, + {0x00000040, 0x00000000}, + {0x00000044, 0x00000000}, + {0x00000048, 0x00000008}, + {0x0000004c, 0x00000010}, + {0x00000050, 0x00000000}, + {0x00001040, 0x002ffc0f}, + {0x00001044, 0x002ffc0f}, + {0x00001048, 0x002ffc0f}, + {0x0000104c, 0x002ffc0f}, + {0x00001050, 0x002ffc0f}, + {0x00001054, 0x002ffc0f}, + {0x00001058, 0x002ffc0f}, + {0x0000105c, 0x002ffc0f}, + {0x00001060, 0x002ffc0f}, + {0x00001064, 0x002ffc0f}, + {0x000010f0, 0x00000100}, + {0x00001270, 0x00000000}, + {0x000012b0, 0x00000000}, + {0x000012f0, 0x00000000}, + {0x0000143c, 0x00000000}, + {0x0000147c, 0x00000000}, + {0x00008000, 0x00000000}, + {0x00008004, 0x00000000}, + {0x00008008, 0x00000000}, + {0x0000800c, 0x00000000}, + {0x00008018, 0x00000000}, + {0x00008020, 0x00000000}, + {0x00008038, 0x00000000}, + {0x0000803c, 0x00000000}, + {0x00008040, 0x00000000}, + {0x00008044, 0x00000000}, + {0x00008048, 0x00000000}, + {0x0000804c, 0xffffffff}, + {0x00008054, 0x00000000}, + {0x00008058, 0x00000000}, + {0x0000805c, 0x000fc78f}, + {0x00008060, 0x0000000f}, + {0x00008064, 0x00000000}, + {0x00008070, 0x00000310}, + {0x00008074, 0x00000020}, + {0x00008078, 0x00000000}, + {0x0000809c, 0x0000000f}, + {0x000080a0, 0x00000000}, + {0x000080a4, 0x02ff0000}, + {0x000080a8, 0x0e070605}, + {0x000080ac, 0x0000000d}, + {0x000080b0, 0x00000000}, + {0x000080b4, 0x00000000}, + {0x000080b8, 0x00000000}, + {0x000080bc, 0x00000000}, + {0x000080c0, 0x2a800000}, + {0x000080c4, 0x06900168}, + {0x000080c8, 0x13881c20}, + {0x000080cc, 0x01f40000}, + {0x000080d0, 0x00252500}, + {0x000080d4, 0x00a00000}, + {0x000080d8, 0x00400000}, + {0x000080dc, 0x00000000}, + {0x000080e0, 0xffffffff}, + {0x000080e4, 0x0000ffff}, + {0x000080e8, 0x3f3f3f3f}, + {0x000080ec, 0x00000000}, + {0x000080f0, 0x00000000}, + {0x000080f4, 0x00000000}, + {0x000080fc, 0x00020000}, + {0x00008100, 0x00000000}, + {0x00008108, 0x00000052}, + {0x0000810c, 0x00000000}, + {0x00008110, 0x00000000}, + {0x00008114, 0x000007ff}, + {0x00008118, 0x000000aa}, + {0x0000811c, 0x00003210}, + {0x00008124, 0x00000000}, + {0x00008128, 0x00000000}, + {0x0000812c, 0x00000000}, + {0x00008130, 0x00000000}, + {0x00008134, 0x00000000}, + {0x00008138, 0x00000000}, + {0x0000813c, 0x0000ffff}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x00008170, 0x18486200}, + {0x00008174, 0x33332210}, + {0x00008178, 0x00000000}, + {0x0000817c, 0x00020000}, + {0x000081c0, 0x00000000}, + {0x000081c4, 0x33332210}, + {0x000081c8, 0x00000000}, + {0x000081cc, 0x00000000}, + {0x000081d4, 0x00000000}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f424}, + {0x00008248, 0x00000800}, + {0x0000824c, 0x0001e848}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x98a00010}, + {0x00008268, 0xffffffff}, + {0x0000826c, 0x0000ffff}, + {0x00008270, 0x00000000}, + {0x00008274, 0x40000000}, + {0x00008278, 0x003e4180}, + {0x0000827c, 0x00000004}, + {0x00008284, 0x0000002c}, + {0x00008288, 0x0000002c}, + {0x0000828c, 0x000000ff}, + {0x00008294, 0x00000000}, + {0x00008298, 0x00000000}, + {0x0000829c, 0x00000000}, + {0x00008300, 0x00000140}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x00000007}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0x00ff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xaa48105b}, + {0x00008348, 0x008f0000}, + {0x0000835c, 0x00000000}, + {0x00008360, 0xffffffff}, + {0x00008364, 0xffffffff}, + {0x00008368, 0x00000000}, + {0x00008370, 0x00000000}, + {0x00008374, 0x000000ff}, + {0x00008378, 0x00000000}, + {0x0000837c, 0x00000000}, + {0x00008380, 0xffffffff}, + {0x00008384, 0xffffffff}, + {0x00008390, 0xffffffff}, + {0x00008394, 0xffffffff}, + {0x00008398, 0x00000000}, + {0x0000839c, 0x00000000}, + {0x000083a0, 0x00000000}, + {0x000083a4, 0x0000fa14}, + {0x000083a8, 0x000f0c00}, + {0x000083ac, 0x33332210}, + {0x000083b0, 0x33332210}, + {0x000083b4, 0x33332210}, + {0x000083b8, 0x33332210}, + {0x000083bc, 0x00000000}, + {0x000083c0, 0x00000000}, + {0x000083c4, 0x00000000}, + {0x000083c8, 0x00000000}, + {0x000083cc, 0x00000200}, + {0x000083d0, 0x000301ff}, +}; + +static const u32 ar9300Common_wo_xlna_rx_gain_table_2p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x03820190}, + {0x0000a030, 0x03840383}, + {0x0000a034, 0x03880385}, + {0x0000a038, 0x038a0389}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x29292929}, + {0x0000a084, 0x29292929}, + {0x0000a088, 0x29292929}, + {0x0000a08c, 0x29292929}, + {0x0000a090, 0x22292929}, + {0x0000a094, 0x1d1d2222}, + {0x0000a098, 0x0c111117}, + {0x0000a09c, 0x00030303}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar9300_2p0_soc_preamble[][2] = { + /* Addr allmodes */ + {0x000040a4, 0x00a0c1c9}, + {0x00007008, 0x00000000}, + {0x00007020, 0x00000000}, + {0x00007034, 0x00000002}, + {0x00007038, 0x000004c2}, +}; + +static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p0[][2] = { + /* Addr allmodes */ + {0x00004040, 0x08212e5e}, + {0x00004040, 0x0008003b}, + {0x00004044, 0x00000000}, +}; + +static const u32 ar9300PciePhy_clkreq_enable_L1_2p0[][2] = { + /* Addr allmodes */ + {0x00004040, 0x08253e5e}, + {0x00004040, 0x0008003b}, + {0x00004044, 0x00000000}, +}; + +static const u32 ar9300PciePhy_clkreq_disable_L1_2p0[][2] = { + /* Addr allmodes */ + {0x00004040, 0x08213e5e}, + {0x00004040, 0x0008003b}, + {0x00004044, 0x00000000}, +}; + +#endif /* INITVALS_9003_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c new file mode 100644 index 00000000000..37ba37481a4 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -0,0 +1,614 @@ +/* + * Copyright (c) 2010 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 "hw.h" +#include "ar9003_mac.h" + +static void ar9003_hw_rx_enable(struct ath_hw *hw) +{ + REG_WRITE(hw, AR_CR, 0); +} + +static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) +{ + int checksum; + + checksum = ads->info + ads->link + + ads->data0 + ads->ctl3 + + ads->data1 + ads->ctl5 + + ads->data2 + ads->ctl7 + + ads->data3 + ads->ctl9; + + return ((checksum & 0xffff) + (checksum >> 16)) & AR_TxPtrChkSum; +} + +static void ar9003_hw_set_desc_link(void *ds, u32 ds_link) +{ + struct ar9003_txc *ads = ds; + + ads->link = ds_link; + ads->ctl10 &= ~AR_TxPtrChkSum; + ads->ctl10 |= ar9003_calc_ptr_chksum(ads); +} + +static void ar9003_hw_get_desc_link(void *ds, u32 **ds_link) +{ + struct ar9003_txc *ads = ds; + + *ds_link = &ads->link; +} + +static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) +{ + u32 isr = 0; + u32 mask2 = 0; + struct ath9k_hw_capabilities *pCap = &ah->caps; + u32 sync_cause = 0; + struct ath_common *common = ath9k_hw_common(ah); + + if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { + if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) + == AR_RTC_STATUS_ON) + isr = REG_READ(ah, AR_ISR); + } + + sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT; + + *masked = 0; + + if (!isr && !sync_cause) + return false; + + if (isr) { + if (isr & AR_ISR_BCNMISC) { + u32 isr2; + isr2 = REG_READ(ah, AR_ISR_S2); + + mask2 |= ((isr2 & AR_ISR_S2_TIM) >> + MAP_ISR_S2_TIM); + mask2 |= ((isr2 & AR_ISR_S2_DTIM) >> + MAP_ISR_S2_DTIM); + mask2 |= ((isr2 & AR_ISR_S2_DTIMSYNC) >> + MAP_ISR_S2_DTIMSYNC); + mask2 |= ((isr2 & AR_ISR_S2_CABEND) >> + MAP_ISR_S2_CABEND); + mask2 |= ((isr2 & AR_ISR_S2_GTT) << + MAP_ISR_S2_GTT); + mask2 |= ((isr2 & AR_ISR_S2_CST) << + MAP_ISR_S2_CST); + mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >> + MAP_ISR_S2_TSFOOR); + + if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { + REG_WRITE(ah, AR_ISR_S2, isr2); + isr &= ~AR_ISR_BCNMISC; + } + } + + if ((pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) + isr = REG_READ(ah, AR_ISR_RAC); + + if (isr == 0xffffffff) { + *masked = 0; + return false; + } + + *masked = isr & ATH9K_INT_COMMON; + + if (ah->config.rx_intr_mitigation) + if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) + *masked |= ATH9K_INT_RXLP; + + if (ah->config.tx_intr_mitigation) + if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM)) + *masked |= ATH9K_INT_TX; + + if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR)) + *masked |= ATH9K_INT_RXLP; + + if (isr & AR_ISR_HP_RXOK) + *masked |= ATH9K_INT_RXHP; + + if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) { + *masked |= ATH9K_INT_TX; + + if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { + u32 s0, s1; + s0 = REG_READ(ah, AR_ISR_S0); + REG_WRITE(ah, AR_ISR_S0, s0); + s1 = REG_READ(ah, AR_ISR_S1); + REG_WRITE(ah, AR_ISR_S1, s1); + + isr &= ~(AR_ISR_TXOK | AR_ISR_TXERR | + AR_ISR_TXEOL); + } + } + + if (isr & AR_ISR_GENTMR) { + u32 s5; + + if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) + s5 = REG_READ(ah, AR_ISR_S5_S); + else + s5 = REG_READ(ah, AR_ISR_S5); + + ah->intr_gen_timer_trigger = + MS(s5, AR_ISR_S5_GENTIMER_TRIG); + + ah->intr_gen_timer_thresh = + MS(s5, AR_ISR_S5_GENTIMER_THRESH); + + if (ah->intr_gen_timer_trigger) + *masked |= ATH9K_INT_GENTIMER; + + if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { + REG_WRITE(ah, AR_ISR_S5, s5); + isr &= ~AR_ISR_GENTMR; + } + + } + + *masked |= mask2; + + if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { + REG_WRITE(ah, AR_ISR, isr); + + (void) REG_READ(ah, AR_ISR); + } + } + + if (sync_cause) { + if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { + REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); + REG_WRITE(ah, AR_RC, 0); + *masked |= ATH9K_INT_FATAL; + } + + if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) + ath_print(common, ATH_DBG_INTERRUPT, + "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); + + REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); + (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); + + } + return true; +} + +static void ar9003_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen, + bool is_firstseg, bool is_lastseg, + const void *ds0, dma_addr_t buf_addr, + unsigned int qcu) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + unsigned int descid = 0; + + ads->info = (ATHEROS_VENDOR_ID << AR_DescId_S) | + (1 << AR_TxRxDesc_S) | + (1 << AR_CtrlStat_S) | + (qcu << AR_TxQcuNum_S) | 0x17; + + ads->data0 = buf_addr; + ads->data1 = 0; + ads->data2 = 0; + ads->data3 = 0; + + ads->ctl3 = (seglen << AR_BufLen_S); + ads->ctl3 &= AR_BufLen; + + /* Fill in pointer checksum and descriptor id */ + ads->ctl10 = ar9003_calc_ptr_chksum(ads); + ads->ctl10 |= (descid << AR_TxDescId_S); + + if (is_firstseg) { + ads->ctl12 |= (is_lastseg ? 0 : AR_TxMore); + } else if (is_lastseg) { + ads->ctl11 = 0; + ads->ctl12 = 0; + ads->ctl13 = AR9003TXC_CONST(ds0)->ctl13; + ads->ctl14 = AR9003TXC_CONST(ds0)->ctl14; + } else { + /* XXX Intermediate descriptor in a multi-descriptor frame.*/ + ads->ctl11 = 0; + ads->ctl12 = AR_TxMore; + ads->ctl13 = 0; + ads->ctl14 = 0; + } +} + +static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, + struct ath_tx_status *ts) +{ + struct ar9003_txs *ads; + + ads = &ah->ts_ring[ah->ts_tail]; + + if ((ads->status8 & AR_TxDone) == 0) + return -EINPROGRESS; + + ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size; + + if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) || + (MS(ads->ds_info, AR_TxRxDesc) != 1)) { + ath_print(ath9k_hw_common(ah), ATH_DBG_XMIT, + "Tx Descriptor error %x\n", ads->ds_info); + memset(ads, 0, sizeof(*ads)); + return -EIO; + } + + ts->qid = MS(ads->ds_info, AR_TxQcuNum); + ts->desc_id = MS(ads->status1, AR_TxDescId); + ts->ts_seqnum = MS(ads->status8, AR_SeqNum); + ts->ts_tstamp = ads->status4; + ts->ts_status = 0; + ts->ts_flags = 0; + + if (ads->status3 & AR_ExcessiveRetries) + ts->ts_status |= ATH9K_TXERR_XRETRY; + if (ads->status3 & AR_Filtered) + ts->ts_status |= ATH9K_TXERR_FILT; + if (ads->status3 & AR_FIFOUnderrun) { + ts->ts_status |= ATH9K_TXERR_FIFO; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->status8 & AR_TxOpExceeded) + ts->ts_status |= ATH9K_TXERR_XTXOP; + if (ads->status3 & AR_TxTimerExpired) + ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED; + + if (ads->status3 & AR_DescCfgErr) + ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR; + if (ads->status3 & AR_TxDataUnderrun) { + ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->status3 & AR_TxDelimUnderrun) { + ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->status2 & AR_TxBaStatus) { + ts->ts_flags |= ATH9K_TX_BA; + ts->ba_low = ads->status5; + ts->ba_high = ads->status6; + } + + ts->ts_rateindex = MS(ads->status8, AR_FinalTxIdx); + + ts->ts_rssi = MS(ads->status7, AR_TxRSSICombined); + ts->ts_rssi_ctl0 = MS(ads->status2, AR_TxRSSIAnt00); + ts->ts_rssi_ctl1 = MS(ads->status2, AR_TxRSSIAnt01); + ts->ts_rssi_ctl2 = MS(ads->status2, AR_TxRSSIAnt02); + ts->ts_rssi_ext0 = MS(ads->status7, AR_TxRSSIAnt10); + ts->ts_rssi_ext1 = MS(ads->status7, AR_TxRSSIAnt11); + ts->ts_rssi_ext2 = MS(ads->status7, AR_TxRSSIAnt12); + ts->ts_shortretry = MS(ads->status3, AR_RTSFailCnt); + ts->ts_longretry = MS(ads->status3, AR_DataFailCnt); + ts->ts_virtcol = MS(ads->status3, AR_VirtRetryCnt); + ts->ts_antenna = 0; + + ts->tid = MS(ads->status8, AR_TxTid); + + memset(ads, 0, sizeof(*ads)); + + return 0; +} + +static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds, + u32 pktlen, enum ath9k_pkt_type type, u32 txpower, + u32 keyIx, enum ath9k_key_type keyType, u32 flags) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + + if (txpower > ah->txpower_limit) + txpower = ah->txpower_limit; + + txpower += ah->txpower_indexoffset; + if (txpower > 63) + txpower = 63; + + ads->ctl11 = (pktlen & AR_FrameLen) + | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) + | SM(txpower, AR_XmitPower) + | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) + | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) + | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) + | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0); + + ads->ctl12 = + (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) + | SM(type, AR_FrameType) + | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) + | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) + | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); + + ads->ctl17 = SM(keyType, AR_EncrType) | + (flags & ATH9K_TXDESC_LDPC ? AR_LDPC : 0); + ads->ctl18 = 0; + ads->ctl19 = AR_Not_Sounding; + + ads->ctl20 = 0; + ads->ctl21 = 0; + ads->ctl22 = 0; +} + +static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, + void *lastds, + u32 durUpdateEn, u32 rtsctsRate, + u32 rtsctsDuration, + struct ath9k_11n_rate_series series[], + u32 nseries, u32 flags) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + struct ar9003_txc *last_ads = (struct ar9003_txc *) lastds; + u_int32_t ctl11; + + if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { + ctl11 = ads->ctl11; + + if (flags & ATH9K_TXDESC_RTSENA) { + ctl11 &= ~AR_CTSEnable; + ctl11 |= AR_RTSEnable; + } else { + ctl11 &= ~AR_RTSEnable; + ctl11 |= AR_CTSEnable; + } + + ads->ctl11 = ctl11; + } else { + ads->ctl11 = (ads->ctl11 & ~(AR_RTSEnable | AR_CTSEnable)); + } + + ads->ctl13 = set11nTries(series, 0) + | set11nTries(series, 1) + | set11nTries(series, 2) + | set11nTries(series, 3) + | (durUpdateEn ? AR_DurUpdateEna : 0) + | SM(0, AR_BurstDur); + + ads->ctl14 = set11nRate(series, 0) + | set11nRate(series, 1) + | set11nRate(series, 2) + | set11nRate(series, 3); + + ads->ctl15 = set11nPktDurRTSCTS(series, 0) + | set11nPktDurRTSCTS(series, 1); + + ads->ctl16 = set11nPktDurRTSCTS(series, 2) + | set11nPktDurRTSCTS(series, 3); + + ads->ctl18 = set11nRateFlags(series, 0) + | set11nRateFlags(series, 1) + | set11nRateFlags(series, 2) + | set11nRateFlags(series, 3) + | SM(rtsctsRate, AR_RTSCTSRate); + ads->ctl19 = AR_Not_Sounding; + + last_ads->ctl13 = ads->ctl13; + last_ads->ctl14 = ads->ctl14; +} + +static void ar9003_hw_set11n_aggr_first(struct ath_hw *ah, void *ds, + u32 aggrLen) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + + ads->ctl12 |= (AR_IsAggr | AR_MoreAggr); + + ads->ctl17 &= ~AR_AggrLen; + ads->ctl17 |= SM(aggrLen, AR_AggrLen); +} + +static void ar9003_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds, + u32 numDelims) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + unsigned int ctl17; + + ads->ctl12 |= (AR_IsAggr | AR_MoreAggr); + + /* + * We use a stack variable to manipulate ctl6 to reduce uncached + * read modify, modfiy, write. + */ + ctl17 = ads->ctl17; + ctl17 &= ~AR_PadDelim; + ctl17 |= SM(numDelims, AR_PadDelim); + ads->ctl17 = ctl17; +} + +static void ar9003_hw_set11n_aggr_last(struct ath_hw *ah, void *ds) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + + ads->ctl12 |= AR_IsAggr; + ads->ctl12 &= ~AR_MoreAggr; + ads->ctl17 &= ~AR_PadDelim; +} + +static void ar9003_hw_clr11n_aggr(struct ath_hw *ah, void *ds) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + + ads->ctl12 &= (~AR_IsAggr & ~AR_MoreAggr); +} + +static void ar9003_hw_set11n_burstduration(struct ath_hw *ah, void *ds, + u32 burstDuration) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + + ads->ctl13 &= ~AR_BurstDur; + ads->ctl13 |= SM(burstDuration, AR_BurstDur); + +} + +static void ar9003_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, + u32 vmf) +{ + struct ar9003_txc *ads = (struct ar9003_txc *) ds; + + if (vmf) + ads->ctl11 |= AR_VirtMoreFrag; + else + ads->ctl11 &= ~AR_VirtMoreFrag; +} + +void ar9003_hw_attach_mac_ops(struct ath_hw *hw) +{ + struct ath_hw_ops *ops = ath9k_hw_ops(hw); + + ops->rx_enable = ar9003_hw_rx_enable; + ops->set_desc_link = ar9003_hw_set_desc_link; + ops->get_desc_link = ar9003_hw_get_desc_link; + ops->get_isr = ar9003_hw_get_isr; + ops->fill_txdesc = ar9003_hw_fill_txdesc; + ops->proc_txdesc = ar9003_hw_proc_txdesc; + ops->set11n_txdesc = ar9003_hw_set11n_txdesc; + ops->set11n_ratescenario = ar9003_hw_set11n_ratescenario; + ops->set11n_aggr_first = ar9003_hw_set11n_aggr_first; + ops->set11n_aggr_middle = ar9003_hw_set11n_aggr_middle; + ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; + ops->clr11n_aggr = ar9003_hw_clr11n_aggr; + ops->set11n_burstduration = ar9003_hw_set11n_burstduration; + ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag; +} + +void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) +{ + REG_WRITE(ah, AR_DATABUF_SIZE, buf_size & AR_DATABUF_SIZE_MASK); +} +EXPORT_SYMBOL(ath9k_hw_set_rx_bufsize); + +void ath9k_hw_addrxbuf_edma(struct ath_hw *ah, u32 rxdp, + enum ath9k_rx_qtype qtype) +{ + if (qtype == ATH9K_RX_QUEUE_HP) + REG_WRITE(ah, AR_HP_RXDP, rxdp); + else + REG_WRITE(ah, AR_LP_RXDP, rxdp); +} +EXPORT_SYMBOL(ath9k_hw_addrxbuf_edma); + +int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, + void *buf_addr) +{ + struct ar9003_rxs *rxsp = (struct ar9003_rxs *) buf_addr; + unsigned int phyerr; + + /* TODO: byte swap on big endian for ar9300_10 */ + + if ((rxsp->status11 & AR_RxDone) == 0) + return -EINPROGRESS; + + if (MS(rxsp->ds_info, AR_DescId) != 0x168c) + return -EINVAL; + + if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0) + return -EINPROGRESS; + + if (!rxs) + return 0; + + rxs->rs_status = 0; + rxs->rs_flags = 0; + + rxs->rs_datalen = rxsp->status2 & AR_DataLen; + rxs->rs_tstamp = rxsp->status3; + + /* XXX: Keycache */ + rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined); + rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00); + rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01); + rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02); + rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10); + rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11); + rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12); + + if (rxsp->status11 & AR_RxKeyIdxValid) + rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx); + else + rxs->rs_keyix = ATH9K_RXKEYIX_INVALID; + + rxs->rs_rate = MS(rxsp->status1, AR_RxRate); + rxs->rs_more = (rxsp->status2 & AR_RxMore) ? 1 : 0; + + rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0; + rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0; + rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7); + rxs->rs_flags = (rxsp->status4 & AR_GI) ? ATH9K_RX_GI : 0; + rxs->rs_flags |= (rxsp->status4 & AR_2040) ? ATH9K_RX_2040 : 0; + + rxs->evm0 = rxsp->status6; + rxs->evm1 = rxsp->status7; + rxs->evm2 = rxsp->status8; + rxs->evm3 = rxsp->status9; + rxs->evm4 = (rxsp->status10 & 0xffff); + + if (rxsp->status11 & AR_PreDelimCRCErr) + rxs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE; + + if (rxsp->status11 & AR_PostDelimCRCErr) + rxs->rs_flags |= ATH9K_RX_DELIM_CRC_POST; + + if (rxsp->status11 & AR_DecryptBusyErr) + rxs->rs_flags |= ATH9K_RX_DECRYPT_BUSY; + + if ((rxsp->status11 & AR_RxFrameOK) == 0) { + if (rxsp->status11 & AR_CRCErr) { + rxs->rs_status |= ATH9K_RXERR_CRC; + } else if (rxsp->status11 & AR_PHYErr) { + rxs->rs_status |= ATH9K_RXERR_PHY; + phyerr = MS(rxsp->status11, AR_PHYErrCode); + rxs->rs_phyerr = phyerr; + } else if (rxsp->status11 & AR_DecryptCRCErr) { + rxs->rs_status |= ATH9K_RXERR_DECRYPT; + } else if (rxsp->status11 & AR_MichaelErr) { + rxs->rs_status |= ATH9K_RXERR_MIC; + } + } + + return 0; +} +EXPORT_SYMBOL(ath9k_hw_process_rxdesc_edma); + +void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah) +{ + ah->ts_tail = 0; + + memset((void *) ah->ts_ring, 0, + ah->ts_size * sizeof(struct ar9003_txs)); + + ath_print(ath9k_hw_common(ah), ATH_DBG_XMIT, + "TS Start 0x%x End 0x%x Virt %p, Size %d\n", + ah->ts_paddr_start, ah->ts_paddr_end, + ah->ts_ring, ah->ts_size); + + REG_WRITE(ah, AR_Q_STATUS_RING_START, ah->ts_paddr_start); + REG_WRITE(ah, AR_Q_STATUS_RING_END, ah->ts_paddr_end); +} + +void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start, + u32 ts_paddr_start, + u8 size) +{ + + ah->ts_paddr_start = ts_paddr_start; + ah->ts_paddr_end = ts_paddr_start + (size * sizeof(struct ar9003_txs)); + ah->ts_size = size; + ah->ts_ring = (struct ar9003_txs *) ts_start; + + ath9k_hw_reset_txstatus_ring(ah); +} +EXPORT_SYMBOL(ath9k_hw_setup_statusring); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h new file mode 100644 index 00000000000..f17558b1453 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2010 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. + */ + +#ifndef AR9003_MAC_H +#define AR9003_MAC_H + +#define AR_DescId 0xffff0000 +#define AR_DescId_S 16 +#define AR_CtrlStat 0x00004000 +#define AR_CtrlStat_S 14 +#define AR_TxRxDesc 0x00008000 +#define AR_TxRxDesc_S 15 +#define AR_TxQcuNum 0x00000f00 +#define AR_TxQcuNum_S 8 + +#define AR_BufLen 0x0fff0000 +#define AR_BufLen_S 16 + +#define AR_TxDescId 0xffff0000 +#define AR_TxDescId_S 16 +#define AR_TxPtrChkSum 0x0000ffff + +#define AR_TxTid 0xf0000000 +#define AR_TxTid_S 28 + +#define AR_LowRxChain 0x00004000 + +#define AR_Not_Sounding 0x20000000 + +#define MAP_ISR_S2_CST 6 +#define MAP_ISR_S2_GTT 6 +#define MAP_ISR_S2_TIM 3 +#define MAP_ISR_S2_CABEND 0 +#define MAP_ISR_S2_DTIMSYNC 7 +#define MAP_ISR_S2_DTIM 7 +#define MAP_ISR_S2_TSFOOR 4 + +#define AR9003TXC_CONST(_ds) ((const struct ar9003_txc *) _ds) + +struct ar9003_rxs { + u32 ds_info; + u32 status1; + u32 status2; + u32 status3; + u32 status4; + u32 status5; + u32 status6; + u32 status7; + u32 status8; + u32 status9; + u32 status10; + u32 status11; +} __packed; + +/* Transmit Control Descriptor */ +struct ar9003_txc { + u32 info; /* descriptor information */ + u32 link; /* link pointer */ + u32 data0; /* data pointer to 1st buffer */ + u32 ctl3; /* DMA control 3 */ + u32 data1; /* data pointer to 2nd buffer */ + u32 ctl5; /* DMA control 5 */ + u32 data2; /* data pointer to 3rd buffer */ + u32 ctl7; /* DMA control 7 */ + u32 data3; /* data pointer to 4th buffer */ + u32 ctl9; /* DMA control 9 */ + u32 ctl10; /* DMA control 10 */ + u32 ctl11; /* DMA control 11 */ + u32 ctl12; /* DMA control 12 */ + u32 ctl13; /* DMA control 13 */ + u32 ctl14; /* DMA control 14 */ + u32 ctl15; /* DMA control 15 */ + u32 ctl16; /* DMA control 16 */ + u32 ctl17; /* DMA control 17 */ + u32 ctl18; /* DMA control 18 */ + u32 ctl19; /* DMA control 19 */ + u32 ctl20; /* DMA control 20 */ + u32 ctl21; /* DMA control 21 */ + u32 ctl22; /* DMA control 22 */ + u32 pad[9]; /* pad to cache line (128 bytes/32 dwords) */ +} __packed; + +struct ar9003_txs { + u32 ds_info; + u32 status1; + u32 status2; + u32 status3; + u32 status4; + u32 status5; + u32 status6; + u32 status7; + u32 status8; +} __packed; + +void ar9003_hw_attach_mac_ops(struct ath_hw *hw); +void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size); +void ath9k_hw_addrxbuf_edma(struct ath_hw *ah, u32 rxdp, + enum ath9k_rx_qtype qtype); + +int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, + struct ath_rx_status *rxs, + void *buf_addr); +void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah); +void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start, + u32 ts_paddr_start, + u8 size); +#endif diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c new file mode 100644 index 00000000000..80431a2f6dc --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -0,0 +1,1134 @@ +/* + * Copyright (c) 2010 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 "hw.h" +#include "ar9003_phy.h" + +/** + * ar9003_hw_set_channel - set channel on single-chip device + * @ah: atheros hardware structure + * @chan: + * + * This is the function to change channel on single-chip devices, that is + * all devices after ar9280. + * + * This function takes the channel value in MHz and sets + * hardware channel value. Assumes writes have been enabled to analog bus. + * + * Actual Expression, + * + * For 2GHz channel, + * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17) + * (freq_ref = 40MHz) + * + * For 5GHz channel, + * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10) + * (freq_ref = 40MHz/(24>>amodeRefSel)) + * + * For 5GHz channels which are 5MHz spaced, + * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17) + * (freq_ref = 40MHz) + */ +static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) +{ + u16 bMode, fracMode = 0, aModeRefSel = 0; + u32 freq, channelSel = 0, reg32 = 0; + struct chan_centers centers; + int loadSynthChannel; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + if (freq < 4800) { /* 2 GHz, fractional mode */ + channelSel = CHANSEL_2G(freq); + /* Set to 2G mode */ + bMode = 1; + } else { + channelSel = CHANSEL_5G(freq); + /* Doubler is ON, so, divide channelSel by 2. */ + channelSel >>= 1; + /* Set to 5G mode */ + bMode = 0; + } + + /* Enable fractional mode for all channels */ + fracMode = 1; + aModeRefSel = 0; + loadSynthChannel = 0; + + reg32 = (bMode << 29); + REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); + + /* Enable Long shift Select for Synthesizer */ + REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH4, + AR_PHY_SYNTH4_LONG_SHIFT_SELECT, 1); + + /* Program Synth. setting */ + reg32 = (channelSel << 2) | (fracMode << 30) | + (aModeRefSel << 28) | (loadSynthChannel << 31); + REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32); + + /* Toggle Load Synth channel bit */ + loadSynthChannel = 1; + reg32 = (channelSel << 2) | (fracMode << 30) | + (aModeRefSel << 28) | (loadSynthChannel << 31); + REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32); + + ah->curchan = chan; + ah->curchan_rad_index = -1; + + return 0; +} + +/** + * ar9003_hw_spur_mitigate - convert baseband spur frequency + * @ah: atheros hardware structure + * @chan: + * + * For single-chip solutions. Converts to baseband spur frequency given the + * input channel frequency and compute register settings below. + * + * Spur mitigation for MRC CCK + */ +static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 spur_freq[4] = { 2420, 2440, 2464, 2480 }; + int cur_bb_spur, negative = 0, cck_spur_freq; + int i; + + /* + * Need to verify range +/- 10 MHz in control channel, otherwise spur + * is out-of-band and can be ignored. + */ + + for (i = 0; i < 4; i++) { + negative = 0; + cur_bb_spur = spur_freq[i] - chan->channel; + + if (cur_bb_spur < 0) { + negative = 1; + cur_bb_spur = -cur_bb_spur; + } + if (cur_bb_spur < 10) { + cck_spur_freq = (int)((cur_bb_spur << 19) / 11); + + if (negative == 1) + cck_spur_freq = -cck_spur_freq; + + cck_spur_freq = cck_spur_freq & 0xfffff; + + REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_YCOK_MAX, 0x7); + REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, + AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR, 0x7f); + REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, + AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE, + 0x2); + REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, + AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, + 0x1); + REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, + AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, + cck_spur_freq); + + return; + } + } + + REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_YCOK_MAX, 0x5); + REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, + AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x0); + REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, + AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 0x0); +} + +/* Clean all spur register fields */ +static void ar9003_hw_spur_ofdm_clear(struct ath_hw *ah) +{ + REG_RMW_FIELD(ah, AR_PHY_TIMING4, + AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0); + REG_RMW_FIELD(ah, AR_PHY_TIMING11, + AR_PHY_TIMING11_SPUR_FREQ_SD, 0); + REG_RMW_FIELD(ah, AR_PHY_TIMING11, + AR_PHY_TIMING11_SPUR_DELTA_PHASE, 0); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, 0); + REG_RMW_FIELD(ah, AR_PHY_TIMING11, + AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0); + REG_RMW_FIELD(ah, AR_PHY_TIMING11, + AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0); + REG_RMW_FIELD(ah, AR_PHY_TIMING4, + AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0); + REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, + AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 0); + REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, + AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 0); + + REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, + AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0); + REG_RMW_FIELD(ah, AR_PHY_TIMING4, + AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0); + REG_RMW_FIELD(ah, AR_PHY_TIMING4, + AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0); + REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK, + AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, 0); + REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, + AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, 0); + REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, + AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, 0); + REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK, + AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0); + REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, + AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0); + REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, + AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0); + REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, + AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0); +} + +static void ar9003_hw_spur_ofdm(struct ath_hw *ah, + int freq_offset, + int spur_freq_sd, + int spur_delta_phase, + int spur_subchannel_sd) +{ + int mask_index = 0; + + /* OFDM Spur mitigation */ + REG_RMW_FIELD(ah, AR_PHY_TIMING4, + AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0x1); + REG_RMW_FIELD(ah, AR_PHY_TIMING11, + AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd); + REG_RMW_FIELD(ah, AR_PHY_TIMING11, + AR_PHY_TIMING11_SPUR_DELTA_PHASE, spur_delta_phase); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, spur_subchannel_sd); + REG_RMW_FIELD(ah, AR_PHY_TIMING11, + AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0x1); + REG_RMW_FIELD(ah, AR_PHY_TIMING11, + AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0x1); + REG_RMW_FIELD(ah, AR_PHY_TIMING4, + AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0x1); + REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, + AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, 34); + REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, + AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1); + + if (REG_READ_FIELD(ah, AR_PHY_MODE, + AR_PHY_MODE_DYNAMIC) == 0x1) + REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, + AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1); + + mask_index = (freq_offset << 4) / 5; + if (mask_index < 0) + mask_index = mask_index - 1; + + mask_index = mask_index & 0x7f; + + REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, + AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0x1); + REG_RMW_FIELD(ah, AR_PHY_TIMING4, + AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0x1); + REG_RMW_FIELD(ah, AR_PHY_TIMING4, + AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0x1); + REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK, + AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, mask_index); + REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, + AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, mask_index); + REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, + AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, mask_index); + REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK, + AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0xc); + REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, + AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0xc); + REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, + AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0); + REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, + AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0xff); +} + +static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah, + struct ath9k_channel *chan, + int freq_offset) +{ + int spur_freq_sd = 0; + int spur_subchannel_sd = 0; + int spur_delta_phase = 0; + + if (IS_CHAN_HT40(chan)) { + if (freq_offset < 0) { + if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, + AR_PHY_GC_DYN2040_PRI_CH) == 0x0) + spur_subchannel_sd = 1; + else + spur_subchannel_sd = 0; + + spur_freq_sd = ((freq_offset + 10) << 9) / 11; + + } else { + if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, + AR_PHY_GC_DYN2040_PRI_CH) == 0x0) + spur_subchannel_sd = 0; + else + spur_subchannel_sd = 1; + + spur_freq_sd = ((freq_offset - 10) << 9) / 11; + + } + + spur_delta_phase = (freq_offset << 17) / 5; + + } else { + spur_subchannel_sd = 0; + spur_freq_sd = (freq_offset << 9) /11; + spur_delta_phase = (freq_offset << 18) / 5; + } + + spur_freq_sd = spur_freq_sd & 0x3ff; + spur_delta_phase = spur_delta_phase & 0xfffff; + + ar9003_hw_spur_ofdm(ah, + freq_offset, + spur_freq_sd, + spur_delta_phase, + spur_subchannel_sd); +} + +/* Spur mitigation for OFDM */ +static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + int synth_freq; + int range = 10; + int freq_offset = 0; + int mode; + u8* spurChansPtr; + unsigned int i; + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + + if (IS_CHAN_5GHZ(chan)) { + spurChansPtr = &(eep->modalHeader5G.spurChans[0]); + mode = 0; + } + else { + spurChansPtr = &(eep->modalHeader2G.spurChans[0]); + mode = 1; + } + + if (spurChansPtr[0] == 0) + return; /* No spur in the mode */ + + if (IS_CHAN_HT40(chan)) { + range = 19; + if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, + AR_PHY_GC_DYN2040_PRI_CH) == 0x0) + synth_freq = chan->channel - 10; + else + synth_freq = chan->channel + 10; + } else { + range = 10; + synth_freq = chan->channel; + } + + ar9003_hw_spur_ofdm_clear(ah); + + for (i = 0; spurChansPtr[i] && i < 5; i++) { + freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq; + if (abs(freq_offset) < range) { + ar9003_hw_spur_ofdm_work(ah, chan, freq_offset); + break; + } + } +} + +static void ar9003_hw_spur_mitigate(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + ar9003_hw_spur_mitigate_mrc_cck(ah, chan); + ar9003_hw_spur_mitigate_ofdm(ah, chan); +} + +static u32 ar9003_hw_compute_pll_control(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 pll; + + pll = SM(0x5, AR_RTC_9300_PLL_REFDIV); + + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9300_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9300_PLL_CLKSEL); + + pll |= SM(0x2c, AR_RTC_9300_PLL_DIV); + + return pll; +} + +static void ar9003_hw_set_channel_regs(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 phymode; + u32 enableDacFifo = 0; + + enableDacFifo = + (REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO); + + /* Enable 11n HT, 20 MHz */ + phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | AR_PHY_GC_WALSH | + AR_PHY_GC_SHORT_GI_40 | enableDacFifo; + + /* Configure baseband for dynamic 20/40 operation */ + if (IS_CHAN_HT40(chan)) { + phymode |= AR_PHY_GC_DYN2040_EN; + /* Configure control (primary) channel at +-10MHz */ + if ((chan->chanmode == CHANNEL_A_HT40PLUS) || + (chan->chanmode == CHANNEL_G_HT40PLUS)) + phymode |= AR_PHY_GC_DYN2040_PRI_CH; + + } + + /* make sure we preserve INI settings */ + phymode |= REG_READ(ah, AR_PHY_GEN_CTRL); + /* turn off Green Field detection for STA for now */ + phymode &= ~AR_PHY_GC_GF_DETECT_EN; + + REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode); + + /* Configure MAC for 20/40 operation */ + ath9k_hw_set11nmac2040(ah); + + /* global transmit timeout (25 TUs default)*/ + REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); + /* carrier sense timeout */ + REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); +} + +static void ar9003_hw_init_bb(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 synthDelay; + + /* + * Wait for the frequency synth to settle (synth goes on + * via AR_PHY_ACTIVE_EN). Read the phy active delay register. + * Value is in 100ns increments. + */ + synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_B(chan)) + synthDelay = (4 * synthDelay) / 22; + else + synthDelay /= 10; + + /* Activate the PHY (includes baseband activate + synthesizer on) */ + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + /* + * There is an issue if the AP starts the calibration before + * the base band timeout completes. This could result in the + * rx_clear false triggering. As a workaround we add delay an + * extra BASE_ACTIVATE_DELAY usecs to ensure this condition + * does not happen. + */ + udelay(synthDelay + BASE_ACTIVATE_DELAY); +} + +void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) +{ + switch (rx) { + case 0x5: + REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, + AR_PHY_SWAP_ALT_CHAIN); + case 0x3: + case 0x1: + case 0x2: + case 0x7: + REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx); + REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx); + break; + default: + break; + } + + REG_WRITE(ah, AR_SELFGEN_MASK, tx); + if (tx == 0x5) { + REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, + AR_PHY_SWAP_ALT_CHAIN); + } +} + +/* + * Override INI values with chip specific configuration. + */ +static void ar9003_hw_override_ini(struct ath_hw *ah) +{ + u32 val; + + /* + * Set the RX_ABORT and RX_DIS and clear it only after + * RXE is set for MAC. This prevents frames with + * corrupted descriptor status. + */ + REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + + /* + * For AR9280 and above, there is a new feature that allows + * Multicast search based on both MAC Address and Key ID. By default, + * this feature is enabled. But since the driver is not using this + * feature, we switch it off; otherwise multicast search based on + * MAC addr only will fail. + */ + val = REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE); + REG_WRITE(ah, AR_PCU_MISC_MODE2, + val | AR_AGG_WEP_ENABLE_FIX | AR_AGG_WEP_ENABLE); +} + +static void ar9003_hw_prog_ini(struct ath_hw *ah, + struct ar5416IniArray *iniArr, + int column) +{ + unsigned int i, regWrites = 0; + + /* New INI format: Array may be undefined (pre, core, post arrays) */ + if (!iniArr->ia_array) + return; + + /* + * New INI format: Pre, core, and post arrays for a given subsystem + * may be modal (> 2 columns) or non-modal (2 columns). Determine if + * the array is non-modal and force the column to 1. + */ + if (column >= iniArr->ia_columns) + column = 1; + + for (i = 0; i < iniArr->ia_rows; i++) { + u32 reg = INI_RA(iniArr, i, 0); + u32 val = INI_RA(iniArr, i, column); + + REG_WRITE(ah, reg, val); + + /* + * Determine if this is a shift register value, and insert the + * configured delay if so. + */ + if (reg >= 0x16000 && reg < 0x17000 + && ah->config.analog_shiftreg) + udelay(100); + + DO_DELAY(regWrites); + } +} + +static int ar9003_hw_process_ini(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + unsigned int regWrites = 0, i; + struct ieee80211_channel *channel = chan->chan; + u32 modesIndex, freqIndex; + + switch (chan->chanmode) { + case CHANNEL_A: + case CHANNEL_A_HT20: + modesIndex = 1; + freqIndex = 1; + break; + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + modesIndex = 2; + freqIndex = 1; + break; + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_B: + modesIndex = 4; + freqIndex = 2; + break; + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + modesIndex = 3; + freqIndex = 2; + break; + + default: + return -EINVAL; + } + + for (i = 0; i < ATH_INI_NUM_SPLIT; i++) { + ar9003_hw_prog_ini(ah, &ah->iniSOC[i], modesIndex); + ar9003_hw_prog_ini(ah, &ah->iniMac[i], modesIndex); + ar9003_hw_prog_ini(ah, &ah->iniBB[i], modesIndex); + ar9003_hw_prog_ini(ah, &ah->iniRadio[i], modesIndex); + } + + REG_WRITE_ARRAY(&ah->iniModesRxGain, 1, regWrites); + REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); + + /* + * For 5GHz channels requiring Fast Clock, apply + * different modal values. + */ + if (IS_CHAN_A_FAST_CLOCK(ah, chan)) + REG_WRITE_ARRAY(&ah->iniModesAdditional, + modesIndex, regWrites); + + ar9003_hw_override_ini(ah); + ar9003_hw_set_channel_regs(ah, chan); + ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); + + /* Set TX power */ + ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(regulatory, chan), + channel->max_antenna_gain * 2, + channel->max_power * 2, + min((u32) MAX_RATE_POWER, + (u32) regulatory->power_limit)); + + return 0; +} + +static void ar9003_hw_set_rfmode(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 rfMode = 0; + + if (chan == NULL) + return; + + rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) + ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; + + if (IS_CHAN_A_FAST_CLOCK(ah, chan)) + rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); + + REG_WRITE(ah, AR_PHY_MODE, rfMode); +} + +static void ar9003_hw_mark_phy_inactive(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); +} + +static void ar9003_hw_set_delta_slope(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 coef_scaled, ds_coef_exp, ds_coef_man; + u32 clockMhzScaled = 0x64000000; + struct chan_centers centers; + + /* + * half and quarter rate can divide the scaled clock by 2 or 4 + * scale for selected channel bandwidth + */ + if (IS_CHAN_HALF_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 1; + else if (IS_CHAN_QUARTER_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 2; + + /* + * ALGO -> coef = 1e8/fcarrier*fclock/40; + * scaled coef to provide precision for this floating calculation + */ + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + coef_scaled = clockMhzScaled / centers.synth_center; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); + + /* + * For Short GI, + * scaled coeff is 9/10 that of normal coeff + */ + coef_scaled = (9 * coef_scaled) / 10; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + /* for short gi */ + REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, + AR_PHY_SGI_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, + AR_PHY_SGI_DSC_EXP, ds_coef_exp); +} + +static bool ar9003_hw_rfbus_req(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); + return ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, + AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT); +} + +/* + * Wait for the frequency synth to settle (synth goes on via PHY_ACTIVE_EN). + * Read the phy active delay register. Value is in 100ns increments. + */ +static void ar9003_hw_rfbus_done(struct ath_hw *ah) +{ + u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_B(ah->curchan)) + synthDelay = (4 * synthDelay) / 22; + else + synthDelay /= 10; + + udelay(synthDelay + BASE_ACTIVATE_DELAY); + + REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); +} + +/* + * Set the interrupt and GPIO values so the ISR can disable RF + * on a switch signal. Assumes GPIO port and interrupt polarity + * are set prior to call. + */ +static void ar9003_hw_enable_rfkill(struct ath_hw *ah) +{ + /* Connect rfsilent_bb_l to baseband */ + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); + /* Set input mux for rfsilent_bb_l to GPIO #0 */ + REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, + AR_GPIO_INPUT_MUX2_RFSILENT); + + /* + * Configure the desired GPIO port for input and + * enable baseband rf silence. + */ + ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio); + REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); +} + +static void ar9003_hw_set_diversity(struct ath_hw *ah, bool value) +{ + u32 v = REG_READ(ah, AR_PHY_CCK_DETECT); + if (value) + v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + else + v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + REG_WRITE(ah, AR_PHY_CCK_DETECT, v); +} + +static bool ar9003_hw_ani_control(struct ath_hw *ah, + enum ath9k_ani_cmd cmd, int param) +{ + struct ar5416AniState *aniState = ah->curani; + struct ath_common *common = ath9k_hw_common(ah); + + switch (cmd & ah->ani_function) { + case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ + u32 level = param; + + if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { + ath_print(common, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned)ARRAY_SIZE(ah->totalSizeDesired)); + return false; + } + + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_TOT_DES, + ah->totalSizeDesired[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC, + AR_PHY_AGC_COARSE_LOW, + ah->coarse_low[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC, + AR_PHY_AGC_COARSE_HIGH, + ah->coarse_high[level]); + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRPWR, ah->firpwr[level]); + + if (level > aniState->noiseImmunityLevel) + ah->stats.ast_ani_niup++; + else if (level < aniState->noiseImmunityLevel) + ah->stats.ast_ani_nidown++; + aniState->noiseImmunityLevel = level; + break; + } + case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ + const int m1ThreshLow[] = { 127, 50 }; + const int m2ThreshLow[] = { 127, 40 }; + const int m1Thresh[] = { 127, 0x4d }; + const int m2Thresh[] = { 127, 0x40 }; + const int m2CountThr[] = { 31, 16 }; + const int m2CountThrLow[] = { 63, 48 }; + u32 on = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M1_THRESH_LOW, + m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2_THRESH_LOW, + m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, + m2CountThrLow[on]); + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]); + + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + else + REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + + if (!on != aniState->ofdmWeakSigDetectOff) { + if (on) + ah->stats.ast_ani_ofdmon++; + else + ah->stats.ast_ani_ofdmoff++; + aniState->ofdmWeakSigDetectOff = !on; + } + break; + } + case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ + const int weakSigThrCck[] = { 8, 6 }; + u32 high = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, + AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, + weakSigThrCck[high]); + if (high != aniState->cckWeakSigThreshold) { + if (high) + ah->stats.ast_ani_cckhigh++; + else + ah->stats.ast_ani_ccklow++; + aniState->cckWeakSigThreshold = high; + } + break; + } + case ATH9K_ANI_FIRSTEP_LEVEL:{ + const int firstep[] = { 0, 4, 8 }; + u32 level = param; + + if (level >= ARRAY_SIZE(firstep)) { + ath_print(common, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) ARRAY_SIZE(firstep)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRSTEP, + firstep[level]); + if (level > aniState->firstepLevel) + ah->stats.ast_ani_stepup++; + else if (level < aniState->firstepLevel) + ah->stats.ast_ani_stepdown++; + aniState->firstepLevel = level; + break; + } + case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ + const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; + u32 level = param; + + if (level >= ARRAY_SIZE(cycpwrThr1)) { + ath_print(common, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) ARRAY_SIZE(cycpwrThr1)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_TIMING5, + AR_PHY_TIMING5_CYCPWR_THR1, + cycpwrThr1[level]); + if (level > aniState->spurImmunityLevel) + ah->stats.ast_ani_spurup++; + else if (level < aniState->spurImmunityLevel) + ah->stats.ast_ani_spurdown++; + aniState->spurImmunityLevel = level; + break; + } + case ATH9K_ANI_PRESENT: + break; + default: + ath_print(common, ATH_DBG_ANI, + "invalid cmd %u\n", cmd); + return false; + } + + ath_print(common, ATH_DBG_ANI, "ANI parameters:\n"); + ath_print(common, ATH_DBG_ANI, + "noiseImmunityLevel=%d, spurImmunityLevel=%d, " + "ofdmWeakSigDetectOff=%d\n", + aniState->noiseImmunityLevel, + aniState->spurImmunityLevel, + !aniState->ofdmWeakSigDetectOff); + ath_print(common, ATH_DBG_ANI, + "cckWeakSigThreshold=%d, " + "firstepLevel=%d, listenTime=%d\n", + aniState->cckWeakSigThreshold, + aniState->firstepLevel, + aniState->listenTime); + ath_print(common, ATH_DBG_ANI, + "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", + aniState->cycleCount, + aniState->ofdmPhyErrCount, + aniState->cckPhyErrCount); + + return true; +} + +static void ar9003_hw_nf_sanitize_2g(struct ath_hw *ah, s16 *nf) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (*nf > ah->nf_2g_max) { + ath_print(common, ATH_DBG_CALIBRATE, + "2 GHz NF (%d) > MAX (%d), " + "correcting to MAX", + *nf, ah->nf_2g_max); + *nf = ah->nf_2g_max; + } else if (*nf < ah->nf_2g_min) { + ath_print(common, ATH_DBG_CALIBRATE, + "2 GHz NF (%d) < MIN (%d), " + "correcting to MIN", + *nf, ah->nf_2g_min); + *nf = ah->nf_2g_min; + } +} + +static void ar9003_hw_nf_sanitize_5g(struct ath_hw *ah, s16 *nf) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (*nf > ah->nf_5g_max) { + ath_print(common, ATH_DBG_CALIBRATE, + "5 GHz NF (%d) > MAX (%d), " + "correcting to MAX", + *nf, ah->nf_5g_max); + *nf = ah->nf_5g_max; + } else if (*nf < ah->nf_5g_min) { + ath_print(common, ATH_DBG_CALIBRATE, + "5 GHz NF (%d) < MIN (%d), " + "correcting to MIN", + *nf, ah->nf_5g_min); + *nf = ah->nf_5g_min; + } +} + +static void ar9003_hw_nf_sanitize(struct ath_hw *ah, s16 *nf) +{ + if (IS_CHAN_2GHZ(ah->curchan)) + ar9003_hw_nf_sanitize_2g(ah, nf); + else + ar9003_hw_nf_sanitize_5g(ah, nf); +} + +static void ar9003_hw_do_getnf(struct ath_hw *ah, + int16_t nfarray[NUM_NF_READINGS]) +{ + struct ath_common *common = ath9k_hw_common(ah); + int16_t nf; + + nf = MS(REG_READ(ah, AR_PHY_CCA_0), AR_PHY_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ar9003_hw_nf_sanitize(ah, &nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 0] is %d\n", nf); + nfarray[0] = nf; + + nf = MS(REG_READ(ah, AR_PHY_CCA_1), AR_PHY_CH1_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ar9003_hw_nf_sanitize(ah, &nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 1] is %d\n", nf); + nfarray[1] = nf; + + nf = MS(REG_READ(ah, AR_PHY_CCA_2), AR_PHY_CH2_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ar9003_hw_nf_sanitize(ah, &nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 2] is %d\n", nf); + nfarray[2] = nf; + + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ar9003_hw_nf_sanitize(ah, &nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 0] is %d\n", nf); + nfarray[3] = nf; + + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_1), AR_PHY_CH1_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ar9003_hw_nf_sanitize(ah, &nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 1] is %d\n", nf); + nfarray[4] = nf; + + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_2), AR_PHY_CH2_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + ar9003_hw_nf_sanitize(ah, &nf); + ath_print(common, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 2] is %d\n", nf); + nfarray[5] = nf; +} + +void ar9003_hw_set_nf_limits(struct ath_hw *ah) +{ + ah->nf_2g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ; + ah->nf_2g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ; + ah->nf_5g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ; + ah->nf_5g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ; +} + +/* + * Find out which of the RX chains are enabled + */ +static u32 ar9003_hw_get_rx_chainmask(struct ath_hw *ah) +{ + u32 chain = REG_READ(ah, AR_PHY_RX_CHAINMASK); + /* + * The bits [2:0] indicate the rx chain mask and are to be + * interpreted as follows: + * 00x => Only chain 0 is enabled + * 01x => Chain 1 and 0 enabled + * 1xx => Chain 2,1 and 0 enabled + */ + return chain & 0x7; +} + +static void ar9003_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) +{ + struct ath9k_nfcal_hist *h; + unsigned i, j; + int32_t val; + const u32 ar9300_cca_regs[6] = { + AR_PHY_CCA_0, + AR_PHY_CCA_1, + AR_PHY_CCA_2, + AR_PHY_EXT_CCA, + AR_PHY_EXT_CCA_1, + AR_PHY_EXT_CCA_2, + }; + u8 chainmask, rx_chain_status; + struct ath_common *common = ath9k_hw_common(ah); + + rx_chain_status = ar9003_hw_get_rx_chainmask(ah); + + chainmask = 0x3F; + h = ah->nfCalHist; + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar9300_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (h[i].privNF) << 1) & 0x1ff); + REG_WRITE(ah, ar9300_cca_regs[i], val); + } + } + + /* + * Load software filtered NF value into baseband internal minCCApwr + * variable. + */ + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_ENABLE_NF); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + + /* + * Wait for load to complete, should be fast, a few 10s of us. + * The max delay was changed from an original 250us to 10000us + * since 250us often results in NF load timeout and causes deaf + * condition during stress testing 12/12/2009 + */ + for (j = 0; j < 1000; j++) { + if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & + AR_PHY_AGC_CONTROL_NF) == 0) + break; + udelay(10); + } + + /* + * We timed out waiting for the noisefloor to load, probably due to an + * in-progress rx. Simply return here and allow the load plenty of time + * to complete before the next calibration interval. We need to avoid + * trying to load -50 (which happens below) while the previous load is + * still in progress as this can cause rx deafness. Instead by returning + * here, the baseband nf cal will just be capped by our present + * noisefloor until the next calibration timer. + */ + if (j == 1000) { + ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf " + "to load: AR_PHY_AGC_CONTROL=0x%x\n", + REG_READ(ah, AR_PHY_AGC_CONTROL)); + return; + } + + /* + * Restore maxCCAPower register parameter again so that we're not capped + * by the median we just loaded. This will be initial (and max) value + * of next noise floor calibration the baseband does. + */ + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar9300_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (-50) << 1) & 0x1ff); + REG_WRITE(ah, ar9300_cca_regs[i], val); + } + } +} + +void ar9003_hw_attach_phy_ops(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + + priv_ops->rf_set_freq = ar9003_hw_set_channel; + priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate; + priv_ops->compute_pll_control = ar9003_hw_compute_pll_control; + priv_ops->set_channel_regs = ar9003_hw_set_channel_regs; + priv_ops->init_bb = ar9003_hw_init_bb; + priv_ops->process_ini = ar9003_hw_process_ini; + priv_ops->set_rfmode = ar9003_hw_set_rfmode; + priv_ops->mark_phy_inactive = ar9003_hw_mark_phy_inactive; + priv_ops->set_delta_slope = ar9003_hw_set_delta_slope; + priv_ops->rfbus_req = ar9003_hw_rfbus_req; + priv_ops->rfbus_done = ar9003_hw_rfbus_done; + priv_ops->enable_rfkill = ar9003_hw_enable_rfkill; + priv_ops->set_diversity = ar9003_hw_set_diversity; + priv_ops->ani_control = ar9003_hw_ani_control; + priv_ops->do_getnf = ar9003_hw_do_getnf; + priv_ops->loadnf = ar9003_hw_loadnf; +} diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h new file mode 100644 index 00000000000..f08cc8bda00 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -0,0 +1,847 @@ +/* + * Copyright (c) 2002-2010 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. + */ + +#ifndef AR9003_PHY_H +#define AR9003_PHY_H + +/* + * Channel Register Map + */ +#define AR_CHAN_BASE 0x9800 + +#define AR_PHY_TIMING1 (AR_CHAN_BASE + 0x0) +#define AR_PHY_TIMING2 (AR_CHAN_BASE + 0x4) +#define AR_PHY_TIMING3 (AR_CHAN_BASE + 0x8) +#define AR_PHY_TIMING4 (AR_CHAN_BASE + 0xc) +#define AR_PHY_TIMING5 (AR_CHAN_BASE + 0x10) +#define AR_PHY_TIMING6 (AR_CHAN_BASE + 0x14) +#define AR_PHY_TIMING11 (AR_CHAN_BASE + 0x18) +#define AR_PHY_SPUR_REG (AR_CHAN_BASE + 0x1c) +#define AR_PHY_RX_IQCAL_CORR_B0 (AR_CHAN_BASE + 0xdc) +#define AR_PHY_TX_IQCAL_CONTROL_3 (AR_CHAN_BASE + 0xb0) + +#define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 +#define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 + +#define AR_PHY_TIMING11_SPUR_DELTA_PHASE 0x000FFFFF +#define AR_PHY_TIMING11_SPUR_DELTA_PHASE_S 0 + +#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC 0x40000000 +#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC_S 30 + +#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR 0x80000000 +#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR_S 31 + +#define AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT 0x4000000 +#define AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT_S 26 + +#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM 0x20000 /* bins move with freq offset */ +#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM_S 17 +#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH 0x000000FF +#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S 0 +#define AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI 0x00000100 +#define AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI_S 8 +#define AR_PHY_SPUR_REG_MASK_RATE_CNTL 0x03FC0000 +#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S 18 + +#define AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN 0x20000000 +#define AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN_S 29 + +#define AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN 0x80000000 +#define AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN_S 31 + +#define AR_PHY_FIND_SIG_LOW (AR_CHAN_BASE + 0x20) + +#define AR_PHY_SFCORR (AR_CHAN_BASE + 0x24) +#define AR_PHY_SFCORR_LOW (AR_CHAN_BASE + 0x28) +#define AR_PHY_SFCORR_EXT (AR_CHAN_BASE + 0x2c) + +#define AR_PHY_EXT_CCA (AR_CHAN_BASE + 0x30) +#define AR_PHY_RADAR_0 (AR_CHAN_BASE + 0x34) +#define AR_PHY_RADAR_1 (AR_CHAN_BASE + 0x38) +#define AR_PHY_RADAR_EXT (AR_CHAN_BASE + 0x3c) +#define AR_PHY_MULTICHAIN_CTRL (AR_CHAN_BASE + 0x80) +#define AR_PHY_PERCHAIN_CSD (AR_CHAN_BASE + 0x84) + +#define AR_PHY_TX_PHASE_RAMP_0 (AR_CHAN_BASE + 0xd0) +#define AR_PHY_ADC_GAIN_DC_CORR_0 (AR_CHAN_BASE + 0xd4) +#define AR_PHY_IQ_ADC_MEAS_0_B0 (AR_CHAN_BASE + 0xc0) +#define AR_PHY_IQ_ADC_MEAS_1_B0 (AR_CHAN_BASE + 0xc4) +#define AR_PHY_IQ_ADC_MEAS_2_B0 (AR_CHAN_BASE + 0xc8) +#define AR_PHY_IQ_ADC_MEAS_3_B0 (AR_CHAN_BASE + 0xcc) + +/* The following registers changed position from AR9300 1.0 to AR9300 2.0 */ +#define AR_PHY_TX_PHASE_RAMP_0_9300_10 (AR_CHAN_BASE + 0xd0 - 0x10) +#define AR_PHY_ADC_GAIN_DC_CORR_0_9300_10 (AR_CHAN_BASE + 0xd4 - 0x10) +#define AR_PHY_IQ_ADC_MEAS_0_B0_9300_10 (AR_CHAN_BASE + 0xc0 + 0x8) +#define AR_PHY_IQ_ADC_MEAS_1_B0_9300_10 (AR_CHAN_BASE + 0xc4 + 0x8) +#define AR_PHY_IQ_ADC_MEAS_2_B0_9300_10 (AR_CHAN_BASE + 0xc8 + 0x8) +#define AR_PHY_IQ_ADC_MEAS_3_B0_9300_10 (AR_CHAN_BASE + 0xcc + 0x8) + +#define AR_PHY_TX_CRC (AR_CHAN_BASE + 0xa0) +#define AR_PHY_TST_DAC_CONST (AR_CHAN_BASE + 0xa4) +#define AR_PHY_SPUR_REPORT_0 (AR_CHAN_BASE + 0xa8) +#define AR_PHY_CHAN_INFO_TAB_0 (AR_CHAN_BASE + 0x300) + +/* + * Channel Field Definitions + */ +#define AR_PHY_TIMING2_USE_FORCE_PPM 0x00001000 +#define AR_PHY_TIMING2_FORCE_PPM_VAL 0x00000fff +#define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 +#define AR_PHY_TIMING3_DSC_MAN_S 17 +#define AR_PHY_TIMING3_DSC_EXP 0x0001E000 +#define AR_PHY_TIMING3_DSC_EXP_S 13 +#define AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX 0xF000 +#define AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX_S 12 +#define AR_PHY_TIMING4_DO_CAL 0x10000 + +#define AR_PHY_TIMING4_ENABLE_PILOT_MASK 0x10000000 +#define AR_PHY_TIMING4_ENABLE_PILOT_MASK_S 28 +#define AR_PHY_TIMING4_ENABLE_CHAN_MASK 0x20000000 +#define AR_PHY_TIMING4_ENABLE_CHAN_MASK_S 29 + +#define AR_PHY_TIMING4_ENABLE_SPUR_FILTER 0x40000000 +#define AR_PHY_TIMING4_ENABLE_SPUR_FILTER_S 30 +#define AR_PHY_TIMING4_ENABLE_SPUR_RSSI 0x80000000 +#define AR_PHY_TIMING4_ENABLE_SPUR_RSSI_S 31 + +#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000 +#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000 +#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW 0x00000001 +#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW 0x00003F00 +#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S 8 +#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW 0x001FC000 +#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S 14 +#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW 0x0FE00000 +#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S 21 +#define AR_PHY_SFCORR_M2COUNT_THR 0x0000001F +#define AR_PHY_SFCORR_M2COUNT_THR_S 0 +#define AR_PHY_SFCORR_M1_THRESH 0x00FE0000 +#define AR_PHY_SFCORR_M1_THRESH_S 17 +#define AR_PHY_SFCORR_M2_THRESH 0x7F000000 +#define AR_PHY_SFCORR_M2_THRESH_S 24 +#define AR_PHY_SFCORR_EXT_M1_THRESH 0x0000007F +#define AR_PHY_SFCORR_EXT_M1_THRESH_S 0 +#define AR_PHY_SFCORR_EXT_M2_THRESH 0x00003F80 +#define AR_PHY_SFCORR_EXT_M2_THRESH_S 7 +#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW 0x001FC000 +#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14 +#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW 0x0FE00000 +#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21 +#define AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD 0x10000000 +#define AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD_S 28 +#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28 +#define AR_PHY_EXT_CCA_THRESH62 0x007F0000 +#define AR_PHY_EXT_CCA_THRESH62_S 16 +#define AR_PHY_EXT_MINCCA_PWR 0x01FF0000 +#define AR_PHY_EXT_MINCCA_PWR_S 16 +#define AR_PHY_TIMING5_CYCPWR_THR1 0x000000FE +#define AR_PHY_TIMING5_CYCPWR_THR1_S 1 +#define AR_PHY_TIMING5_CYCPWR_THR1_ENABLE 0x00000001 +#define AR_PHY_TIMING5_CYCPWR_THR1_ENABLE_S 0 +#define AR_PHY_TIMING5_CYCPWR_THR1A 0x007F0000 +#define AR_PHY_TIMING5_CYCPWR_THR1A_S 16 +#define AR_PHY_TIMING5_RSSI_THR1A (0x7F << 16) +#define AR_PHY_TIMING5_RSSI_THR1A_S 16 +#define AR_PHY_TIMING5_RSSI_THR1A_ENA (0x1 << 15) +#define AR_PHY_RADAR_0_ENA 0x00000001 +#define AR_PHY_RADAR_0_FFT_ENA 0x80000000 +#define AR_PHY_RADAR_0_INBAND 0x0000003e +#define AR_PHY_RADAR_0_INBAND_S 1 +#define AR_PHY_RADAR_0_PRSSI 0x00000FC0 +#define AR_PHY_RADAR_0_PRSSI_S 6 +#define AR_PHY_RADAR_0_HEIGHT 0x0003F000 +#define AR_PHY_RADAR_0_HEIGHT_S 12 +#define AR_PHY_RADAR_0_RRSSI 0x00FC0000 +#define AR_PHY_RADAR_0_RRSSI_S 18 +#define AR_PHY_RADAR_0_FIRPWR 0x7F000000 +#define AR_PHY_RADAR_0_FIRPWR_S 24 +#define AR_PHY_RADAR_1_RELPWR_ENA 0x00800000 +#define AR_PHY_RADAR_1_USE_FIR128 0x00400000 +#define AR_PHY_RADAR_1_RELPWR_THRESH 0x003F0000 +#define AR_PHY_RADAR_1_RELPWR_THRESH_S 16 +#define AR_PHY_RADAR_1_BLOCK_CHECK 0x00008000 +#define AR_PHY_RADAR_1_MAX_RRSSI 0x00004000 +#define AR_PHY_RADAR_1_RELSTEP_CHECK 0x00002000 +#define AR_PHY_RADAR_1_RELSTEP_THRESH 0x00001F00 +#define AR_PHY_RADAR_1_RELSTEP_THRESH_S 8 +#define AR_PHY_RADAR_1_MAXLEN 0x000000FF +#define AR_PHY_RADAR_1_MAXLEN_S 0 +#define AR_PHY_RADAR_EXT_ENA 0x00004000 +#define AR_PHY_RADAR_DC_PWR_THRESH 0x007f8000 +#define AR_PHY_RADAR_DC_PWR_THRESH_S 15 +#define AR_PHY_RADAR_LB_DC_CAP 0x7f800000 +#define AR_PHY_RADAR_LB_DC_CAP_S 23 +#define AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW (0x3f << 6) +#define AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW_S 6 +#define AR_PHY_FIND_SIG_LOW_FIRPWR (0x7f << 12) +#define AR_PHY_FIND_SIG_LOW_FIRPWR_S 12 +#define AR_PHY_FIND_SIG_LOW_FIRPWR_SIGN_BIT 19 +#define AR_PHY_FIND_SIG_LOW_RELSTEP 0x1f +#define AR_PHY_FIND_SIG_LOW_RELSTEP_S 0 +#define AR_PHY_FIND_SIG_LOW_RELSTEP_SIGN_BIT 5 +#define AR_PHY_CHAN_INFO_TAB_S2_READ 0x00000008 +#define AR_PHY_CHAN_INFO_TAB_S2_READ_S 3 +#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF 0x0000007F +#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF_S 0 +#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF 0x00003F80 +#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF_S 7 +#define AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE 0x00004000 +#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_Q_COFF 0x003f8000 +#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_Q_COFF_S 15 +#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_I_COFF 0x1fc00000 +#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_I_COFF_S 22 + +/* + * MRC Register Map + */ +#define AR_MRC_BASE 0x9c00 + +#define AR_PHY_TIMING_3A (AR_MRC_BASE + 0x0) +#define AR_PHY_LDPC_CNTL1 (AR_MRC_BASE + 0x4) +#define AR_PHY_LDPC_CNTL2 (AR_MRC_BASE + 0x8) +#define AR_PHY_PILOT_SPUR_MASK (AR_MRC_BASE + 0xc) +#define AR_PHY_CHAN_SPUR_MASK (AR_MRC_BASE + 0x10) +#define AR_PHY_SGI_DELTA (AR_MRC_BASE + 0x14) +#define AR_PHY_ML_CNTL_1 (AR_MRC_BASE + 0x18) +#define AR_PHY_ML_CNTL_2 (AR_MRC_BASE + 0x1c) +#define AR_PHY_TST_ADC (AR_MRC_BASE + 0x20) + +#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A 0x00000FE0 +#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A_S 5 +#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A 0x1F +#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A_S 0 + +#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A 0x00000FE0 +#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A_S 5 +#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A 0x1F +#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A_S 0 + +/* + * MRC Feild Definitions + */ +#define AR_PHY_SGI_DSC_MAN 0x0007FFF0 +#define AR_PHY_SGI_DSC_MAN_S 4 +#define AR_PHY_SGI_DSC_EXP 0x0000000F +#define AR_PHY_SGI_DSC_EXP_S 0 +/* + * BBB Register Map + */ +#define AR_BBB_BASE 0x9d00 + +/* + * AGC Register Map + */ +#define AR_AGC_BASE 0x9e00 + +#define AR_PHY_SETTLING (AR_AGC_BASE + 0x0) +#define AR_PHY_FORCEMAX_GAINS_0 (AR_AGC_BASE + 0x4) +#define AR_PHY_GAINS_MINOFF0 (AR_AGC_BASE + 0x8) +#define AR_PHY_DESIRED_SZ (AR_AGC_BASE + 0xc) +#define AR_PHY_FIND_SIG (AR_AGC_BASE + 0x10) +#define AR_PHY_AGC (AR_AGC_BASE + 0x14) +#define AR_PHY_EXT_ATTEN_CTL_0 (AR_AGC_BASE + 0x18) +#define AR_PHY_CCA_0 (AR_AGC_BASE + 0x1c) +#define AR_PHY_EXT_CCA0 (AR_AGC_BASE + 0x20) +#define AR_PHY_RESTART (AR_AGC_BASE + 0x24) +#define AR_PHY_MC_GAIN_CTRL (AR_AGC_BASE + 0x28) +#define AR_PHY_EXTCHN_PWRTHR1 (AR_AGC_BASE + 0x2c) +#define AR_PHY_EXT_CHN_WIN (AR_AGC_BASE + 0x30) +#define AR_PHY_20_40_DET_THR (AR_AGC_BASE + 0x34) +#define AR_PHY_RIFS_SRCH (AR_AGC_BASE + 0x38) +#define AR_PHY_PEAK_DET_CTRL_1 (AR_AGC_BASE + 0x3c) +#define AR_PHY_PEAK_DET_CTRL_2 (AR_AGC_BASE + 0x40) +#define AR_PHY_RX_GAIN_BOUNDS_1 (AR_AGC_BASE + 0x44) +#define AR_PHY_RX_GAIN_BOUNDS_2 (AR_AGC_BASE + 0x48) +#define AR_PHY_RSSI_0 (AR_AGC_BASE + 0x180) +#define AR_PHY_SPUR_CCK_REP0 (AR_AGC_BASE + 0x184) +#define AR_PHY_CCK_DETECT (AR_AGC_BASE + 0x1c0) +#define AR_PHY_DAG_CTRLCCK (AR_AGC_BASE + 0x1c4) +#define AR_PHY_IQCORR_CTRL_CCK (AR_AGC_BASE + 0x1c8) + +#define AR_PHY_CCK_SPUR_MIT (AR_AGC_BASE + 0x1cc) +#define AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR 0x000001fe +#define AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR_S 1 +#define AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE 0x60000000 +#define AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE_S 29 +#define AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT 0x00000001 +#define AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT_S 0 +#define AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ 0x1ffffe00 +#define AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ_S 9 + +#define AR_PHY_RX_OCGAIN (AR_AGC_BASE + 0x200) + +#define AR_PHY_CCA_NOM_VAL_9300_2GHZ -110 +#define AR_PHY_CCA_NOM_VAL_9300_5GHZ -115 +#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ -125 +#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ -125 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ -95 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ -100 + +/* + * AGC Field Definitions + */ +#define AR_PHY_EXT_ATTEN_CTL_RXTX_MARGIN 0x00FC0000 +#define AR_PHY_EXT_ATTEN_CTL_RXTX_MARGIN_S 18 +#define AR_PHY_EXT_ATTEN_CTL_BSW_MARGIN 0x00003C00 +#define AR_PHY_EXT_ATTEN_CTL_BSW_MARGIN_S 10 +#define AR_PHY_EXT_ATTEN_CTL_BSW_ATTEN 0x0000001F +#define AR_PHY_EXT_ATTEN_CTL_BSW_ATTEN_S 0 +#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_MARGIN 0x003E0000 +#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_MARGIN_S 17 +#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN 0x0001F000 +#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN_S 12 +#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_DB 0x00000FC0 +#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_DB_S 6 +#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB 0x0000003F +#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB_S 0 +#define AR_PHY_RXGAIN_TXRX_ATTEN 0x0003F000 +#define AR_PHY_RXGAIN_TXRX_ATTEN_S 12 +#define AR_PHY_RXGAIN_TXRX_RF_MAX 0x007C0000 +#define AR_PHY_RXGAIN_TXRX_RF_MAX_S 18 +#define AR9280_PHY_RXGAIN_TXRX_ATTEN 0x00003F80 +#define AR9280_PHY_RXGAIN_TXRX_ATTEN_S 7 +#define AR9280_PHY_RXGAIN_TXRX_MARGIN 0x001FC000 +#define AR9280_PHY_RXGAIN_TXRX_MARGIN_S 14 +#define AR_PHY_SETTLING_SWITCH 0x00003F80 +#define AR_PHY_SETTLING_SWITCH_S 7 +#define AR_PHY_DESIRED_SZ_ADC 0x000000FF +#define AR_PHY_DESIRED_SZ_ADC_S 0 +#define AR_PHY_DESIRED_SZ_PGA 0x0000FF00 +#define AR_PHY_DESIRED_SZ_PGA_S 8 +#define AR_PHY_DESIRED_SZ_TOT_DES 0x0FF00000 +#define AR_PHY_DESIRED_SZ_TOT_DES_S 20 +#define AR_PHY_MINCCA_PWR 0x1FF00000 +#define AR_PHY_MINCCA_PWR_S 20 +#define AR_PHY_CCA_THRESH62 0x0007F000 +#define AR_PHY_CCA_THRESH62_S 12 +#define AR9280_PHY_MINCCA_PWR 0x1FF00000 +#define AR9280_PHY_MINCCA_PWR_S 20 +#define AR9280_PHY_CCA_THRESH62 0x000FF000 +#define AR9280_PHY_CCA_THRESH62_S 12 +#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF +#define AR_PHY_EXT_CCA0_THRESH62_S 0 +#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F +#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0 +#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0 +#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6 +#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 + +#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR 0x00000200 +#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR_S 9 +#define AR_PHY_DAG_CTRLCCK_RSSI_THR 0x0001FC00 +#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S 10 + +#define AR_PHY_RIFS_INIT_DELAY 0x3ff0000 +#define AR_PHY_AGC_COARSE_LOW 0x00007F80 +#define AR_PHY_AGC_COARSE_LOW_S 7 +#define AR_PHY_AGC_COARSE_HIGH 0x003F8000 +#define AR_PHY_AGC_COARSE_HIGH_S 15 +#define AR_PHY_AGC_COARSE_PWR_CONST 0x0000007F +#define AR_PHY_AGC_COARSE_PWR_CONST_S 0 +#define AR_PHY_FIND_SIG_FIRSTEP 0x0003F000 +#define AR_PHY_FIND_SIG_FIRSTEP_S 12 +#define AR_PHY_FIND_SIG_FIRPWR 0x03FC0000 +#define AR_PHY_FIND_SIG_FIRPWR_S 18 +#define AR_PHY_FIND_SIG_FIRPWR_SIGN_BIT 25 +#define AR_PHY_FIND_SIG_RELPWR (0x1f << 6) +#define AR_PHY_FIND_SIG_RELPWR_S 6 +#define AR_PHY_FIND_SIG_RELPWR_SIGN_BIT 11 +#define AR_PHY_FIND_SIG_RELSTEP 0x1f +#define AR_PHY_FIND_SIG_RELSTEP_S 0 +#define AR_PHY_FIND_SIG_RELSTEP_SIGN_BIT 5 +#define AR_PHY_RESTART_DIV_GC 0x001C0000 +#define AR_PHY_RESTART_DIV_GC_S 18 +#define AR_PHY_RESTART_ENA 0x01 +#define AR_PHY_DC_RESTART_DIS 0x40000000 + +#define AR_PHY_TPC_OLPC_GAIN_DELTA_PAL_ON 0xFF000000 +#define AR_PHY_TPC_OLPC_GAIN_DELTA_PAL_ON_S 24 +#define AR_PHY_TPC_OLPC_GAIN_DELTA 0x00FF0000 +#define AR_PHY_TPC_OLPC_GAIN_DELTA_S 16 + +#define AR_PHY_TPC_6_ERROR_EST_MODE 0x03000000 +#define AR_PHY_TPC_6_ERROR_EST_MODE_S 24 + +/* + * SM Register Map + */ +#define AR_SM_BASE 0xa200 + +#define AR_PHY_D2_CHIP_ID (AR_SM_BASE + 0x0) +#define AR_PHY_GEN_CTRL (AR_SM_BASE + 0x4) +#define AR_PHY_MODE (AR_SM_BASE + 0x8) +#define AR_PHY_ACTIVE (AR_SM_BASE + 0xc) +#define AR_PHY_SPUR_MASK_A (AR_SM_BASE + 0x20) +#define AR_PHY_SPUR_MASK_B (AR_SM_BASE + 0x24) +#define AR_PHY_SPECTRAL_SCAN (AR_SM_BASE + 0x28) +#define AR_PHY_RADAR_BW_FILTER (AR_SM_BASE + 0x2c) +#define AR_PHY_SEARCH_START_DELAY (AR_SM_BASE + 0x30) +#define AR_PHY_MAX_RX_LEN (AR_SM_BASE + 0x34) +#define AR_PHY_FRAME_CTL (AR_SM_BASE + 0x38) +#define AR_PHY_RFBUS_REQ (AR_SM_BASE + 0x3c) +#define AR_PHY_RFBUS_GRANT (AR_SM_BASE + 0x40) +#define AR_PHY_RIFS (AR_SM_BASE + 0x44) +#define AR_PHY_RX_CLR_DELAY (AR_SM_BASE + 0x50) +#define AR_PHY_RX_DELAY (AR_SM_BASE + 0x54) + +#define AR_PHY_XPA_TIMING_CTL (AR_SM_BASE + 0x64) +#define AR_PHY_MISC_PA_CTL (AR_SM_BASE + 0x80) +#define AR_PHY_SWITCH_CHAIN_0 (AR_SM_BASE + 0x84) +#define AR_PHY_SWITCH_COM (AR_SM_BASE + 0x88) +#define AR_PHY_SWITCH_COM_2 (AR_SM_BASE + 0x8c) +#define AR_PHY_RX_CHAINMASK (AR_SM_BASE + 0xa0) +#define AR_PHY_CAL_CHAINMASK (AR_SM_BASE + 0xc0) +#define AR_PHY_CALMODE (AR_SM_BASE + 0xc8) +#define AR_PHY_FCAL_1 (AR_SM_BASE + 0xcc) +#define AR_PHY_FCAL_2_0 (AR_SM_BASE + 0xd0) +#define AR_PHY_DFT_TONE_CTL_0 (AR_SM_BASE + 0xd4) +#define AR_PHY_CL_CAL_CTL (AR_SM_BASE + 0xd8) +#define AR_PHY_CL_TAB_0 (AR_SM_BASE + 0x100) +#define AR_PHY_SYNTH_CONTROL (AR_SM_BASE + 0x140) +#define AR_PHY_ADDAC_CLK_SEL (AR_SM_BASE + 0x144) +#define AR_PHY_PLL_CTL (AR_SM_BASE + 0x148) +#define AR_PHY_ANALOG_SWAP (AR_SM_BASE + 0x14c) +#define AR_PHY_ADDAC_PARA_CTL (AR_SM_BASE + 0x150) +#define AR_PHY_XPA_CFG (AR_SM_BASE + 0x158) + +#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A 0x0001FC00 +#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A_S 10 +#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A 0x3FF +#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A_S 0 + +#define AR_PHY_TEST (AR_SM_BASE + 0x160) + +#define AR_PHY_TEST_BBB_OBS_SEL 0x780000 +#define AR_PHY_TEST_BBB_OBS_SEL_S 19 + +#define AR_PHY_TEST_RX_OBS_SEL_BIT5_S 23 +#define AR_PHY_TEST_RX_OBS_SEL_BIT5 (1 << AR_PHY_TEST_RX_OBS_SEL_BIT5_S) + +#define AR_PHY_TEST_CHAIN_SEL 0xC0000000 +#define AR_PHY_TEST_CHAIN_SEL_S 30 + +#define AR_PHY_TEST_CTL_STATUS (AR_SM_BASE + 0x164) +#define AR_PHY_TEST_CTL_TSTDAC_EN 0x1 +#define AR_PHY_TEST_CTL_TSTDAC_EN_S 0 +#define AR_PHY_TEST_CTL_TX_OBS_SEL 0x1C +#define AR_PHY_TEST_CTL_TX_OBS_SEL_S 2 +#define AR_PHY_TEST_CTL_TX_OBS_MUX_SEL 0x60 +#define AR_PHY_TEST_CTL_TX_OBS_MUX_SEL_S 5 +#define AR_PHY_TEST_CTL_TSTADC_EN 0x100 +#define AR_PHY_TEST_CTL_TSTADC_EN_S 8 +#define AR_PHY_TEST_CTL_RX_OBS_SEL 0x3C00 +#define AR_PHY_TEST_CTL_RX_OBS_SEL_S 10 + + +#define AR_PHY_TSTDAC (AR_SM_BASE + 0x168) + +#define AR_PHY_CHAN_STATUS (AR_SM_BASE + 0x16c) +#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + 0x170) +#define AR_PHY_CHNINFO_NOISEPWR (AR_SM_BASE + 0x174) +#define AR_PHY_CHNINFO_GAINDIFF (AR_SM_BASE + 0x178) +#define AR_PHY_CHNINFO_FINETIM (AR_SM_BASE + 0x17c) +#define AR_PHY_CHAN_INFO_GAIN_0 (AR_SM_BASE + 0x180) +#define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + 0x190) +#define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + 0x194) + +#define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + 0x1a4) +#define AR_PHY_HEAVYCLIP_20 (AR_SM_BASE + 0x1a8) +#define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac) +#define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0) + +#define AR_PHY_PWRTX_MAX (AR_SM_BASE + 0x1f0) +#define AR_PHY_POWER_TX_SUB (AR_SM_BASE + 0x1f4) + +#define AR_PHY_TPC_4_B0 (AR_SM_BASE + 0x204) +#define AR_PHY_TPC_5_B0 (AR_SM_BASE + 0x208) +#define AR_PHY_TPC_6_B0 (AR_SM_BASE + 0x20c) +#define AR_PHY_TPC_11_B0 (AR_SM_BASE + 0x220) +#define AR_PHY_TPC_18 (AR_SM_BASE + 0x23c) +#define AR_PHY_TPC_19 (AR_SM_BASE + 0x240) + +#define AR_PHY_TX_FORCED_GAIN (AR_SM_BASE + 0x258) + +#define AR_PHY_PDADC_TAB_0 (AR_SM_BASE + 0x280) + +#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + 0x448) +#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + 0x440) +#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + 0x48c) +#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B0 (AR_SM_BASE + 0x450) + +#define AR_PHY_PANIC_WD_STATUS (AR_SM_BASE + 0x5c0) +#define AR_PHY_PANIC_WD_CTL_1 (AR_SM_BASE + 0x5c4) +#define AR_PHY_PANIC_WD_CTL_2 (AR_SM_BASE + 0x5c8) +#define AR_PHY_BT_CTL (AR_SM_BASE + 0x5cc) +#define AR_PHY_ONLY_WARMRESET (AR_SM_BASE + 0x5d0) +#define AR_PHY_ONLY_CTL (AR_SM_BASE + 0x5d4) +#define AR_PHY_ECO_CTRL (AR_SM_BASE + 0x5dc) +#define AR_PHY_BB_THERM_ADC_1 (AR_SM_BASE + 0x248) + +#define AR_PHY_65NM_CH0_SYNTH4 0x1608c +#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT 0x00000002 +#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S 1 +#define AR_PHY_65NM_CH0_SYNTH7 0x16098 +#define AR_PHY_65NM_CH0_BIAS1 0x160c0 +#define AR_PHY_65NM_CH0_BIAS2 0x160c4 +#define AR_PHY_65NM_CH0_BIAS4 0x160cc +#define AR_PHY_65NM_CH0_RXTX4 0x1610c +#define AR_PHY_65NM_CH0_THERM 0x16290 + +#define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000 +#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 +#define AR_PHY_65NM_CH0_THERM_START 0x20000000 +#define AR_PHY_65NM_CH0_THERM_START_S 29 +#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT 0x0000ff00 +#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8 + +#define AR_PHY_65NM_CH0_RXTX1 0x16100 +#define AR_PHY_65NM_CH0_RXTX2 0x16104 +#define AR_PHY_65NM_CH1_RXTX1 0x16500 +#define AR_PHY_65NM_CH1_RXTX2 0x16504 +#define AR_PHY_65NM_CH2_RXTX1 0x16900 +#define AR_PHY_65NM_CH2_RXTX2 0x16904 + +#define AR_PHY_RX1DB_BIQUAD_LONG_SHIFT 0x00380000 +#define AR_PHY_RX1DB_BIQUAD_LONG_SHIFT_S 19 +#define AR_PHY_RX6DB_BIQUAD_LONG_SHIFT 0x00c00000 +#define AR_PHY_RX6DB_BIQUAD_LONG_SHIFT_S 22 +#define AR_PHY_LNAGAIN_LONG_SHIFT 0xe0000000 +#define AR_PHY_LNAGAIN_LONG_SHIFT_S 29 +#define AR_PHY_MXRGAIN_LONG_SHIFT 0x03000000 +#define AR_PHY_MXRGAIN_LONG_SHIFT_S 24 +#define AR_PHY_VGAGAIN_LONG_SHIFT 0x1c000000 +#define AR_PHY_VGAGAIN_LONG_SHIFT_S 26 +#define AR_PHY_SCFIR_GAIN_LONG_SHIFT 0x00000001 +#define AR_PHY_SCFIR_GAIN_LONG_SHIFT_S 0 +#define AR_PHY_MANRXGAIN_LONG_SHIFT 0x00000002 +#define AR_PHY_MANRXGAIN_LONG_SHIFT_S 1 + +/* + * SM Field Definitions + */ +#define AR_PHY_CL_CAL_ENABLE 0x00000002 +#define AR_PHY_PARALLEL_CAL_ENABLE 0x00000001 +#define AR_PHY_TPCRG1_PD_CAL_ENABLE 0x00400000 +#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22 + +#define AR_PHY_ADDAC_PARACTL_OFF_PWDADC 0x00008000 + +#define AR_PHY_FCAL20_CAP_STATUS_0 0x01f00000 +#define AR_PHY_FCAL20_CAP_STATUS_0_S 20 + +#define AR_PHY_RFBUS_REQ_EN 0x00000001 /* request for RF bus */ +#define AR_PHY_RFBUS_GRANT_EN 0x00000001 /* RF bus granted */ +#define AR_PHY_GC_TURBO_MODE 0x00000001 /* set turbo mode bits */ +#define AR_PHY_GC_TURBO_SHORT 0x00000002 /* set short symbols to turbo mode setting */ +#define AR_PHY_GC_DYN2040_EN 0x00000004 /* enable dyn 20/40 mode */ +#define AR_PHY_GC_DYN2040_PRI_ONLY 0x00000008 /* dyn 20/40 - primary only */ +#define AR_PHY_GC_DYN2040_PRI_CH 0x00000010 /* dyn 20/40 - primary ch offset (0=+10MHz, 1=-10MHz)*/ +#define AR_PHY_GC_DYN2040_PRI_CH_S 4 +#define AR_PHY_GC_DYN2040_EXT_CH 0x00000020 /* dyn 20/40 - ext ch spacing (0=20MHz/ 1=25MHz) */ +#define AR_PHY_GC_HT_EN 0x00000040 /* ht enable */ +#define AR_PHY_GC_SHORT_GI_40 0x00000080 /* allow short GI for HT 40 */ +#define AR_PHY_GC_WALSH 0x00000100 /* walsh spatial spreading for 2 chains,2 streams TX */ +#define AR_PHY_GC_SINGLE_HT_LTF1 0x00000200 /* single length (4us) 1st HT long training symbol */ +#define AR_PHY_GC_GF_DETECT_EN 0x00000400 /* enable Green Field detection. Only affects rx, not tx */ +#define AR_PHY_GC_ENABLE_DAC_FIFO 0x00000800 /* fifo between bb and dac */ +#define AR_PHY_RX_DELAY_DELAY 0x00003FFF /* delay from wakeup to rx ena */ + +#define AR_PHY_CALMODE_IQ 0x00000000 +#define AR_PHY_CALMODE_ADC_GAIN 0x00000001 +#define AR_PHY_CALMODE_ADC_DC_PER 0x00000002 +#define AR_PHY_CALMODE_ADC_DC_INIT 0x00000003 +#define AR_PHY_SWAP_ALT_CHAIN 0x00000040 +#define AR_PHY_MODE_OFDM 0x00000000 +#define AR_PHY_MODE_CCK 0x00000001 +#define AR_PHY_MODE_DYNAMIC 0x00000004 +#define AR_PHY_MODE_DYNAMIC_S 2 +#define AR_PHY_MODE_HALF 0x00000020 +#define AR_PHY_MODE_QUARTER 0x00000040 +#define AR_PHY_MAC_CLK_MODE 0x00000080 +#define AR_PHY_MODE_DYN_CCK_DISABLE 0x00000100 +#define AR_PHY_MODE_SVD_HALF 0x00000200 +#define AR_PHY_ACTIVE_EN 0x00000001 +#define AR_PHY_ACTIVE_DIS 0x00000000 +#define AR_PHY_FORCE_XPA_CFG 0x000000001 +#define AR_PHY_FORCE_XPA_CFG_S 0 +#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF 0xFF000000 +#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF_S 24 +#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF 0x00FF0000 +#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF_S 16 +#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAB_ON 0x0000FF00 +#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAB_ON_S 8 +#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAA_ON 0x000000FF +#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAA_ON_S 0 +#define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000 +#define AR_PHY_TX_END_TO_A2_RX_ON_S 16 +#define AR_PHY_TX_END_DATA_START 0x000000FF +#define AR_PHY_TX_END_DATA_START_S 0 +#define AR_PHY_TX_END_PA_ON 0x0000FF00 +#define AR_PHY_TX_END_PA_ON_S 8 +#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP 0x0000000F +#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S 0 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1 0x000003F0 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S 4 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2 0x0000FC00 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S 10 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3 0x003F0000 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S 16 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0FC00000 +#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22 +#define AR_PHY_TPCRG1_NUM_PD_GAIN 0x0000c000 +#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14 +#define AR_PHY_TPCRG1_PD_GAIN_1 0x00030000 +#define AR_PHY_TPCRG1_PD_GAIN_1_S 16 +#define AR_PHY_TPCRG1_PD_GAIN_2 0x000C0000 +#define AR_PHY_TPCRG1_PD_GAIN_2_S 18 +#define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000 +#define AR_PHY_TPCRG1_PD_GAIN_3_S 20 +#define AR_PHY_TPCGR1_FORCED_DAC_GAIN 0x0000003e +#define AR_PHY_TPCGR1_FORCED_DAC_GAIN_S 1 +#define AR_PHY_TPCGR1_FORCE_DAC_GAIN 0x00000001 +#define AR_PHY_TXGAIN_FORCE 0x00000001 +#define AR_PHY_TXGAIN_FORCED_PADVGNRA 0x00003c00 +#define AR_PHY_TXGAIN_FORCED_PADVGNRA_S 10 +#define AR_PHY_TXGAIN_FORCED_PADVGNRB 0x0003c000 +#define AR_PHY_TXGAIN_FORCED_PADVGNRB_S 14 +#define AR_PHY_TXGAIN_FORCED_PADVGNRD 0x00c00000 +#define AR_PHY_TXGAIN_FORCED_PADVGNRD_S 22 +#define AR_PHY_TXGAIN_FORCED_TXMXRGAIN 0x000003c0 +#define AR_PHY_TXGAIN_FORCED_TXMXRGAIN_S 6 +#define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN 0x0000000e +#define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN_S 1 + +#define AR_PHY_POWER_TX_RATE1 0x9934 +#define AR_PHY_POWER_TX_RATE2 0x9938 +#define AR_PHY_POWER_TX_RATE_MAX 0x993c +#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040 +#define PHY_AGC_CLR 0x10000000 +#define RFSILENT_BB 0x00002000 +#define AR_PHY_CHAN_INFO_GAIN_DIFF_PPM_MASK 0xFFF +#define AR_PHY_CHAN_INFO_GAIN_DIFF_PPM_SIGNED_BIT 0x800 +#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320 +#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001 +#define AR_PHY_RX_DELAY_DELAY 0x00003FFF +#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010 +#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x00000001 +#define AR_PHY_SPECTRAL_SCAN_ENABLE_S 0 +#define AR_PHY_SPECTRAL_SCAN_ACTIVE 0x00000002 +#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S 1 +#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD 0x000000F0 +#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S 4 +#define AR_PHY_SPECTRAL_SCAN_PERIOD 0x0000FF00 +#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8 +#define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 +#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16 +#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 +#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 +#define AR_PHY_CHANNEL_STATUS_RX_CLEAR 0x00000004 +#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000 +#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18 +#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001 +#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0 + +#define AR_PHY_TX_IQCAL_STATUS_FAILED 0x00000001 +#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE 0x00003fff +#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE_S 0 + +#define AR_PHY_TPC_18_THERM_CAL_VALUE 0xff +#define AR_PHY_TPC_18_THERM_CAL_VALUE_S 0 +#define AR_PHY_TPC_19_ALPHA_THERM 0xff +#define AR_PHY_TPC_19_ALPHA_THERM_S 0 + +#define AR_PHY_65NM_CH0_RXTX4_THERM_ON 0x10000000 +#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S 28 + +#define AR_PHY_BB_THERM_ADC_1_INIT_THERM 0x000000ff +#define AR_PHY_BB_THERM_ADC_1_INIT_THERM_S 0 + +/* + * Channel 1 Register Map + */ +#define AR_CHAN1_BASE 0xa800 + +#define AR_PHY_EXT_CCA_1 (AR_CHAN1_BASE + 0x30) +#define AR_PHY_TX_PHASE_RAMP_1 (AR_CHAN1_BASE + 0xd0) +#define AR_PHY_ADC_GAIN_DC_CORR_1 (AR_CHAN1_BASE + 0xd4) + +#define AR_PHY_SPUR_REPORT_1 (AR_CHAN1_BASE + 0xa8) +#define AR_PHY_CHAN_INFO_TAB_1 (AR_CHAN1_BASE + 0x300) +#define AR_PHY_RX_IQCAL_CORR_B1 (AR_CHAN1_BASE + 0xdc) + +/* + * Channel 1 Field Definitions + */ +#define AR_PHY_CH1_EXT_MINCCA_PWR 0x01FF0000 +#define AR_PHY_CH1_EXT_MINCCA_PWR_S 16 + +/* + * AGC 1 Register Map + */ +#define AR_AGC1_BASE 0xae00 + +#define AR_PHY_FORCEMAX_GAINS_1 (AR_AGC1_BASE + 0x4) +#define AR_PHY_EXT_ATTEN_CTL_1 (AR_AGC1_BASE + 0x18) +#define AR_PHY_CCA_1 (AR_AGC1_BASE + 0x1c) +#define AR_PHY_CCA_CTRL_1 (AR_AGC1_BASE + 0x20) +#define AR_PHY_RSSI_1 (AR_AGC1_BASE + 0x180) +#define AR_PHY_SPUR_CCK_REP_1 (AR_AGC1_BASE + 0x184) +#define AR_PHY_RX_OCGAIN_2 (AR_AGC1_BASE + 0x200) + +/* + * AGC 1 Field Definitions + */ +#define AR_PHY_CH1_MINCCA_PWR 0x1FF00000 +#define AR_PHY_CH1_MINCCA_PWR_S 20 + +/* + * SM 1 Register Map + */ +#define AR_SM1_BASE 0xb200 + +#define AR_PHY_SWITCH_CHAIN_1 (AR_SM1_BASE + 0x84) +#define AR_PHY_FCAL_2_1 (AR_SM1_BASE + 0xd0) +#define AR_PHY_DFT_TONE_CTL_1 (AR_SM1_BASE + 0xd4) +#define AR_PHY_CL_TAB_1 (AR_SM1_BASE + 0x100) +#define AR_PHY_CHAN_INFO_GAIN_1 (AR_SM1_BASE + 0x180) +#define AR_PHY_TPC_4_B1 (AR_SM1_BASE + 0x204) +#define AR_PHY_TPC_5_B1 (AR_SM1_BASE + 0x208) +#define AR_PHY_TPC_6_B1 (AR_SM1_BASE + 0x20c) +#define AR_PHY_TPC_11_B1 (AR_SM1_BASE + 0x220) +#define AR_PHY_PDADC_TAB_1 (AR_SM1_BASE + 0x240) +#define AR_PHY_TX_IQCAL_STATUS_B1 (AR_SM1_BASE + 0x48c) +#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B1 (AR_SM1_BASE + 0x450) + +/* + * Channel 2 Register Map + */ +#define AR_CHAN2_BASE 0xb800 + +#define AR_PHY_EXT_CCA_2 (AR_CHAN2_BASE + 0x30) +#define AR_PHY_TX_PHASE_RAMP_2 (AR_CHAN2_BASE + 0xd0) +#define AR_PHY_ADC_GAIN_DC_CORR_2 (AR_CHAN2_BASE + 0xd4) + +#define AR_PHY_SPUR_REPORT_2 (AR_CHAN2_BASE + 0xa8) +#define AR_PHY_CHAN_INFO_TAB_2 (AR_CHAN2_BASE + 0x300) +#define AR_PHY_RX_IQCAL_CORR_B2 (AR_CHAN2_BASE + 0xdc) + +/* + * Channel 2 Field Definitions + */ +#define AR_PHY_CH2_EXT_MINCCA_PWR 0x01FF0000 +#define AR_PHY_CH2_EXT_MINCCA_PWR_S 16 +/* + * AGC 2 Register Map + */ +#define AR_AGC2_BASE 0xbe00 + +#define AR_PHY_FORCEMAX_GAINS_2 (AR_AGC2_BASE + 0x4) +#define AR_PHY_EXT_ATTEN_CTL_2 (AR_AGC2_BASE + 0x18) +#define AR_PHY_CCA_2 (AR_AGC2_BASE + 0x1c) +#define AR_PHY_CCA_CTRL_2 (AR_AGC2_BASE + 0x20) +#define AR_PHY_RSSI_2 (AR_AGC2_BASE + 0x180) + +/* + * AGC 2 Field Definitions + */ +#define AR_PHY_CH2_MINCCA_PWR 0x1FF00000 +#define AR_PHY_CH2_MINCCA_PWR_S 20 + +/* + * SM 2 Register Map + */ +#define AR_SM2_BASE 0xc200 + +#define AR_PHY_SWITCH_CHAIN_2 (AR_SM2_BASE + 0x84) +#define AR_PHY_FCAL_2_2 (AR_SM2_BASE + 0xd0) +#define AR_PHY_DFT_TONE_CTL_2 (AR_SM2_BASE + 0xd4) +#define AR_PHY_CL_TAB_2 (AR_SM2_BASE + 0x100) +#define AR_PHY_CHAN_INFO_GAIN_2 (AR_SM2_BASE + 0x180) +#define AR_PHY_TPC_4_B2 (AR_SM2_BASE + 0x204) +#define AR_PHY_TPC_5_B2 (AR_SM2_BASE + 0x208) +#define AR_PHY_TPC_6_B2 (AR_SM2_BASE + 0x20c) +#define AR_PHY_TPC_11_B2 (AR_SM2_BASE + 0x220) +#define AR_PHY_PDADC_TAB_2 (AR_SM2_BASE + 0x240) +#define AR_PHY_TX_IQCAL_STATUS_B2 (AR_SM2_BASE + 0x48c) +#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B2 (AR_SM2_BASE + 0x450) + +#define AR_PHY_TX_IQCAL_STATUS_B2_FAILED 0x00000001 + +/* + * AGC 3 Register Map + */ +#define AR_AGC3_BASE 0xce00 + +#define AR_PHY_RSSI_3 (AR_AGC3_BASE + 0x180) + +/* + * Misc helper defines + */ +#define AR_PHY_CHAIN_OFFSET (AR_CHAN1_BASE - AR_CHAN_BASE) + +#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (AR_PHY_ADC_GAIN_DC_CORR_0 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_NEW_ADC_DC_GAIN_CORR_9300_10(_i) (AR_PHY_ADC_GAIN_DC_CORR_0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_SWITCH_CHAIN(_i) (AR_PHY_SWITCH_CHAIN_0 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_EXT_ATTEN_CTL(_i) (AR_PHY_EXT_ATTEN_CTL_0 + (AR_PHY_CHAIN_OFFSET * (_i))) + +#define AR_PHY_RXGAIN(_i) (AR_PHY_FORCEMAX_GAINS_0 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_TPCRG5(_i) (AR_PHY_TPC_5_B0 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_PDADC_TAB(_i) (AR_PHY_PDADC_TAB_0 + (AR_PHY_CHAIN_OFFSET * (_i))) + +#define AR_PHY_CAL_MEAS_0(_i) (AR_PHY_IQ_ADC_MEAS_0_B0 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_CAL_MEAS_1(_i) (AR_PHY_IQ_ADC_MEAS_1_B0 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_CAL_MEAS_2(_i) (AR_PHY_IQ_ADC_MEAS_2_B0 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_CAL_MEAS_3(_i) (AR_PHY_IQ_ADC_MEAS_3_B0 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_CAL_MEAS_0_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_0_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_CAL_MEAS_1_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_1_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_CAL_MEAS_2_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_2_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i))) +#define AR_PHY_CAL_MEAS_3_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_3_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i))) + +#define AR_PHY_BB_PANIC_NON_IDLE_ENABLE 0x00000001 +#define AR_PHY_BB_PANIC_IDLE_ENABLE 0x00000002 +#define AR_PHY_BB_PANIC_IDLE_MASK 0xFFFF0000 +#define AR_PHY_BB_PANIC_NON_IDLE_MASK 0x0000FFFC + +#define AR_PHY_BB_PANIC_RST_ENABLE 0x00000002 +#define AR_PHY_BB_PANIC_IRQ_ENABLE 0x00000004 +#define AR_PHY_BB_PANIC_CNTL2_MASK 0xFFFFFFF9 + +#define AR_PHY_BB_WD_STATUS 0x00000007 +#define AR_PHY_BB_WD_STATUS_S 0 +#define AR_PHY_BB_WD_DET_HANG 0x00000008 +#define AR_PHY_BB_WD_DET_HANG_S 3 +#define AR_PHY_BB_WD_RADAR_SM 0x000000F0 +#define AR_PHY_BB_WD_RADAR_SM_S 4 +#define AR_PHY_BB_WD_RX_OFDM_SM 0x00000F00 +#define AR_PHY_BB_WD_RX_OFDM_SM_S 8 +#define AR_PHY_BB_WD_RX_CCK_SM 0x0000F000 +#define AR_PHY_BB_WD_RX_CCK_SM_S 12 +#define AR_PHY_BB_WD_TX_OFDM_SM 0x000F0000 +#define AR_PHY_BB_WD_TX_OFDM_SM_S 16 +#define AR_PHY_BB_WD_TX_CCK_SM 0x00F00000 +#define AR_PHY_BB_WD_TX_CCK_SM_S 20 +#define AR_PHY_BB_WD_AGC_SM 0x0F000000 +#define AR_PHY_BB_WD_AGC_SM_S 24 +#define AR_PHY_BB_WD_SRCH_SM 0xF0000000 +#define AR_PHY_BB_WD_SRCH_SM_S 28 + +#define AR_PHY_BB_WD_STATUS_CLR 0x00000008 + +void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); + +#endif /* AR9003_PHY_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 83c7ea4c007..fbb7dec6dde 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -114,8 +114,10 @@ enum buffer_type { #define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) #define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) +#define ATH_TXSTATUS_RING_SIZE 64 + struct ath_descdma { - struct ath_desc *dd_desc; + void *dd_desc; dma_addr_t dd_desc_paddr; u32 dd_desc_len; struct ath_buf *dd_bufptr; @@ -123,7 +125,7 @@ struct ath_descdma { int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, struct list_head *head, const char *name, - int nbuf, int ndesc); + int nbuf, int ndesc, bool is_tx); void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, struct list_head *head); @@ -178,9 +180,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, #define BAW_WITHIN(_start, _bawsz, _seqno) \ ((((_seqno) - (_start)) & 4095) < (_bawsz)) -#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) -#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) -#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) #define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) #define ATH_TX_COMPLETE_POLL_INT 1000 @@ -191,6 +190,7 @@ enum ATH_AGGR_STATUS { ATH_AGGR_LIMITED, }; +#define ATH_TXFIFO_DEPTH 8 struct ath_txq { u32 axq_qnum; u32 *axq_link; @@ -200,6 +200,10 @@ struct ath_txq { bool stopped; bool axq_tx_inprogress; struct list_head axq_acq; + struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; + struct list_head txq_fifo_pending; + u8 txq_headidx; + u8 txq_tailidx; }; #define AGGR_CLEANUP BIT(1) @@ -226,6 +230,12 @@ struct ath_tx { struct ath_descdma txdma; }; +struct ath_rx_edma { + struct sk_buff_head rx_fifo; + struct sk_buff_head rx_buffers; + u32 rx_fifo_hwsize; +}; + struct ath_rx { u8 defant; u8 rxotherant; @@ -235,6 +245,8 @@ struct ath_rx { spinlock_t rxbuflock; struct list_head rxbuf; struct ath_descdma rxdma; + struct ath_buf *rx_bufptr; + struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; }; int ath_startrecv(struct ath_softc *sc); @@ -243,7 +255,7 @@ void ath_flushrecv(struct ath_softc *sc); u32 ath_calcrxfilter(struct ath_softc *sc); int ath_rx_init(struct ath_softc *sc, int nbufs); void ath_rx_cleanup(struct ath_softc *sc); -int ath_rx_tasklet(struct ath_softc *sc, int flush); +int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp); struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_setup(struct ath_softc *sc, int haltype); @@ -261,6 +273,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl); void ath_tx_tasklet(struct ath_softc *sc); +void ath_tx_edma_tasklet(struct ath_softc *sc); void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb); bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, @@ -483,7 +496,6 @@ struct ath_softc { bool ps_enabled; bool ps_idle; unsigned long ps_usecount; - enum ath9k_int imask; struct ath_config config; struct ath_rx rx; @@ -511,6 +523,8 @@ struct ath_softc { struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; struct ath_btcoex btcoex; + + struct ath_descdma txsdma; }; struct ath_wiphy { diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index b4a31a43a62..c8a4558f79b 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -93,8 +93,6 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); } - ds->ds_data = bf->bf_buf_addr; - sband = &sc->sbands[common->hw->conf.channel->band]; rate = sband->bitrates[rateidx].hw_value; if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) @@ -109,7 +107,8 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, /* NB: beacon's BufLen must be a multiple of 4 bytes */ ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4), - true, true, ds); + true, true, ds, bf->bf_buf_addr, + sc->beacon.beaconq); memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); series[0].Tries = 1; @@ -524,6 +523,7 @@ static void ath9k_beacon_init(struct ath_softc *sc, static void ath_beacon_config_ap(struct ath_softc *sc, struct ath_beacon_config *conf) { + struct ath_hw *ah = sc->sc_ah; u32 nexttbtt, intval; /* NB: the beacon interval is kept internally in TU's */ @@ -539,15 +539,15 @@ static void ath_beacon_config_ap(struct ath_softc *sc, * prepare beacon frames. */ intval |= ATH9K_BEACON_ENA; - sc->imask |= ATH9K_INT_SWBA; + ah->imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); /* Set the computed AP beacon timers */ - ath9k_hw_set_interrupts(sc->sc_ah, 0); + ath9k_hw_set_interrupts(ah, 0); ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); /* Clear the reset TSF flag, so that subsequent beacon updation will not reset the HW TSF. */ @@ -566,7 +566,8 @@ static void ath_beacon_config_ap(struct ath_softc *sc, static void ath_beacon_config_sta(struct ath_softc *sc, struct ath_beacon_config *conf) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_beacon_state bs; int dtimperiod, dtimcount, sleepduration; int cfpperiod, cfpcount; @@ -605,7 +606,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc, * Pull nexttbtt forward to reflect the current * TSF and calculate dtim+cfp state for the result. */ - tsf = ath9k_hw_gettsf64(sc->sc_ah); + tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; num_beacons = tsftu / intval + 1; @@ -678,17 +679,18 @@ static void ath_beacon_config_sta(struct ath_softc *sc, /* Set the computed STA beacon timers */ - ath9k_hw_set_interrupts(sc->sc_ah, 0); - ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs); - sc->imask |= ATH9K_INT_BMISS; - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_set_sta_beacon_timers(ah, &bs); + ah->imask |= ATH9K_INT_BMISS; + ath9k_hw_set_interrupts(ah, ah->imask); } static void ath_beacon_config_adhoc(struct ath_softc *sc, struct ath_beacon_config *conf, struct ieee80211_vif *vif) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); u64 tsf; u32 tsftu, intval, nexttbtt; @@ -703,7 +705,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, else if (intval) nexttbtt = roundup(nexttbtt, intval); - tsf = ath9k_hw_gettsf64(sc->sc_ah); + tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; do { nexttbtt += intval; @@ -719,20 +721,20 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, * self-linked tx descriptor and let the hardware deal with things. */ intval |= ATH9K_BEACON_ENA; - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) - sc->imask |= ATH9K_INT_SWBA; + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) + ah->imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); /* Set the computed ADHOC beacon timers */ - ath9k_hw_set_interrupts(sc->sc_ah, 0); + ath9k_hw_set_interrupts(ah, 0); ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); /* FIXME: Handle properly when vif is NULL */ - if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) + if (vif && ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) ath_beacon_start_adhoc(sc, vif); } diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 238a5744d8e..07b8fa6fb62 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -15,6 +15,9 @@ */ #include "hw.h" +#include "hw-ops.h" + +/* Common calibration code */ /* We can tune this as we go by monitoring really low values */ #define ATH9K_NF_TOO_LOW -60 @@ -83,93 +86,11 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); } } - return; } -static void ath9k_hw_do_getnf(struct ath_hw *ah, - int16_t nfarray[NUM_NF_READINGS]) -{ - struct ath_common *common = ath9k_hw_common(ah); - int16_t nf; - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - ath_print(common, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 0] is %d\n", nf); - nfarray[0] = nf; - - if (!AR_SREV_9285(ah)) { - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR9280_PHY_CH1_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR_PHY_CH1_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - ath_print(common, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 1] is %d\n", nf); - nfarray[1] = nf; - - if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), - AR_PHY_CH2_MINCCA_PWR); - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - ath_print(common, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 2] is %d\n", nf); - nfarray[2] = nf; - } - } - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), - AR9280_PHY_EXT_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), - AR_PHY_EXT_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - ath_print(common, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 0] is %d\n", nf); - nfarray[3] = nf; - - if (!AR_SREV_9285(ah)) { - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR9280_PHY_CH1_EXT_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR_PHY_CH1_EXT_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - ath_print(common, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 1] is %d\n", nf); - nfarray[4] = nf; - - if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), - AR_PHY_CH2_EXT_MINCCA_PWR); - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - ath_print(common, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 2] is %d\n", nf); - nfarray[5] = nf; - } - } -} - -static bool getNoiseFloorThresh(struct ath_hw *ah, - enum ieee80211_band band, - int16_t *nft) +static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah, + enum ieee80211_band band, + int16_t *nft) { switch (band) { case IEEE80211_BAND_5GHZ: @@ -186,44 +107,8 @@ static bool getNoiseFloorThresh(struct ath_hw *ah, return true; } -static void ath9k_hw_setup_calibration(struct ath_hw *ah, - struct ath9k_cal_list *currCal) -{ - struct ath_common *common = ath9k_hw_common(ah); - - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, - currCal->calData->calCountMax); - - switch (currCal->calData->calType) { - case IQ_MISMATCH_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); - ath_print(common, ATH_DBG_CALIBRATE, - "starting IQ Mismatch Calibration\n"); - break; - case ADC_GAIN_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); - ath_print(common, ATH_DBG_CALIBRATE, - "starting ADC Gain Calibration\n"); - break; - case ADC_DC_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); - ath_print(common, ATH_DBG_CALIBRATE, - "starting ADC DC Calibration\n"); - break; - case ADC_DC_INIT_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); - ath_print(common, ATH_DBG_CALIBRATE, - "starting Init ADC DC Calibration\n"); - break; - } - - REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_DO_CAL); -} - -static void ath9k_hw_reset_calibration(struct ath_hw *ah, - struct ath9k_cal_list *currCal) +void ath9k_hw_reset_calibration(struct ath_hw *ah, + struct ath9k_cal_list *currCal) { int i; @@ -241,324 +126,6 @@ static void ath9k_hw_reset_calibration(struct ath_hw *ah, ah->cal_samples = 0; } -static bool ath9k_hw_per_calibration(struct ath_hw *ah, - struct ath9k_channel *ichan, - u8 rxchainmask, - struct ath9k_cal_list *currCal) -{ - bool iscaldone = false; - - if (currCal->calState == CAL_RUNNING) { - if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & - AR_PHY_TIMING_CTRL4_DO_CAL)) { - - currCal->calData->calCollect(ah); - ah->cal_samples++; - - if (ah->cal_samples >= currCal->calData->calNumSamples) { - int i, numChains = 0; - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (rxchainmask & (1 << i)) - numChains++; - } - - currCal->calData->calPostProc(ah, numChains); - ichan->CalValid |= currCal->calData->calType; - currCal->calState = CAL_DONE; - iscaldone = true; - } else { - ath9k_hw_setup_calibration(ah, currCal); - } - } - } else if (!(ichan->CalValid & currCal->calData->calType)) { - ath9k_hw_reset_calibration(ah, currCal); - } - - return iscaldone; -} - -/* Assumes you are talking about the currently configured channel */ -static bool ath9k_hw_iscal_supported(struct ath_hw *ah, - enum ath9k_cal_types calType) -{ - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; - - switch (calType & ah->supp_cals) { - case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */ - return true; - case ADC_GAIN_CAL: - case ADC_DC_CAL: - if (!(conf->channel->band == IEEE80211_BAND_2GHZ && - conf_is_ht20(conf))) - return true; - break; - } - return false; -} - -static void ath9k_hw_iqcal_collect(struct ath_hw *ah) -{ - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ah->totalPowerMeasI[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ah->totalPowerMeasQ[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ah->totalIqCorrMeas[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, - "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", - ah->cal_samples, i, ah->totalPowerMeasI[i], - ah->totalPowerMeasQ[i], - ah->totalIqCorrMeas[i]); - } -} - -static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah) -{ - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ah->totalAdcIOddPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ah->totalAdcIEvenPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ah->totalAdcQOddPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ah->totalAdcQEvenPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - - ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ah->cal_samples, i, - ah->totalAdcIOddPhase[i], - ah->totalAdcIEvenPhase[i], - ah->totalAdcQOddPhase[i], - ah->totalAdcQEvenPhase[i]); - } -} - -static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah) -{ - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ah->totalAdcDcOffsetIOddPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ah->totalAdcDcOffsetIEvenPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ah->totalAdcDcOffsetQOddPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ah->totalAdcDcOffsetQEvenPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - - ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ah->cal_samples, i, - ah->totalAdcDcOffsetIOddPhase[i], - ah->totalAdcDcOffsetIEvenPhase[i], - ah->totalAdcDcOffsetQOddPhase[i], - ah->totalAdcDcOffsetQEvenPhase[i]); - } -} - -static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) -{ - struct ath_common *common = ath9k_hw_common(ah); - u32 powerMeasQ, powerMeasI, iqCorrMeas; - u32 qCoffDenom, iCoffDenom; - int32_t qCoff, iCoff; - int iqCorrNeg, i; - - for (i = 0; i < numChains; i++) { - powerMeasI = ah->totalPowerMeasI[i]; - powerMeasQ = ah->totalPowerMeasQ[i]; - iqCorrMeas = ah->totalIqCorrMeas[i]; - - ath_print(common, ATH_DBG_CALIBRATE, - "Starting IQ Cal and Correction for Chain %d\n", - i); - - ath_print(common, ATH_DBG_CALIBRATE, - "Orignal: Chn %diq_corr_meas = 0x%08x\n", - i, ah->totalIqCorrMeas[i]); - - iqCorrNeg = 0; - - if (iqCorrMeas > 0x80000000) { - iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; - iqCorrNeg = 1; - } - - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); - ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", - iqCorrNeg); - - iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; - qCoffDenom = powerMeasQ / 64; - - if ((powerMeasQ != 0) && (iCoffDenom != 0) && - (qCoffDenom != 0)) { - iCoff = iqCorrMeas / iCoffDenom; - qCoff = powerMeasI / qCoffDenom - 64; - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d iCoff = 0x%08x\n", i, iCoff); - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d qCoff = 0x%08x\n", i, qCoff); - - iCoff = iCoff & 0x3f; - ath_print(common, ATH_DBG_CALIBRATE, - "New: Chn %d iCoff = 0x%08x\n", i, iCoff); - if (iqCorrNeg == 0x0) - iCoff = 0x40 - iCoff; - - if (qCoff > 15) - qCoff = 15; - else if (qCoff <= -16) - qCoff = 16; - - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", - i, iCoff, qCoff); - - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, - iCoff); - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, - qCoff); - ath_print(common, ATH_DBG_CALIBRATE, - "IQ Cal and Correction done for Chain %d\n", - i); - } - } - - REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); -} - -static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) -{ - struct ath_common *common = ath9k_hw_common(ah); - u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; - u32 qGainMismatch, iGainMismatch, val, i; - - for (i = 0; i < numChains; i++) { - iOddMeasOffset = ah->totalAdcIOddPhase[i]; - iEvenMeasOffset = ah->totalAdcIEvenPhase[i]; - qOddMeasOffset = ah->totalAdcQOddPhase[i]; - qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; - - ath_print(common, ATH_DBG_CALIBRATE, - "Starting ADC Gain Cal for Chain %d\n", i); - - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = 0x%08x\n", i, - iOddMeasOffset); - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = 0x%08x\n", i, - iEvenMeasOffset); - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = 0x%08x\n", i, - qOddMeasOffset); - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = 0x%08x\n", i, - qEvenMeasOffset); - - if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { - iGainMismatch = - ((iEvenMeasOffset * 32) / - iOddMeasOffset) & 0x3f; - qGainMismatch = - ((qOddMeasOffset * 32) / - qEvenMeasOffset) & 0x3f; - - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_i = 0x%08x\n", i, - iGainMismatch); - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_q = 0x%08x\n", i, - qGainMismatch); - - val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); - val &= 0xfffff000; - val |= (qGainMismatch) | (iGainMismatch << 6); - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - - ath_print(common, ATH_DBG_CALIBRATE, - "ADC Gain Cal done for Chain %d\n", i); - } - } - - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), - REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | - AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); -} - -static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) -{ - struct ath_common *common = ath9k_hw_common(ah); - u32 iOddMeasOffset, iEvenMeasOffset, val, i; - int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; - const struct ath9k_percal_data *calData = - ah->cal_list_curr->calData; - u32 numSamples = - (1 << (calData->calCountMax + 5)) * calData->calNumSamples; - - for (i = 0; i < numChains; i++) { - iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i]; - iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i]; - qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; - qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; - - ath_print(common, ATH_DBG_CALIBRATE, - "Starting ADC DC Offset Cal for Chain %d\n", i); - - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = %d\n", i, - iOddMeasOffset); - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = %d\n", i, - iEvenMeasOffset); - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = %d\n", i, - qOddMeasOffset); - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = %d\n", i, - qEvenMeasOffset); - - iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / - numSamples) & 0x1ff; - qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / - numSamples) & 0x1ff; - - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, - iDcMismatch); - ath_print(common, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, - qDcMismatch); - - val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); - val &= 0xc0000fff; - val |= (qDcMismatch << 12) | (iDcMismatch << 21); - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - - ath_print(common, ATH_DBG_CALIBRATE, - "ADC DC Offset Cal done for Chain %d\n", i); - } - - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), - REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | - AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); -} - /* This is done for the currently configured channel */ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) { @@ -605,72 +172,6 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah) REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); } -void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) -{ - struct ath9k_nfcal_hist *h; - int i, j; - int32_t val; - const u32 ar5416_cca_regs[6] = { - AR_PHY_CCA, - AR_PHY_CH1_CCA, - AR_PHY_CH2_CCA, - AR_PHY_EXT_CCA, - AR_PHY_CH1_EXT_CCA, - AR_PHY_CH2_EXT_CCA - }; - u8 chainmask, rx_chain_status; - - rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK); - if (AR_SREV_9285(ah)) - chainmask = 0x9; - else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) { - if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4)) - chainmask = 0x1B; - else - chainmask = 0x09; - } else { - if (rx_chain_status & 0x4) - chainmask = 0x3F; - else if (rx_chain_status & 0x2) - chainmask = 0x1B; - else - chainmask = 0x09; - } - - h = ah->nfCalHist; - - for (i = 0; i < NUM_NF_READINGS; i++) { - if (chainmask & (1 << i)) { - val = REG_READ(ah, ar5416_cca_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (h[i].privNF) << 1) & 0x1ff); - REG_WRITE(ah, ar5416_cca_regs[i], val); - } - } - - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_ENABLE_NF); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_NO_UPDATE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); - - for (j = 0; j < 5; j++) { - if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & - AR_PHY_AGC_CONTROL_NF) == 0) - break; - udelay(50); - } - - for (i = 0; i < NUM_NF_READINGS; i++) { - if (chainmask & (1 << i)) { - val = REG_READ(ah, ar5416_cca_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (-50) << 1) & 0x1ff); - REG_WRITE(ah, ar5416_cca_regs[i], val); - } - } -} - int16_t ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -690,7 +191,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah, } else { ath9k_hw_do_getnf(ah, nfarray); nf = nfarray[0]; - if (getNoiseFloorThresh(ah, c->band, &nfThresh) + if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh) && nf > nfThresh) { ath_print(common, ATH_DBG_CALIBRATE, "noise floor failed detected; " @@ -715,7 +216,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah) if (AR_SREV_9280(ah)) noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE; - else if (AR_SREV_9285(ah)) + else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE; else if (AR_SREV_9287(ah)) noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE; @@ -748,508 +249,3 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) return nf; } EXPORT_SYMBOL(ath9k_hw_getchan_noise); - -static void ath9k_olc_temp_compensation_9287(struct ath_hw *ah) -{ - u32 rddata; - int32_t delta, currPDADC, slope; - - rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); - currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); - - if (ah->initPDADC == 0 || currPDADC == 0) { - /* - * Zero value indicates that no frames have been transmitted yet, - * can't do temperature compensation until frames are transmitted. - */ - return; - } else { - slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE); - - if (slope == 0) { /* to avoid divide by zero case */ - delta = 0; - } else { - delta = ((currPDADC - ah->initPDADC)*4) / slope; - } - REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, - AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); - REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, - AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); - } -} - -static void ath9k_olc_temp_compensation(struct ath_hw *ah) -{ - u32 rddata, i; - int delta, currPDADC, regval; - - if (OLC_FOR_AR9287_10_LATER) { - ath9k_olc_temp_compensation_9287(ah); - } else { - rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); - currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); - - if (ah->initPDADC == 0 || currPDADC == 0) { - return; - } else { - if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) - delta = (currPDADC - ah->initPDADC + 4) / 8; - else - delta = (currPDADC - ah->initPDADC + 5) / 10; - - if (delta != ah->PDADCdelta) { - ah->PDADCdelta = delta; - for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { - regval = ah->originalGain[i] - delta; - if (regval < 0) - regval = 0; - - REG_RMW_FIELD(ah, - AR_PHY_TX_GAIN_TBL1 + i * 4, - AR_PHY_TX_GAIN, regval); - } - } - } - } -} - -static void ath9k_hw_9271_pa_cal(struct ath_hw *ah, bool is_reset) -{ - u32 regVal; - unsigned int i; - u32 regList [][2] = { - { 0x786c, 0 }, - { 0x7854, 0 }, - { 0x7820, 0 }, - { 0x7824, 0 }, - { 0x7868, 0 }, - { 0x783c, 0 }, - { 0x7838, 0 } , - { 0x7828, 0 } , - }; - - for (i = 0; i < ARRAY_SIZE(regList); i++) - regList[i][1] = REG_READ(ah, regList[i][0]); - - regVal = REG_READ(ah, 0x7834); - regVal &= (~(0x1)); - REG_WRITE(ah, 0x7834, regVal); - regVal = REG_READ(ah, 0x9808); - regVal |= (0x1 << 27); - REG_WRITE(ah, 0x9808, regVal); - - /* 786c,b23,1, pwddac=1 */ - REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); - /* 7854, b5,1, pdrxtxbb=1 */ - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); - /* 7854, b7,1, pdv2i=1 */ - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); - /* 7854, b8,1, pddacinterface=1 */ - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); - /* 7824,b12,0, offcal=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); - /* 7838, b1,0, pwddb=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); - /* 7820,b11,0, enpacal=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); - /* 7820,b25,1, pdpadrv1=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); - /* 7820,b24,0, pdpadrv2=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1,AR9285_AN_RF2G1_PDPADRV2,0); - /* 7820,b23,0, pdpaout=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); - /* 783c,b14-16,7, padrvgn2tab_0=7 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G8,AR9285_AN_RF2G8_PADRVGN2TAB0, 7); - /* - * 7838,b29-31,0, padrvgn1tab_0=0 - * does not matter since we turn it off - */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G7,AR9285_AN_RF2G7_PADRVGN2TAB0, 0); - - REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff); - - /* Set: - * localmode=1,bmode=1,bmoderxtx=1,synthon=1, - * txon=1,paon=1,oscon=1,synthon_force=1 - */ - REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); - udelay(30); - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0); - - /* find off_6_1; */ - for (i = 6; i > 0; i--) { - regVal = REG_READ(ah, 0x7834); - regVal |= (1 << (20 + i)); - REG_WRITE(ah, 0x7834, regVal); - udelay(1); - //regVal = REG_READ(ah, 0x7834); - regVal &= (~(0x1 << (20 + i))); - regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9) - << (20 + i)); - REG_WRITE(ah, 0x7834, regVal); - } - - regVal = (regVal >>20) & 0x7f; - - /* Update PA cal info */ - if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) { - if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) - ah->pacal_info.max_skipcount = - 2 * ah->pacal_info.max_skipcount; - ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; - } else { - ah->pacal_info.max_skipcount = 1; - ah->pacal_info.skipcount = 0; - ah->pacal_info.prev_offset = regVal; - } - - regVal = REG_READ(ah, 0x7834); - regVal |= 0x1; - REG_WRITE(ah, 0x7834, regVal); - regVal = REG_READ(ah, 0x9808); - regVal &= (~(0x1 << 27)); - REG_WRITE(ah, 0x9808, regVal); - - for (i = 0; i < ARRAY_SIZE(regList); i++) - REG_WRITE(ah, regList[i][0], regList[i][1]); -} - -static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) -{ - struct ath_common *common = ath9k_hw_common(ah); - u32 regVal; - int i, offset, offs_6_1, offs_0; - u32 ccomp_org, reg_field; - u32 regList[][2] = { - { 0x786c, 0 }, - { 0x7854, 0 }, - { 0x7820, 0 }, - { 0x7824, 0 }, - { 0x7868, 0 }, - { 0x783c, 0 }, - { 0x7838, 0 }, - }; - - ath_print(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); - - /* PA CAL is not needed for high power solution */ - if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == - AR5416_EEP_TXGAIN_HIGH_POWER) - return; - - if (AR_SREV_9285_11(ah)) { - REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); - udelay(10); - } - - for (i = 0; i < ARRAY_SIZE(regList); i++) - regList[i][1] = REG_READ(ah, regList[i][0]); - - regVal = REG_READ(ah, 0x7834); - regVal &= (~(0x1)); - REG_WRITE(ah, 0x7834, regVal); - regVal = REG_READ(ah, 0x9808); - regVal |= (0x1 << 27); - REG_WRITE(ah, 0x9808, regVal); - - REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); - REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); - REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); - ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf); - - REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); - udelay(30); - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); - REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); - - for (i = 6; i > 0; i--) { - regVal = REG_READ(ah, 0x7834); - regVal |= (1 << (19 + i)); - REG_WRITE(ah, 0x7834, regVal); - udelay(1); - regVal = REG_READ(ah, 0x7834); - regVal &= (~(0x1 << (19 + i))); - reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); - regVal |= (reg_field << (19 + i)); - REG_WRITE(ah, 0x7834, regVal); - } - - REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); - udelay(1); - reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); - REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); - offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); - offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); - - offset = (offs_6_1<<1) | offs_0; - offset = offset - 0; - offs_6_1 = offset>>1; - offs_0 = offset & 1; - - if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) { - if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) - ah->pacal_info.max_skipcount = - 2 * ah->pacal_info.max_skipcount; - ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; - } else { - ah->pacal_info.max_skipcount = 1; - ah->pacal_info.skipcount = 0; - ah->pacal_info.prev_offset = offset; - } - - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); - REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); - - regVal = REG_READ(ah, 0x7834); - regVal |= 0x1; - REG_WRITE(ah, 0x7834, regVal); - regVal = REG_READ(ah, 0x9808); - regVal &= (~(0x1 << 27)); - REG_WRITE(ah, 0x9808, regVal); - - for (i = 0; i < ARRAY_SIZE(regList); i++) - REG_WRITE(ah, regList[i][0], regList[i][1]); - - REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); - - if (AR_SREV_9285_11(ah)) - REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); - -} - -bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal) -{ - bool iscaldone = true; - struct ath9k_cal_list *currCal = ah->cal_list_curr; - - if (currCal && - (currCal->calState == CAL_RUNNING || - currCal->calState == CAL_WAITING)) { - iscaldone = ath9k_hw_per_calibration(ah, chan, - rxchainmask, currCal); - if (iscaldone) { - ah->cal_list_curr = currCal = currCal->calNext; - - if (currCal->calState == CAL_WAITING) { - iscaldone = false; - ath9k_hw_reset_calibration(ah, currCal); - } - } - } - - /* Do NF cal only at longer intervals */ - if (longcal) { - /* Do periodic PAOffset Cal */ - if (AR_SREV_9271(ah)) - ath9k_hw_9271_pa_cal(ah, false); - else if (AR_SREV_9285_11_OR_LATER(ah)) { - if (!ah->pacal_info.skipcount) - ath9k_hw_9285_pa_cal(ah, false); - else - ah->pacal_info.skipcount--; - } - - if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER) - ath9k_olc_temp_compensation(ah); - - /* Get the value from the previous NF cal and update history buffer */ - ath9k_hw_getnf(ah, chan); - - /* - * Load the NF from history buffer of the current channel. - * NF is slow time-variant, so it is OK to use a historical value. - */ - ath9k_hw_loadnf(ah, ah->curchan); - - ath9k_hw_start_nfcal(ah); - } - - return iscaldone; -} -EXPORT_SYMBOL(ath9k_hw_calibrate); - -/* Carrier leakage Calibration fix */ -static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) -{ - struct ath_common *common = ath9k_hw_common(ah); - - REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - if (IS_CHAN_HT20(chan)) { - REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); - REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_FLTR_CAL); - REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { - ath_print(common, ATH_DBG_CALIBRATE, "offset " - "calibration failed to complete in " - "1ms; noisy ??\n"); - return false; - } - REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); - REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); - REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - } - REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, - 0, AH_WAIT_TIMEOUT)) { - ath_print(common, ATH_DBG_CALIBRATE, "offset calibration " - "failed to complete in 1ms; noisy ??\n"); - return false; - } - - REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); - - return true; -} - -bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) -{ - struct ath_common *common = ath9k_hw_common(ah); - - if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) { - if (!ar9285_clc(ah, chan)) - return false; - } else { - if (AR_SREV_9280_10_OR_LATER(ah)) { - if (!AR_SREV_9287_10_OR_LATER(ah)) - REG_CLR_BIT(ah, AR_PHY_ADC_CTL, - AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_FLTR_CAL); - } - - /* Calibrate the AGC */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); - - /* Poll for offset calibration complete */ - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, - 0, AH_WAIT_TIMEOUT)) { - ath_print(common, ATH_DBG_CALIBRATE, - "offset calibration failed to " - "complete in 1ms; noisy environment?\n"); - return false; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - if (!AR_SREV_9287_10_OR_LATER(ah)) - REG_SET_BIT(ah, AR_PHY_ADC_CTL, - AR_PHY_ADC_CTL_OFF_PWDADC); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_FLTR_CAL); - } - } - - /* Do PA Calibration */ - if (AR_SREV_9271(ah)) - ath9k_hw_9271_pa_cal(ah, true); - else if (AR_SREV_9285_11_OR_LATER(ah)) - ath9k_hw_9285_pa_cal(ah, true); - - /* Do NF Calibration after DC offset and other calibrations */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); - - ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; - - /* Enable IQ, ADC Gain and ADC DC offset CALs */ - if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { - if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) { - INIT_CAL(&ah->adcgain_caldata); - INSERT_CAL(ah, &ah->adcgain_caldata); - ath_print(common, ATH_DBG_CALIBRATE, - "enabling ADC Gain Calibration.\n"); - } - if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) { - INIT_CAL(&ah->adcdc_caldata); - INSERT_CAL(ah, &ah->adcdc_caldata); - ath_print(common, ATH_DBG_CALIBRATE, - "enabling ADC DC Calibration.\n"); - } - if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { - INIT_CAL(&ah->iq_caldata); - INSERT_CAL(ah, &ah->iq_caldata); - ath_print(common, ATH_DBG_CALIBRATE, - "enabling IQ Calibration.\n"); - } - - ah->cal_list_curr = ah->cal_list; - - if (ah->cal_list_curr) - ath9k_hw_reset_calibration(ah, ah->cal_list_curr); - } - - chan->CalValid = 0; - - return true; -} - -const struct ath9k_percal_data iq_cal_multi_sample = { - IQ_MISMATCH_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_iqcal_collect, - ath9k_hw_iqcalibrate -}; -const struct ath9k_percal_data iq_cal_single_sample = { - IQ_MISMATCH_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_iqcal_collect, - ath9k_hw_iqcalibrate -}; -const struct ath9k_percal_data adc_gain_cal_multi_sample = { - ADC_GAIN_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_adc_gaincal_collect, - ath9k_hw_adc_gaincal_calibrate -}; -const struct ath9k_percal_data adc_gain_cal_single_sample = { - ADC_GAIN_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_adc_gaincal_collect, - ath9k_hw_adc_gaincal_calibrate -}; -const struct ath9k_percal_data adc_dc_cal_multi_sample = { - ADC_DC_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; -const struct ath9k_percal_data adc_dc_cal_single_sample = { - ADC_DC_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; -const struct ath9k_percal_data adc_init_dc_cal = { - ADC_DC_INIT_CAL, - MIN_CAL_SAMPLES, - INIT_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index b2c873e9748..24538bdb912 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -19,14 +19,6 @@ #include "hw.h" -extern const struct ath9k_percal_data iq_cal_multi_sample; -extern const struct ath9k_percal_data iq_cal_single_sample; -extern const struct ath9k_percal_data adc_gain_cal_multi_sample; -extern const struct ath9k_percal_data adc_gain_cal_single_sample; -extern const struct ath9k_percal_data adc_dc_cal_multi_sample; -extern const struct ath9k_percal_data adc_dc_cal_single_sample; -extern const struct ath9k_percal_data adc_init_dc_cal; - #define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE -85 #define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE -112 #define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE -118 @@ -76,7 +68,8 @@ enum ath9k_cal_types { ADC_DC_INIT_CAL = 0x1, ADC_GAIN_CAL = 0x2, ADC_DC_CAL = 0x4, - IQ_MISMATCH_CAL = 0x8 + IQ_MISMATCH_CAL = 0x8, + TEMP_COMP_CAL = 0x10, }; enum ath9k_cal_state { @@ -122,14 +115,12 @@ struct ath9k_pacal_info{ bool ath9k_hw_reset_calvalid(struct ath_hw *ah); void ath9k_hw_start_nfcal(struct ath_hw *ah); -void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); int16_t ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah); s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); -bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal); -bool ath9k_hw_init_cal(struct ath_hw *ah, - struct ath9k_channel *chan); +void ath9k_hw_reset_calibration(struct ath_hw *ah, + struct ath9k_cal_list *currCal); + #endif /* CALIB_H */ diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 4d775ae141d..7707341cd0d 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -57,13 +57,19 @@ static bool ath9k_rx_accept(struct ath_common *common, * rs_more indicates chained descriptors which can be used * to link buffers together for a sort of scatter-gather * operation. - * + * reject the frame, we don't support scatter-gather yet and + * the frame is probably corrupt anyway + */ + if (rx_stats->rs_more) + return false; + + /* * 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 != 0) { if (rx_stats->rs_status & ATH9K_RXERR_CRC) rxs->flag |= RX_FLAG_FAILED_FCS_CRC; if (rx_stats->rs_status & ATH9K_RXERR_PHY) @@ -102,11 +108,11 @@ static bool ath9k_rx_accept(struct ath_common *common, 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) +static int 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; @@ -122,25 +128,32 @@ static u8 ath9k_process_rate(struct ath_common *common, 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; + rxs->rate_idx = rx_stats->rs_rate & 0x7f; + return 0; } 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 == rx_stats->rs_rate) { + rxs->rate_idx = i; + return 0; + } if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { rxs->flag |= RX_FLAG_SHORTPRE; - return i; + rxs->rate_idx = i; + return 0; } } - /* No valid hardware bitrate found -- we should not get here */ + /* + * No valid hardware bitrate found -- we should not get here + * because hardware has already validated this frame as OK. + */ 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; + return -EINVAL; } static void ath9k_process_rssi(struct ath_common *common, @@ -202,17 +215,22 @@ int ath9k_cmn_rx_skb_preprocess(struct ath_common *common, struct ath_hw *ah = common->ah; memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + + /* + * everything but the rate is checked here, the rate check is done + * separately to avoid doing two lookups for a rate for each frame. + */ 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); + if (ath9k_process_rate(common, hw, rx_stats, rx_status, skb)) + return -EINVAL; + 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; @@ -255,7 +273,8 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, keyix = rx_stats->rs_keyix; - if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { + if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && + ieee80211_has_protected(fc)) { rxs->flag |= RX_FLAG_DECRYPTED; } else if (ieee80211_has_protected(fc) && !decrypt_error && skb->len >= hdrlen + 4) { @@ -286,6 +305,345 @@ int ath9k_cmn_padpos(__le16 frame_control) } EXPORT_SYMBOL(ath9k_cmn_padpos); +int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + + if (tx_info->control.hw_key) { + if (tx_info->control.hw_key->alg == ALG_WEP) + return ATH9K_KEY_TYPE_WEP; + else if (tx_info->control.hw_key->alg == ALG_TKIP) + return ATH9K_KEY_TYPE_TKIP; + else if (tx_info->control.hw_key->alg == ALG_CCMP) + return ATH9K_KEY_TYPE_AES; + } + + return ATH9K_KEY_TYPE_CLEAR; +} +EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype); + +static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + u32 chanmode = 0; + + switch (chan->band) { + case IEEE80211_BAND_2GHZ: + switch (channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + chanmode = CHANNEL_G_HT20; + break; + case NL80211_CHAN_HT40PLUS: + chanmode = CHANNEL_G_HT40PLUS; + break; + case NL80211_CHAN_HT40MINUS: + chanmode = CHANNEL_G_HT40MINUS; + break; + } + break; + case IEEE80211_BAND_5GHZ: + switch (channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + chanmode = CHANNEL_A_HT20; + break; + case NL80211_CHAN_HT40PLUS: + chanmode = CHANNEL_A_HT40PLUS; + break; + case NL80211_CHAN_HT40MINUS: + chanmode = CHANNEL_A_HT40MINUS; + break; + } + break; + default: + break; + } + + return chanmode; +} + +/* + * Update internal channel flags. + */ +void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, + struct ath9k_channel *ichan) +{ + struct ieee80211_channel *chan = hw->conf.channel; + struct ieee80211_conf *conf = &hw->conf; + + ichan->channel = chan->center_freq; + ichan->chan = chan; + + if (chan->band == IEEE80211_BAND_2GHZ) { + ichan->chanmode = CHANNEL_G; + ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; + } else { + ichan->chanmode = CHANNEL_A; + ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; + } + + if (conf_is_ht(conf)) + ichan->chanmode = ath9k_get_extchanmode(chan, + conf->channel_type); +} +EXPORT_SYMBOL(ath9k_cmn_update_ichannel); + +/* + * Get the internal channel reference. + */ +struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, + struct ath_hw *ah) +{ + struct ieee80211_channel *curchan = hw->conf.channel; + struct ath9k_channel *channel; + u8 chan_idx; + + chan_idx = curchan->hw_value; + channel = &ah->channels[chan_idx]; + ath9k_cmn_update_ichannel(hw, channel); + + return channel; +} +EXPORT_SYMBOL(ath9k_cmn_get_curchannel); + +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; + + key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; + key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; + + if (addr == NULL) { + /* + * Group key installation - only two key cache entries are used + * regardless of splitmic capability since group key is only + * used either for TX or RX. + */ + if (authenticator) { + memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); + memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); + } else { + 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(ah, keyix, hk, addr); + } + 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(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(ah, keyix, hk, NULL)) { + /* TX MIC entry failed. No need to proceed further */ + 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(ah, keyix + 32, hk, addr); +} + +static int ath_reserve_key_cache_slot_tkip(struct ath_common *common) +{ + int i; + + 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 (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 */ + return i; + } + return -1; +} + +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 (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, 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, 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, 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 < common->keymax / 2; i++) { + if (!test_bit(i, common->keymap) && + test_bit(i + 64, common->keymap)) + return i; + 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 < 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 (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, common->keymap)) + return i; /* Found a free slot for a key */ + } + + /* No free slot found */ + return -1; +} + +/* + * Configure encryption in the HW. + */ +int ath9k_cmn_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; + int idx; + + memset(&hk, 0, sizeof(hk)); + + switch (key->alg) { + case ALG_WEP: + hk.kv_type = ATH9K_CIPHER_WEP; + break; + case ALG_TKIP: + hk.kv_type = ATH9K_CIPHER_TKIP; + break; + case ALG_CCMP: + hk.kv_type = ATH9K_CIPHER_AES_CCM; + break; + default: + return -EOPNOTSUPP; + } + + hk.kv_len = key->keylen; + memcpy(hk.kv_val, key->key, key->keylen); + + if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + /* For now, use the default keys for broadcast keys. This may + * need to change with virtual interfaces. */ + idx = key->keyidx; + } else if (key->keyidx) { + if (WARN_ON(!sta)) + return -EOPNOTSUPP; + mac = sta->addr; + + if (vif->type != NL80211_IFTYPE_AP) { + /* Only keyidx 0 should be used with unicast key, but + * allow this for client mode for now. */ + idx = key->keyidx; + } else + return -EIO; + } else { + if (WARN_ON(!sta)) + return -EOPNOTSUPP; + mac = sta->addr; + + if (key->alg == ALG_TKIP) + idx = ath_reserve_key_cache_slot_tkip(common); + else + 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(common, idx, key->key, &hk, mac, + vif->type == NL80211_IFTYPE_AP); + else + ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac); + + if (!ret) + return -EIO; + + set_bit(idx, common->keymap); + if (key->alg == ALG_TKIP) { + set_bit(idx + 64, common->keymap); + if (common->splitmic) { + set_bit(idx + 32, common->keymap); + set_bit(idx + 64 + 32, common->keymap); + } + } + + return idx; +} +EXPORT_SYMBOL(ath9k_cmn_key_config); + +/* + * Delete Key. + */ +void ath9k_cmn_key_delete(struct ath_common *common, + struct ieee80211_key_conf *key) +{ + 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, common->keymap); + if (key->alg != ALG_TKIP) + return; + + clear_bit(key->hw_key_idx + 64, common->keymap); + if (common->splitmic) { + ath9k_hw_keyreset(ah, key->hw_key_idx + 32); + clear_bit(key->hw_key_idx + 32, common->keymap); + clear_bit(key->hw_key_idx + 64 + 32, common->keymap); + } +} +EXPORT_SYMBOL(ath9k_cmn_key_delete); + static int __init ath9k_cmn_init(void) { return 0; diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 042999c2fe9..e08f7e5a26e 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -20,9 +20,12 @@ #include "../debug.h" #include "hw.h" +#include "hw-ops.h" /* Common header for Atheros 802.11n base driver cores */ +#define IEEE80211_WEP_NKID 4 + #define WME_NUM_TID 16 #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE @@ -74,11 +77,12 @@ struct ath_buf { 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 */ + void *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; bool bf_isnullfunc; + bool bf_tx_aborted; u16 bf_flags; struct ath_buf_state bf_state; dma_addr_t bf_dmacontext; @@ -125,3 +129,14 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, bool decrypt_error); int ath9k_cmn_padpos(__le16 frame_control); +int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); +void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, + struct ath9k_channel *ichan); +struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, + struct ath_hw *ah); +int ath9k_cmn_key_config(struct ath_common *common, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); +void ath9k_cmn_key_delete(struct ath_common *common, + struct ieee80211_key_conf *key); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 081e0085ed4..29898f8d189 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -78,6 +78,90 @@ static const struct file_operations fops_debug = { #define DMA_BUF_LEN 1024 +static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + char buf[32]; + unsigned int len; + + len = snprintf(buf, sizeof(buf), "0x%08x\n", common->tx_chainmask); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_tx_chainmask(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + unsigned long mask; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &mask)) + return -EINVAL; + + common->tx_chainmask = mask; + sc->sc_ah->caps.tx_chainmask = mask; + return count; +} + +static const struct file_operations fops_tx_chainmask = { + .read = read_file_tx_chainmask, + .write = write_file_tx_chainmask, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + + +static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + char buf[32]; + unsigned int len; + + len = snprintf(buf, sizeof(buf), "0x%08x\n", common->rx_chainmask); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_rx_chainmask(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + unsigned long mask; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &mask)) + return -EINVAL; + + common->rx_chainmask = mask; + sc->sc_ah->caps.rx_chainmask = mask; + return count; +} + +static const struct file_operations fops_rx_chainmask = { + .read = read_file_rx_chainmask, + .write = write_file_rx_chainmask, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + + static ssize_t read_file_dma(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -157,10 +241,10 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); - len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x \n", + len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x\n", REG_READ_D(ah, AR_OBS_BUS_1)); len += snprintf(buf + len, DMA_BUF_LEN - len, - "AR_CR: 0x%x \n", REG_READ_D(ah, AR_CR)); + "AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR)); ath9k_ps_restore(sc); @@ -180,8 +264,15 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { if (status) sc->debug.stats.istats.total++; - if (status & ATH9K_INT_RX) - sc->debug.stats.istats.rxok++; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + if (status & ATH9K_INT_RXLP) + sc->debug.stats.istats.rxlp++; + if (status & ATH9K_INT_RXHP) + sc->debug.stats.istats.rxhp++; + } else { + if (status & ATH9K_INT_RX) + sc->debug.stats.istats.rxok++; + } if (status & ATH9K_INT_RXEOL) sc->debug.stats.istats.rxeol++; if (status & ATH9K_INT_RXORN) @@ -223,8 +314,15 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, char buf[512]; unsigned int len = 0; - len += snprintf(buf + len, sizeof(buf) - len, - "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok); + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXLP", sc->debug.stats.istats.rxlp); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXHP", sc->debug.stats.istats.rxhp); + } else { + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok); + } len += snprintf(buf + len, sizeof(buf) - len, "%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol); len += snprintf(buf + len, sizeof(buf) - len, @@ -557,10 +655,8 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, } void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, - struct ath_buf *bf) + struct ath_buf *bf, struct ath_tx_status *ts) { - struct ath_desc *ds = bf->bf_desc; - if (bf_isampdu(bf)) { if (bf_isxretried(bf)) TX_STAT_INC(txq->axq_qnum, a_xretries); @@ -570,17 +666,17 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, TX_STAT_INC(txq->axq_qnum, completed); } - if (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO) + if (ts->ts_status & ATH9K_TXERR_FIFO) TX_STAT_INC(txq->axq_qnum, fifo_underrun); - if (ds->ds_txstat.ts_status & ATH9K_TXERR_XTXOP) + if (ts->ts_status & ATH9K_TXERR_XTXOP) TX_STAT_INC(txq->axq_qnum, xtxop); - if (ds->ds_txstat.ts_status & ATH9K_TXERR_TIMER_EXPIRED) + if (ts->ts_status & ATH9K_TXERR_TIMER_EXPIRED) TX_STAT_INC(txq->axq_qnum, timer_exp); - if (ds->ds_txstat.ts_flags & ATH9K_TX_DESC_CFG_ERR) + if (ts->ts_flags & ATH9K_TX_DESC_CFG_ERR) TX_STAT_INC(txq->axq_qnum, desc_cfg_err); - if (ds->ds_txstat.ts_flags & ATH9K_TX_DATA_UNDERRUN) + if (ts->ts_flags & ATH9K_TX_DATA_UNDERRUN) TX_STAT_INC(txq->axq_qnum, data_underrun); - if (ds->ds_txstat.ts_flags & ATH9K_TX_DELIM_UNDERRUN) + if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) TX_STAT_INC(txq->axq_qnum, delim_underrun); } @@ -663,30 +759,29 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, #undef PHY_ERR } -void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf) +void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { #define RX_STAT_INC(c) sc->debug.stats.rxstats.c++ #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ - struct ath_desc *ds = bf->bf_desc; u32 phyerr; - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) + if (rs->rs_status & ATH9K_RXERR_CRC) RX_STAT_INC(crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) + if (rs->rs_status & ATH9K_RXERR_DECRYPT) RX_STAT_INC(decrypt_crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) + if (rs->rs_status & ATH9K_RXERR_MIC) RX_STAT_INC(mic_err); - if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_PRE) + if (rs->rs_status & ATH9K_RX_DELIM_CRC_PRE) RX_STAT_INC(pre_delim_crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_POST) + if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST) RX_STAT_INC(post_delim_crc_err); - if (ds->ds_rxstat.rs_status & ATH9K_RX_DECRYPT_BUSY) + if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY) RX_STAT_INC(decrypt_busy_err); - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) { + if (rs->rs_status & ATH9K_RXERR_PHY) { RX_STAT_INC(phy_err); - phyerr = ds->ds_rxstat.rs_phyerr & 0x24; + phyerr = rs->rs_phyerr & 0x24; RX_PHY_ERR_INC(phyerr); } @@ -700,6 +795,86 @@ static const struct file_operations fops_recv = { .owner = THIS_MODULE }; +static ssize_t read_file_regidx(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[32]; + unsigned int len; + + len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.regidx); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_regidx(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned long regidx; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, ®idx)) + return -EINVAL; + + sc->debug.regidx = regidx; + return count; +} + +static const struct file_operations fops_regidx = { + .read = read_file_regidx, + .write = write_file_regidx, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + +static ssize_t read_file_regval(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + char buf[32]; + unsigned int len; + u32 regval; + + regval = REG_READ_D(ah, sc->debug.regidx); + len = snprintf(buf, sizeof(buf), "0x%08x\n", regval); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_regval(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + unsigned long regval; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, ®val)) + return -EINVAL; + + REG_WRITE_D(ah, sc->debug.regidx, regval); + return count; +} + +static const struct file_operations fops_regval = { + .read = read_file_regval, + .write = write_file_regval, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -711,54 +886,55 @@ int ath9k_init_debug(struct ath_hw *ah) sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), ath9k_debugfs_root); if (!sc->debug.debugfs_phy) - goto err; + return -ENOMEM; #ifdef CONFIG_ATH_DEBUG - sc->debug.debugfs_debug = debugfs_create_file("debug", - S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug); - if (!sc->debug.debugfs_debug) + if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_debug)) goto err; #endif - sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR, - sc->debug.debugfs_phy, sc, &fops_dma); - if (!sc->debug.debugfs_dma) + if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, + sc, &fops_dma)) + goto err; + + if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, + sc, &fops_interrupt)) + goto err; + + if (!debugfs_create_file("rcstat", S_IRUSR, sc->debug.debugfs_phy, + sc, &fops_rcstat)) + goto err; + + if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_wiphy)) + goto err; + + if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, + sc, &fops_xmit)) goto err; - sc->debug.debugfs_interrupt = debugfs_create_file("interrupt", - S_IRUSR, - sc->debug.debugfs_phy, - sc, &fops_interrupt); - if (!sc->debug.debugfs_interrupt) + if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, + sc, &fops_recv)) goto err; - sc->debug.debugfs_rcstat = debugfs_create_file("rcstat", - S_IRUSR, - sc->debug.debugfs_phy, - sc, &fops_rcstat); - if (!sc->debug.debugfs_rcstat) + if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_rx_chainmask)) goto err; - sc->debug.debugfs_wiphy = debugfs_create_file( - "wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, - &fops_wiphy); - if (!sc->debug.debugfs_wiphy) + if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_tx_chainmask)) goto err; - sc->debug.debugfs_xmit = debugfs_create_file("xmit", - S_IRUSR, - sc->debug.debugfs_phy, - sc, &fops_xmit); - if (!sc->debug.debugfs_xmit) + if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_regidx)) goto err; - sc->debug.debugfs_recv = debugfs_create_file("recv", - S_IRUSR, - sc->debug.debugfs_phy, - sc, &fops_recv); - if (!sc->debug.debugfs_recv) + if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_regval)) goto err; + sc->debug.regidx = 0; return 0; err: ath9k_exit_debug(ah); @@ -770,14 +946,7 @@ void ath9k_exit_debug(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath_softc *sc = (struct ath_softc *) common->priv; - debugfs_remove(sc->debug.debugfs_recv); - debugfs_remove(sc->debug.debugfs_xmit); - debugfs_remove(sc->debug.debugfs_wiphy); - debugfs_remove(sc->debug.debugfs_rcstat); - debugfs_remove(sc->debug.debugfs_interrupt); - debugfs_remove(sc->debug.debugfs_dma); - debugfs_remove(sc->debug.debugfs_debug); - debugfs_remove(sc->debug.debugfs_phy); + debugfs_remove_recursive(sc->debug.debugfs_phy); } int ath9k_debug_create_root(void) diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 86780e68b31..5147b8709e1 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -35,6 +35,8 @@ struct ath_buf; * struct ath_interrupt_stats - Contains statistics about interrupts * @total: Total no. of interrupts generated so far * @rxok: RX with no errors + * @rxlp: RX with low priority RX + * @rxhp: RX with high priority, uapsd only * @rxeol: RX with no more RXDESC available * @rxorn: RX FIFO overrun * @txok: TX completed at the requested rate @@ -55,6 +57,8 @@ struct ath_buf; struct ath_interrupt_stats { u32 total; u32 rxok; + u32 rxlp; + u32 rxhp; u32 rxeol; u32 rxorn; u32 txok; @@ -149,13 +153,7 @@ struct ath_stats { struct ath9k_debug { struct dentry *debugfs_phy; - struct dentry *debugfs_debug; - struct dentry *debugfs_dma; - struct dentry *debugfs_interrupt; - struct dentry *debugfs_rcstat; - struct dentry *debugfs_wiphy; - struct dentry *debugfs_xmit; - struct dentry *debugfs_recv; + u32 regidx; struct ath_stats stats; }; @@ -167,8 +165,8 @@ void ath9k_debug_remove_root(void); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_rc(struct ath_softc *sc, int final_rate); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, - struct ath_buf *bf); -void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf); + struct ath_buf *bf, struct ath_tx_status *ts); +void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs); void ath_debug_stat_retries(struct ath_softc *sc, int rix, int xretries, int retries, u8 per); @@ -204,12 +202,13 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc, static inline void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, - struct ath_buf *bf) + struct ath_buf *bf, + struct ath_tx_status *ts) { } static inline void ath_debug_stat_rx(struct ath_softc *sc, - struct ath_buf *bf) + struct ath_rx_status *rs) { } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index dacaae93414..ca8704a9d7a 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -36,8 +36,6 @@ void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, if (ah->config.analog_shiftreg) udelay(100); - - return; } int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, @@ -256,14 +254,13 @@ int ath9k_hw_eeprom_init(struct ath_hw *ah) { int status; - if (AR_SREV_9287(ah)) { - ah->eep_map = EEP_MAP_AR9287; - ah->eep_ops = &eep_AR9287_ops; + if (AR_SREV_9300_20_OR_LATER(ah)) + ah->eep_ops = &eep_ar9300_ops; + else if (AR_SREV_9287(ah)) { + ah->eep_ops = &eep_ar9287_ops; } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) { - ah->eep_map = EEP_MAP_4KBITS; ah->eep_ops = &eep_4k_ops; } else { - ah->eep_map = EEP_MAP_DEFAULT; ah->eep_ops = &eep_def_ops; } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 2f2993b50e2..21354c15a9a 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -19,6 +19,7 @@ #include "../ath.h" #include <net/cfg80211.h> +#include "ar9003_eeprom.h" #define AH_USE_EEPROM 0x1 @@ -93,7 +94,6 @@ */ #define AR9285_RDEXT_DEFAULT 0x1F -#define AR_EEPROM_MAC(i) (0x1d+(i)) #define ATH9K_POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) #define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) #define ath9k_hw_use_flash(_ah) (!(_ah->ah_flags & AH_USE_EEPROM)) @@ -155,6 +155,7 @@ #define AR5416_BCHAN_UNUSED 0xFF #define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 #define AR5416_MAX_CHAINS 3 +#define AR9300_MAX_CHAINS 3 #define AR5416_PWR_TABLE_OFFSET_DB -5 /* Rx gain type values */ @@ -249,16 +250,20 @@ enum eeprom_param { EEP_MINOR_REV, EEP_TX_MASK, EEP_RX_MASK, + EEP_FSTCLK_5G, EEP_RXGAIN_TYPE, - EEP_TXGAIN_TYPE, EEP_OL_PWRCTRL, + EEP_TXGAIN_TYPE, EEP_RC_CHAIN_MASK, EEP_DAC_HPWR_5G, EEP_FRAC_N_5G, EEP_DEV_TYPE, EEP_TEMPSENSE_SLOPE, EEP_TEMPSENSE_SLOPE_PAL_ON, - EEP_PWR_TABLE_OFFSET + EEP_PWR_TABLE_OFFSET, + EEP_DRIVE_STRENGTH, + EEP_INTERNAL_REGULATOR, + EEP_SWREG }; enum ar5416_rates { @@ -295,7 +300,8 @@ struct base_eep_header { u32 binBuildNumber; u8 deviceType; u8 pwdclkind; - u8 futureBase_1[2]; + u8 fastClk5g; + u8 divChain; u8 rxGainType; u8 dacHiPwrMode_5G; u8 openLoopPwrCntl; @@ -656,13 +662,6 @@ struct ath9k_country_entry { u8 iso[3]; }; -enum ath9k_eep_map { - EEP_MAP_DEFAULT = 0x0, - EEP_MAP_4KBITS, - EEP_MAP_AR9287, - EEP_MAP_MAX -}; - struct eeprom_ops { int (*check_eeprom)(struct ath_hw *hw); u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param); @@ -713,6 +712,8 @@ int ath9k_hw_eeprom_init(struct ath_hw *ah); extern const struct eeprom_ops eep_def_ops; extern const struct eeprom_ops eep_4k_ops; -extern const struct eeprom_ops eep_AR9287_ops; +extern const struct eeprom_ops eep_ar9287_ops; +extern const struct eeprom_ops eep_ar9287_ops; +extern const struct eeprom_ops eep_ar9300_ops; #endif /* EEPROM_H */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 68db16690ab..41a77d1bd43 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -15,6 +15,7 @@ */ #include "hw.h" +#include "ar9002_phy.h" static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) { @@ -43,7 +44,7 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { ath_print(common, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); + "Unable to read eeprom region\n"); return false; } eep_data++; @@ -182,11 +183,11 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, switch (param) { case EEP_NFTHRESH_2: return pModal->noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): + case EEP_MAC_LSW: return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): + case EEP_MAC_MID: return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): + case EEP_MAC_MSW: return pBase->macAddr[4] << 8 | pBase->macAddr[5]; case EEP_REG_0: return pBase->regDmn[0]; @@ -453,6 +454,8 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, &tMinCalPower, gainBoundaries, pdadcValues, numXpdGain); + ENABLE_REGWRITE_BUFFER(ah); + if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, SM(pdGainOverlap_t2, @@ -493,6 +496,9 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, regOffset += 4; } + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); } } @@ -758,6 +764,8 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; } + ENABLE_REGWRITE_BUFFER(ah); + /* OFDM power per rate */ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, ATH9K_POW_SM(ratesArray[rate18mb], 24) @@ -820,6 +828,9 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); } static void ath9k_hw_4k_set_addac(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 839d05a1df2..b471db5fb82 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -15,6 +15,7 @@ */ #include "hw.h" +#include "ar9002_phy.h" static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah) { @@ -44,7 +45,7 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah) if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) { ath_print(common, ATH_DBG_EEPROM, - "Unable to read eeprom region \n"); + "Unable to read eeprom region\n"); return false; } eep_data++; @@ -172,11 +173,11 @@ static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah, switch (param) { case EEP_NFTHRESH_2: return pModal->noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): + case EEP_MAC_LSW: return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): + case EEP_MAC_MID: return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): + case EEP_MAC_MSW: return pBase->macAddr[4] << 8 | pBase->macAddr[5]; case EEP_REG_0: return pBase->regDmn[0]; @@ -1169,7 +1170,7 @@ static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah, #undef EEP_MAP9287_SPURCHAN } -const struct eeprom_ops eep_AR9287_ops = { +const struct eeprom_ops eep_ar9287_ops = { .check_eeprom = ath9k_hw_AR9287_check_eeprom, .get_eeprom = ath9k_hw_AR9287_get_eeprom, .fill_eeprom = ath9k_hw_AR9287_fill_eeprom, diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 404a0341242..7e1ed78d0e6 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -15,6 +15,7 @@ */ #include "hw.h" +#include "ar9002_phy.h" static void ath9k_get_txgain_index(struct ath_hw *ah, struct ath9k_channel *chan, @@ -49,7 +50,6 @@ static void ath9k_get_txgain_index(struct ath_hw *ah, i++; *pcdacIdx = i; - return; } static void ath9k_olc_get_pdadcs(struct ath_hw *ah, @@ -222,6 +222,12 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) return -EINVAL; } + /* Enable fixup for AR_AN_TOP2 if necessary */ + if (AR_SREV_9280_10_OR_LATER(ah) && + (eep->baseEepHeader.version & 0xff) > 0x0a && + eep->baseEepHeader.pwdclkind == 0) + ah->need_an_top2_fixup = 1; + return 0; } @@ -237,11 +243,11 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, return pModal[0].noiseFloorThreshCh[0]; case EEP_NFTHRESH_2: return pModal[1].noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): + case EEP_MAC_LSW: return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): + case EEP_MAC_MID: return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): + case EEP_MAC_MSW: return pBase->macAddr[4] << 8 | pBase->macAddr[5]; case EEP_REG_0: return pBase->regDmn[0]; @@ -267,6 +273,8 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, return pBase->txMask; case EEP_RX_MASK: return pBase->rxMask; + case EEP_FSTCLK_5G: + return pBase->fastClk5g; case EEP_RXGAIN_TYPE: return pBase->rxGainType; case EEP_TXGAIN_TYPE: @@ -742,8 +750,6 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah, pPDADCValues[k] = pPDADCValues[k - 1]; k++; } - - return; } static int16_t ath9k_change_gain_boundary_setting(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index deab8beb068..0ee75e79fe3 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -283,22 +283,17 @@ static void ath9k_gen_timer_start(struct ath_hw *ah, u32 timer_next, u32 timer_period) { - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); - if ((sc->imask & ATH9K_INT_GENTIMER) == 0) { + if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { ath9k_hw_set_interrupts(ah, 0); - sc->imask |= ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, sc->imask); + ah->imask |= ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, ah->imask); } } static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) { - struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; ath9k_hw_gen_timer_stop(ah, timer); @@ -306,8 +301,8 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) /* if no timer is enabled, turn off interrupt mask */ if (timer_table->timer_mask.val == 0) { ath9k_hw_set_interrupts(ah, 0); - sc->imask &= ~ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, sc->imask); + ah->imask &= ~ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah, ah->imask); } } @@ -364,7 +359,7 @@ static void ath_btcoex_no_stomp_timer(void *arg) bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN; ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, - "no stomp timer running \n"); + "no stomp timer running\n"); spin_lock_bh(&btcoex->btcoex_lock); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c new file mode 100644 index 00000000000..46dc41a16fa --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -0,0 +1,1008 @@ +/* + * Copyright (c) 2010 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 "htc.h" + +#define ATH9K_FW_USB_DEV(devid, fw) \ + { USB_DEVICE(0x0cf3, devid), .driver_info = (unsigned long) fw } + +static struct usb_device_id ath9k_hif_usb_ids[] = { + ATH9K_FW_USB_DEV(0x9271, "ar9271.fw"), + ATH9K_FW_USB_DEV(0x1006, "ar9271.fw"), + { }, +}; + +MODULE_DEVICE_TABLE(usb, ath9k_hif_usb_ids); + +static int __hif_usb_tx(struct hif_device_usb *hif_dev); + +static void hif_usb_regout_cb(struct urb *urb) +{ + struct cmd_buf *cmd = (struct cmd_buf *)urb->context; + + switch (urb->status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ENODEV: + case -ESHUTDOWN: + goto free; + default: + break; + } + + if (cmd) { + ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle, + cmd->skb, 1); + kfree(cmd); + } + + return; +free: + kfree_skb(cmd->skb); + kfree(cmd); +} + +static int hif_usb_send_regout(struct hif_device_usb *hif_dev, + struct sk_buff *skb) +{ + struct urb *urb; + struct cmd_buf *cmd; + int ret = 0; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (urb == NULL) + return -ENOMEM; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (cmd == NULL) { + usb_free_urb(urb); + return -ENOMEM; + } + + cmd->skb = skb; + cmd->hif_dev = hif_dev; + + usb_fill_int_urb(urb, hif_dev->udev, + usb_sndintpipe(hif_dev->udev, USB_REG_OUT_PIPE), + skb->data, skb->len, + hif_usb_regout_cb, cmd, 1); + + usb_anchor_urb(urb, &hif_dev->regout_submitted); + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret) { + usb_unanchor_urb(urb); + kfree(cmd); + } + usb_free_urb(urb); + + return ret; +} + +static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, + struct sk_buff_head *list) +{ + struct sk_buff *skb; + + while ((skb = __skb_dequeue(list)) != NULL) { + dev_kfree_skb_any(skb); + TX_STAT_INC(skb_dropped); + } +} + +static void hif_usb_tx_cb(struct urb *urb) +{ + struct tx_buf *tx_buf = (struct tx_buf *) urb->context; + struct hif_device_usb *hif_dev = tx_buf->hif_dev; + struct sk_buff *skb; + + if (!hif_dev || !tx_buf) + return; + + switch (urb->status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ENODEV: + case -ESHUTDOWN: + /* + * The URB has been killed, free the SKBs + * and return. + */ + ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); + return; + default: + break; + } + + /* Check if TX has been stopped */ + spin_lock(&hif_dev->tx.tx_lock); + if (hif_dev->tx.flags & HIF_USB_TX_STOP) { + spin_unlock(&hif_dev->tx.tx_lock); + ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); + goto add_free; + } + spin_unlock(&hif_dev->tx.tx_lock); + + /* Complete the queued SKBs. */ + while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) { + ath9k_htc_txcompletion_cb(hif_dev->htc_handle, + skb, 1); + TX_STAT_INC(skb_completed); + } + +add_free: + /* Re-initialize the SKB queue */ + tx_buf->len = tx_buf->offset = 0; + __skb_queue_head_init(&tx_buf->skb_queue); + + /* Add this TX buffer to the free list */ + spin_lock(&hif_dev->tx.tx_lock); + list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); + hif_dev->tx.tx_buf_cnt++; + if (!(hif_dev->tx.flags & HIF_USB_TX_STOP)) + __hif_usb_tx(hif_dev); /* Check for pending SKBs */ + TX_STAT_INC(buf_completed); + spin_unlock(&hif_dev->tx.tx_lock); +} + +/* TX lock has to be taken */ +static int __hif_usb_tx(struct hif_device_usb *hif_dev) +{ + struct tx_buf *tx_buf = NULL; + struct sk_buff *nskb = NULL; + int ret = 0, i; + u16 *hdr, tx_skb_cnt = 0; + u8 *buf; + + if (hif_dev->tx.tx_skb_cnt == 0) + return 0; + + /* Check if a free TX buffer is available */ + if (list_empty(&hif_dev->tx.tx_buf)) + return 0; + + tx_buf = list_first_entry(&hif_dev->tx.tx_buf, struct tx_buf, list); + list_move_tail(&tx_buf->list, &hif_dev->tx.tx_pending); + hif_dev->tx.tx_buf_cnt--; + + tx_skb_cnt = min_t(u16, hif_dev->tx.tx_skb_cnt, MAX_TX_AGGR_NUM); + + for (i = 0; i < tx_skb_cnt; i++) { + nskb = __skb_dequeue(&hif_dev->tx.tx_skb_queue); + + /* Should never be NULL */ + BUG_ON(!nskb); + + hif_dev->tx.tx_skb_cnt--; + + buf = tx_buf->buf; + buf += tx_buf->offset; + hdr = (u16 *)buf; + *hdr++ = nskb->len; + *hdr++ = ATH_USB_TX_STREAM_MODE_TAG; + buf += 4; + memcpy(buf, nskb->data, nskb->len); + tx_buf->len = nskb->len + 4; + + if (i < (tx_skb_cnt - 1)) + tx_buf->offset += (((tx_buf->len - 1) / 4) + 1) * 4; + + if (i == (tx_skb_cnt - 1)) + tx_buf->len += tx_buf->offset; + + __skb_queue_tail(&tx_buf->skb_queue, nskb); + TX_STAT_INC(skb_queued); + } + + usb_fill_bulk_urb(tx_buf->urb, hif_dev->udev, + usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE), + tx_buf->buf, tx_buf->len, + hif_usb_tx_cb, tx_buf); + + ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC); + if (ret) { + tx_buf->len = tx_buf->offset = 0; + ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); + __skb_queue_head_init(&tx_buf->skb_queue); + list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); + hif_dev->tx.tx_buf_cnt++; + } + + if (!ret) + TX_STAT_INC(buf_queued); + + return ret; +} + +static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb, + struct ath9k_htc_tx_ctl *tx_ctl) +{ + unsigned long flags; + + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); + + if (hif_dev->tx.flags & HIF_USB_TX_STOP) { + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); + return -ENODEV; + } + + /* Check if the max queue count has been reached */ + if (hif_dev->tx.tx_skb_cnt > MAX_TX_BUF_NUM) { + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); + return -ENOMEM; + } + + __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb); + hif_dev->tx.tx_skb_cnt++; + + /* Send normal frames immediately */ + if (!tx_ctl || (tx_ctl && (tx_ctl->type == ATH9K_HTC_NORMAL))) + __hif_usb_tx(hif_dev); + + /* Check if AMPDUs have to be sent immediately */ + if (tx_ctl && (tx_ctl->type == ATH9K_HTC_AMPDU) && + (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) && + (hif_dev->tx.tx_skb_cnt < 2)) { + __hif_usb_tx(hif_dev); + } + + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); + + return 0; +} + +static void hif_usb_start(void *hif_handle, u8 pipe_id) +{ + struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + unsigned long flags; + + hif_dev->flags |= HIF_USB_START; + + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); + hif_dev->tx.flags &= ~HIF_USB_TX_STOP; + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); +} + +static void hif_usb_stop(void *hif_handle, u8 pipe_id) +{ + struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + unsigned long flags; + + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); + ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue); + hif_dev->tx.tx_skb_cnt = 0; + hif_dev->tx.flags |= HIF_USB_TX_STOP; + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); +} + +static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, + struct ath9k_htc_tx_ctl *tx_ctl) +{ + struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + int ret = 0; + + switch (pipe_id) { + case USB_WLAN_TX_PIPE: + ret = hif_usb_send_tx(hif_dev, skb, tx_ctl); + break; + case USB_REG_OUT_PIPE: + ret = hif_usb_send_regout(hif_dev, skb); + break; + default: + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Invalid TX pipe: %d\n", pipe_id); + ret = -EINVAL; + break; + } + + return ret; +} + +static struct ath9k_htc_hif hif_usb = { + .transport = ATH9K_HIF_USB, + .name = "ath9k_hif_usb", + + .control_ul_pipe = USB_REG_OUT_PIPE, + .control_dl_pipe = USB_REG_IN_PIPE, + + .start = hif_usb_start, + .stop = hif_usb_stop, + .send = hif_usb_send, +}; + +static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, + struct sk_buff *skb) +{ + struct sk_buff *nskb, *skb_pool[MAX_PKT_NUM_IN_TRANSFER]; + int index = 0, i = 0, chk_idx, len = skb->len; + int rx_remain_len = 0, rx_pkt_len = 0; + u16 pkt_len, pkt_tag, pool_index = 0; + u8 *ptr; + + spin_lock(&hif_dev->rx_lock); + + rx_remain_len = hif_dev->rx_remain_len; + rx_pkt_len = hif_dev->rx_transfer_len; + + if (rx_remain_len != 0) { + struct sk_buff *remain_skb = hif_dev->remain_skb; + + if (remain_skb) { + ptr = (u8 *) remain_skb->data; + + index = rx_remain_len; + rx_remain_len -= hif_dev->rx_pad_len; + ptr += rx_pkt_len; + + memcpy(ptr, skb->data, rx_remain_len); + + rx_pkt_len += rx_remain_len; + hif_dev->rx_remain_len = 0; + skb_put(remain_skb, rx_pkt_len); + + skb_pool[pool_index++] = remain_skb; + + } else { + index = rx_remain_len; + } + } + + spin_unlock(&hif_dev->rx_lock); + + while (index < len) { + ptr = (u8 *) skb->data; + + pkt_len = ptr[index] + (ptr[index+1] << 8); + pkt_tag = ptr[index+2] + (ptr[index+3] << 8); + + if (pkt_tag == ATH_USB_RX_STREAM_MODE_TAG) { + u16 pad_len; + + pad_len = 4 - (pkt_len & 0x3); + if (pad_len == 4) + pad_len = 0; + + chk_idx = index; + index = index + 4 + pkt_len + pad_len; + + if (index > MAX_RX_BUF_SIZE) { + spin_lock(&hif_dev->rx_lock); + hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE; + hif_dev->rx_transfer_len = + MAX_RX_BUF_SIZE - chk_idx - 4; + hif_dev->rx_pad_len = pad_len; + + nskb = __dev_alloc_skb(pkt_len + 32, + GFP_ATOMIC); + if (!nskb) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: RX memory allocation" + " error\n"); + spin_unlock(&hif_dev->rx_lock); + goto err; + } + skb_reserve(nskb, 32); + RX_STAT_INC(skb_allocated); + + memcpy(nskb->data, &(skb->data[chk_idx+4]), + hif_dev->rx_transfer_len); + + /* Record the buffer pointer */ + hif_dev->remain_skb = nskb; + spin_unlock(&hif_dev->rx_lock); + } else { + nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC); + if (!nskb) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: RX memory allocation" + " error\n"); + goto err; + } + skb_reserve(nskb, 32); + RX_STAT_INC(skb_allocated); + + memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len); + skb_put(nskb, pkt_len); + skb_pool[pool_index++] = nskb; + } + } else { + RX_STAT_INC(skb_dropped); + return; + } + } + +err: + for (i = 0; i < pool_index; i++) { + ath9k_htc_rx_msg(hif_dev->htc_handle, skb_pool[i], + skb_pool[i]->len, USB_WLAN_RX_PIPE); + RX_STAT_INC(skb_completed); + } +} + +static void ath9k_hif_usb_rx_cb(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct hif_device_usb *hif_dev = (struct hif_device_usb *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + int ret; + + if (!skb) + return; + + if (!hif_dev) + goto free; + + switch (urb->status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ENODEV: + case -ESHUTDOWN: + goto free; + default: + goto resubmit; + } + + if (likely(urb->actual_length != 0)) { + skb_put(skb, urb->actual_length); + ath9k_hif_usb_rx_stream(hif_dev, skb); + } + +resubmit: + skb_reset_tail_pointer(skb); + skb_trim(skb, 0); + + usb_anchor_urb(urb, &hif_dev->rx_submitted); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + usb_unanchor_urb(urb); + goto free; + } + + return; +free: + kfree_skb(skb); +} + +static void ath9k_hif_usb_reg_in_cb(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct sk_buff *nskb; + struct hif_device_usb *hif_dev = (struct hif_device_usb *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + int ret; + + if (!skb) + return; + + if (!hif_dev) + goto free; + + switch (urb->status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ENODEV: + case -ESHUTDOWN: + goto free; + default: + goto resubmit; + } + + if (likely(urb->actual_length != 0)) { + skb_put(skb, urb->actual_length); + + /* Process the command first */ + ath9k_htc_rx_msg(hif_dev->htc_handle, skb, + skb->len, USB_REG_IN_PIPE); + + + nskb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC); + if (!nskb) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: REG_IN memory allocation failure\n"); + urb->context = NULL; + return; + } + + usb_fill_int_urb(urb, hif_dev->udev, + usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE), + nskb->data, MAX_REG_IN_BUF_SIZE, + ath9k_hif_usb_reg_in_cb, nskb, 1); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + kfree_skb(nskb); + urb->context = NULL; + } + + return; + } + +resubmit: + skb_reset_tail_pointer(skb); + skb_trim(skb, 0); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) + goto free; + + return; +free: + kfree_skb(skb); + urb->context = NULL; +} + +static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) +{ + struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; + + list_for_each_entry_safe(tx_buf, tx_buf_tmp, + &hif_dev->tx.tx_buf, list) { + usb_kill_urb(tx_buf->urb); + list_del(&tx_buf->list); + usb_free_urb(tx_buf->urb); + kfree(tx_buf->buf); + kfree(tx_buf); + } + + list_for_each_entry_safe(tx_buf, tx_buf_tmp, + &hif_dev->tx.tx_pending, list) { + usb_kill_urb(tx_buf->urb); + list_del(&tx_buf->list); + usb_free_urb(tx_buf->urb); + kfree(tx_buf->buf); + kfree(tx_buf); + } +} + +static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) +{ + struct tx_buf *tx_buf; + int i; + + INIT_LIST_HEAD(&hif_dev->tx.tx_buf); + INIT_LIST_HEAD(&hif_dev->tx.tx_pending); + spin_lock_init(&hif_dev->tx.tx_lock); + __skb_queue_head_init(&hif_dev->tx.tx_skb_queue); + + for (i = 0; i < MAX_TX_URB_NUM; i++) { + tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL); + if (!tx_buf) + goto err; + + tx_buf->buf = kzalloc(MAX_TX_BUF_SIZE, GFP_KERNEL); + if (!tx_buf->buf) + goto err; + + tx_buf->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!tx_buf->urb) + goto err; + + tx_buf->hif_dev = hif_dev; + __skb_queue_head_init(&tx_buf->skb_queue); + + list_add_tail(&tx_buf->list, &hif_dev->tx.tx_buf); + } + + hif_dev->tx.tx_buf_cnt = MAX_TX_URB_NUM; + + return 0; +err: + ath9k_hif_usb_dealloc_tx_urbs(hif_dev); + return -ENOMEM; +} + +static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev) +{ + usb_kill_anchored_urbs(&hif_dev->rx_submitted); +} + +static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev) +{ + struct urb *urb = NULL; + struct sk_buff *skb = NULL; + int i, ret; + + init_usb_anchor(&hif_dev->rx_submitted); + spin_lock_init(&hif_dev->rx_lock); + + for (i = 0; i < MAX_RX_URB_NUM; i++) { + + /* Allocate URB */ + urb = usb_alloc_urb(0, GFP_KERNEL); + if (urb == NULL) { + ret = -ENOMEM; + goto err_urb; + } + + /* Allocate buffer */ + skb = alloc_skb(MAX_RX_BUF_SIZE, GFP_KERNEL); + if (!skb) { + ret = -ENOMEM; + goto err_skb; + } + + usb_fill_bulk_urb(urb, hif_dev->udev, + usb_rcvbulkpipe(hif_dev->udev, + USB_WLAN_RX_PIPE), + skb->data, MAX_RX_BUF_SIZE, + ath9k_hif_usb_rx_cb, skb); + + /* Anchor URB */ + usb_anchor_urb(urb, &hif_dev->rx_submitted); + + /* Submit URB */ + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret) { + usb_unanchor_urb(urb); + goto err_submit; + } + + /* + * Drop reference count. + * This ensures that the URB is freed when killing them. + */ + usb_free_urb(urb); + } + + return 0; + +err_submit: + kfree_skb(skb); +err_skb: + usb_free_urb(urb); +err_urb: + ath9k_hif_usb_dealloc_rx_urbs(hif_dev); + return ret; +} + +static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev) +{ + if (hif_dev->reg_in_urb) { + usb_kill_urb(hif_dev->reg_in_urb); + if (hif_dev->reg_in_urb->context) + kfree_skb((void *)hif_dev->reg_in_urb->context); + usb_free_urb(hif_dev->reg_in_urb); + hif_dev->reg_in_urb = NULL; + } +} + +static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev) +{ + struct sk_buff *skb; + + hif_dev->reg_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (hif_dev->reg_in_urb == NULL) + return -ENOMEM; + + skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL); + if (!skb) + goto err; + + usb_fill_int_urb(hif_dev->reg_in_urb, hif_dev->udev, + usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE), + skb->data, MAX_REG_IN_BUF_SIZE, + ath9k_hif_usb_reg_in_cb, skb, 1); + + if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0) + goto err; + + return 0; + +err: + ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); + return -ENOMEM; +} + +static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) +{ + /* Register Write */ + init_usb_anchor(&hif_dev->regout_submitted); + + /* TX */ + if (ath9k_hif_usb_alloc_tx_urbs(hif_dev) < 0) + goto err; + + /* RX */ + if (ath9k_hif_usb_alloc_rx_urbs(hif_dev) < 0) + goto err; + + /* Register Read */ + if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0) + goto err; + + return 0; +err: + return -ENOMEM; +} + +static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) +{ + usb_kill_anchored_urbs(&hif_dev->regout_submitted); + ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); + ath9k_hif_usb_dealloc_tx_urbs(hif_dev); + ath9k_hif_usb_dealloc_rx_urbs(hif_dev); +} + +static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) +{ + int transfer, err; + const void *data = hif_dev->firmware->data; + size_t len = hif_dev->firmware->size; + u32 addr = AR9271_FIRMWARE; + u8 *buf = kzalloc(4096, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + + while (len) { + transfer = min_t(int, len, 4096); + memcpy(buf, data, transfer); + + err = usb_control_msg(hif_dev->udev, + usb_sndctrlpipe(hif_dev->udev, 0), + FIRMWARE_DOWNLOAD, 0x40 | USB_DIR_OUT, + addr >> 8, 0, buf, transfer, HZ); + if (err < 0) { + kfree(buf); + return err; + } + + len -= transfer; + data += transfer; + addr += transfer; + } + kfree(buf); + + /* + * Issue FW download complete command to firmware. + */ + err = usb_control_msg(hif_dev->udev, usb_sndctrlpipe(hif_dev->udev, 0), + FIRMWARE_DOWNLOAD_COMP, + 0x40 | USB_DIR_OUT, + AR9271_FIRMWARE_TEXT >> 8, 0, NULL, 0, HZ); + if (err) + return -EIO; + + dev_info(&hif_dev->udev->dev, "ath9k_htc: Transferred FW: %s, size: %ld\n", + "ar9271.fw", (unsigned long) hif_dev->firmware->size); + + return 0; +} + +static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev, + const char *fw_name) +{ + int ret; + + /* Request firmware */ + ret = request_firmware(&hif_dev->firmware, fw_name, &hif_dev->udev->dev); + if (ret) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Firmware - %s not found\n", fw_name); + goto err_fw_req; + } + + /* Alloc URBs */ + ret = ath9k_hif_usb_alloc_urbs(hif_dev); + if (ret) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Unable to allocate URBs\n"); + goto err_urb; + } + + /* Download firmware */ + ret = ath9k_hif_usb_download_fw(hif_dev); + if (ret) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Firmware - %s download failed\n", fw_name); + goto err_fw_download; + } + + return 0; + +err_fw_download: + ath9k_hif_usb_dealloc_urbs(hif_dev); +err_urb: + release_firmware(hif_dev->firmware); +err_fw_req: + hif_dev->firmware = NULL; + return ret; +} + +static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev) +{ + ath9k_hif_usb_dealloc_urbs(hif_dev); + if (hif_dev->firmware) + release_firmware(hif_dev->firmware); +} + +static int ath9k_hif_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct hif_device_usb *hif_dev; + const char *fw_name = (const char *) id->driver_info; + int ret = 0; + + hif_dev = kzalloc(sizeof(struct hif_device_usb), GFP_KERNEL); + if (!hif_dev) { + ret = -ENOMEM; + goto err_alloc; + } + + usb_get_dev(udev); + hif_dev->udev = udev; + hif_dev->interface = interface; + hif_dev->device_id = id->idProduct; +#ifdef CONFIG_PM + udev->reset_resume = 1; +#endif + usb_set_intfdata(interface, hif_dev); + + hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb, + &hif_dev->udev->dev); + if (hif_dev->htc_handle == NULL) { + ret = -ENOMEM; + goto err_htc_hw_alloc; + } + + ret = ath9k_hif_usb_dev_init(hif_dev, fw_name); + if (ret) { + ret = -EINVAL; + goto err_hif_init_usb; + } + + ret = ath9k_htc_hw_init(hif_dev->htc_handle, + &hif_dev->udev->dev, hif_dev->device_id); + if (ret) { + ret = -EINVAL; + goto err_htc_hw_init; + } + + dev_info(&hif_dev->udev->dev, "ath9k_htc: USB layer initialized\n"); + + return 0; + +err_htc_hw_init: + ath9k_hif_usb_dev_deinit(hif_dev); +err_hif_init_usb: + ath9k_htc_hw_free(hif_dev->htc_handle); +err_htc_hw_alloc: + usb_set_intfdata(interface, NULL); + kfree(hif_dev); + usb_put_dev(udev); +err_alloc: + return ret; +} + +static void ath9k_hif_usb_reboot(struct usb_device *udev) +{ + u32 reboot_cmd = 0xffffffff; + void *buf; + int ret; + + buf = kmalloc(4, GFP_KERNEL); + if (!buf) + return; + + memcpy(buf, &reboot_cmd, 4); + + ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, USB_REG_OUT_PIPE), + buf, 4, NULL, HZ); + if (ret) + dev_err(&udev->dev, "ath9k_htc: USB reboot failed\n"); + + kfree(buf); +} + +static void ath9k_hif_usb_disconnect(struct usb_interface *interface) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct hif_device_usb *hif_dev = + (struct hif_device_usb *) usb_get_intfdata(interface); + + if (hif_dev) { + ath9k_htc_hw_deinit(hif_dev->htc_handle, + (udev->state == USB_STATE_NOTATTACHED) ? true : false); + ath9k_htc_hw_free(hif_dev->htc_handle); + ath9k_hif_usb_dev_deinit(hif_dev); + usb_set_intfdata(interface, NULL); + } + + if (hif_dev->flags & HIF_USB_START) + ath9k_hif_usb_reboot(udev); + + kfree(hif_dev); + dev_info(&udev->dev, "ath9k_htc: USB layer deinitialized\n"); + usb_put_dev(udev); +} + +#ifdef CONFIG_PM +static int ath9k_hif_usb_suspend(struct usb_interface *interface, + pm_message_t message) +{ + struct hif_device_usb *hif_dev = + (struct hif_device_usb *) usb_get_intfdata(interface); + + ath9k_hif_usb_dealloc_urbs(hif_dev); + + return 0; +} + +static int ath9k_hif_usb_resume(struct usb_interface *interface) +{ + struct hif_device_usb *hif_dev = + (struct hif_device_usb *) usb_get_intfdata(interface); + int ret; + + ret = ath9k_hif_usb_alloc_urbs(hif_dev); + if (ret) + return ret; + + if (hif_dev->firmware) { + ret = ath9k_hif_usb_download_fw(hif_dev); + if (ret) + goto fail_resume; + } else { + ath9k_hif_usb_dealloc_urbs(hif_dev); + return -EIO; + } + + mdelay(100); + + ret = ath9k_htc_resume(hif_dev->htc_handle); + + if (ret) + goto fail_resume; + + return 0; + +fail_resume: + ath9k_hif_usb_dealloc_urbs(hif_dev); + + return ret; +} +#endif + +static struct usb_driver ath9k_hif_usb_driver = { + .name = "ath9k_hif_usb", + .probe = ath9k_hif_usb_probe, + .disconnect = ath9k_hif_usb_disconnect, +#ifdef CONFIG_PM + .suspend = ath9k_hif_usb_suspend, + .resume = ath9k_hif_usb_resume, + .reset_resume = ath9k_hif_usb_resume, +#endif + .id_table = ath9k_hif_usb_ids, + .soft_unbind = 1, +}; + +int ath9k_hif_usb_init(void) +{ + return usb_register(&ath9k_hif_usb_driver); +} + +void ath9k_hif_usb_exit(void) +{ + usb_deregister(&ath9k_hif_usb_driver); +} diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h new file mode 100644 index 00000000000..0aca49b6fcb --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2010 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. + */ + +#ifndef HTC_USB_H +#define HTC_USB_H + +#define AR9271_FIRMWARE 0x501000 +#define AR9271_FIRMWARE_TEXT 0x903000 + +#define FIRMWARE_DOWNLOAD 0x30 +#define FIRMWARE_DOWNLOAD_COMP 0x31 + +#define ATH_USB_RX_STREAM_MODE_TAG 0x4e00 +#define ATH_USB_TX_STREAM_MODE_TAG 0x697e + +/* FIXME: Verify these numbers (with Windows) */ +#define MAX_TX_URB_NUM 8 +#define MAX_TX_BUF_NUM 1024 +#define MAX_TX_BUF_SIZE 32768 +#define MAX_TX_AGGR_NUM 20 + +#define MAX_RX_URB_NUM 8 +#define MAX_RX_BUF_SIZE 16384 +#define MAX_PKT_NUM_IN_TRANSFER 10 + +#define MAX_REG_OUT_URB_NUM 1 +#define MAX_REG_OUT_BUF_NUM 8 + +#define MAX_REG_IN_BUF_SIZE 64 + +/* USB Endpoint definition */ +#define USB_WLAN_TX_PIPE 1 +#define USB_WLAN_RX_PIPE 2 +#define USB_REG_IN_PIPE 3 +#define USB_REG_OUT_PIPE 4 + +#define HIF_USB_MAX_RXPIPES 2 +#define HIF_USB_MAX_TXPIPES 4 + +struct tx_buf { + u8 *buf; + u16 len; + u16 offset; + struct urb *urb; + struct sk_buff_head skb_queue; + struct hif_device_usb *hif_dev; + struct list_head list; +}; + +#define HIF_USB_TX_STOP BIT(0) + +struct hif_usb_tx { + u8 flags; + u8 tx_buf_cnt; + u16 tx_skb_cnt; + struct sk_buff_head tx_skb_queue; + struct list_head tx_buf; + struct list_head tx_pending; + spinlock_t tx_lock; +}; + +struct cmd_buf { + struct sk_buff *skb; + struct hif_device_usb *hif_dev; +}; + +#define HIF_USB_START BIT(0) + +struct hif_device_usb { + u16 device_id; + struct usb_device *udev; + struct usb_interface *interface; + const struct firmware *firmware; + struct htc_target *htc_handle; + struct hif_usb_tx tx; + struct urb *reg_in_urb; + struct usb_anchor regout_submitted; + struct usb_anchor rx_submitted; + struct sk_buff *remain_skb; + int rx_remain_len; + int rx_pkt_len; + int rx_transfer_len; + int rx_pad_len; + spinlock_t rx_lock; + u8 flags; /* HIF_USB_* */ +}; + +int ath9k_hif_usb_init(void); +void ath9k_hif_usb_exit(void); + +#endif /* HTC_USB_H */ diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h new file mode 100644 index 00000000000..ad556aa8da3 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2010 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. + */ + +#ifndef HTC_H +#define HTC_H + +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/firmware.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/leds.h> +#include <net/mac80211.h> + +#include "common.h" +#include "htc_hst.h" +#include "hif_usb.h" +#include "wmi.h" + +#define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */ +#define ATH_ANI_POLLINTERVAL 100 /* 100 ms */ +#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ +#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ + +#define ATH_DEFAULT_BMISS_LIMIT 10 +#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) +#define TSF_TO_TU(_h, _l) \ + ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) + +extern struct ieee80211_ops ath9k_htc_ops; +extern int htc_modparam_nohwcrypt; + +enum htc_phymode { + HTC_MODE_AUTO = 0, + HTC_MODE_11A = 1, + HTC_MODE_11B = 2, + HTC_MODE_11G = 3, + HTC_MODE_FH = 4, + HTC_MODE_TURBO_A = 5, + HTC_MODE_TURBO_G = 6, + HTC_MODE_11NA = 7, + HTC_MODE_11NG = 8 +}; + +enum htc_opmode { + HTC_M_STA = 1, + HTC_M_IBSS = 0, + HTC_M_AHDEMO = 3, + HTC_M_HOSTAP = 6, + HTC_M_MONITOR = 8, + HTC_M_WDS = 2 +}; + +#define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr) +#define ATH9K_HTC_AMPDU 1 +#define ATH9K_HTC_NORMAL 2 + +#define ATH9K_HTC_TX_CTSONLY 0x1 +#define ATH9K_HTC_TX_RTSCTS 0x2 +#define ATH9K_HTC_TX_USE_MIN_RATE 0x100 + +struct tx_frame_hdr { + u8 data_type; + u8 node_idx; + u8 vif_idx; + u8 tidno; + u32 flags; /* ATH9K_HTC_TX_* */ + u8 key_type; + u8 keyix; + u8 reserved[26]; +} __packed; + +struct tx_mgmt_hdr { + u8 node_idx; + u8 vif_idx; + u8 tidno; + u8 flags; + u8 key_type; + u8 keyix; + u16 reserved; +} __packed; + +struct tx_beacon_header { + u8 len_changed; + u8 vif_index; + u16 rev; +} __packed; + +struct ath9k_htc_target_hw { + u32 flags; + u32 flags_ext; + u32 ampdu_limit; + u8 ampdu_subframes; + u8 tx_chainmask; + u8 tx_chainmask_legacy; + u8 rtscts_ratecode; + u8 protmode; +} __packed; + +struct ath9k_htc_cap_target { + u32 flags; + u32 flags_ext; + u32 ampdu_limit; + u8 ampdu_subframes; + u8 tx_chainmask; + u8 tx_chainmask_legacy; + u8 rtscts_ratecode; + u8 protmode; +} __packed; + +struct ath9k_htc_target_vif { + u8 index; + u8 des_bssid[ETH_ALEN]; + __be32 opmode; + u8 myaddr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u32 flags; + u32 flags_ext; + u16 ps_sta; + __be16 rtsthreshold; + u8 ath_cap; + u8 node; + s8 mcast_rate; +} __packed; + +#define ATH_HTC_STA_AUTH 0x0001 +#define ATH_HTC_STA_QOS 0x0002 +#define ATH_HTC_STA_ERP 0x0004 +#define ATH_HTC_STA_HT 0x0008 + +/* FIXME: UAPSD variables */ +struct ath9k_htc_target_sta { + u16 associd; + u16 txpower; + u32 ucastkey; + u8 macaddr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u8 sta_index; + u8 vif_index; + u8 vif_sta; + __be16 flags; /* ATH_HTC_STA_* */ + u16 htcap; + u8 valid; + u16 capinfo; + struct ath9k_htc_target_hw *hw; + struct ath9k_htc_target_vif *vif; + u16 txseqmgmt; + u8 is_vif_sta; + u16 maxampdu; + u16 iv16; + u32 iv32; +} __packed; + +struct ath9k_htc_target_aggr { + u8 sta_index; + u8 tidno; + u8 aggr_enable; + u8 padding; +} __packed; + +#define ATH_HTC_RATE_MAX 30 + +#define WLAN_RC_DS_FLAG 0x01 +#define WLAN_RC_40_FLAG 0x02 +#define WLAN_RC_SGI_FLAG 0x04 +#define WLAN_RC_HT_FLAG 0x08 + +struct ath9k_htc_rateset { + u8 rs_nrates; + u8 rs_rates[ATH_HTC_RATE_MAX]; +}; + +struct ath9k_htc_rate { + struct ath9k_htc_rateset legacy_rates; + struct ath9k_htc_rateset ht_rates; +} __packed; + +struct ath9k_htc_target_rate { + u8 sta_index; + u8 isnew; + __be32 capflags; + struct ath9k_htc_rate rates; +}; + +struct ath9k_htc_target_stats { + __be32 tx_shortretry; + __be32 tx_longretry; + __be32 tx_xretries; + __be32 ht_txunaggr_xretry; + __be32 ht_tx_xretries; +} __packed; + +struct ath9k_htc_vif { + u8 index; +}; + +#define ATH9K_HTC_MAX_STA 8 +#define ATH9K_HTC_MAX_TID 8 + +enum tid_aggr_state { + AGGR_STOP = 0, + AGGR_PROGRESS, + AGGR_START, + AGGR_OPERATIONAL +}; + +struct ath9k_htc_sta { + u8 index; + enum tid_aggr_state tid_state[ATH9K_HTC_MAX_TID]; +}; + +struct ath9k_htc_aggr_work { + u16 tid; + u8 sta_addr[ETH_ALEN]; + struct ieee80211_hw *hw; + struct ieee80211_vif *vif; + enum ieee80211_ampdu_mlme_action action; + struct mutex mutex; +}; + +#define ATH9K_HTC_RXBUF 256 +#define HTC_RX_FRAME_HEADER_SIZE 40 + +struct ath9k_htc_rxbuf { + bool in_process; + struct sk_buff *skb; + struct ath_htc_rx_status rxstatus; + struct list_head list; +}; + +struct ath9k_htc_rx { + int last_rssi; /* FIXME: per-STA */ + struct list_head rxbuf; + spinlock_t rxbuflock; +}; + +struct ath9k_htc_tx_ctl { + u8 type; /* ATH9K_HTC_* */ +}; + +#ifdef CONFIG_ATH9K_HTC_DEBUGFS + +#define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) +#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) + +struct ath_tx_stats { + u32 buf_queued; + u32 buf_completed; + u32 skb_queued; + u32 skb_completed; + u32 skb_dropped; +}; + +struct ath_rx_stats { + u32 skb_allocated; + u32 skb_completed; + u32 skb_dropped; +}; + +struct ath9k_debug { + struct dentry *debugfs_phy; + struct dentry *debugfs_tgt_stats; + struct dentry *debugfs_xmit; + struct dentry *debugfs_recv; + struct ath_tx_stats tx_stats; + struct ath_rx_stats rx_stats; + u32 txrate; +}; + +#else + +#define TX_STAT_INC(c) do { } while (0) +#define RX_STAT_INC(c) do { } while (0) + +#endif /* CONFIG_ATH9K_HTC_DEBUGFS */ + +#define ATH_LED_PIN_DEF 1 +#define ATH_LED_PIN_9287 8 +#define ATH_LED_PIN_9271 15 +#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ +#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ + +enum ath_led_type { + ATH_LED_RADIO, + ATH_LED_ASSOC, + ATH_LED_TX, + ATH_LED_RX +}; + +struct ath_led { + struct ath9k_htc_priv *priv; + struct led_classdev led_cdev; + enum ath_led_type led_type; + struct delayed_work brightness_work; + char name[32]; + bool registered; + int brightness; +}; + +struct htc_beacon_config { + u16 beacon_interval; + u16 listen_interval; + u16 dtim_period; + u16 bmiss_timeout; + u8 dtim_count; +}; + +#define OP_INVALID BIT(0) +#define OP_SCANNING BIT(1) +#define OP_FULL_RESET BIT(2) +#define OP_LED_ASSOCIATED BIT(3) +#define OP_LED_ON BIT(4) +#define OP_PREAMBLE_SHORT BIT(5) +#define OP_PROTECT_ENABLE BIT(6) +#define OP_TXAGGR BIT(7) +#define OP_ASSOCIATED BIT(8) +#define OP_ENABLE_BEACON BIT(9) +#define OP_LED_DEINIT BIT(10) +#define OP_UNPLUGGED BIT(11) + +struct ath9k_htc_priv { + struct device *dev; + struct ieee80211_hw *hw; + struct ath_hw *ah; + struct htc_target *htc; + struct wmi *wmi; + + enum htc_endpoint_id wmi_cmd_ep; + enum htc_endpoint_id beacon_ep; + enum htc_endpoint_id cab_ep; + enum htc_endpoint_id uapsd_ep; + enum htc_endpoint_id mgmt_ep; + enum htc_endpoint_id data_be_ep; + enum htc_endpoint_id data_bk_ep; + enum htc_endpoint_id data_vi_ep; + enum htc_endpoint_id data_vo_ep; + + u16 op_flags; + u16 curtxpow; + u16 txpowlimit; + u16 nvifs; + u16 nstations; + u16 seq_no; + u32 bmiss_cnt; + + spinlock_t beacon_lock; + + bool tx_queues_stop; + spinlock_t tx_lock; + + struct ieee80211_vif *vif; + struct htc_beacon_config cur_beacon_conf; + unsigned int rxfilter; + struct tasklet_struct wmi_tasklet; + struct tasklet_struct rx_tasklet; + struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; + struct ath9k_htc_rx rx; + struct tasklet_struct tx_tasklet; + struct sk_buff_head tx_queue; + struct ath9k_htc_aggr_work aggr_work; + struct delayed_work ath9k_aggr_work; + struct delayed_work ath9k_ani_work; + struct work_struct ps_work; + + struct mutex htc_pm_lock; + unsigned long ps_usecount; + bool ps_enabled; + bool ps_idle; + + struct ath_led radio_led; + struct ath_led assoc_led; + struct ath_led tx_led; + struct ath_led rx_led; + struct delayed_work ath9k_led_blink_work; + int led_on_duration; + int led_off_duration; + int led_on_cnt; + int led_off_cnt; + int hwq_map[ATH9K_WME_AC_VO+1]; + +#ifdef CONFIG_ATH9K_HTC_DEBUGFS + struct ath9k_debug debug; +#endif + struct ath9k_htc_target_rate tgt_rate; + + struct mutex mutex; +}; + +static inline void ath_read_cachesize(struct ath_common *common, int *csz) +{ + common->bus_ops->read_cachesize(common, csz); +} + +void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif); +void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending); + +void ath9k_htc_rxep(void *priv, struct sk_buff *skb, + enum htc_endpoint_id ep_id); +void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, + bool txok); +void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, + enum htc_endpoint_id ep_id, bool txok); + +void ath9k_htc_station_work(struct work_struct *work); +void ath9k_htc_aggr_work(struct work_struct *work); +void ath9k_ani_work(struct work_struct *work);; + +int ath9k_tx_init(struct ath9k_htc_priv *priv); +void ath9k_tx_tasklet(unsigned long data); +int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb); +void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); +bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, + enum ath9k_tx_queue_subtype qtype); +int get_hw_qnum(u16 queue, int *hwq_map); +int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, + struct ath9k_tx_queue_info *qinfo); + +int ath9k_rx_init(struct ath9k_htc_priv *priv); +void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); +void ath9k_host_rx_init(struct ath9k_htc_priv *priv); +void ath9k_rx_tasklet(unsigned long data); +u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv); + +void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv); +void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv); +void ath9k_ps_work(struct work_struct *work); + +void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); +void ath9k_init_leds(struct ath9k_htc_priv *priv); +void ath9k_deinit_leds(struct ath9k_htc_priv *priv); + +int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, + u16 devid); +void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug); +#ifdef CONFIG_PM +int ath9k_htc_resume(struct htc_target *htc_handle); +#endif +#ifdef CONFIG_ATH9K_HTC_DEBUGFS +int ath9k_htc_debug_create_root(void); +void ath9k_htc_debug_remove_root(void); +int ath9k_htc_init_debug(struct ath_hw *ah); +void ath9k_htc_exit_debug(struct ath_hw *ah); +#else +static inline int ath9k_htc_debug_create_root(void) { return 0; }; +static inline void ath9k_htc_debug_remove_root(void) {}; +static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; }; +static inline void ath9k_htc_exit_debug(struct ath_hw *ah) {}; +#endif /* CONFIG_ATH9K_HTC_DEBUGFS */ + +#endif /* HTC_H */ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c new file mode 100644 index 00000000000..c10c7d002eb --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2010 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 "htc.h" + +#define FUDGE 2 + +static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, + struct htc_beacon_config *bss_conf) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_beacon_state bs; + enum ath9k_int imask = 0; + int dtimperiod, dtimcount, sleepduration; + int cfpperiod, cfpcount, bmiss_timeout; + u32 nexttbtt = 0, intval, tsftu; + __be32 htc_imask = 0; + u64 tsf; + int num_beacons, offset, dtim_dec_count, cfp_dec_count; + int ret; + u8 cmd_rsp; + + memset(&bs, 0, sizeof(bs)); + + intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; + bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval); + + /* + * Setup dtim and cfp parameters according to + * last beacon we received (which may be none). + */ + dtimperiod = bss_conf->dtim_period; + if (dtimperiod <= 0) /* NB: 0 if not known */ + dtimperiod = 1; + dtimcount = 1; + if (dtimcount >= dtimperiod) /* NB: sanity check */ + dtimcount = 0; + cfpperiod = 1; /* NB: no PCF support yet */ + cfpcount = 0; + + sleepduration = intval; + if (sleepduration <= 0) + sleepduration = intval; + + /* + * Pull nexttbtt forward to reflect the current + * TSF and calculate dtim+cfp state for the result. + */ + tsf = ath9k_hw_gettsf64(priv->ah); + tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; + + num_beacons = tsftu / intval + 1; + offset = tsftu % intval; + nexttbtt = tsftu - offset; + if (offset) + nexttbtt += intval; + + /* DTIM Beacon every dtimperiod Beacon */ + dtim_dec_count = num_beacons % dtimperiod; + /* CFP every cfpperiod DTIM Beacon */ + cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; + if (dtim_dec_count) + cfp_dec_count++; + + dtimcount -= dtim_dec_count; + if (dtimcount < 0) + dtimcount += dtimperiod; + + cfpcount -= cfp_dec_count; + if (cfpcount < 0) + cfpcount += cfpperiod; + + bs.bs_intval = intval; + bs.bs_nexttbtt = nexttbtt; + bs.bs_dtimperiod = dtimperiod*intval; + bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; + bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; + bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; + bs.bs_cfpmaxduration = 0; + + /* + * Calculate the number of consecutive beacons to miss* before taking + * a BMISS interrupt. The configuration is specified in TU so we only + * need calculate based on the beacon interval. Note that we clamp the + * result to at most 15 beacons. + */ + if (sleepduration > intval) { + bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2; + } else { + bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval); + if (bs.bs_bmissthreshold > 15) + bs.bs_bmissthreshold = 15; + else if (bs.bs_bmissthreshold <= 0) + bs.bs_bmissthreshold = 1; + } + + /* + * Calculate sleep duration. The configuration is given in ms. + * We ensure a multiple of the beacon period is used. Also, if the sleep + * duration is greater than the DTIM period then it makes senses + * to make it a multiple of that. + * + * XXX fixed at 100ms + */ + + bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); + if (bs.bs_sleepduration > bs.bs_dtimperiod) + bs.bs_sleepduration = bs.bs_dtimperiod; + + /* TSF out of range threshold fixed at 1 second */ + bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; + + ath_print(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); + ath_print(common, ATH_DBG_BEACON, + "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", + bs.bs_bmissthreshold, bs.bs_sleepduration, + bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); + + /* Set the computed STA beacon timers */ + + WMI_CMD(WMI_DISABLE_INTR_CMDID); + ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); + imask |= ATH9K_INT_BMISS; + htc_imask = cpu_to_be32(imask); + WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); +} + +static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, + struct htc_beacon_config *bss_conf) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + enum ath9k_int imask = 0; + u32 nexttbtt, intval; + __be32 htc_imask = 0; + int ret; + u8 cmd_rsp; + + intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD; + nexttbtt = intval; + intval |= ATH9K_BEACON_ENA; + if (priv->op_flags & OP_ENABLE_BEACON) + imask |= ATH9K_INT_SWBA; + + ath_print(common, ATH_DBG_BEACON, + "IBSS Beacon config, intval: %d, imask: 0x%x\n", + bss_conf->beacon_interval, imask); + + WMI_CMD(WMI_DISABLE_INTR_CMDID); + ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); + priv->bmiss_cnt = 0; + htc_imask = cpu_to_be32(imask); + WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); +} + +void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, + enum htc_endpoint_id ep_id, bool txok) +{ + dev_kfree_skb_any(skb); +} + +void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) +{ + struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv; + struct tx_beacon_header beacon_hdr; + struct ath9k_htc_tx_ctl tx_ctl; + struct ieee80211_tx_info *info; + struct sk_buff *beacon; + u8 *tx_fhdr; + + memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); + memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); + + /* FIXME: Handle BMISS */ + if (beacon_pending != 0) { + priv->bmiss_cnt++; + return; + } + + spin_lock_bh(&priv->beacon_lock); + + if (unlikely(priv->op_flags & OP_SCANNING)) { + spin_unlock_bh(&priv->beacon_lock); + return; + } + + /* Get a new beacon */ + beacon = ieee80211_beacon_get(priv->hw, priv->vif); + if (!beacon) { + spin_unlock_bh(&priv->beacon_lock); + return; + } + + info = IEEE80211_SKB_CB(beacon); + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) beacon->data; + priv->seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(priv->seq_no); + } + + tx_ctl.type = ATH9K_HTC_NORMAL; + beacon_hdr.vif_index = avp->index; + tx_fhdr = skb_push(beacon, sizeof(beacon_hdr)); + memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); + + htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl); + + spin_unlock_bh(&priv->beacon_lock); +} + + +void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + + cur_conf->beacon_interval = bss_conf->beacon_int; + if (cur_conf->beacon_interval == 0) + cur_conf->beacon_interval = 100; + + cur_conf->dtim_period = bss_conf->dtim_period; + cur_conf->listen_interval = 1; + cur_conf->dtim_count = 1; + cur_conf->bmiss_timeout = + ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + ath9k_htc_beacon_config_sta(priv, cur_conf); + break; + case NL80211_IFTYPE_ADHOC: + ath9k_htc_beacon_config_adhoc(priv, cur_conf); + break; + default: + ath_print(common, ATH_DBG_CONFIG, + "Unsupported beaconing mode\n"); + return; + } +} diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c new file mode 100644 index 00000000000..dc015077a8d --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -0,0 +1,834 @@ +/* + * Copyright (c) 2010 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 "htc.h" + +MODULE_AUTHOR("Atheros Communications"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("Atheros driver 802.11n HTC based wireless devices"); + +static unsigned int ath9k_debug = ATH_DBG_DEFAULT; +module_param_named(debug, ath9k_debug, uint, 0); +MODULE_PARM_DESC(debug, "Debugging mask"); + +int htc_modparam_nohwcrypt; +module_param_named(nohwcrypt, htc_modparam_nohwcrypt, int, 0444); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); + +#define CHAN2G(_freq, _idx) { \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +static struct ieee80211_channel ath9k_2ghz_channels[] = { + CHAN2G(2412, 0), /* Channel 1 */ + CHAN2G(2417, 1), /* Channel 2 */ + CHAN2G(2422, 2), /* Channel 3 */ + CHAN2G(2427, 3), /* Channel 4 */ + CHAN2G(2432, 4), /* Channel 5 */ + CHAN2G(2437, 5), /* Channel 6 */ + CHAN2G(2442, 6), /* Channel 7 */ + CHAN2G(2447, 7), /* Channel 8 */ + CHAN2G(2452, 8), /* Channel 9 */ + CHAN2G(2457, 9), /* Channel 10 */ + CHAN2G(2462, 10), /* Channel 11 */ + CHAN2G(2467, 11), /* Channel 12 */ + CHAN2G(2472, 12), /* Channel 13 */ + CHAN2G(2484, 13), /* Channel 14 */ +}; + +/* Atheros hardware rate code addition for short premble */ +#define SHPCHECK(__hw_rate, __flags) \ + ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0) + +#define RATE(_bitrate, _hw_rate, _flags) { \ + .bitrate = (_bitrate), \ + .flags = (_flags), \ + .hw_value = (_hw_rate), \ + .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ +} + +static struct ieee80211_rate ath9k_legacy_rates[] = { + RATE(10, 0x1b, 0), + RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */ + RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */ + RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */ + RATE(60, 0x0b, 0), + RATE(90, 0x0f, 0), + RATE(120, 0x0a, 0), + RATE(180, 0x0e, 0), + RATE(240, 0x09, 0), + RATE(360, 0x0d, 0), + RATE(480, 0x08, 0), + RATE(540, 0x0c, 0), +}; + +static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) +{ + int time_left; + + if (atomic_read(&priv->htc->tgt_ready) > 0) { + atomic_dec(&priv->htc->tgt_ready); + return 0; + } + + /* Firmware can take up to 50ms to get ready, to be safe use 1 second */ + time_left = wait_for_completion_timeout(&priv->htc->target_wait, HZ); + if (!time_left) { + dev_err(priv->dev, "ath9k_htc: Target is unresponsive\n"); + return -ETIMEDOUT; + } + + atomic_dec(&priv->htc->tgt_ready); + + return 0; +} + +static void ath9k_deinit_priv(struct ath9k_htc_priv *priv) +{ + ath9k_htc_exit_debug(priv->ah); + ath9k_hw_deinit(priv->ah); + tasklet_kill(&priv->wmi_tasklet); + tasklet_kill(&priv->rx_tasklet); + tasklet_kill(&priv->tx_tasklet); + kfree(priv->ah); + priv->ah = NULL; +} + +static void ath9k_deinit_device(struct ath9k_htc_priv *priv) +{ + struct ieee80211_hw *hw = priv->hw; + + wiphy_rfkill_stop_polling(hw->wiphy); + ath9k_deinit_leds(priv); + ieee80211_unregister_hw(hw); + ath9k_rx_cleanup(priv); + ath9k_tx_cleanup(priv); + ath9k_deinit_priv(priv); +} + +static inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv, + u16 service_id, + void (*tx) (void *, + struct sk_buff *, + enum htc_endpoint_id, + bool txok), + enum htc_endpoint_id *ep_id) +{ + struct htc_service_connreq req; + + memset(&req, 0, sizeof(struct htc_service_connreq)); + + req.service_id = service_id; + req.ep_callbacks.priv = priv; + req.ep_callbacks.rx = ath9k_htc_rxep; + req.ep_callbacks.tx = tx; + + return htc_connect_service(priv->htc, &req, ep_id); +} + +static int ath9k_init_htc_services(struct ath9k_htc_priv *priv) +{ + int ret; + + /* WMI CMD*/ + ret = ath9k_wmi_connect(priv->htc, priv->wmi, &priv->wmi_cmd_ep); + if (ret) + goto err; + + /* Beacon */ + ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, ath9k_htc_beaconep, + &priv->beacon_ep); + if (ret) + goto err; + + /* CAB */ + ret = ath9k_htc_connect_svc(priv, WMI_CAB_SVC, ath9k_htc_txep, + &priv->cab_ep); + if (ret) + goto err; + + + /* UAPSD */ + ret = ath9k_htc_connect_svc(priv, WMI_UAPSD_SVC, ath9k_htc_txep, + &priv->uapsd_ep); + if (ret) + goto err; + + /* MGMT */ + ret = ath9k_htc_connect_svc(priv, WMI_MGMT_SVC, ath9k_htc_txep, + &priv->mgmt_ep); + if (ret) + goto err; + + /* DATA BE */ + ret = ath9k_htc_connect_svc(priv, WMI_DATA_BE_SVC, ath9k_htc_txep, + &priv->data_be_ep); + if (ret) + goto err; + + /* DATA BK */ + ret = ath9k_htc_connect_svc(priv, WMI_DATA_BK_SVC, ath9k_htc_txep, + &priv->data_bk_ep); + if (ret) + goto err; + + /* DATA VI */ + ret = ath9k_htc_connect_svc(priv, WMI_DATA_VI_SVC, ath9k_htc_txep, + &priv->data_vi_ep); + if (ret) + goto err; + + /* DATA VO */ + ret = ath9k_htc_connect_svc(priv, WMI_DATA_VO_SVC, ath9k_htc_txep, + &priv->data_vo_ep); + if (ret) + goto err; + + ret = htc_init(priv->htc); + if (ret) + goto err; + + return 0; + +err: + dev_err(priv->dev, "ath9k_htc: Unable to initialize HTC services\n"); + return ret; +} + +static int ath9k_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct ath9k_htc_priv *priv = hw->priv; + + return ath_reg_notifier_apply(wiphy, request, + ath9k_hw_regulatory(priv->ah)); +} + +static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + __be32 val, reg = cpu_to_be32(reg_offset); + int r; + + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID, + (u8 *) ®, sizeof(reg), + (u8 *) &val, sizeof(val), + 100); + if (unlikely(r)) { + ath_print(common, ATH_DBG_WMI, + "REGISTER READ FAILED: (0x%04x, %d)\n", + reg_offset, r); + return -EIO; + } + + return be32_to_cpu(val); +} + +static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + __be32 buf[2] = { + cpu_to_be32(reg_offset), + cpu_to_be32(val), + }; + int r; + + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, + (u8 *) &buf, sizeof(buf), + (u8 *) &val, sizeof(val), + 100); + if (unlikely(r)) { + ath_print(common, ATH_DBG_WMI, + "REGISTER WRITE FAILED:(0x%04x, %d)\n", + reg_offset, r); + } +} + +static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + u32 rsp_status; + int r; + + mutex_lock(&priv->wmi->multi_write_mutex); + + /* Store the register/value */ + priv->wmi->multi_write[priv->wmi->multi_write_idx].reg = + cpu_to_be32(reg_offset); + priv->wmi->multi_write[priv->wmi->multi_write_idx].val = + cpu_to_be32(val); + + priv->wmi->multi_write_idx++; + + /* If the buffer is full, send it out. */ + if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) { + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, + (u8 *) &priv->wmi->multi_write, + sizeof(struct register_write) * priv->wmi->multi_write_idx, + (u8 *) &rsp_status, sizeof(rsp_status), + 100); + if (unlikely(r)) { + ath_print(common, ATH_DBG_WMI, + "REGISTER WRITE FAILED, multi len: %d\n", + priv->wmi->multi_write_idx); + } + priv->wmi->multi_write_idx = 0; + } + + mutex_unlock(&priv->wmi->multi_write_mutex); +} + +static void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + + if (atomic_read(&priv->wmi->mwrite_cnt)) + ath9k_regwrite_buffer(hw_priv, val, reg_offset); + else + ath9k_regwrite_single(hw_priv, val, reg_offset); +} + +static void ath9k_enable_regwrite_buffer(void *hw_priv) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + + atomic_inc(&priv->wmi->mwrite_cnt); +} + +static void ath9k_disable_regwrite_buffer(void *hw_priv) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + + atomic_dec(&priv->wmi->mwrite_cnt); +} + +static void ath9k_regwrite_flush(void *hw_priv) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + u32 rsp_status; + int r; + + mutex_lock(&priv->wmi->multi_write_mutex); + + if (priv->wmi->multi_write_idx) { + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, + (u8 *) &priv->wmi->multi_write, + sizeof(struct register_write) * priv->wmi->multi_write_idx, + (u8 *) &rsp_status, sizeof(rsp_status), + 100); + if (unlikely(r)) { + ath_print(common, ATH_DBG_WMI, + "REGISTER WRITE FAILED, multi len: %d\n", + priv->wmi->multi_write_idx); + } + priv->wmi->multi_write_idx = 0; + } + + mutex_unlock(&priv->wmi->multi_write_mutex); +} + +static const struct ath_ops ath9k_common_ops = { + .read = ath9k_regread, + .write = ath9k_regwrite, + .enable_write_buffer = ath9k_enable_regwrite_buffer, + .disable_write_buffer = ath9k_disable_regwrite_buffer, + .write_flush = ath9k_regwrite_flush, +}; + +static void ath_usb_read_cachesize(struct ath_common *common, int *csz) +{ + *csz = L1_CACHE_BYTES >> 2; +} + +static bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data) +{ + struct ath_hw *ah = (struct ath_hw *) common->ah; + + (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + + if (!ath9k_hw_wait(ah, + AR_EEPROM_STATUS_DATA, + AR_EEPROM_STATUS_DATA_BUSY | + AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, + AH_WAIT_TIMEOUT)) + return false; + + *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), + AR_EEPROM_STATUS_DATA_VAL); + + return true; +} + +static const struct ath_bus_ops ath9k_usb_bus_ops = { + .ath_bus_type = ATH_USB, + .read_cachesize = ath_usb_read_cachesize, + .eeprom_read = ath_usb_eeprom_read, +}; + +static void setup_ht_cap(struct ath9k_htc_priv *priv, + struct ieee80211_sta_ht_cap *ht_info) +{ + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; + + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + ht_info->mcs.rx_mask[0] = 0xff; + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; +} + +static int ath9k_init_queues(struct ath9k_htc_priv *priv) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + int i; + + for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++) + priv->hwq_map[i] = -1; + + if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_BE)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for BE traffic\n"); + goto err; + } + + if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_BK)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for BK traffic\n"); + goto err; + } + if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_VI)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for VI traffic\n"); + goto err; + } + if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_VO)) { + ath_print(common, ATH_DBG_FATAL, + "Unable to setup xmit queue for VO traffic\n"); + goto err; + } + + return 0; + +err: + return -EINVAL; +} + +static void ath9k_init_crypto(struct ath9k_htc_priv *priv) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + int i = 0; + + /* Get the hardware key cache size. */ + common->keymax = priv->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, 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 < common->keymax; i++) + ath9k_hw_keyreset(priv->ah, (u16) i); + + if (ath9k_hw_getcapability(priv->ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL)) { + /* + * Whether we should enable h/w TKIP MIC. + * XXX: if we don't support WME TKIP MIC, then we wouldn't + * report WMM capable, so it's always safe to turn on + * TKIP MIC in this case. + */ + ath9k_hw_setcapability(priv->ah, ATH9K_CAP_TKIP_MIC, 0, 1, NULL); + } + + /* + * Check whether the separate key cache entries + * are required to handle both tx+rx MIC keys. + * With split mic keys the number of stations is limited + * to 27 otherwise 59. + */ + if (ath9k_hw_getcapability(priv->ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL) + && ath9k_hw_getcapability(priv->ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_MIC, NULL) + && ath9k_hw_getcapability(priv->ah, ATH9K_CAP_TKIP_SPLIT, + 0, NULL)) + common->splitmic = 1; + + /* turn on mcast key search if possible */ + if (!ath9k_hw_getcapability(priv->ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) + (void)ath9k_hw_setcapability(priv->ah, ATH9K_CAP_MCAST_KEYSRCH, + 1, 1, NULL); +} + +static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) +{ + if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) { + priv->sbands[IEEE80211_BAND_2GHZ].channels = + ath9k_2ghz_channels; + priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; + priv->sbands[IEEE80211_BAND_2GHZ].n_channels = + ARRAY_SIZE(ath9k_2ghz_channels); + priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; + priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates); + } +} + +static void ath9k_init_misc(struct ath9k_htc_priv *priv) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + + common->tx_chainmask = priv->ah->caps.tx_chainmask; + common->rx_chainmask = priv->ah->caps.rx_chainmask; + + if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + + priv->op_flags |= OP_TXAGGR; + priv->ah->opmode = NL80211_IFTYPE_STATION; +} + +static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid) +{ + struct ath_hw *ah = NULL; + struct ath_common *common; + int ret = 0, csz = 0; + + priv->op_flags |= OP_INVALID; + + ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); + if (!ah) + return -ENOMEM; + + ah->hw_version.devid = devid; + ah->hw_version.subsysid = 0; /* FIXME */ + priv->ah = ah; + + common = ath9k_hw_common(ah); + common->ops = &ath9k_common_ops; + common->bus_ops = &ath9k_usb_bus_ops; + common->ah = ah; + common->hw = priv->hw; + common->priv = priv; + common->debug_mask = ath9k_debug; + + spin_lock_init(&priv->wmi->wmi_lock); + spin_lock_init(&priv->beacon_lock); + spin_lock_init(&priv->tx_lock); + mutex_init(&priv->mutex); + mutex_init(&priv->aggr_work.mutex); + mutex_init(&priv->htc_pm_lock); + tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet, + (unsigned long)priv); + tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, + (unsigned long)priv); + tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv); + INIT_DELAYED_WORK(&priv->ath9k_aggr_work, ath9k_htc_aggr_work); + INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work); + INIT_WORK(&priv->ps_work, ath9k_ps_work); + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + ath_read_cachesize(common, &csz); + common->cachelsz = csz << 2; /* convert to bytes */ + + ret = ath9k_hw_init(ah); + if (ret) { + ath_print(common, ATH_DBG_FATAL, + "Unable to initialize hardware; " + "initialization status: %d\n", ret); + goto err_hw; + } + + ret = ath9k_htc_init_debug(ah); + if (ret) { + ath_print(common, ATH_DBG_FATAL, + "Unable to create debugfs files\n"); + goto err_debug; + } + + ret = ath9k_init_queues(priv); + if (ret) + goto err_queues; + + ath9k_init_crypto(priv); + ath9k_init_channels_rates(priv); + ath9k_init_misc(priv); + + return 0; + +err_queues: + ath9k_htc_exit_debug(ah); +err_debug: + ath9k_hw_deinit(ah); +err_hw: + + kfree(ah); + priv->ah = NULL; + + return ret; +} + +static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, + struct ieee80211_hw *hw) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + + hw->flags = IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_SPECTRUM_MGMT | + IEEE80211_HW_HAS_RATE_CONTROL | + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + + hw->queues = 4; + hw->channel_change_time = 5000; + hw->max_listen_interval = 10; + hw->vif_data_size = sizeof(struct ath9k_htc_vif); + hw->sta_data_size = sizeof(struct ath9k_htc_sta); + + /* tx_frame_hdr is larger than tx_mgmt_hdr anyway */ + hw->extra_tx_headroom = sizeof(struct tx_frame_hdr) + + sizeof(struct htc_frame_hdr) + 4; + + if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &priv->sbands[IEEE80211_BAND_2GHZ]; + + if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) + setup_ht_cap(priv, + &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap); + } + + SET_IEEE80211_PERM_ADDR(hw, common->macaddr); +} + +static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid) +{ + struct ieee80211_hw *hw = priv->hw; + struct ath_common *common; + struct ath_hw *ah; + int error = 0; + struct ath_regulatory *reg; + + /* Bring up device */ + error = ath9k_init_priv(priv, devid); + if (error != 0) + goto err_init; + + ah = priv->ah; + common = ath9k_hw_common(ah); + ath9k_set_hw_capab(priv, hw); + + /* Initialize regulatory */ + error = ath_regd_init(&common->regulatory, priv->hw->wiphy, + ath9k_reg_notifier); + if (error) + goto err_regd; + + reg = &common->regulatory; + + /* Setup TX */ + error = ath9k_tx_init(priv); + if (error != 0) + goto err_tx; + + /* Setup RX */ + error = ath9k_rx_init(priv); + if (error != 0) + goto err_rx; + + /* Register with mac80211 */ + error = ieee80211_register_hw(hw); + if (error) + goto err_register; + + /* Handle world regulatory */ + if (!ath_is_world_regd(reg)) { + error = regulatory_hint(hw->wiphy, reg->alpha2); + if (error) + goto err_world; + } + + ath9k_init_leds(priv); + ath9k_start_rfkill_poll(priv); + + return 0; + +err_world: + ieee80211_unregister_hw(hw); +err_register: + ath9k_rx_cleanup(priv); +err_rx: + ath9k_tx_cleanup(priv); +err_tx: + /* Nothing */ +err_regd: + ath9k_deinit_priv(priv); +err_init: + return error; +} + +int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, + u16 devid) +{ + struct ieee80211_hw *hw; + struct ath9k_htc_priv *priv; + int ret; + + hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops); + if (!hw) + return -ENOMEM; + + priv = hw->priv; + priv->hw = hw; + priv->htc = htc_handle; + priv->dev = dev; + htc_handle->drv_priv = priv; + SET_IEEE80211_DEV(hw, priv->dev); + + ret = ath9k_htc_wait_for_target(priv); + if (ret) + goto err_free; + + priv->wmi = ath9k_init_wmi(priv); + if (!priv->wmi) { + ret = -EINVAL; + goto err_free; + } + + ret = ath9k_init_htc_services(priv); + if (ret) + goto err_init; + + /* The device may have been unplugged earlier. */ + priv->op_flags &= ~OP_UNPLUGGED; + + ret = ath9k_init_device(priv, devid); + if (ret) + goto err_init; + + return 0; + +err_init: + ath9k_deinit_wmi(priv); +err_free: + ieee80211_free_hw(hw); + return ret; +} + +void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug) +{ + if (htc_handle->drv_priv) { + + /* Check if the device has been yanked out. */ + if (hotunplug) + htc_handle->drv_priv->op_flags |= OP_UNPLUGGED; + + ath9k_deinit_device(htc_handle->drv_priv); + ath9k_deinit_wmi(htc_handle->drv_priv); + ieee80211_free_hw(htc_handle->drv_priv->hw); + } +} + +#ifdef CONFIG_PM +int ath9k_htc_resume(struct htc_target *htc_handle) +{ + int ret; + + ret = ath9k_htc_wait_for_target(htc_handle->drv_priv); + if (ret) + return ret; + + ret = ath9k_init_htc_services(htc_handle->drv_priv); + return ret; +} +#endif + +static int __init ath9k_htc_init(void) +{ + int error; + + error = ath9k_htc_debug_create_root(); + if (error < 0) { + printk(KERN_ERR + "ath9k_htc: Unable to create debugfs root: %d\n", + error); + goto err_dbg; + } + + error = ath9k_hif_usb_init(); + if (error < 0) { + printk(KERN_ERR + "ath9k_htc: No USB devices found," + " driver not installed.\n"); + error = -ENODEV; + goto err_usb; + } + + return 0; + +err_usb: + ath9k_htc_debug_remove_root(); +err_dbg: + return error; +} +module_init(ath9k_htc_init); + +static void __exit ath9k_htc_exit(void) +{ + ath9k_hif_usb_exit(); + ath9k_htc_debug_remove_root(); + printk(KERN_INFO "ath9k_htc: Driver unloaded\n"); +} +module_exit(ath9k_htc_exit); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c new file mode 100644 index 00000000000..9d371c18eb4 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -0,0 +1,1775 @@ +/* + * Copyright (c) 2010 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 "htc.h" + +#ifdef CONFIG_ATH9K_HTC_DEBUGFS +static struct dentry *ath9k_debugfs_root; +#endif + +/*************/ +/* Utilities */ +/*************/ + +static void ath_update_txpow(struct ath9k_htc_priv *priv) +{ + struct ath_hw *ah = priv->ah; + u32 txpow; + + if (priv->curtxpow != priv->txpowlimit) { + ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit); + /* read back in case value is clamped */ + ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); + priv->curtxpow = txpow; + } +} + +/* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */ +static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv, + struct ath9k_channel *ichan) +{ + enum htc_phymode mode; + + mode = HTC_MODE_AUTO; + + switch (ichan->chanmode) { + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + mode = HTC_MODE_11NG; + break; + case CHANNEL_A: + case CHANNEL_A_HT20: + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + mode = HTC_MODE_11NA; + break; + default: + break; + } + + return mode; +} + +static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, + enum ath9k_power_mode mode) +{ + bool ret; + + mutex_lock(&priv->htc_pm_lock); + ret = ath9k_hw_setpower(priv->ah, mode); + mutex_unlock(&priv->htc_pm_lock); + + return ret; +} + +void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv) +{ + mutex_lock(&priv->htc_pm_lock); + if (++priv->ps_usecount != 1) + goto unlock; + ath9k_hw_setpower(priv->ah, ATH9K_PM_AWAKE); + +unlock: + mutex_unlock(&priv->htc_pm_lock); +} + +void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv) +{ + mutex_lock(&priv->htc_pm_lock); + if (--priv->ps_usecount != 0) + goto unlock; + + if (priv->ps_idle) + ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP); + else if (priv->ps_enabled) + ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP); + +unlock: + mutex_unlock(&priv->htc_pm_lock); +} + +void ath9k_ps_work(struct work_struct *work) +{ + struct ath9k_htc_priv *priv = + container_of(work, struct ath9k_htc_priv, + ps_work); + ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); + + /* The chip wakes up after receiving the first beacon + while network sleep is enabled. For the driver to + be in sync with the hw, set the chip to awake and + only then set it to sleep. + */ + ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); +} + +static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, + struct ieee80211_hw *hw, + struct ath9k_channel *hchan) +{ + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &common->hw->conf; + bool fastcc = true; + struct ieee80211_channel *channel = hw->conf.channel; + enum htc_phymode mode; + __be16 htc_mode; + u8 cmd_rsp; + int ret; + + if (priv->op_flags & OP_INVALID) + return -EIO; + + if (priv->op_flags & OP_FULL_RESET) + fastcc = false; + + /* Fiddle around with fastcc later on, for now just use full reset */ + fastcc = false; + ath9k_htc_ps_wakeup(priv); + htc_stop(priv->htc); + WMI_CMD(WMI_DISABLE_INTR_CMDID); + WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); + WMI_CMD(WMI_STOP_RECV_CMDID); + + ath_print(common, ATH_DBG_CONFIG, + "(%u MHz) -> (%u MHz), HT: %d, HT40: %d\n", + priv->ah->curchan->channel, + channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf)); + + ret = ath9k_hw_reset(ah, hchan, fastcc); + if (ret) { + ath_print(common, ATH_DBG_FATAL, + "Unable to reset channel (%u Mhz) " + "reset status %d\n", channel->center_freq, ret); + goto err; + } + + ath_update_txpow(priv); + + WMI_CMD(WMI_START_RECV_CMDID); + if (ret) + goto err; + + ath9k_host_rx_init(priv); + + mode = ath9k_htc_get_curmode(priv, hchan); + htc_mode = cpu_to_be16(mode); + WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); + if (ret) + goto err; + + WMI_CMD(WMI_ENABLE_INTR_CMDID); + if (ret) + goto err; + + htc_start(priv->htc); + + priv->op_flags &= ~OP_FULL_RESET; +err: + ath9k_htc_ps_restore(priv); + return ret; +} + +static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_target_vif hvif; + int ret = 0; + u8 cmd_rsp; + + if (priv->nvifs > 0) + return -ENOBUFS; + + memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); + memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); + + hvif.opmode = cpu_to_be32(HTC_M_MONITOR); + priv->ah->opmode = NL80211_IFTYPE_MONITOR; + hvif.index = priv->nvifs; + + WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); + if (ret) + return ret; + + priv->nvifs++; + return 0; +} + +static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_target_vif hvif; + int ret = 0; + u8 cmd_rsp; + + memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); + memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); + hvif.index = 0; /* Should do for now */ + WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); + priv->nvifs--; + + return ret; +} + +static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_target_sta tsta; + struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; + struct ath9k_htc_sta *ista; + int ret; + u8 cmd_rsp; + + if (priv->nstations >= ATH9K_HTC_MAX_STA) + return -ENOBUFS; + + memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); + + if (sta) { + ista = (struct ath9k_htc_sta *) sta->drv_priv; + memcpy(&tsta.macaddr, sta->addr, ETH_ALEN); + memcpy(&tsta.bssid, common->curbssid, ETH_ALEN); + tsta.associd = common->curaid; + tsta.is_vif_sta = 0; + tsta.valid = true; + ista->index = priv->nstations; + } else { + memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); + tsta.is_vif_sta = 1; + } + + tsta.sta_index = priv->nstations; + tsta.vif_index = avp->index; + tsta.maxampdu = 0xffff; + if (sta && sta->ht_cap.ht_supported) + tsta.flags = cpu_to_be16(ATH_HTC_STA_HT); + + WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); + if (ret) { + if (sta) + ath_print(common, ATH_DBG_FATAL, + "Unable to add station entry for: %pM\n", sta->addr); + return ret; + } + + if (sta) + ath_print(common, ATH_DBG_CONFIG, + "Added a station entry for: %pM (idx: %d)\n", + sta->addr, tsta.sta_index); + + priv->nstations++; + return 0; +} + +static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_sta *ista; + int ret; + u8 cmd_rsp, sta_idx; + + if (sta) { + ista = (struct ath9k_htc_sta *) sta->drv_priv; + sta_idx = ista->index; + } else { + sta_idx = 0; + } + + WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); + if (ret) { + if (sta) + ath_print(common, ATH_DBG_FATAL, + "Unable to remove station entry for: %pM\n", + sta->addr); + return ret; + } + + if (sta) + ath_print(common, ATH_DBG_CONFIG, + "Removed a station entry for: %pM (idx: %d)\n", + sta->addr, sta_idx); + + priv->nstations--; + return 0; +} + +static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv) +{ + struct ath9k_htc_cap_target tcap; + int ret; + u8 cmd_rsp; + + memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target)); + + /* FIXME: Values are hardcoded */ + tcap.flags = 0x240c40; + tcap.flags_ext = 0x80601000; + tcap.ampdu_limit = 0xffff0000; + tcap.ampdu_subframes = 20; + tcap.tx_chainmask_legacy = 1; + tcap.protmode = 1; + tcap.tx_chainmask = 1; + + WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap); + + return ret; +} + +static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; + struct ieee80211_supported_band *sband; + struct ath9k_htc_target_rate trate; + u32 caps = 0; + u8 cmd_rsp; + int i, j, ret; + + memset(&trate, 0, sizeof(trate)); + + /* Only 2GHz is supported */ + sband = priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; + + for (i = 0, j = 0; i < sband->n_bitrates; i++) { + if (sta->supp_rates[sband->band] & BIT(i)) { + priv->tgt_rate.rates.legacy_rates.rs_rates[j] + = (sband->bitrates[i].bitrate * 2) / 10; + j++; + } + } + priv->tgt_rate.rates.legacy_rates.rs_nrates = j; + + if (sta->ht_cap.ht_supported) { + for (i = 0, j = 0; i < 77; i++) { + if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) + priv->tgt_rate.rates.ht_rates.rs_rates[j++] = i; + if (j == ATH_HTC_RATE_MAX) + break; + } + priv->tgt_rate.rates.ht_rates.rs_nrates = j; + + caps = WLAN_RC_HT_FLAG; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + caps |= WLAN_RC_40_FLAG; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) + caps |= WLAN_RC_SGI_FLAG; + + } + + priv->tgt_rate.sta_index = ista->index; + priv->tgt_rate.isnew = 1; + trate = priv->tgt_rate; + priv->tgt_rate.capflags = cpu_to_be32(caps); + trate.capflags = cpu_to_be32(caps); + + WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate); + if (ret) { + ath_print(common, ATH_DBG_FATAL, + "Unable to initialize Rate information on target\n"); + return ret; + } + + ath_print(common, ATH_DBG_CONFIG, + "Updated target STA: %pM (caps: 0x%x)\n", sta->addr, caps); + return 0; +} + +static bool check_rc_update(struct ieee80211_hw *hw, bool *cw40) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + + if (!conf_is_ht(conf)) + return false; + + if (!(priv->op_flags & OP_ASSOCIATED) || + (priv->op_flags & OP_SCANNING)) + return false; + + if (conf_is_ht40(conf)) { + if (priv->ah->curchan->chanmode & + (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS)) { + return false; + } else { + *cw40 = true; + return true; + } + } else { /* ht20 */ + if (priv->ah->curchan->chanmode & CHANNEL_HT20) + return false; + else + return true; + } +} + +static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40) +{ + struct ath9k_htc_target_rate trate; + struct ath_common *common = ath9k_hw_common(priv->ah); + int ret; + u32 caps = be32_to_cpu(priv->tgt_rate.capflags); + u8 cmd_rsp; + + memset(&trate, 0, sizeof(trate)); + + trate = priv->tgt_rate; + + if (is_cw40) + caps |= WLAN_RC_40_FLAG; + else + caps &= ~WLAN_RC_40_FLAG; + + priv->tgt_rate.capflags = cpu_to_be32(caps); + trate.capflags = cpu_to_be32(caps); + + WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate); + if (ret) { + ath_print(common, ATH_DBG_FATAL, + "Unable to update Rate information on target\n"); + return; + } + + ath_print(common, ATH_DBG_CONFIG, "Rate control updated with " + "caps:0x%x on target\n", priv->tgt_rate.capflags); +} + +static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv, + struct ieee80211_vif *vif, + u8 *sta_addr, u8 tid, bool oper) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_target_aggr aggr; + struct ieee80211_sta *sta = NULL; + struct ath9k_htc_sta *ista; + int ret = 0; + u8 cmd_rsp; + + if (tid >= ATH9K_HTC_MAX_TID) + return -EINVAL; + + memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr)); + + rcu_read_lock(); + + /* Check if we are able to retrieve the station */ + sta = ieee80211_find_sta(vif, sta_addr); + if (!sta) { + rcu_read_unlock(); + return -EINVAL; + } + + ista = (struct ath9k_htc_sta *) sta->drv_priv; + + if (oper) + ista->tid_state[tid] = AGGR_START; + else + ista->tid_state[tid] = AGGR_STOP; + + aggr.sta_index = ista->index; + + rcu_read_unlock(); + + aggr.tidno = tid; + aggr.aggr_enable = oper; + + WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr); + if (ret) + ath_print(common, ATH_DBG_CONFIG, + "Unable to %s TX aggregation for (%pM, %d)\n", + (oper) ? "start" : "stop", sta->addr, tid); + else + ath_print(common, ATH_DBG_CONFIG, + "%s aggregation for (%pM, %d)\n", + (oper) ? "Starting" : "Stopping", sta->addr, tid); + + return ret; +} + +void ath9k_htc_aggr_work(struct work_struct *work) +{ + int ret = 0; + struct ath9k_htc_priv *priv = + container_of(work, struct ath9k_htc_priv, + ath9k_aggr_work.work); + struct ath9k_htc_aggr_work *wk = &priv->aggr_work; + + mutex_lock(&wk->mutex); + + switch (wk->action) { + case IEEE80211_AMPDU_TX_START: + ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr, + wk->tid, true); + if (!ret) + ieee80211_start_tx_ba_cb(wk->vif, wk->sta_addr, + wk->tid); + break; + case IEEE80211_AMPDU_TX_STOP: + ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr, + wk->tid, false); + ieee80211_stop_tx_ba_cb(wk->vif, wk->sta_addr, wk->tid); + break; + default: + ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL, + "Unknown AMPDU action\n"); + } + + mutex_unlock(&wk->mutex); +} + +/*********/ +/* DEBUG */ +/*********/ + +#ifdef CONFIG_ATH9K_HTC_DEBUGFS + +static int ath9k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = + (struct ath9k_htc_priv *) file->private_data; + struct ath9k_htc_target_stats cmd_rsp; + char buf[512]; + unsigned int len = 0; + int ret = 0; + + memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + + WMI_CMD(WMI_TGT_STATS_CMDID); + if (ret) + return -EINVAL; + + + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Short Retries", + be32_to_cpu(cmd_rsp.tx_shortretry)); + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Long Retries", + be32_to_cpu(cmd_rsp.tx_longretry)); + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Xretries", + be32_to_cpu(cmd_rsp.tx_xretries)); + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Unaggr. Xretries", + be32_to_cpu(cmd_rsp.ht_txunaggr_xretry)); + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Xretries (HT)", + be32_to_cpu(cmd_rsp.ht_tx_xretries)); + len += snprintf(buf + len, sizeof(buf) - len, + "%19s : %10u\n", "TX Rate", priv->debug.txrate); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_tgt_stats = { + .read = read_file_tgt_stats, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + +static ssize_t read_file_xmit(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = + (struct ath9k_htc_priv *) file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Buffers queued", + priv->debug.tx_stats.buf_queued); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Buffers completed", + priv->debug.tx_stats.buf_completed); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs queued", + priv->debug.tx_stats.skb_queued); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs completed", + priv->debug.tx_stats.skb_completed); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs dropped", + priv->debug.tx_stats.skb_dropped); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_xmit = { + .read = read_file_xmit, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + +static ssize_t read_file_recv(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = + (struct ath9k_htc_priv *) file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs allocated", + priv->debug.rx_stats.skb_allocated); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs completed", + priv->debug.rx_stats.skb_completed); + len += snprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs Dropped", + priv->debug.rx_stats.skb_dropped); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_recv = { + .read = read_file_recv, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + +int ath9k_htc_init_debug(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + + if (!ath9k_debugfs_root) + return -ENOENT; + + priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy), + ath9k_debugfs_root); + if (!priv->debug.debugfs_phy) + goto err; + + priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR, + priv->debug.debugfs_phy, + priv, &fops_tgt_stats); + if (!priv->debug.debugfs_tgt_stats) + goto err; + + + priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR, + priv->debug.debugfs_phy, + priv, &fops_xmit); + if (!priv->debug.debugfs_xmit) + goto err; + + priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR, + priv->debug.debugfs_phy, + priv, &fops_recv); + if (!priv->debug.debugfs_recv) + goto err; + + return 0; + +err: + ath9k_htc_exit_debug(ah); + return -ENOMEM; +} + +void ath9k_htc_exit_debug(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + + debugfs_remove(priv->debug.debugfs_recv); + debugfs_remove(priv->debug.debugfs_xmit); + debugfs_remove(priv->debug.debugfs_tgt_stats); + debugfs_remove(priv->debug.debugfs_phy); +} + +int ath9k_htc_debug_create_root(void) +{ + ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!ath9k_debugfs_root) + return -ENOENT; + + return 0; +} + +void ath9k_htc_debug_remove_root(void) +{ + debugfs_remove(ath9k_debugfs_root); + ath9k_debugfs_root = NULL; +} + +#endif /* CONFIG_ATH9K_HTC_DEBUGFS */ + +/*******/ +/* ANI */ +/*******/ + +static void ath_start_ani(struct ath9k_htc_priv *priv) +{ + struct ath_common *common = ath9k_hw_common(priv->ah); + unsigned long timestamp = jiffies_to_msecs(jiffies); + + common->ani.longcal_timer = timestamp; + common->ani.shortcal_timer = timestamp; + common->ani.checkani_timer = timestamp; + + ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work, + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); +} + +void ath9k_ani_work(struct work_struct *work) +{ + struct ath9k_htc_priv *priv = + container_of(work, struct ath9k_htc_priv, + ath9k_ani_work.work); + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + bool longcal = false; + bool shortcal = false; + bool aniflag = false; + unsigned int timestamp = jiffies_to_msecs(jiffies); + u32 cal_interval, short_cal_interval; + + short_cal_interval = ATH_STA_SHORT_CALINTERVAL; + + /* Only calibrate if awake */ + if (ah->power_mode != ATH9K_PM_AWAKE) + goto set_timer; + + /* Long calibration runs independently of short calibration. */ + if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { + longcal = true; + ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); + common->ani.longcal_timer = timestamp; + } + + /* Short calibration applies only while caldone is false */ + 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); + common->ani.shortcal_timer = timestamp; + common->ani.resetcal_timer = timestamp; + } + } else { + if ((timestamp - common->ani.resetcal_timer) >= + ATH_RESTART_CALINTERVAL) { + 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 - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { + aniflag = true; + common->ani.checkani_timer = timestamp; + } + + /* Skip all processing if there's nothing to do. */ + if (longcal || shortcal || aniflag) { + + ath9k_htc_ps_wakeup(priv); + + /* Call ANI routine if necessary */ + if (aniflag) + ath9k_hw_ani_monitor(ah, ah->curchan); + + /* Perform calibration if necessary */ + if (longcal || shortcal) { + common->ani.caldone = + ath9k_hw_calibrate(ah, ah->curchan, + common->rx_chainmask, + longcal); + + if (longcal) + 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, + common->ani.noise_floor); + } + + ath9k_htc_ps_restore(priv); + } + +set_timer: + /* + * Set timer interval based on previous results. + * The interval must be the shortest necessary to satisfy ANI, + * short calibration and long calibration. + */ + cal_interval = ATH_LONG_CALINTERVAL; + if (priv->ah->config.enable_ani) + cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); + if (!common->ani.caldone) + cal_interval = min(cal_interval, (u32)short_cal_interval); + + ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work, + msecs_to_jiffies(cal_interval)); +} + +/*******/ +/* LED */ +/*******/ + +static void ath9k_led_blink_work(struct work_struct *work) +{ + struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, + ath9k_led_blink_work.work); + + if (!(priv->op_flags & OP_LED_ASSOCIATED)) + return; + + if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) || + (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) + ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); + else + ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, + (priv->op_flags & OP_LED_ON) ? 1 : 0); + + ieee80211_queue_delayed_work(priv->hw, + &priv->ath9k_led_blink_work, + (priv->op_flags & OP_LED_ON) ? + msecs_to_jiffies(priv->led_off_duration) : + msecs_to_jiffies(priv->led_on_duration)); + + priv->led_on_duration = priv->led_on_cnt ? + max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) : + ATH_LED_ON_DURATION_IDLE; + priv->led_off_duration = priv->led_off_cnt ? + max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) : + ATH_LED_OFF_DURATION_IDLE; + priv->led_on_cnt = priv->led_off_cnt = 0; + + if (priv->op_flags & OP_LED_ON) + priv->op_flags &= ~OP_LED_ON; + else + priv->op_flags |= OP_LED_ON; +} + +static void ath9k_led_brightness_work(struct work_struct *work) +{ + struct ath_led *led = container_of(work, struct ath_led, + brightness_work.work); + struct ath9k_htc_priv *priv = led->priv; + + switch (led->brightness) { + case LED_OFF: + if (led->led_type == ATH_LED_ASSOC || + led->led_type == ATH_LED_RADIO) { + ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, + (led->led_type == ATH_LED_RADIO)); + priv->op_flags &= ~OP_LED_ASSOCIATED; + if (led->led_type == ATH_LED_RADIO) + priv->op_flags &= ~OP_LED_ON; + } else { + priv->led_off_cnt++; + } + break; + case LED_FULL: + if (led->led_type == ATH_LED_ASSOC) { + priv->op_flags |= OP_LED_ASSOCIATED; + ieee80211_queue_delayed_work(priv->hw, + &priv->ath9k_led_blink_work, 0); + } else if (led->led_type == ATH_LED_RADIO) { + ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); + priv->op_flags |= OP_LED_ON; + } else { + priv->led_on_cnt++; + } + break; + default: + break; + } +} + +static void ath9k_led_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); + struct ath9k_htc_priv *priv = led->priv; + + led->brightness = brightness; + if (!(priv->op_flags & OP_LED_DEINIT)) + ieee80211_queue_delayed_work(priv->hw, + &led->brightness_work, 0); +} + +static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv) +{ + cancel_delayed_work_sync(&priv->radio_led.brightness_work); + cancel_delayed_work_sync(&priv->assoc_led.brightness_work); + cancel_delayed_work_sync(&priv->tx_led.brightness_work); + cancel_delayed_work_sync(&priv->rx_led.brightness_work); +} + +static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led, + char *trigger) +{ + int ret; + + led->priv = priv; + led->led_cdev.name = led->name; + led->led_cdev.default_trigger = trigger; + led->led_cdev.brightness_set = ath9k_led_brightness; + + ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev); + if (ret) + ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL, + "Failed to register led:%s", led->name); + else + led->registered = 1; + + INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work); + + return ret; +} + +static void ath9k_unregister_led(struct ath_led *led) +{ + if (led->registered) { + led_classdev_unregister(&led->led_cdev); + led->registered = 0; + } +} + +void ath9k_deinit_leds(struct ath9k_htc_priv *priv) +{ + priv->op_flags |= OP_LED_DEINIT; + ath9k_unregister_led(&priv->assoc_led); + priv->op_flags &= ~OP_LED_ASSOCIATED; + ath9k_unregister_led(&priv->tx_led); + ath9k_unregister_led(&priv->rx_led); + ath9k_unregister_led(&priv->radio_led); +} + +void ath9k_init_leds(struct ath9k_htc_priv *priv) +{ + char *trigger; + int ret; + + if (AR_SREV_9287(priv->ah)) + priv->ah->led_pin = ATH_LED_PIN_9287; + else if (AR_SREV_9271(priv->ah)) + priv->ah->led_pin = ATH_LED_PIN_9271; + else + priv->ah->led_pin = ATH_LED_PIN_DEF; + + /* Configure gpio 1 for output */ + ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + /* LED off, active low */ + ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); + + INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work); + + trigger = ieee80211_get_radio_led_name(priv->hw); + snprintf(priv->radio_led.name, sizeof(priv->radio_led.name), + "ath9k-%s::radio", wiphy_name(priv->hw->wiphy)); + ret = ath9k_register_led(priv, &priv->radio_led, trigger); + priv->radio_led.led_type = ATH_LED_RADIO; + if (ret) + goto fail; + + trigger = ieee80211_get_assoc_led_name(priv->hw); + snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name), + "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy)); + ret = ath9k_register_led(priv, &priv->assoc_led, trigger); + priv->assoc_led.led_type = ATH_LED_ASSOC; + if (ret) + goto fail; + + trigger = ieee80211_get_tx_led_name(priv->hw); + snprintf(priv->tx_led.name, sizeof(priv->tx_led.name), + "ath9k-%s::tx", wiphy_name(priv->hw->wiphy)); + ret = ath9k_register_led(priv, &priv->tx_led, trigger); + priv->tx_led.led_type = ATH_LED_TX; + if (ret) + goto fail; + + trigger = ieee80211_get_rx_led_name(priv->hw); + snprintf(priv->rx_led.name, sizeof(priv->rx_led.name), + "ath9k-%s::rx", wiphy_name(priv->hw->wiphy)); + ret = ath9k_register_led(priv, &priv->rx_led, trigger); + priv->rx_led.led_type = ATH_LED_RX; + if (ret) + goto fail; + + priv->op_flags &= ~OP_LED_DEINIT; + + return; + +fail: + cancel_delayed_work_sync(&priv->ath9k_led_blink_work); + ath9k_deinit_leds(priv); +} + +/*******************/ +/* Rfkill */ +/*******************/ + +static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv) +{ + return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) == + priv->ah->rfkill_polarity; +} + +static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw) +{ + struct ath9k_htc_priv *priv = hw->priv; + bool blocked = !!ath_is_rfkill_set(priv); + + wiphy_rfkill_set_hw_state(hw->wiphy, blocked); +} + +void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv) +{ + if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + wiphy_rfkill_start_polling(priv->hw->wiphy); +} + +/**********************/ +/* mac80211 Callbacks */ +/**********************/ + +static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + struct ath9k_htc_priv *priv = hw->priv; + int padpos, padsize, ret; + + hdr = (struct ieee80211_hdr *) skb->data; + + /* Add the padding after the header if this is not already done */ + padpos = ath9k_cmn_padpos(hdr->frame_control); + padsize = padpos & 3; + if (padsize && skb->len > padpos) { + if (skb_headroom(skb) < padsize) + return -1; + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, padpos); + } + + ret = ath9k_htc_tx_start(priv, skb); + if (ret != 0) { + if (ret == -ENOMEM) { + ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, + "Stopping TX queues\n"); + ieee80211_stop_queues(hw); + spin_lock_bh(&priv->tx_lock); + priv->tx_queues_stop = true; + spin_unlock_bh(&priv->tx_lock); + } else { + ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, + "Tx failed"); + } + goto fail_tx; + } + + return 0; + +fail_tx: + dev_kfree_skb_any(skb); + return 0; +} + +static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_channel *curchan = hw->conf.channel; + struct ath9k_channel *init_channel; + int ret = 0; + enum htc_phymode mode; + __be16 htc_mode; + u8 cmd_rsp; + + ath_print(common, ATH_DBG_CONFIG, + "Starting driver with initial channel: %d MHz\n", + curchan->center_freq); + + /* setup initial channel */ + init_channel = ath9k_cmn_get_curchannel(hw, ah); + + /* Reset SERDES registers */ + ath9k_hw_configpcipowersave(ah, 0, 0); + + ath9k_hw_htc_resetinit(ah); + ret = ath9k_hw_reset(ah, init_channel, false); + if (ret) { + ath_print(common, ATH_DBG_FATAL, + "Unable to reset hardware; reset status %d " + "(freq %u MHz)\n", ret, curchan->center_freq); + return ret; + } + + ath_update_txpow(priv); + + mode = ath9k_htc_get_curmode(priv, init_channel); + htc_mode = cpu_to_be16(mode); + WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); + WMI_CMD(WMI_ATH_INIT_CMDID); + WMI_CMD(WMI_START_RECV_CMDID); + + ath9k_host_rx_init(priv); + + priv->op_flags &= ~OP_INVALID; + htc_start(priv->htc); + + spin_lock_bh(&priv->tx_lock); + priv->tx_queues_stop = false; + spin_unlock_bh(&priv->tx_lock); + + if (led) { + /* Enable LED */ + ath9k_hw_cfg_output(ah, ah->led_pin, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(ah, ah->led_pin, 0); + } + + ieee80211_wake_queues(hw); + + return ret; +} + +static int ath9k_htc_start(struct ieee80211_hw *hw) +{ + struct ath9k_htc_priv *priv = hw->priv; + int ret = 0; + + mutex_lock(&priv->mutex); + ret = ath9k_htc_radio_enable(hw, false); + mutex_unlock(&priv->mutex); + + return ret; +} + +static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + int ret = 0; + u8 cmd_rsp; + + if (priv->op_flags & OP_INVALID) { + ath_print(common, ATH_DBG_ANY, "Device not present\n"); + return; + } + + if (led) { + /* Disable LED */ + ath9k_hw_set_gpio(ah, ah->led_pin, 1); + ath9k_hw_cfg_gpio_input(ah, ah->led_pin); + } + + /* Cancel all the running timers/work .. */ + cancel_work_sync(&priv->ps_work); + cancel_delayed_work_sync(&priv->ath9k_ani_work); + cancel_delayed_work_sync(&priv->ath9k_aggr_work); + cancel_delayed_work_sync(&priv->ath9k_led_blink_work); + ath9k_led_stop_brightness(priv); + + ath9k_htc_ps_wakeup(priv); + htc_stop(priv->htc); + WMI_CMD(WMI_DISABLE_INTR_CMDID); + WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); + WMI_CMD(WMI_STOP_RECV_CMDID); + ath9k_hw_phy_disable(ah); + ath9k_hw_disable(ah); + ath9k_hw_configpcipowersave(ah, 1, 1); + ath9k_htc_ps_restore(priv); + ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); + + skb_queue_purge(&priv->tx_queue); + + /* Remove monitor interface here */ + if (ah->opmode == NL80211_IFTYPE_MONITOR) { + if (ath9k_htc_remove_monitor_interface(priv)) + ath_print(common, ATH_DBG_FATAL, + "Unable to remove monitor interface\n"); + else + ath_print(common, ATH_DBG_CONFIG, + "Monitor interface removed\n"); + } + + priv->op_flags |= OP_INVALID; + + ath_print(common, ATH_DBG_CONFIG, "Driver halt\n"); +} + +static void ath9k_htc_stop(struct ieee80211_hw *hw) +{ + struct ath9k_htc_priv *priv = hw->priv; + + mutex_lock(&priv->mutex); + ath9k_htc_radio_disable(hw, false); + mutex_unlock(&priv->mutex); +} + + +static int ath9k_htc_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath9k_htc_vif *avp = (void *)vif->drv_priv; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_target_vif hvif; + int ret = 0; + u8 cmd_rsp; + + mutex_lock(&priv->mutex); + + /* Only one interface for now */ + if (priv->nvifs > 0) { + ret = -ENOBUFS; + goto out; + } + + ath9k_htc_ps_wakeup(priv); + memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); + memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + hvif.opmode = cpu_to_be32(HTC_M_STA); + break; + case NL80211_IFTYPE_ADHOC: + hvif.opmode = cpu_to_be32(HTC_M_IBSS); + break; + default: + ath_print(common, ATH_DBG_FATAL, + "Interface type %d not yet supported\n", vif->type); + ret = -EOPNOTSUPP; + goto out; + } + + ath_print(common, ATH_DBG_CONFIG, + "Attach a VIF of type: %d\n", vif->type); + + priv->ah->opmode = vif->type; + + /* Index starts from zero on the target */ + avp->index = hvif.index = priv->nvifs; + hvif.rtsthreshold = cpu_to_be16(2304); + WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); + if (ret) + goto out; + + priv->nvifs++; + + /* + * We need a node in target to tx mgmt frames + * before association. + */ + ret = ath9k_htc_add_station(priv, vif, NULL); + if (ret) + goto out; + + ret = ath9k_htc_update_cap_target(priv); + if (ret) + ath_print(common, ATH_DBG_CONFIG, "Failed to update" + " capability in target \n"); + + priv->vif = vif; +out: + ath9k_htc_ps_restore(priv); + mutex_unlock(&priv->mutex); + return ret; +} + +static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_vif *avp = (void *)vif->drv_priv; + struct ath9k_htc_target_vif hvif; + int ret = 0; + u8 cmd_rsp; + + ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); + + mutex_lock(&priv->mutex); + + memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); + memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); + hvif.index = avp->index; + WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); + priv->nvifs--; + + ath9k_htc_remove_station(priv, vif, NULL); + priv->vif = NULL; + + mutex_unlock(&priv->mutex); +} + +static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ieee80211_conf *conf = &hw->conf; + + mutex_lock(&priv->mutex); + + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + bool enable_radio = false; + bool idle = !!(conf->flags & IEEE80211_CONF_IDLE); + + if (!idle && priv->ps_idle) + enable_radio = true; + + priv->ps_idle = idle; + + if (enable_radio) { + ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); + ath9k_htc_radio_enable(hw, true); + ath_print(common, ATH_DBG_CONFIG, + "not-idle: enabling radio\n"); + } + } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + struct ieee80211_channel *curchan = hw->conf.channel; + int pos = curchan->hw_value; + bool is_cw40 = false; + + ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n", + curchan->center_freq); + + if (check_rc_update(hw, &is_cw40)) + ath9k_htc_rc_update(priv, is_cw40); + + ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]); + + if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) { + ath_print(common, ATH_DBG_FATAL, + "Unable to set channel\n"); + mutex_unlock(&priv->mutex); + return -EINVAL; + } + + } + if (changed & IEEE80211_CONF_CHANGE_PS) { + if (conf->flags & IEEE80211_CONF_PS) { + ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); + priv->ps_enabled = true; + } else { + priv->ps_enabled = false; + cancel_work_sync(&priv->ps_work); + ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); + } + } + + if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + if (conf->flags & IEEE80211_CONF_MONITOR) { + if (ath9k_htc_add_monitor_interface(priv)) + ath_print(common, ATH_DBG_FATAL, + "Failed to set monitor mode\n"); + else + ath_print(common, ATH_DBG_CONFIG, + "HW opmode set to Monitor mode\n"); + } + } + + if (priv->ps_idle) { + ath_print(common, ATH_DBG_CONFIG, + "idle: disabling radio\n"); + ath9k_htc_radio_disable(hw, true); + } + + mutex_unlock(&priv->mutex); + + return 0; +} + +#define SUPPORTED_FILTERS \ + (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_CONTROL | \ + FIF_PSPOLL | \ + FIF_OTHER_BSS | \ + FIF_BCN_PRBRESP_PROMISC | \ + FIF_FCSFAIL) + +static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct ath9k_htc_priv *priv = hw->priv; + u32 rfilt; + + mutex_lock(&priv->mutex); + + ath9k_htc_ps_wakeup(priv); + changed_flags &= SUPPORTED_FILTERS; + *total_flags &= SUPPORTED_FILTERS; + + priv->rxfilter = *total_flags; + rfilt = ath9k_htc_calcrxfilter(priv); + ath9k_hw_setrxfilter(priv->ah, rfilt); + + ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG, + "Set HW RX filter: 0x%x\n", rfilt); + + ath9k_htc_ps_restore(priv); + mutex_unlock(&priv->mutex); +} + +static void ath9k_htc_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + struct ath9k_htc_priv *priv = hw->priv; + int ret; + + mutex_lock(&priv->mutex); + + switch (cmd) { + case STA_NOTIFY_ADD: + ret = ath9k_htc_add_station(priv, vif, sta); + if (!ret) + ath9k_htc_init_rate(priv, vif, sta); + break; + case STA_NOTIFY_REMOVE: + ath9k_htc_remove_station(priv, vif, sta); + break; + default: + break; + } + + mutex_unlock(&priv->mutex); +} + +static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_tx_queue_info qi; + int ret = 0, qnum; + + if (queue >= WME_NUM_AC) + return 0; + + mutex_lock(&priv->mutex); + + memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); + + qi.tqi_aifs = params->aifs; + qi.tqi_cwmin = params->cw_min; + qi.tqi_cwmax = params->cw_max; + qi.tqi_burstTime = params->txop; + + qnum = get_hw_qnum(queue, priv->hwq_map); + + ath_print(common, ATH_DBG_CONFIG, + "Configure tx [queue/hwq] [%d/%d], " + "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", + queue, qnum, params->aifs, params->cw_min, + params->cw_max, params->txop); + + ret = ath_htc_txq_update(priv, qnum, &qi); + if (ret) + ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n"); + + mutex_unlock(&priv->mutex); + + return ret; +} + +static int ath9k_htc_set_key(struct ieee80211_hw *hw, + enum set_key_cmd cmd, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); + int ret = 0; + + if (htc_modparam_nohwcrypt) + return -ENOSPC; + + mutex_lock(&priv->mutex); + ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n"); + ath9k_htc_ps_wakeup(priv); + + switch (cmd) { + case SET_KEY: + ret = ath9k_cmn_key_config(common, vif, sta, key); + if (ret >= 0) { + key->hw_key_idx = ret; + /* push IV and Michael MIC generation to stack */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + if (key->alg == ALG_TKIP) + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP) + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; + ret = 0; + } + break; + case DISABLE_KEY: + ath9k_cmn_key_delete(common, key); + break; + default: + ret = -EINVAL; + } + + ath9k_htc_ps_restore(priv); + mutex_unlock(&priv->mutex); + + return ret; +} + +static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changed) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + + mutex_lock(&priv->mutex); + ath9k_htc_ps_wakeup(priv); + + if (changed & BSS_CHANGED_ASSOC) { + common->curaid = bss_conf->assoc ? + bss_conf->aid : 0; + ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", + bss_conf->assoc); + + if (bss_conf->assoc) { + priv->op_flags |= OP_ASSOCIATED; + ath_start_ani(priv); + } else { + priv->op_flags &= ~OP_ASSOCIATED; + cancel_work_sync(&priv->ps_work); + cancel_delayed_work_sync(&priv->ath9k_ani_work); + } + } + + if (changed & BSS_CHANGED_BSSID) { + /* Set BSSID */ + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + ath9k_hw_write_associd(ah); + + ath_print(common, ATH_DBG_CONFIG, + "BSSID: %pM aid: 0x%x\n", + common->curbssid, common->curaid); + } + + if ((changed & BSS_CHANGED_BEACON_INT) || + (changed & BSS_CHANGED_BEACON) || + ((changed & BSS_CHANGED_BEACON_ENABLED) && + bss_conf->enable_beacon)) { + priv->op_flags |= OP_ENABLE_BEACON; + ath9k_htc_beacon_config(priv, vif); + } + + if ((changed & BSS_CHANGED_BEACON_ENABLED) && + !bss_conf->enable_beacon) { + priv->op_flags &= ~OP_ENABLE_BEACON; + ath9k_htc_beacon_config(priv, vif); + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", + bss_conf->use_short_preamble); + if (bss_conf->use_short_preamble) + priv->op_flags |= OP_PREAMBLE_SHORT; + else + priv->op_flags &= ~OP_PREAMBLE_SHORT; + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", + bss_conf->use_cts_prot); + if (bss_conf->use_cts_prot && + hw->conf.channel->band != IEEE80211_BAND_5GHZ) + priv->op_flags |= OP_PROTECT_ENABLE; + else + priv->op_flags &= ~OP_PROTECT_ENABLE; + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (bss_conf->use_short_slot) + ah->slottime = 9; + else + ah->slottime = 20; + + ath9k_hw_init_global_settings(ah); + } + + ath9k_htc_ps_restore(priv); + mutex_unlock(&priv->mutex); +} + +static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw) +{ + struct ath9k_htc_priv *priv = hw->priv; + u64 tsf; + + mutex_lock(&priv->mutex); + tsf = ath9k_hw_gettsf64(priv->ah); + mutex_unlock(&priv->mutex); + + return tsf; +} + +static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf) +{ + struct ath9k_htc_priv *priv = hw->priv; + + mutex_lock(&priv->mutex); + ath9k_hw_settsf64(priv->ah, tsf); + mutex_unlock(&priv->mutex); +} + +static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw) +{ + struct ath9k_htc_priv *priv = hw->priv; + + ath9k_htc_ps_wakeup(priv); + mutex_lock(&priv->mutex); + ath9k_hw_reset_tsf(priv->ah); + mutex_unlock(&priv->mutex); + ath9k_htc_ps_restore(priv); +} + +static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, + u16 tid, u16 *ssn) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath9k_htc_aggr_work *work = &priv->aggr_work; + struct ath9k_htc_sta *ista; + + switch (action) { + case IEEE80211_AMPDU_RX_START: + break; + case IEEE80211_AMPDU_RX_STOP: + break; + case IEEE80211_AMPDU_TX_START: + case IEEE80211_AMPDU_TX_STOP: + if (!(priv->op_flags & OP_TXAGGR)) + return -ENOTSUPP; + memcpy(work->sta_addr, sta->addr, ETH_ALEN); + work->hw = hw; + work->vif = vif; + work->action = action; + work->tid = tid; + ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + ista = (struct ath9k_htc_sta *) sta->drv_priv; + ista->tid_state[tid] = AGGR_OPERATIONAL; + break; + default: + ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL, + "Unknown AMPDU action\n"); + } + + return 0; +} + +static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) +{ + struct ath9k_htc_priv *priv = hw->priv; + + mutex_lock(&priv->mutex); + spin_lock_bh(&priv->beacon_lock); + priv->op_flags |= OP_SCANNING; + spin_unlock_bh(&priv->beacon_lock); + cancel_work_sync(&priv->ps_work); + cancel_delayed_work_sync(&priv->ath9k_ani_work); + mutex_unlock(&priv->mutex); +} + +static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) +{ + struct ath9k_htc_priv *priv = hw->priv; + + ath9k_htc_ps_wakeup(priv); + mutex_lock(&priv->mutex); + spin_lock_bh(&priv->beacon_lock); + priv->op_flags &= ~OP_SCANNING; + spin_unlock_bh(&priv->beacon_lock); + priv->op_flags |= OP_FULL_RESET; + if (priv->op_flags & OP_ASSOCIATED) + ath9k_htc_beacon_config(priv, priv->vif); + ath_start_ani(priv); + mutex_unlock(&priv->mutex); + ath9k_htc_ps_restore(priv); +} + +static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + return 0; +} + +static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw, + u8 coverage_class) +{ + struct ath9k_htc_priv *priv = hw->priv; + + mutex_lock(&priv->mutex); + priv->ah->coverage_class = coverage_class; + ath9k_hw_init_global_settings(priv->ah); + mutex_unlock(&priv->mutex); +} + +struct ieee80211_ops ath9k_htc_ops = { + .tx = ath9k_htc_tx, + .start = ath9k_htc_start, + .stop = ath9k_htc_stop, + .add_interface = ath9k_htc_add_interface, + .remove_interface = ath9k_htc_remove_interface, + .config = ath9k_htc_config, + .configure_filter = ath9k_htc_configure_filter, + .sta_notify = ath9k_htc_sta_notify, + .conf_tx = ath9k_htc_conf_tx, + .bss_info_changed = ath9k_htc_bss_info_changed, + .set_key = ath9k_htc_set_key, + .get_tsf = ath9k_htc_get_tsf, + .set_tsf = ath9k_htc_set_tsf, + .reset_tsf = ath9k_htc_reset_tsf, + .ampdu_action = ath9k_htc_ampdu_action, + .sw_scan_start = ath9k_htc_sw_scan_start, + .sw_scan_complete = ath9k_htc_sw_scan_complete, + .set_rts_threshold = ath9k_htc_set_rts_threshold, + .rfkill_poll = ath9k_htc_rfkill_poll_state, + .set_coverage_class = ath9k_htc_set_coverage_class, +}; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c new file mode 100644 index 00000000000..2571b443ac8 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -0,0 +1,707 @@ +/* + * Copyright (c) 2010 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 "htc.h" + +/******/ +/* TX */ +/******/ + +int get_hw_qnum(u16 queue, int *hwq_map) +{ + switch (queue) { + case 0: + return hwq_map[ATH9K_WME_AC_VO]; + case 1: + return hwq_map[ATH9K_WME_AC_VI]; + case 2: + return hwq_map[ATH9K_WME_AC_BE]; + case 3: + return hwq_map[ATH9K_WME_AC_BK]; + default: + return hwq_map[ATH9K_WME_AC_BE]; + } +} + +int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, + struct ath9k_tx_queue_info *qinfo) +{ + struct ath_hw *ah = priv->ah; + int error = 0; + struct ath9k_tx_queue_info qi; + + ath9k_hw_get_txq_props(ah, qnum, &qi); + + qi.tqi_aifs = qinfo->tqi_aifs; + qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */ + qi.tqi_cwmax = qinfo->tqi_cwmax; + qi.tqi_burstTime = qinfo->tqi_burstTime; + qi.tqi_readyTime = qinfo->tqi_readyTime; + + if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "Unable to update hardware queue %u!\n", qnum); + error = -EIO; + } else { + ath9k_hw_resettxqueue(ah, qnum); + } + + return error; +} + +int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = tx_info->control.sta; + struct ath9k_htc_sta *ista; + struct ath9k_htc_vif *avp; + struct ath9k_htc_tx_ctl tx_ctl; + enum htc_endpoint_id epid; + u16 qnum, hw_qnum; + __le16 fc; + u8 *tx_fhdr; + u8 sta_idx; + + hdr = (struct ieee80211_hdr *) skb->data; + fc = hdr->frame_control; + + avp = (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv; + if (sta) { + ista = (struct ath9k_htc_sta *) sta->drv_priv; + sta_idx = ista->index; + } else { + sta_idx = 0; + } + + memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); + + if (ieee80211_is_data(fc)) { + struct tx_frame_hdr tx_hdr; + u8 *qc; + + memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); + + tx_hdr.node_idx = sta_idx; + tx_hdr.vif_idx = avp->index; + + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + tx_ctl.type = ATH9K_HTC_AMPDU; + tx_hdr.data_type = ATH9K_HTC_AMPDU; + } else { + tx_ctl.type = ATH9K_HTC_NORMAL; + tx_hdr.data_type = ATH9K_HTC_NORMAL; + } + + if (ieee80211_is_data(fc)) { + qc = ieee80211_get_qos_ctl(hdr); + tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + } + + /* Check for RTS protection */ + if (priv->hw->wiphy->rts_threshold != (u32) -1) + if (skb->len > priv->hw->wiphy->rts_threshold) + tx_hdr.flags |= ATH9K_HTC_TX_RTSCTS; + + /* CTS-to-self */ + if (!(tx_hdr.flags & ATH9K_HTC_TX_RTSCTS) && + (priv->op_flags & OP_PROTECT_ENABLE)) + tx_hdr.flags |= ATH9K_HTC_TX_CTSONLY; + + tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); + if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) + tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; + else + tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; + + tx_fhdr = skb_push(skb, sizeof(tx_hdr)); + memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); + + qnum = skb_get_queue_mapping(skb); + hw_qnum = get_hw_qnum(qnum, priv->hwq_map); + + switch (hw_qnum) { + case 0: + epid = priv->data_be_ep; + break; + case 2: + epid = priv->data_vi_ep; + break; + case 3: + epid = priv->data_vo_ep; + break; + case 1: + default: + epid = priv->data_bk_ep; + break; + } + } else { + struct tx_mgmt_hdr mgmt_hdr; + + memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); + + tx_ctl.type = ATH9K_HTC_NORMAL; + + mgmt_hdr.node_idx = sta_idx; + mgmt_hdr.vif_idx = avp->index; + mgmt_hdr.tidno = 0; + mgmt_hdr.flags = 0; + + mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); + if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) + mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; + else + mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; + + tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); + memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); + epid = priv->mgmt_ep; + } + + return htc_send(priv->htc, skb, epid, &tx_ctl); +} + +void ath9k_tx_tasklet(unsigned long data) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; + struct ieee80211_sta *sta; + struct ieee80211_hdr *hdr; + struct ieee80211_tx_info *tx_info; + struct sk_buff *skb = NULL; + __le16 fc; + + while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) { + + hdr = (struct ieee80211_hdr *) skb->data; + fc = hdr->frame_control; + tx_info = IEEE80211_SKB_CB(skb); + + memset(&tx_info->status, 0, sizeof(tx_info->status)); + + rcu_read_lock(); + + sta = ieee80211_find_sta(priv->vif, hdr->addr1); + if (!sta) { + rcu_read_unlock(); + ieee80211_tx_status(priv->hw, skb); + continue; + } + + /* Check if we need to start aggregation */ + + if (sta && conf_is_ht(&priv->hw->conf) && + (priv->op_flags & OP_TXAGGR) + && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { + if (ieee80211_is_data_qos(fc)) { + u8 *qc, tid; + struct ath9k_htc_sta *ista; + + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & 0xf; + ista = (struct ath9k_htc_sta *)sta->drv_priv; + + if ((tid < ATH9K_HTC_MAX_TID) && + ista->tid_state[tid] == AGGR_STOP) { + ieee80211_start_tx_ba_session(sta, tid); + ista->tid_state[tid] = AGGR_PROGRESS; + } + } + } + + rcu_read_unlock(); + + /* Send status to mac80211 */ + ieee80211_tx_status(priv->hw, skb); + } + + /* Wake TX queues if needed */ + spin_lock_bh(&priv->tx_lock); + if (priv->tx_queues_stop) { + priv->tx_queues_stop = false; + spin_unlock_bh(&priv->tx_lock); + ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, + "Waking up TX queues\n"); + ieee80211_wake_queues(priv->hw); + return; + } + spin_unlock_bh(&priv->tx_lock); +} + +void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, + enum htc_endpoint_id ep_id, bool txok) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ieee80211_tx_info *tx_info; + + if (!skb) + return; + + if (ep_id == priv->mgmt_ep) { + skb_pull(skb, sizeof(struct tx_mgmt_hdr)); + } else if ((ep_id == priv->data_bk_ep) || + (ep_id == priv->data_be_ep) || + (ep_id == priv->data_vi_ep) || + (ep_id == priv->data_vo_ep)) { + skb_pull(skb, sizeof(struct tx_frame_hdr)); + } else { + ath_print(common, ATH_DBG_FATAL, + "Unsupported TX EPID: %d\n", ep_id); + dev_kfree_skb_any(skb); + return; + } + + tx_info = IEEE80211_SKB_CB(skb); + + if (txok) + tx_info->flags |= IEEE80211_TX_STAT_ACK; + + skb_queue_tail(&priv->tx_queue, skb); + tasklet_schedule(&priv->tx_tasklet); +} + +int ath9k_tx_init(struct ath9k_htc_priv *priv) +{ + skb_queue_head_init(&priv->tx_queue); + return 0; +} + +void ath9k_tx_cleanup(struct ath9k_htc_priv *priv) +{ + +} + +bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, + enum ath9k_tx_queue_subtype subtype) +{ + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_tx_queue_info qi; + int qnum; + + memset(&qi, 0, sizeof(qi)); + + qi.tqi_subtype = subtype; + qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; + qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; + qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; + qi.tqi_physCompBuf = 0; + qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE; + + qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi); + if (qnum == -1) + return false; + + if (qnum >= ARRAY_SIZE(priv->hwq_map)) { + ath_print(common, ATH_DBG_FATAL, + "qnum %u out of range, max %u!\n", + qnum, (unsigned int)ARRAY_SIZE(priv->hwq_map)); + ath9k_hw_releasetxqueue(ah, qnum); + return false; + } + + priv->hwq_map[subtype] = qnum; + return true; +} + +/******/ +/* RX */ +/******/ + +/* + * Calculate the RX filter to be set in the HW. + */ +u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) +{ +#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) + + struct ath_hw *ah = priv->ah; + u32 rfilt; + + rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) + | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST + | ATH9K_RX_FILTER_MCAST; + + /* If not a STA, enable processing of Probe Requests */ + if (ah->opmode != NL80211_IFTYPE_STATION) + rfilt |= ATH9K_RX_FILTER_PROBEREQ; + + /* + * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station + * mode interface or when in monitor mode. AP mode does not need this + * since it receives all in-BSS frames anyway. + */ + if (((ah->opmode != NL80211_IFTYPE_AP) && + (priv->rxfilter & FIF_PROMISC_IN_BSS)) || + (ah->opmode == NL80211_IFTYPE_MONITOR)) + rfilt |= ATH9K_RX_FILTER_PROM; + + if (priv->rxfilter & FIF_CONTROL) + rfilt |= ATH9K_RX_FILTER_CONTROL; + + if ((ah->opmode == NL80211_IFTYPE_STATION) && + !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC)) + rfilt |= ATH9K_RX_FILTER_MYBEACON; + else + rfilt |= ATH9K_RX_FILTER_BEACON; + + if (conf_is_ht(&priv->hw->conf)) + rfilt |= ATH9K_RX_FILTER_COMP_BAR; + + return rfilt; + +#undef RX_FILTER_PRESERVE +} + +/* + * Recv initialization for opmode change. + */ +static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) +{ + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + + u32 rfilt, mfilt[2]; + + /* configure rx filter */ + rfilt = ath9k_htc_calcrxfilter(priv); + ath9k_hw_setrxfilter(ah, rfilt); + + /* configure bssid mask */ + if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + ath_hw_setbssidmask(common); + + /* configure operational mode */ + ath9k_hw_setopmode(ah); + + /* Handle any link-level address change. */ + ath9k_hw_setmac(ah, common->macaddr); + + /* calculate and install multicast filter */ + mfilt[0] = mfilt[1] = ~0; + ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); +} + +void ath9k_host_rx_init(struct ath9k_htc_priv *priv) +{ + ath9k_hw_rxena(priv->ah); + ath9k_htc_opmode_init(priv); + ath9k_hw_startpcureceive(priv->ah); + priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; +} + +static void ath9k_process_rate(struct ieee80211_hw *hw, + struct ieee80211_rx_status *rxs, + u8 rx_rate, u8 rs_flags) +{ + struct ieee80211_supported_band *sband; + enum ieee80211_band band; + unsigned int i = 0; + + if (rx_rate & 0x80) { + /* HT rate */ + rxs->flag |= RX_FLAG_HT; + if (rs_flags & ATH9K_RX_2040) + rxs->flag |= RX_FLAG_40MHZ; + if (rs_flags & ATH9K_RX_GI) + rxs->flag |= RX_FLAG_SHORT_GI; + rxs->rate_idx = rx_rate & 0x7f; + return; + } + + band = hw->conf.channel->band; + sband = hw->wiphy->bands[band]; + + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].hw_value == rx_rate) { + rxs->rate_idx = i; + return; + } + if (sband->bitrates[i].hw_value_short == rx_rate) { + rxs->rate_idx = i; + rxs->flag |= RX_FLAG_SHORTPRE; + return; + } + } + +} + +static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, + struct ath9k_htc_rxbuf *rxbuf, + struct ieee80211_rx_status *rx_status) + +{ + struct ieee80211_hdr *hdr; + struct ieee80211_hw *hw = priv->hw; + struct sk_buff *skb = rxbuf->skb; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath_htc_rx_status *rxstatus; + int hdrlen, padpos, padsize; + int last_rssi = ATH_RSSI_DUMMY_MARKER; + __le16 fc; + + if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) { + ath_print(common, ATH_DBG_FATAL, + "Corrupted RX frame, dropping\n"); + goto rx_next; + } + + rxstatus = (struct ath_htc_rx_status *)skb->data; + + if (be16_to_cpu(rxstatus->rs_datalen) - + (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { + ath_print(common, ATH_DBG_FATAL, + "Corrupted RX data len, dropping " + "(dlen: %d, skblen: %d)\n", + rxstatus->rs_datalen, skb->len); + goto rx_next; + } + + /* Get the RX status information */ + memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); + skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + + padpos = ath9k_cmn_padpos(fc); + + padsize = padpos & 3; + if (padsize && skb->len >= padpos+padsize+FCS_LEN) { + memmove(skb->data + padsize, skb->data, padpos); + skb_pull(skb, padsize); + } + + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + + if (rxbuf->rxstatus.rs_status != 0) { + if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) + goto rx_next; + + if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { + /* FIXME */ + } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { + if (ieee80211_is_ctl(fc)) + /* + * Sometimes, we get invalid + * MIC failures on valid control frames. + * Remove these mic errors. + */ + rxbuf->rxstatus.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 (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { + if (rxbuf->rxstatus.rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | + ATH9K_RXERR_CRC)) + goto rx_next; + } else { + if (rxbuf->rxstatus.rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { + goto rx_next; + } + } + } + + if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { + u8 keyix; + keyix = rxbuf->rxstatus.rs_keyix; + if (keyix != ATH9K_RXKEYIX_INVALID) { + rx_status->flag |= RX_FLAG_DECRYPTED; + } else if (ieee80211_has_protected(fc) && + skb->len >= hdrlen + 4) { + keyix = skb->data[hdrlen + 3] >> 6; + if (test_bit(keyix, common->keymap)) + rx_status->flag |= RX_FLAG_DECRYPTED; + } + } + + ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate, + rxbuf->rxstatus.rs_flags); + + if (priv->op_flags & OP_ASSOCIATED) { + if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD && + !rxbuf->rxstatus.rs_moreaggr) + ATH_RSSI_LPF(priv->rx.last_rssi, + rxbuf->rxstatus.rs_rssi); + + last_rssi = priv->rx.last_rssi; + + if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) + rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi, + ATH_RSSI_EP_MULTIPLIER); + + if (rxbuf->rxstatus.rs_rssi < 0) + rxbuf->rxstatus.rs_rssi = 0; + + if (ieee80211_is_beacon(fc)) + priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi; + } + + rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp); + rx_status->band = hw->conf.channel->band; + rx_status->freq = hw->conf.channel->center_freq; + rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; + rx_status->antenna = rxbuf->rxstatus.rs_antenna; + rx_status->flag |= RX_FLAG_TSFT; + + return true; + +rx_next: + return false; +} + +/* + * FIXME: Handle FLUSH later on. + */ +void ath9k_rx_tasklet(unsigned long data) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; + struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; + struct ieee80211_rx_status rx_status; + struct sk_buff *skb; + unsigned long flags; + struct ieee80211_hdr *hdr; + + do { + spin_lock_irqsave(&priv->rx.rxbuflock, flags); + list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { + if (tmp_buf->in_process) { + rxbuf = tmp_buf; + break; + } + } + + if (rxbuf == NULL) { + spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); + break; + } + + if (!rxbuf->skb) + goto requeue; + + if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) { + dev_kfree_skb_any(rxbuf->skb); + goto requeue; + } + + memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status, + sizeof(struct ieee80211_rx_status)); + skb = rxbuf->skb; + hdr = (struct ieee80211_hdr *) skb->data; + + if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled) + ieee80211_queue_work(priv->hw, &priv->ps_work); + + spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); + + ieee80211_rx(priv->hw, skb); + + spin_lock_irqsave(&priv->rx.rxbuflock, flags); +requeue: + rxbuf->in_process = false; + rxbuf->skb = NULL; + list_move_tail(&rxbuf->list, &priv->rx.rxbuf); + rxbuf = NULL; + spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); + } while (1); + +} + +void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, + enum htc_endpoint_id ep_id) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv; + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; + + spin_lock(&priv->rx.rxbuflock); + list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { + if (!tmp_buf->in_process) { + rxbuf = tmp_buf; + break; + } + } + spin_unlock(&priv->rx.rxbuflock); + + if (rxbuf == NULL) { + ath_print(common, ATH_DBG_ANY, + "No free RX buffer\n"); + goto err; + } + + spin_lock(&priv->rx.rxbuflock); + rxbuf->skb = skb; + rxbuf->in_process = true; + spin_unlock(&priv->rx.rxbuflock); + + tasklet_schedule(&priv->rx_tasklet); + return; +err: + dev_kfree_skb_any(skb); +} + +/* FIXME: Locking for cleanup/init */ + +void ath9k_rx_cleanup(struct ath9k_htc_priv *priv) +{ + struct ath9k_htc_rxbuf *rxbuf, *tbuf; + + list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) { + list_del(&rxbuf->list); + if (rxbuf->skb) + dev_kfree_skb_any(rxbuf->skb); + kfree(rxbuf); + } +} + +int ath9k_rx_init(struct ath9k_htc_priv *priv) +{ + struct ath_hw *ah = priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_rxbuf *rxbuf; + int i = 0; + + INIT_LIST_HEAD(&priv->rx.rxbuf); + spin_lock_init(&priv->rx.rxbuflock); + + for (i = 0; i < ATH9K_HTC_RXBUF; i++) { + rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL); + if (rxbuf == NULL) { + ath_print(common, ATH_DBG_FATAL, + "Unable to allocate RX buffers\n"); + goto err; + } + list_add_tail(&rxbuf->list, &priv->rx.rxbuf); + } + + return 0; + +err: + ath9k_rx_cleanup(priv); + return -ENOMEM; +} diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c new file mode 100644 index 00000000000..064397fd738 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2010 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 "htc.h" + +static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, + u16 len, u8 flags, u8 epid, + struct ath9k_htc_tx_ctl *tx_ctl) +{ + struct htc_frame_hdr *hdr; + struct htc_endpoint *endpoint = &target->endpoint[epid]; + int status; + + hdr = (struct htc_frame_hdr *) + skb_push(skb, sizeof(struct htc_frame_hdr)); + hdr->endpoint_id = epid; + hdr->flags = flags; + hdr->payload_len = cpu_to_be16(len); + + status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb, + tx_ctl); + return status; +} + +static struct htc_endpoint *get_next_avail_ep(struct htc_endpoint *endpoint) +{ + enum htc_endpoint_id avail_epid; + + for (avail_epid = (ENDPOINT_MAX - 1); avail_epid > ENDPOINT0; avail_epid--) + if (endpoint[avail_epid].service_id == 0) + return &endpoint[avail_epid]; + return NULL; +} + +static u8 service_to_ulpipe(u16 service_id) +{ + switch (service_id) { + case WMI_CONTROL_SVC: + return 4; + case WMI_BEACON_SVC: + case WMI_CAB_SVC: + case WMI_UAPSD_SVC: + case WMI_MGMT_SVC: + case WMI_DATA_VO_SVC: + case WMI_DATA_VI_SVC: + case WMI_DATA_BE_SVC: + case WMI_DATA_BK_SVC: + return 1; + default: + return 0; + } +} + +static u8 service_to_dlpipe(u16 service_id) +{ + switch (service_id) { + case WMI_CONTROL_SVC: + return 3; + case WMI_BEACON_SVC: + case WMI_CAB_SVC: + case WMI_UAPSD_SVC: + case WMI_MGMT_SVC: + case WMI_DATA_VO_SVC: + case WMI_DATA_VI_SVC: + case WMI_DATA_BE_SVC: + case WMI_DATA_BK_SVC: + return 2; + default: + return 0; + } +} + +static void htc_process_target_rdy(struct htc_target *target, + void *buf) +{ + struct htc_endpoint *endpoint; + struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf; + + target->credits = be16_to_cpu(htc_ready_msg->credits); + target->credit_size = be16_to_cpu(htc_ready_msg->credit_size); + + endpoint = &target->endpoint[ENDPOINT0]; + endpoint->service_id = HTC_CTRL_RSVD_SVC; + endpoint->max_msglen = HTC_MAX_CONTROL_MESSAGE_LENGTH; + atomic_inc(&target->tgt_ready); + complete(&target->target_wait); +} + +static void htc_process_conn_rsp(struct htc_target *target, + struct htc_frame_hdr *htc_hdr) +{ + struct htc_conn_svc_rspmsg *svc_rspmsg; + struct htc_endpoint *endpoint, *tmp_endpoint = NULL; + u16 service_id; + u16 max_msglen; + enum htc_endpoint_id epid, tepid; + + svc_rspmsg = (struct htc_conn_svc_rspmsg *) + ((void *) htc_hdr + sizeof(struct htc_frame_hdr)); + + if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) { + epid = svc_rspmsg->endpoint_id; + service_id = be16_to_cpu(svc_rspmsg->service_id); + max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len); + endpoint = &target->endpoint[epid]; + + for (tepid = (ENDPOINT_MAX - 1); tepid > ENDPOINT0; tepid--) { + tmp_endpoint = &target->endpoint[tepid]; + if (tmp_endpoint->service_id == service_id) { + tmp_endpoint->service_id = 0; + break; + } + } + + if (tepid == ENDPOINT0) + return; + + endpoint->service_id = service_id; + endpoint->max_txqdepth = tmp_endpoint->max_txqdepth; + endpoint->ep_callbacks = tmp_endpoint->ep_callbacks; + endpoint->ul_pipeid = tmp_endpoint->ul_pipeid; + endpoint->dl_pipeid = tmp_endpoint->dl_pipeid; + endpoint->max_msglen = max_msglen; + target->conn_rsp_epid = epid; + complete(&target->cmd_wait); + } else { + target->conn_rsp_epid = ENDPOINT_UNUSED; + } +} + +static int htc_config_pipe_credits(struct htc_target *target) +{ + struct sk_buff *skb; + struct htc_config_pipe_msg *cp_msg; + int ret, time_left; + + skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC); + if (!skb) { + dev_err(target->dev, "failed to allocate send buffer\n"); + return -ENOMEM; + } + skb_reserve(skb, sizeof(struct htc_frame_hdr)); + + cp_msg = (struct htc_config_pipe_msg *) + skb_put(skb, sizeof(struct htc_config_pipe_msg)); + + cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID); + cp_msg->pipe_id = USB_WLAN_TX_PIPE; + cp_msg->credits = 28; + + target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS; + + ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); + if (ret) + goto err; + + time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); + if (!time_left) { + dev_err(target->dev, "HTC credit config timeout\n"); + return -ETIMEDOUT; + } + + return 0; +err: + kfree_skb(skb); + return -EINVAL; +} + +static int htc_setup_complete(struct htc_target *target) +{ + struct sk_buff *skb; + struct htc_comp_msg *comp_msg; + int ret = 0, time_left; + + skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC); + if (!skb) { + dev_err(target->dev, "failed to allocate send buffer\n"); + return -ENOMEM; + } + skb_reserve(skb, sizeof(struct htc_frame_hdr)); + + comp_msg = (struct htc_comp_msg *) + skb_put(skb, sizeof(struct htc_comp_msg)); + comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID); + + target->htc_flags |= HTC_OP_START_WAIT; + + ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); + if (ret) + goto err; + + time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); + if (!time_left) { + dev_err(target->dev, "HTC start timeout\n"); + return -ETIMEDOUT; + } + + return 0; + +err: + kfree_skb(skb); + return -EINVAL; +} + +/* HTC APIs */ + +int htc_init(struct htc_target *target) +{ + int ret; + + ret = htc_config_pipe_credits(target); + if (ret) + return ret; + + return htc_setup_complete(target); +} + +int htc_connect_service(struct htc_target *target, + struct htc_service_connreq *service_connreq, + enum htc_endpoint_id *conn_rsp_epid) +{ + struct sk_buff *skb; + struct htc_endpoint *endpoint; + struct htc_conn_svc_msg *conn_msg; + int ret, time_left; + + /* Find an available endpoint */ + endpoint = get_next_avail_ep(target->endpoint); + if (!endpoint) { + dev_err(target->dev, "Endpoint is not available for" + "service %d\n", service_connreq->service_id); + return -EINVAL; + } + + endpoint->service_id = service_connreq->service_id; + endpoint->max_txqdepth = service_connreq->max_send_qdepth; + endpoint->ul_pipeid = service_to_ulpipe(service_connreq->service_id); + endpoint->dl_pipeid = service_to_dlpipe(service_connreq->service_id); + endpoint->ep_callbacks = service_connreq->ep_callbacks; + + skb = alloc_skb(sizeof(struct htc_conn_svc_msg) + + sizeof(struct htc_frame_hdr), GFP_ATOMIC); + if (!skb) { + dev_err(target->dev, "Failed to allocate buf to send" + "service connect req\n"); + return -ENOMEM; + } + + skb_reserve(skb, sizeof(struct htc_frame_hdr)); + + conn_msg = (struct htc_conn_svc_msg *) + skb_put(skb, sizeof(struct htc_conn_svc_msg)); + conn_msg->service_id = cpu_to_be16(service_connreq->service_id); + conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID); + conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags); + conn_msg->dl_pipeid = endpoint->dl_pipeid; + conn_msg->ul_pipeid = endpoint->ul_pipeid; + + ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); + if (ret) + goto err; + + time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); + if (!time_left) { + dev_err(target->dev, "Service connection timeout for: %d\n", + service_connreq->service_id); + return -ETIMEDOUT; + } + + *conn_rsp_epid = target->conn_rsp_epid; + return 0; +err: + kfree_skb(skb); + return ret; +} + +int htc_send(struct htc_target *target, struct sk_buff *skb, + enum htc_endpoint_id epid, struct ath9k_htc_tx_ctl *tx_ctl) +{ + return htc_issue_send(target, skb, skb->len, 0, epid, tx_ctl); +} + +void htc_stop(struct htc_target *target) +{ + enum htc_endpoint_id epid; + struct htc_endpoint *endpoint; + + for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) { + endpoint = &target->endpoint[epid]; + if (endpoint->service_id != 0) + target->hif->stop(target->hif_dev, endpoint->ul_pipeid); + } +} + +void htc_start(struct htc_target *target) +{ + enum htc_endpoint_id epid; + struct htc_endpoint *endpoint; + + for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) { + endpoint = &target->endpoint[epid]; + if (endpoint->service_id != 0) + target->hif->start(target->hif_dev, + endpoint->ul_pipeid); + } +} + +void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, + struct sk_buff *skb, bool txok) +{ + struct htc_endpoint *endpoint; + struct htc_frame_hdr *htc_hdr = NULL; + + if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) { + complete(&htc_handle->cmd_wait); + htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS; + goto ret; + } + + if (htc_handle->htc_flags & HTC_OP_START_WAIT) { + complete(&htc_handle->cmd_wait); + htc_handle->htc_flags &= ~HTC_OP_START_WAIT; + goto ret; + } + + if (skb) { + htc_hdr = (struct htc_frame_hdr *) skb->data; + endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id]; + skb_pull(skb, sizeof(struct htc_frame_hdr)); + + if (endpoint->ep_callbacks.tx) { + endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv, + skb, htc_hdr->endpoint_id, + txok); + } + } + + return; +ret: + /* HTC-generated packets are freed here. */ + if (htc_hdr && htc_hdr->endpoint_id != ENDPOINT0) + dev_kfree_skb_any(skb); + else + kfree_skb(skb); +} + +/* + * HTC Messages are handled directly here and the obtained SKB + * is freed. + * + * Sevice messages (Data, WMI) passed to the corresponding + * endpoint RX handlers, which have to free the SKB. + */ +void ath9k_htc_rx_msg(struct htc_target *htc_handle, + struct sk_buff *skb, u32 len, u8 pipe_id) +{ + struct htc_frame_hdr *htc_hdr; + enum htc_endpoint_id epid; + struct htc_endpoint *endpoint; + __be16 *msg_id; + + if (!htc_handle || !skb) + return; + + htc_hdr = (struct htc_frame_hdr *) skb->data; + epid = htc_hdr->endpoint_id; + + if (epid >= ENDPOINT_MAX) { + if (pipe_id != USB_REG_IN_PIPE) + dev_kfree_skb_any(skb); + else + kfree_skb(skb); + return; + } + + if (epid == ENDPOINT0) { + + /* Handle trailer */ + if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) { + if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000) + /* Move past the Watchdog pattern */ + htc_hdr = (struct htc_frame_hdr *)(skb->data + 4); + } + + /* Get the message ID */ + msg_id = (__be16 *) ((void *) htc_hdr + + sizeof(struct htc_frame_hdr)); + + /* Now process HTC messages */ + switch (be16_to_cpu(*msg_id)) { + case HTC_MSG_READY_ID: + htc_process_target_rdy(htc_handle, htc_hdr); + break; + case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID: + htc_process_conn_rsp(htc_handle, htc_hdr); + break; + default: + break; + } + + kfree_skb(skb); + + } else { + if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) + skb_trim(skb, len - htc_hdr->control[0]); + + skb_pull(skb, sizeof(struct htc_frame_hdr)); + + endpoint = &htc_handle->endpoint[epid]; + if (endpoint->ep_callbacks.rx) + endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv, + skb, epid); + } +} + +struct htc_target *ath9k_htc_hw_alloc(void *hif_handle, + struct ath9k_htc_hif *hif, + struct device *dev) +{ + struct htc_endpoint *endpoint; + struct htc_target *target; + + target = kzalloc(sizeof(struct htc_target), GFP_KERNEL); + if (!target) { + printk(KERN_ERR "Unable to allocate memory for" + "target device\n"); + return NULL; + } + + init_completion(&target->target_wait); + init_completion(&target->cmd_wait); + + target->hif = hif; + target->hif_dev = hif_handle; + target->dev = dev; + + /* Assign control endpoint pipe IDs */ + endpoint = &target->endpoint[ENDPOINT0]; + endpoint->ul_pipeid = hif->control_ul_pipe; + endpoint->dl_pipeid = hif->control_dl_pipe; + + atomic_set(&target->tgt_ready, 0); + + return target; +} + +void ath9k_htc_hw_free(struct htc_target *htc) +{ + kfree(htc); +} + +int ath9k_htc_hw_init(struct htc_target *target, + struct device *dev, u16 devid) +{ + if (ath9k_htc_probe_device(target, dev, devid)) { + printk(KERN_ERR "Failed to initialize the device\n"); + return -ENODEV; + } + + return 0; +} + +void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug) +{ + if (target) + ath9k_htc_disconnect_device(target, hot_unplug); +} diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h new file mode 100644 index 00000000000..faba6790328 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2010 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. + */ + +#ifndef HTC_HST_H +#define HTC_HST_H + +struct ath9k_htc_priv; +struct htc_target; +struct ath9k_htc_tx_ctl; + +enum ath9k_hif_transports { + ATH9K_HIF_USB, +}; + +struct ath9k_htc_hif { + struct list_head list; + const enum ath9k_hif_transports transport; + const char *name; + + u8 control_dl_pipe; + u8 control_ul_pipe; + + void (*start) (void *hif_handle, u8 pipe); + void (*stop) (void *hif_handle, u8 pipe); + int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf, + struct ath9k_htc_tx_ctl *tx_ctl); +}; + +enum htc_endpoint_id { + ENDPOINT_UNUSED = -1, + ENDPOINT0 = 0, + ENDPOINT1 = 1, + ENDPOINT2 = 2, + ENDPOINT3 = 3, + ENDPOINT4 = 4, + ENDPOINT5 = 5, + ENDPOINT6 = 6, + ENDPOINT7 = 7, + ENDPOINT8 = 8, + ENDPOINT_MAX = 22 +}; + +/* Htc frame hdr flags */ +#define HTC_FLAGS_RECV_TRAILER (1 << 1) + +struct htc_frame_hdr { + u8 endpoint_id; + u8 flags; + __be16 payload_len; + u8 control[4]; +} __packed; + +struct htc_ready_msg { + __be16 message_id; + __be16 credits; + __be16 credit_size; + u8 max_endpoints; + u8 pad; +} __packed; + +struct htc_config_pipe_msg { + __be16 message_id; + u8 pipe_id; + u8 credits; +} __packed; + +struct htc_packet { + void *pktcontext; + u8 *buf; + u8 *buf_payload; + u32 buflen; + u32 payload_len; + + int endpoint; + int status; + + void *context; + u32 reserved; +}; + +struct htc_ep_callbacks { + void *priv; + void (*tx) (void *, struct sk_buff *, enum htc_endpoint_id, bool txok); + void (*rx) (void *, struct sk_buff *, enum htc_endpoint_id); +}; + +#define HTC_TX_QUEUE_SIZE 256 + +struct htc_txq { + struct sk_buff *buf[HTC_TX_QUEUE_SIZE]; + u32 txqdepth; + u16 txbuf_cnt; + u16 txq_head; + u16 txq_tail; +}; + +struct htc_endpoint { + u16 service_id; + + struct htc_ep_callbacks ep_callbacks; + struct htc_txq htc_txq; + u32 max_txqdepth; + int max_msglen; + + u8 ul_pipeid; + u8 dl_pipeid; +}; + +#define HTC_MAX_CONTROL_MESSAGE_LENGTH 255 +#define HTC_CONTROL_BUFFER_SIZE \ + (HTC_MAX_CONTROL_MESSAGE_LENGTH + sizeof(struct htc_frame_hdr)) + +struct htc_control_buf { + struct htc_packet htc_pkt; + u8 buf[HTC_CONTROL_BUFFER_SIZE]; +}; + +#define HTC_OP_START_WAIT BIT(0) +#define HTC_OP_CONFIG_PIPE_CREDITS BIT(1) + +struct htc_target { + void *hif_dev; + struct ath9k_htc_priv *drv_priv; + struct device *dev; + struct ath9k_htc_hif *hif; + struct htc_endpoint endpoint[ENDPOINT_MAX]; + struct completion target_wait; + struct completion cmd_wait; + struct list_head list; + enum htc_endpoint_id conn_rsp_epid; + u16 credits; + u16 credit_size; + u8 htc_flags; + atomic_t tgt_ready; +}; + +enum htc_msg_id { + HTC_MSG_READY_ID = 1, + HTC_MSG_CONNECT_SERVICE_ID, + HTC_MSG_CONNECT_SERVICE_RESPONSE_ID, + HTC_MSG_SETUP_COMPLETE_ID, + HTC_MSG_CONFIG_PIPE_ID, + HTC_MSG_CONFIG_PIPE_RESPONSE_ID, +}; + +struct htc_service_connreq { + u16 service_id; + u16 con_flags; + u32 max_send_qdepth; + struct htc_ep_callbacks ep_callbacks; +}; + +/* Current service IDs */ + +enum htc_service_group_ids{ + RSVD_SERVICE_GROUP = 0, + WMI_SERVICE_GROUP = 1, + + HTC_SERVICE_GROUP_LAST = 255 +}; + +#define MAKE_SERVICE_ID(group, index) \ + (int)(((int)group << 8) | (int)(index)) + +/* NOTE: service ID of 0x0000 is reserved and should never be used */ +#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 1) +#define HTC_LOOPBACK_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 2) + +#define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 0) +#define WMI_BEACON_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 1) +#define WMI_CAB_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 2) +#define WMI_UAPSD_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 3) +#define WMI_MGMT_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4) +#define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 5) +#define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 6) +#define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 7) +#define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 8) + +struct htc_conn_svc_msg { + __be16 msg_id; + __be16 service_id; + __be16 con_flags; + u8 dl_pipeid; + u8 ul_pipeid; + u8 svc_meta_len; + u8 pad; +} __packed; + +/* connect response status codes */ +#define HTC_SERVICE_SUCCESS 0 +#define HTC_SERVICE_NOT_FOUND 1 +#define HTC_SERVICE_FAILED 2 +#define HTC_SERVICE_NO_RESOURCES 3 +#define HTC_SERVICE_NO_MORE_EP 4 + +struct htc_conn_svc_rspmsg { + __be16 msg_id; + __be16 service_id; + u8 status; + u8 endpoint_id; + __be16 max_msg_len; + u8 svc_meta_len; + u8 pad; +} __packed; + +struct htc_comp_msg { + __be16 msg_id; +} __packed; + +int htc_init(struct htc_target *target); +int htc_connect_service(struct htc_target *target, + struct htc_service_connreq *service_connreq, + enum htc_endpoint_id *conn_rsp_eid); +int htc_send(struct htc_target *target, struct sk_buff *skb, + enum htc_endpoint_id eid, struct ath9k_htc_tx_ctl *tx_ctl); +void htc_stop(struct htc_target *target); +void htc_start(struct htc_target *target); + +void ath9k_htc_rx_msg(struct htc_target *htc_handle, + struct sk_buff *skb, u32 len, u8 pipe_id); +void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, + struct sk_buff *skb, bool txok); + +struct htc_target *ath9k_htc_hw_alloc(void *hif_handle, + struct ath9k_htc_hif *hif, + struct device *dev); +void ath9k_htc_hw_free(struct htc_target *htc); +int ath9k_htc_hw_init(struct htc_target *target, + struct device *dev, u16 devid); +void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug); + +#endif /* HTC_HST_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h new file mode 100644 index 00000000000..624422a8169 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2010 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. + */ + +#ifndef ATH9K_HW_OPS_H +#define ATH9K_HW_OPS_H + +#include "hw.h" + +/* Hardware core and driver accessible callbacks */ + +static inline void ath9k_hw_configpcipowersave(struct ath_hw *ah, + int restore, + int power_off) +{ + ath9k_hw_ops(ah)->config_pci_powersave(ah, restore, power_off); +} + +static inline void ath9k_hw_rxena(struct ath_hw *ah) +{ + ath9k_hw_ops(ah)->rx_enable(ah); +} + +static inline void ath9k_hw_set_desc_link(struct ath_hw *ah, void *ds, + u32 link) +{ + ath9k_hw_ops(ah)->set_desc_link(ds, link); +} + +static inline void ath9k_hw_get_desc_link(struct ath_hw *ah, void *ds, + u32 **link) +{ + ath9k_hw_ops(ah)->get_desc_link(ds, link); +} +static inline bool ath9k_hw_calibrate(struct ath_hw *ah, + struct ath9k_channel *chan, + u8 rxchainmask, + bool longcal) +{ + return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal); +} + +static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) +{ + return ath9k_hw_ops(ah)->get_isr(ah, masked); +} + +static inline void ath9k_hw_filltxdesc(struct ath_hw *ah, void *ds, u32 seglen, + bool is_firstseg, bool is_lastseg, + const void *ds0, dma_addr_t buf_addr, + unsigned int qcu) +{ + ath9k_hw_ops(ah)->fill_txdesc(ah, ds, seglen, is_firstseg, is_lastseg, + ds0, buf_addr, qcu); +} + +static inline int ath9k_hw_txprocdesc(struct ath_hw *ah, void *ds, + struct ath_tx_status *ts) +{ + return ath9k_hw_ops(ah)->proc_txdesc(ah, ds, ts); +} + +static inline void ath9k_hw_set11n_txdesc(struct ath_hw *ah, void *ds, + u32 pktLen, enum ath9k_pkt_type type, + u32 txPower, u32 keyIx, + enum ath9k_key_type keyType, + u32 flags) +{ + ath9k_hw_ops(ah)->set11n_txdesc(ah, ds, pktLen, type, txPower, keyIx, + keyType, flags); +} + +static inline void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, + void *lastds, + u32 durUpdateEn, u32 rtsctsRate, + u32 rtsctsDuration, + struct ath9k_11n_rate_series series[], + u32 nseries, u32 flags) +{ + ath9k_hw_ops(ah)->set11n_ratescenario(ah, ds, lastds, durUpdateEn, + rtsctsRate, rtsctsDuration, series, + nseries, flags); +} + +static inline void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, void *ds, + u32 aggrLen) +{ + ath9k_hw_ops(ah)->set11n_aggr_first(ah, ds, aggrLen); +} + +static inline void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds, + u32 numDelims) +{ + ath9k_hw_ops(ah)->set11n_aggr_middle(ah, ds, numDelims); +} + +static inline void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, void *ds) +{ + ath9k_hw_ops(ah)->set11n_aggr_last(ah, ds); +} + +static inline void ath9k_hw_clr11n_aggr(struct ath_hw *ah, void *ds) +{ + ath9k_hw_ops(ah)->clr11n_aggr(ah, ds); +} + +static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds, + u32 burstDuration) +{ + ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration); +} + +static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds, + u32 vmf) +{ + ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf); +} + +/* Private hardware call ops */ + +/* PHY ops */ + +static inline int ath9k_hw_rf_set_freq(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return ath9k_hw_private_ops(ah)->rf_set_freq(ah, chan); +} + +static inline void ath9k_hw_spur_mitigate_freq(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + ath9k_hw_private_ops(ah)->spur_mitigate_freq(ah, chan); +} + +static inline int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah) +{ + if (!ath9k_hw_private_ops(ah)->rf_alloc_ext_banks) + return 0; + + return ath9k_hw_private_ops(ah)->rf_alloc_ext_banks(ah); +} + +static inline void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah) +{ + if (!ath9k_hw_private_ops(ah)->rf_free_ext_banks) + return; + + ath9k_hw_private_ops(ah)->rf_free_ext_banks(ah); +} + +static inline bool ath9k_hw_set_rf_regs(struct ath_hw *ah, + struct ath9k_channel *chan, + u16 modesIndex) +{ + if (!ath9k_hw_private_ops(ah)->set_rf_regs) + return true; + + return ath9k_hw_private_ops(ah)->set_rf_regs(ah, chan, modesIndex); +} + +static inline void ath9k_hw_init_bb(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return ath9k_hw_private_ops(ah)->init_bb(ah, chan); +} + +static inline void ath9k_hw_set_channel_regs(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return ath9k_hw_private_ops(ah)->set_channel_regs(ah, chan); +} + +static inline int ath9k_hw_process_ini(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return ath9k_hw_private_ops(ah)->process_ini(ah, chan); +} + +static inline void ath9k_olc_init(struct ath_hw *ah) +{ + if (!ath9k_hw_private_ops(ah)->olc_init) + return; + + return ath9k_hw_private_ops(ah)->olc_init(ah); +} + +static inline void ath9k_hw_set_rfmode(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return ath9k_hw_private_ops(ah)->set_rfmode(ah, chan); +} + +static inline void ath9k_hw_mark_phy_inactive(struct ath_hw *ah) +{ + return ath9k_hw_private_ops(ah)->mark_phy_inactive(ah); +} + +static inline void ath9k_hw_set_delta_slope(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return ath9k_hw_private_ops(ah)->set_delta_slope(ah, chan); +} + +static inline bool ath9k_hw_rfbus_req(struct ath_hw *ah) +{ + return ath9k_hw_private_ops(ah)->rfbus_req(ah); +} + +static inline void ath9k_hw_rfbus_done(struct ath_hw *ah) +{ + return ath9k_hw_private_ops(ah)->rfbus_done(ah); +} + +static inline void ath9k_enable_rfkill(struct ath_hw *ah) +{ + return ath9k_hw_private_ops(ah)->enable_rfkill(ah); +} + +static inline void ath9k_hw_restore_chainmask(struct ath_hw *ah) +{ + if (!ath9k_hw_private_ops(ah)->restore_chainmask) + return; + + return ath9k_hw_private_ops(ah)->restore_chainmask(ah); +} + +static inline void ath9k_hw_set_diversity(struct ath_hw *ah, bool value) +{ + return ath9k_hw_private_ops(ah)->set_diversity(ah, value); +} + +static inline bool ath9k_hw_ani_control(struct ath_hw *ah, + enum ath9k_ani_cmd cmd, int param) +{ + return ath9k_hw_private_ops(ah)->ani_control(ah, cmd, param); +} + +static inline void ath9k_hw_do_getnf(struct ath_hw *ah, + int16_t nfarray[NUM_NF_READINGS]) +{ + ath9k_hw_private_ops(ah)->do_getnf(ah, nfarray); +} + +static inline void ath9k_hw_loadnf(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + ath9k_hw_private_ops(ah)->loadnf(ah, chan); +} + +static inline bool ath9k_hw_init_cal(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return ath9k_hw_private_ops(ah)->init_cal(ah, chan); +} + +static inline void ath9k_hw_setup_calibration(struct ath_hw *ah, + struct ath9k_cal_list *currCal) +{ + ath9k_hw_private_ops(ah)->setup_calibration(ah, currCal); +} + +static inline bool ath9k_hw_iscal_supported(struct ath_hw *ah, + enum ath9k_cal_types calType) +{ + return ath9k_hw_private_ops(ah)->iscal_supported(ah, calType); +} + +#endif /* ATH9K_HW_OPS_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 78b571129c9..c33f17dbe6f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2009 Atheros Communications Inc. + * Copyright (c) 2008-2010 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 @@ -19,18 +19,16 @@ #include <asm/unaligned.h> #include "hw.h" +#include "hw-ops.h" #include "rc.h" -#include "initvals.h" +#include "ar9003_mac.h" #define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 +#define ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM 44 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); -static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan); -static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, - struct ar5416_eeprom_def *pEepData, - u32 reg, u32 value); MODULE_AUTHOR("Atheros Communications"); MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); @@ -49,6 +47,39 @@ static void __exit ath9k_exit(void) } module_exit(ath9k_exit); +/* Private hardware callbacks */ + +static void ath9k_hw_init_cal_settings(struct ath_hw *ah) +{ + ath9k_hw_private_ops(ah)->init_cal_settings(ah); +} + +static void ath9k_hw_init_mode_regs(struct ath_hw *ah) +{ + ath9k_hw_private_ops(ah)->init_mode_regs(ah); +} + +static bool ath9k_hw_macversion_supported(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + + return priv_ops->macversion_supported(ah->hw_version.macVersion); +} + +static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan); +} + +static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) +{ + if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs) + return; + + ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah); +} + /********************/ /* Helper Functions */ /********************/ @@ -61,7 +92,11 @@ static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) return usecs *ATH9K_CLOCK_RATE_CCK; if (conf->channel->band == IEEE80211_BAND_2GHZ) return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM; - return usecs *ATH9K_CLOCK_RATE_5GHZ_OFDM; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK) + return usecs * ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM; + else + return usecs * ATH9K_CLOCK_RATE_5GHZ_OFDM; } static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) @@ -236,21 +271,6 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) } } -static int ath9k_hw_get_radiorev(struct ath_hw *ah) -{ - u32 val; - int i; - - REG_WRITE(ah, AR_PHY(0x36), 0x00007058); - - for (i = 0; i < 8; i++) - REG_WRITE(ah, AR_PHY(0x20), 0x00010000); - val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; - val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); - - return ath9k_hw_reverse_bits(val, 8); -} - /************************************/ /* HW Attach, Detach, Init Routines */ /************************************/ @@ -260,6 +280,8 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah) if (AR_SREV_9100(ah)) return; + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029); @@ -271,20 +293,30 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah) REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007); REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); } +/* This should work for all families including legacy */ static bool ath9k_hw_chip_test(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) }; + u32 regAddr[2] = { AR_STA_ID0 }; u32 regHold[2]; u32 patternData[4] = { 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999 }; - int i, j; + int i, j, loop_max; + + if (!AR_SREV_9300_20_OR_LATER(ah)) { + loop_max = 2; + regAddr[1] = AR_PHY_BASE + (8 << 2); + } else + loop_max = 1; - for (i = 0; i < 2; i++) { + for (i = 0; i < loop_max; i++) { u32 addr = regAddr[i]; u32 wrData, rdData; @@ -339,7 +371,13 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.ofdm_trig_high = 500; ah->config.cck_trig_high = 200; ah->config.cck_trig_low = 100; - ah->config.enable_ani = 1; + + /* + * For now ANI is disabled for AR9003, it is still + * being tested. + */ + if (!AR_SREV_9300_20_OR_LATER(ah)) + ah->config.enable_ani = 1; for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { ah->config.spurchans[i][0] = AR_NO_SPUR; @@ -354,6 +392,12 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.rx_intr_mitigation = true; /* + * Tx IQ Calibration (ah->config.tx_iq_calibration) is only + * used by AR9003, but it is showing reliability issues. + * It will take a while to fix so this is currently disabled. + */ + + /* * We need this for PCI devices only (Cardbus, PCI, miniPCI) * _and_ if on non-uniprocessor systems (Multiprocessor/HT). * This means we use it for all AR5416 devices, and the few @@ -372,7 +416,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) if (num_possible_cpus() > 1) ah->config.serialize_regmode = SER_REG_MODE_AUTO; } -EXPORT_SYMBOL(ath9k_hw_init); static void ath9k_hw_init_defaults(struct ath_hw *ah) { @@ -386,8 +429,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->hw_version.subvendorid = 0; ah->ah_flags = 0; - if (ah->hw_version.devid == AR5416_AR9100_DEVID) - ah->hw_version.macVersion = AR_SREV_VERSION_9100; if (!AR_SREV_9100(ah)) ah->ah_flags = AH_USE_EEPROM; @@ -400,44 +441,17 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->power_mode = ATH9K_PM_UNDEFINED; } -static int ath9k_hw_rf_claim(struct ath_hw *ah) -{ - u32 val; - - REG_WRITE(ah, AR_PHY(0), 0x00000007); - - val = ath9k_hw_get_radiorev(ah); - switch (val & AR_RADIO_SREV_MAJOR) { - case 0: - val = AR_RAD5133_SREV_MAJOR; - break; - case AR_RAD5133_SREV_MAJOR: - case AR_RAD5122_SREV_MAJOR: - case AR_RAD2133_SREV_MAJOR: - case AR_RAD2122_SREV_MAJOR: - break; - default: - ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, - "Radio Chip Rev 0x%02X not supported\n", - val & AR_RADIO_SREV_MAJOR); - return -EOPNOTSUPP; - } - - ah->hw_version.analog5GhzRev = val; - - return 0; -} - static int ath9k_hw_init_macaddr(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); u32 sum; int i; u16 eeval; + u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW }; sum = 0; for (i = 0; i < 3; i++) { - eeval = ah->eep_ops->get_eeprom(ah, AR_EEPROM_MAC(i)); + eeval = ah->eep_ops->get_eeprom(ah, EEP_MAC[i]); sum += eeval; common->macaddr[2 * i] = eeval >> 8; common->macaddr[2 * i + 1] = eeval & 0xff; @@ -448,64 +462,20 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah) return 0; } -static void ath9k_hw_init_rxgain_ini(struct ath_hw *ah) -{ - u32 rxgain_type; - - if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) { - rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE); - - if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_backoff_13db_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6); - else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_backoff_23db_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6); - else - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_original_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); - } else { - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_original_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); - } -} - -static void ath9k_hw_init_txgain_ini(struct ath_hw *ah) -{ - u32 txgain_type; - - if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) { - txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); - - if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9280Modes_high_power_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9280Modes_original_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); - } else { - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9280Modes_original_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); - } -} - static int ath9k_hw_post_init(struct ath_hw *ah) { int ecode; - if (!ath9k_hw_chip_test(ah)) - return -ENODEV; + if (!AR_SREV_9271(ah)) { + if (!ath9k_hw_chip_test(ah)) + return -ENODEV; + } - ecode = ath9k_hw_rf_claim(ah); - if (ecode != 0) - return ecode; + if (!AR_SREV_9300_20_OR_LATER(ah)) { + ecode = ar9002_hw_rf_claim(ah); + if (ecode != 0) + return ecode; + } ecode = ath9k_hw_eeprom_init(ah); if (ecode != 0) @@ -516,14 +486,12 @@ static int ath9k_hw_post_init(struct ath_hw *ah) ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah)); - if (!AR_SREV_9280_10_OR_LATER(ah)) { - ecode = ath9k_hw_rf_alloc_ext_banks(ah); - if (ecode) { - ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, - "Failed allocating banks for " - "external radio\n"); - return ecode; - } + ecode = ath9k_hw_rf_alloc_ext_banks(ah); + if (ecode) { + ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, + "Failed allocating banks for " + "external radio\n"); + return ecode; } if (!AR_SREV_9100(ah)) { @@ -534,321 +502,22 @@ static int ath9k_hw_post_init(struct ath_hw *ah) return 0; } -static bool ath9k_hw_devid_supported(u16 devid) +static void ath9k_hw_attach_ops(struct ath_hw *ah) { - switch (devid) { - case AR5416_DEVID_PCI: - case AR5416_DEVID_PCIE: - case AR5416_AR9100_DEVID: - case AR9160_DEVID_PCI: - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - case AR9285_DEVID_PCIE: - case AR5416_DEVID_AR9287_PCI: - case AR5416_DEVID_AR9287_PCIE: - case AR9271_USB: - case AR2427_DEVID_PCIE: - return true; - default: - break; - } - return false; -} - -static bool ath9k_hw_macversion_supported(u32 macversion) -{ - switch (macversion) { - case AR_SREV_VERSION_5416_PCI: - case AR_SREV_VERSION_5416_PCIE: - case AR_SREV_VERSION_9160: - case AR_SREV_VERSION_9100: - case AR_SREV_VERSION_9280: - case AR_SREV_VERSION_9285: - case AR_SREV_VERSION_9287: - case AR_SREV_VERSION_9271: - return true; - default: - break; - } - return false; -} - -static void ath9k_hw_init_cal_settings(struct ath_hw *ah) -{ - if (AR_SREV_9160_10_OR_LATER(ah)) { - if (AR_SREV_9280_10_OR_LATER(ah)) { - ah->iq_caldata.calData = &iq_cal_single_sample; - ah->adcgain_caldata.calData = - &adc_gain_cal_single_sample; - ah->adcdc_caldata.calData = - &adc_dc_cal_single_sample; - ah->adcdc_calinitdata.calData = - &adc_init_dc_cal; - } else { - ah->iq_caldata.calData = &iq_cal_multi_sample; - ah->adcgain_caldata.calData = - &adc_gain_cal_multi_sample; - ah->adcdc_caldata.calData = - &adc_dc_cal_multi_sample; - ah->adcdc_calinitdata.calData = - &adc_init_dc_cal; - } - ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; - } -} - -static void ath9k_hw_init_mode_regs(struct ath_hw *ah) -{ - if (AR_SREV_9271(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271, - ARRAY_SIZE(ar9271Modes_9271), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271, - ARRAY_SIZE(ar9271Common_9271), 2); - INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only, - ar9271Modes_9271_1_0_only, - ARRAY_SIZE(ar9271Modes_9271_1_0_only), 6); - return; - } - - if (AR_SREV_9287_11_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, - ARRAY_SIZE(ar9287Modes_9287_1_1), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1, - ARRAY_SIZE(ar9287Common_9287_1_1), 2); - if (ah->config.pcie_clock_req) - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9287PciePhy_clkreq_off_L1_9287_1_1, - ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2); - else - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9287PciePhy_clkreq_always_on_L1_9287_1_1, - ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1), - 2); - } else if (AR_SREV_9287_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0, - ARRAY_SIZE(ar9287Modes_9287_1_0), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0, - ARRAY_SIZE(ar9287Common_9287_1_0), 2); - - if (ah->config.pcie_clock_req) - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9287PciePhy_clkreq_off_L1_9287_1_0, - ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2); - else - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9287PciePhy_clkreq_always_on_L1_9287_1_0, - ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0), - 2); - } else if (AR_SREV_9285_12_OR_LATER(ah)) { - - - INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, - ARRAY_SIZE(ar9285Modes_9285_1_2), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2, - ARRAY_SIZE(ar9285Common_9285_1_2), 2); - - if (ah->config.pcie_clock_req) { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9285PciePhy_clkreq_off_L1_9285_1_2, - ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2); - } else { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9285PciePhy_clkreq_always_on_L1_9285_1_2, - ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2), - 2); - } - } else if (AR_SREV_9285_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285, - ARRAY_SIZE(ar9285Modes_9285), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285, - ARRAY_SIZE(ar9285Common_9285), 2); - - if (ah->config.pcie_clock_req) { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9285PciePhy_clkreq_off_L1_9285, - ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2); - } else { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9285PciePhy_clkreq_always_on_L1_9285, - ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2); - } - } else if (AR_SREV_9280_20_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2, - ARRAY_SIZE(ar9280Modes_9280_2), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2, - ARRAY_SIZE(ar9280Common_9280_2), 2); - - if (ah->config.pcie_clock_req) { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_off_L1_9280, - ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2); - } else { - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_always_on_L1_9280, - ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); - } - INIT_INI_ARRAY(&ah->iniModesAdditional, - ar9280Modes_fast_clock_9280_2, - ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); - } else if (AR_SREV_9280_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280, - ARRAY_SIZE(ar9280Modes_9280), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280, - ARRAY_SIZE(ar9280Common_9280), 2); - } else if (AR_SREV_9160_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160, - ARRAY_SIZE(ar5416Modes_9160), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160, - ARRAY_SIZE(ar5416Common_9160), 2); - INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160, - ARRAY_SIZE(ar5416Bank0_9160), 2); - INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160, - ARRAY_SIZE(ar5416BB_RfGain_9160), 3); - INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160, - ARRAY_SIZE(ar5416Bank1_9160), 2); - INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160, - ARRAY_SIZE(ar5416Bank2_9160), 2); - INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160, - ARRAY_SIZE(ar5416Bank3_9160), 3); - INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160, - ARRAY_SIZE(ar5416Bank6_9160), 3); - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160, - ARRAY_SIZE(ar5416Bank6TPC_9160), 3); - INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160, - ARRAY_SIZE(ar5416Bank7_9160), 2); - if (AR_SREV_9160_11(ah)) { - INIT_INI_ARRAY(&ah->iniAddac, - ar5416Addac_91601_1, - ARRAY_SIZE(ar5416Addac_91601_1), 2); - } else { - INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160, - ARRAY_SIZE(ar5416Addac_9160), 2); - } - } else if (AR_SREV_9100_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100, - ARRAY_SIZE(ar5416Modes_9100), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100, - ARRAY_SIZE(ar5416Common_9100), 2); - INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100, - ARRAY_SIZE(ar5416Bank0_9100), 2); - INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100, - ARRAY_SIZE(ar5416BB_RfGain_9100), 3); - INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100, - ARRAY_SIZE(ar5416Bank1_9100), 2); - INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100, - ARRAY_SIZE(ar5416Bank2_9100), 2); - INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100, - ARRAY_SIZE(ar5416Bank3_9100), 3); - INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100, - ARRAY_SIZE(ar5416Bank6_9100), 3); - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100, - ARRAY_SIZE(ar5416Bank6TPC_9100), 3); - INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100, - ARRAY_SIZE(ar5416Bank7_9100), 2); - INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100, - ARRAY_SIZE(ar5416Addac_9100), 2); - } else { - INIT_INI_ARRAY(&ah->iniModes, ar5416Modes, - ARRAY_SIZE(ar5416Modes), 6); - INIT_INI_ARRAY(&ah->iniCommon, ar5416Common, - ARRAY_SIZE(ar5416Common), 2); - INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0, - ARRAY_SIZE(ar5416Bank0), 2); - INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain, - ARRAY_SIZE(ar5416BB_RfGain), 3); - INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1, - ARRAY_SIZE(ar5416Bank1), 2); - INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2, - ARRAY_SIZE(ar5416Bank2), 2); - INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3, - ARRAY_SIZE(ar5416Bank3), 3); - INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6, - ARRAY_SIZE(ar5416Bank6), 3); - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC, - ARRAY_SIZE(ar5416Bank6TPC), 3); - INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7, - ARRAY_SIZE(ar5416Bank7), 2); - INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, - ARRAY_SIZE(ar5416Addac), 2); - } -} - -static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) -{ - if (AR_SREV_9287_11_OR_LATER(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9287Modes_rx_gain_9287_1_1, - ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6); - else if (AR_SREV_9287_10(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9287Modes_rx_gain_9287_1_0, - ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6); - else if (AR_SREV_9280_20(ah)) - ath9k_hw_init_rxgain_ini(ah); - - if (AR_SREV_9287_11_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9287Modes_tx_gain_9287_1_1, - ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6); - } else if (AR_SREV_9287_10(ah)) { - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9287Modes_tx_gain_9287_1_0, - ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6); - } else if (AR_SREV_9280_20(ah)) { - ath9k_hw_init_txgain_ini(ah); - } else if (AR_SREV_9285_12_OR_LATER(ah)) { - u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE); - - /* txgain table */ - if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) { - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9285Modes_high_power_tx_gain_9285_1_2, - ARRAY_SIZE(ar9285Modes_high_power_tx_gain_9285_1_2), 6); - } else { - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9285Modes_original_tx_gain_9285_1_2, - ARRAY_SIZE(ar9285Modes_original_tx_gain_9285_1_2), 6); - } - - } -} - -static void ath9k_hw_init_eeprom_fix(struct ath_hw *ah) -{ - u32 i, j; - - if (ah->hw_version.devid == AR9280_DEVID_PCI) { - - /* EEPROM Fixup */ - for (i = 0; i < ah->iniModes.ia_rows; i++) { - u32 reg = INI_RA(&ah->iniModes, i, 0); - - for (j = 1; j < ah->iniModes.ia_columns; j++) { - u32 val = INI_RA(&ah->iniModes, i, j); - - INI_RA(&ah->iniModes, i, j) = - ath9k_hw_ini_fixup(ah, - &ah->eeprom.def, - reg, val); - } - } - } + if (AR_SREV_9300_20_OR_LATER(ah)) + ar9003_hw_attach_ops(ah); + else + ar9002_hw_attach_ops(ah); } -int ath9k_hw_init(struct ath_hw *ah) +/* Called for all hardware families */ +static int __ath9k_hw_init(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); int r = 0; - if (!ath9k_hw_devid_supported(ah->hw_version.devid)) { - ath_print(common, ATH_DBG_FATAL, - "Unsupported device ID: 0x%0x\n", - ah->hw_version.devid); - return -EOPNOTSUPP; - } - - ath9k_hw_init_defaults(ah); - ath9k_hw_init_config(ah); + if (ah->hw_version.devid == AR5416_AR9100_DEVID) + ah->hw_version.macVersion = AR_SREV_VERSION_9100; if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { ath_print(common, ATH_DBG_FATAL, @@ -856,6 +525,11 @@ int ath9k_hw_init(struct ath_hw *ah) return -EIO; } + ath9k_hw_init_defaults(ah); + ath9k_hw_init_config(ah); + + ath9k_hw_attach_ops(ah); + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { ath_print(common, ATH_DBG_FATAL, "Couldn't wakeup chip\n"); return -EIO; @@ -880,7 +554,7 @@ int ath9k_hw_init(struct ath_hw *ah) else ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD; - if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { + if (!ath9k_hw_macversion_supported(ah)) { ath_print(common, ATH_DBG_FATAL, "Mac Chip Rev 0x%02x.%x is not supported by " "this driver\n", ah->hw_version.macVersion, @@ -888,45 +562,45 @@ int ath9k_hw_init(struct ath_hw *ah) return -EOPNOTSUPP; } - if (AR_SREV_9100(ah)) { - ah->iq_caldata.calData = &iq_cal_multi_sample; - ah->supp_cals = IQ_MISMATCH_CAL; - ah->is_pciexpress = false; - } - - if (AR_SREV_9271(ah)) + if (AR_SREV_9271(ah) || AR_SREV_9100(ah)) ah->is_pciexpress = false; ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); - ath9k_hw_init_cal_settings(ah); ah->ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_10_OR_LATER(ah)) { + if (AR_SREV_9280_10_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; - ah->ath9k_hw_rf_set_freq = &ath9k_hw_ar9280_set_channel; - ah->ath9k_hw_spur_mitigate_freq = &ath9k_hw_9280_spur_mitigate; - } else { - ah->ath9k_hw_rf_set_freq = &ath9k_hw_set_channel; - ah->ath9k_hw_spur_mitigate_freq = &ath9k_hw_spur_mitigate; - } ath9k_hw_init_mode_regs(ah); + /* + * Configire PCIE after Ini init. SERDES values now come from ini file + * This enables PCIe low power mode. + */ + if (AR_SREV_9300_20_OR_LATER(ah)) { + u32 regval; + unsigned int i; + + /* Set Bits 16 and 17 in the AR_WA register. */ + regval = REG_READ(ah, AR_WA); + regval |= 0x00030000; + REG_WRITE(ah, AR_WA, regval); + + for (i = 0; i < ah->iniPcieSerdesLowPower.ia_rows; i++) { + REG_WRITE(ah, + INI_RA(&ah->iniPcieSerdesLowPower, i, 0), + INI_RA(&ah->iniPcieSerdesLowPower, i, 1)); + } + } + if (ah->is_pciexpress) ath9k_hw_configpcipowersave(ah, 0, 0); else ath9k_hw_disablepcie(ah); - /* Support for Japan ch.14 (2484) spread */ - if (AR_SREV_9287_11_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniCckfirNormal, - ar9287Common_normal_cck_fir_coeff_92871_1, - ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_92871_1), 2); - INIT_INI_ARRAY(&ah->iniCckfirJapan2484, - ar9287Common_japan_2484_cck_fir_coeff_92871_1, - ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_92871_1), 2); - } + if (!AR_SREV_9300_20_OR_LATER(ah)) + ar9002_hw_cck_chan14_spread(ah); r = ath9k_hw_post_init(ah); if (r) @@ -937,8 +611,6 @@ int ath9k_hw_init(struct ath_hw *ah) if (r) return r; - ath9k_hw_init_eeprom_fix(ah); - r = ath9k_hw_init_macaddr(ah); if (r) { ath_print(common, ATH_DBG_FATAL, @@ -951,6 +623,9 @@ int ath9k_hw_init(struct ath_hw *ah) else ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); + if (AR_SREV_9300_20_OR_LATER(ah)) + ar9003_hw_set_nf_limits(ah); + ath9k_init_nfcal_hist_buffer(ah); common->state = ATH_HW_INITIALIZED; @@ -958,24 +633,50 @@ int ath9k_hw_init(struct ath_hw *ah) return 0; } -static void ath9k_hw_init_bb(struct ath_hw *ah, - struct ath9k_channel *chan) +int ath9k_hw_init(struct ath_hw *ah) { - u32 synthDelay; + int ret; + struct ath_common *common = ath9k_hw_common(ah); - synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(chan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; + /* These are all the AR5008/AR9001/AR9002 hardware family of chipsets */ + switch (ah->hw_version.devid) { + case AR5416_DEVID_PCI: + case AR5416_DEVID_PCIE: + case AR5416_AR9100_DEVID: + case AR9160_DEVID_PCI: + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + case AR9285_DEVID_PCIE: + case AR9287_DEVID_PCI: + case AR9287_DEVID_PCIE: + case AR2427_DEVID_PCIE: + case AR9300_DEVID_PCIE: + break; + default: + if (common->bus_ops->ath_bus_type == ATH_USB) + break; + ath_print(common, ATH_DBG_FATAL, + "Hardware device ID 0x%04x not supported\n", + ah->hw_version.devid); + return -EOPNOTSUPP; + } - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + ret = __ath9k_hw_init(ah); + if (ret) { + ath_print(common, ATH_DBG_FATAL, + "Unable to initialize hardware; " + "initialization status: %d\n", ret); + return ret; + } - udelay(synthDelay + BASE_ACTIVATE_DELAY); + return 0; } +EXPORT_SYMBOL(ath9k_hw_init); static void ath9k_hw_init_qos(struct ath_hw *ah) { + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); @@ -989,105 +690,22 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); -} - -static void ath9k_hw_change_target_baud(struct ath_hw *ah, u32 freq, u32 baud) -{ - u32 lcr; - u32 baud_divider = freq * 1000 * 1000 / 16 / baud; - - lcr = REG_READ(ah , 0x5100c); - lcr |= 0x80; - REG_WRITE(ah, 0x5100c, lcr); - REG_WRITE(ah, 0x51004, (baud_divider >> 8)); - REG_WRITE(ah, 0x51000, (baud_divider & 0xff)); - - lcr &= ~0x80; - REG_WRITE(ah, 0x5100c, lcr); + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); } static void ath9k_hw_init_pll(struct ath_hw *ah, struct ath9k_channel *chan) { - u32 pll; - - if (AR_SREV_9100(ah)) { - if (chan && IS_CHAN_5GHZ(chan)) - pll = 0x1450; - else - pll = 0x1458; - } else { - if (AR_SREV_9280_10_OR_LATER(ah)) { - pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); - - if (chan && IS_CHAN_5GHZ(chan)) { - pll |= SM(0x28, AR_RTC_9160_PLL_DIV); - - - if (AR_SREV_9280_20(ah)) { - if (((chan->channel % 20) == 0) - || ((chan->channel % 10) == 0)) - pll = 0x2850; - else - pll = 0x142c; - } - } else { - pll |= SM(0x2c, AR_RTC_9160_PLL_DIV); - } - - } else if (AR_SREV_9160_10_OR_LATER(ah)) { - - pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); - - if (chan && IS_CHAN_5GHZ(chan)) - pll |= SM(0x50, AR_RTC_9160_PLL_DIV); - else - pll |= SM(0x58, AR_RTC_9160_PLL_DIV); - } else { - pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_PLL_CLKSEL); + u32 pll = ath9k_hw_compute_pll_control(ah, chan); - if (chan && IS_CHAN_5GHZ(chan)) - pll |= SM(0xa, AR_RTC_PLL_DIV); - else - pll |= SM(0xb, AR_RTC_PLL_DIV); - } - } REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); /* Switch the core clock for ar9271 to 117Mhz */ if (AR_SREV_9271(ah)) { - if ((pll == 0x142c) || (pll == 0x2850) ) { - udelay(500); - /* set CLKOBS to output AHB clock */ - REG_WRITE(ah, 0x7020, 0xe); - /* - * 0x304: 117Mhz, ahb_ratio: 1x1 - * 0x306: 40Mhz, ahb_ratio: 1x1 - */ - REG_WRITE(ah, 0x50040, 0x304); - /* - * makes adjustments for the baud dividor to keep the - * targetted baud rate based on the used core clock. - */ - ath9k_hw_change_target_baud(ah, AR9271_CORE_CLOCK, - AR9271_TARGET_BAUD_RATE); - } + udelay(500); + REG_WRITE(ah, 0x50040, 0x304); } udelay(RTC_PLL_SETTLE_DELAY); @@ -1095,70 +713,58 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); } -static void ath9k_hw_init_chain_masks(struct ath_hw *ah) -{ - int rx_chainmask, tx_chainmask; - - rx_chainmask = ah->rxchainmask; - tx_chainmask = ah->txchainmask; - - switch (rx_chainmask) { - case 0x5: - REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, - AR_PHY_SWAP_ALT_CHAIN); - case 0x3: - if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) { - REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); - REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); - break; - } - case 0x1: - case 0x2: - case 0x7: - REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); - REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); - break; - default: - break; - } - - REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask); - if (tx_chainmask == 0x5) { - REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, - AR_PHY_SWAP_ALT_CHAIN); - } - if (AR_SREV_9100(ah)) - REG_WRITE(ah, AR_PHY_ANALOG_SWAP, - REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001); -} - static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, enum nl80211_iftype opmode) { - ah->mask_reg = AR_IMR_TXERR | + u32 imr_reg = AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_BCNMISC; - if (ah->config.rx_intr_mitigation) - ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; - else - ah->mask_reg |= AR_IMR_RXOK; + if (AR_SREV_9300_20_OR_LATER(ah)) { + imr_reg |= AR_IMR_RXOK_HP; + if (ah->config.rx_intr_mitigation) + imr_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; + else + imr_reg |= AR_IMR_RXOK_LP; - ah->mask_reg |= AR_IMR_TXOK; + } else { + if (ah->config.rx_intr_mitigation) + imr_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; + else + imr_reg |= AR_IMR_RXOK; + } + + if (ah->config.tx_intr_mitigation) + imr_reg |= AR_IMR_TXINTM | AR_IMR_TXMINTR; + else + imr_reg |= AR_IMR_TXOK; if (opmode == NL80211_IFTYPE_AP) - ah->mask_reg |= AR_IMR_MIB; + imr_reg |= AR_IMR_MIB; + + ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_IMR, ah->mask_reg); - REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); + REG_WRITE(ah, AR_IMR, imr_reg); + ah->imrs2_reg |= AR_IMR_S2_GTT; + REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); if (!AR_SREV_9100(ah)) { REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); } + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + + if (AR_SREV_9300_20_OR_LATER(ah)) { + REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, 0); + REG_WRITE(ah, AR_INTR_PRIO_ASYNC_MASK, 0); + REG_WRITE(ah, AR_INTR_PRIO_SYNC_ENABLE, 0); + REG_WRITE(ah, AR_INTR_PRIO_SYNC_MASK, 0); + } } static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) @@ -1241,19 +847,13 @@ void ath9k_hw_deinit(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - if (common->state <= ATH_HW_INITIALIZED) + if (common->state < ATH_HW_INITIALIZED) goto free_hw; - if (!AR_SREV_9100(ah)) - ath9k_hw_ani_disable(ah); - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); free_hw: - if (!AR_SREV_9280_10_OR_LATER(ah)) - ath9k_hw_rf_free_ext_banks(ah); - kfree(ah); - ah = NULL; + ath9k_hw_rf_free_ext_banks(ah); } EXPORT_SYMBOL(ath9k_hw_deinit); @@ -1261,136 +861,7 @@ EXPORT_SYMBOL(ath9k_hw_deinit); /* INI */ /*******/ -static void ath9k_hw_override_ini(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - u32 val; - - if (AR_SREV_9271(ah)) { - /* - * Enable spectral scan to solution for issues with stuck - * beacons on AR9271 1.0. The beacon stuck issue is not seeon on - * AR9271 1.1 - */ - if (AR_SREV_9271_10(ah)) { - val = REG_READ(ah, AR_PHY_SPECTRAL_SCAN) | - AR_PHY_SPECTRAL_SCAN_ENABLE; - REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val); - } - else if (AR_SREV_9271_11(ah)) - /* - * change AR_PHY_RF_CTL3 setting to fix MAC issue - * present on AR9271 1.1 - */ - REG_WRITE(ah, AR_PHY_RF_CTL3, 0x3a020001); - return; - } - - /* - * Set the RX_ABORT and RX_DIS and clear if off only after - * RXE is set for MAC. This prevents frames with corrupted - * descriptor status. - */ - REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - - if (AR_SREV_9280_10_OR_LATER(ah)) { - val = REG_READ(ah, AR_PCU_MISC_MODE2) & - (~AR_PCU_MISC_MODE2_HWWAR1); - - if (AR_SREV_9287_10_OR_LATER(ah)) - val = val & (~AR_PCU_MISC_MODE2_HWWAR2); - - REG_WRITE(ah, AR_PCU_MISC_MODE2, val); - } - - if (!AR_SREV_5416_20_OR_LATER(ah) || - AR_SREV_9280_10_OR_LATER(ah)) - return; - /* - * Disable BB clock gating - * Necessary to avoid issues on AR5416 2.0 - */ - REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); - - /* - * Disable RIFS search on some chips to avoid baseband - * hang issues. - */ - if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) { - val = REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS); - val &= ~AR_PHY_RIFS_INIT_DELAY; - REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val); - } -} - -static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah, - struct ar5416_eeprom_def *pEepData, - u32 reg, u32 value) -{ - struct base_eep_header *pBase = &(pEepData->baseEepHeader); - struct ath_common *common = ath9k_hw_common(ah); - - switch (ah->hw_version.devid) { - case AR9280_DEVID_PCI: - if (reg == 0x7894) { - ath_print(common, ATH_DBG_EEPROM, - "ini VAL: %x EEPROM: %x\n", value, - (pBase->version & 0xff)); - - if ((pBase->version & 0xff) > 0x0a) { - ath_print(common, ATH_DBG_EEPROM, - "PWDCLKIND: %d\n", - pBase->pwdclkind); - value &= ~AR_AN_TOP2_PWDCLKIND; - value |= AR_AN_TOP2_PWDCLKIND & - (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); - } else { - ath_print(common, ATH_DBG_EEPROM, - "PWDCLKIND Earlier Rev\n"); - } - - ath_print(common, ATH_DBG_EEPROM, - "final ini VAL: %x\n", value); - } - break; - } - - return value; -} - -static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, - struct ar5416_eeprom_def *pEepData, - u32 reg, u32 value) -{ - if (ah->eep_map == EEP_MAP_4KBITS) - return value; - else - return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value); -} - -static void ath9k_olc_init(struct ath_hw *ah) -{ - u32 i; - - if (OLC_FOR_AR9287_10_LATER) { - REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9, - AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL); - ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TXPC0, - AR9287_AN_TXPC0_TXPCMODE, - AR9287_AN_TXPC0_TXPCMODE_S, - AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE); - udelay(100); - } else { - for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) - ah->originalGain[i] = - MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), - AR_PHY_TX_GAIN); - ah->PDADCdelta = 0; - } -} - -static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, - struct ath9k_channel *chan) +u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan) { u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band); @@ -1404,173 +875,24 @@ static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, return ctl; } -static int ath9k_hw_process_ini(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); - int i, regWrites = 0; - struct ieee80211_channel *channel = chan->chan; - u32 modesIndex, freqIndex; - - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - modesIndex = 1; - freqIndex = 1; - break; - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - modesIndex = 2; - freqIndex = 1; - break; - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_B: - modesIndex = 4; - freqIndex = 2; - break; - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - modesIndex = 3; - freqIndex = 2; - break; - - default: - return -EINVAL; - } - - REG_WRITE(ah, AR_PHY(0), 0x00000007); - REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); - ah->eep_ops->set_addac(ah, chan); - - if (AR_SREV_5416_22_OR_LATER(ah)) { - REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites); - } else { - struct ar5416IniArray temp; - u32 addacSize = - sizeof(u32) * ah->iniAddac.ia_rows * - ah->iniAddac.ia_columns; - - memcpy(ah->addac5416_21, - ah->iniAddac.ia_array, addacSize); - - (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0; - - temp.ia_array = ah->addac5416_21; - temp.ia_columns = ah->iniAddac.ia_columns; - temp.ia_rows = ah->iniAddac.ia_rows; - REG_WRITE_ARRAY(&temp, 1, regWrites); - } - - REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); - - for (i = 0; i < ah->iniModes.ia_rows; i++) { - u32 reg = INI_RA(&ah->iniModes, i, 0); - u32 val = INI_RA(&ah->iniModes, i, modesIndex); - - REG_WRITE(ah, reg, val); - - if (reg >= 0x7800 && reg < 0x78a0 - && ah->config.analog_shiftreg) { - udelay(100); - } - - DO_DELAY(regWrites); - } - - if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah)) - REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites); - - if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) || - AR_SREV_9287_10_OR_LATER(ah)) - REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); - - for (i = 0; i < ah->iniCommon.ia_rows; i++) { - u32 reg = INI_RA(&ah->iniCommon, i, 0); - u32 val = INI_RA(&ah->iniCommon, i, 1); - - REG_WRITE(ah, reg, val); - - if (reg >= 0x7800 && reg < 0x78a0 - && ah->config.analog_shiftreg) { - udelay(100); - } - - DO_DELAY(regWrites); - } - - ath9k_hw_write_regs(ah, freqIndex, regWrites); - - if (AR_SREV_9271_10(ah)) - REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only, - modesIndex, regWrites); - - if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) { - REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, - regWrites); - } - - ath9k_hw_override_ini(ah, chan); - ath9k_hw_set_regs(ah, chan); - ath9k_hw_init_chain_masks(ah); - - if (OLC_FOR_AR9280_20_LATER) - ath9k_olc_init(ah); - - ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(regulatory, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) regulatory->power_limit)); - - if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { - ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, - "ar5416SetRfRegs failed\n"); - return -EIO; - } - - return 0; -} - /****************************************/ /* Reset and Channel Switching Routines */ /****************************************/ -static void ath9k_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan) -{ - u32 rfMode = 0; - - if (chan == NULL) - return; - - rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) - ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; - - if (!AR_SREV_9280_10_OR_LATER(ah)) - rfMode |= (IS_CHAN_5GHZ(chan)) ? - AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; - - if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) - rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); - - REG_WRITE(ah, AR_PHY_MODE, rfMode); -} - -static void ath9k_hw_mark_phy_inactive(struct ath_hw *ah) -{ - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); -} - static inline void ath9k_hw_set_dma(struct ath_hw *ah) { + struct ath_common *common = ath9k_hw_common(ah); u32 regval; + ENABLE_REGWRITE_BUFFER(ah); + /* * set AHB_MODE not to do cacheline prefetches */ - regval = REG_READ(ah, AR_AHB_MODE); - REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); + if (!AR_SREV_9300_20_OR_LATER(ah)) { + regval = REG_READ(ah, AR_AHB_MODE); + REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); + } /* * let mac dma reads be in 128 byte chunks @@ -1578,12 +900,18 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + /* * Restore TX Trigger Level to its pre-reset value. * The initial value depends on whether aggregation is enabled, and is * adjusted whenever underruns are detected. */ - REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level); + if (!AR_SREV_9300_20_OR_LATER(ah)) + REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level); + + ENABLE_REGWRITE_BUFFER(ah); /* * let mac dma writes be in 128 byte chunks @@ -1596,6 +924,14 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) */ REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + if (AR_SREV_9300_20_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_HP, 0x1); + REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_LP, 0x1); + + ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize - + ah->caps.rx_status_len); + } + /* * reduce the number of usable entries in PCU TXBUF to avoid * wrap around issues. @@ -1611,6 +947,12 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE); } + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + + if (AR_SREV_9300_20_OR_LATER(ah)) + ath9k_hw_reset_txstatus_ring(ah); } static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) @@ -1638,10 +980,8 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) } } -static inline void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, - u32 coef_scaled, - u32 *coef_mantissa, - u32 *coef_exponent) +void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, + u32 *coef_mantissa, u32 *coef_exponent) { u32 coef_exp, coef_man; @@ -1657,40 +997,6 @@ static inline void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, *coef_exponent = coef_exp - 16; } -static void ath9k_hw_set_delta_slope(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - u32 coef_scaled, ds_coef_exp, ds_coef_man; - u32 clockMhzScaled = 0x64000000; - struct chan_centers centers; - - if (IS_CHAN_HALF_RATE(chan)) - clockMhzScaled = clockMhzScaled >> 1; - else if (IS_CHAN_QUARTER_RATE(chan)) - clockMhzScaled = clockMhzScaled >> 2; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - coef_scaled = clockMhzScaled / centers.synth_center; - - ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, - &ds_coef_exp); - - REG_RMW_FIELD(ah, AR_PHY_TIMING3, - AR_PHY_TIMING3_DSC_MAN, ds_coef_man); - REG_RMW_FIELD(ah, AR_PHY_TIMING3, - AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); - - coef_scaled = (9 * coef_scaled) / 10; - - ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, - &ds_coef_exp); - - REG_RMW_FIELD(ah, AR_PHY_HALFGI, - AR_PHY_HALFGI_DSC_MAN, ds_coef_man); - REG_RMW_FIELD(ah, AR_PHY_HALFGI, - AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); -} - static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) { u32 rst_flags; @@ -1704,6 +1010,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) (void)REG_READ(ah, AR_RTC_DERIVED_CLK); } + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); @@ -1715,11 +1023,16 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) if (tmpReg & (AR_INTR_SYNC_LOCAL_TIMEOUT | AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { + u32 val; REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); - REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - } else { + + val = AR_RC_HOSTIF; + if (!AR_SREV_9300_20_OR_LATER(ah)) + val |= AR_RC_AHB; + REG_WRITE(ah, AR_RC, val); + + } else if (!AR_SREV_9300_20_OR_LATER(ah)) REG_WRITE(ah, AR_RC, AR_RC_AHB); - } rst_flags = AR_RTC_RC_MAC_WARM; if (type == ATH9K_RESET_COLD) @@ -1727,6 +1040,10 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) } REG_WRITE(ah, AR_RTC_RC, rst_flags); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + udelay(50); REG_WRITE(ah, AR_RTC_RC, 0); @@ -1747,16 +1064,23 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) { + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); - if (!AR_SREV_9100(ah)) + if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah)) REG_WRITE(ah, AR_RC, AR_RC_AHB); REG_WRITE(ah, AR_RTC_RESET, 0); - udelay(2); - if (!AR_SREV_9100(ah)) + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + + if (!AR_SREV_9300_20_OR_LATER(ah)) + udelay(2); + + if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah)) REG_WRITE(ah, AR_RC, 0); REG_WRITE(ah, AR_RTC_RESET, 1); @@ -1792,34 +1116,6 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) } } -static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan) -{ - u32 phymode; - u32 enableDacFifo = 0; - - if (AR_SREV_9285_10_OR_LATER(ah)) - enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) & - AR_PHY_FC_ENABLE_DAC_FIFO); - - phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 - | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo; - - if (IS_CHAN_HT40(chan)) { - phymode |= AR_PHY_FC_DYN2040_EN; - - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) - phymode |= AR_PHY_FC_DYN2040_PRI_CH; - - } - REG_WRITE(ah, AR_PHY_TURBO, phymode); - - ath9k_hw_set11nmac2040(ah); - - REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); - REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); -} - static bool ath9k_hw_chip_reset(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -1845,7 +1141,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *channel = chan->chan; - u32 synthDelay, qnum; + u32 qnum; int r; for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { @@ -1857,17 +1153,15 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, } } - REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); - if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, - AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) { + if (!ath9k_hw_rfbus_req(ah)) { ath_print(common, ATH_DBG_FATAL, "Could not kill baseband RX\n"); return false; } - ath9k_hw_set_regs(ah, chan); + ath9k_hw_set_channel_regs(ah, chan); - r = ah->ath9k_hw_rf_set_freq(ah, chan); + r = ath9k_hw_rf_set_freq(ah, chan); if (r) { ath_print(common, ATH_DBG_FATAL, "Failed to set channel\n"); @@ -1881,20 +1175,12 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, min((u32) MAX_RATE_POWER, (u32) regulatory->power_limit)); - synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_B(chan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; - - udelay(synthDelay + BASE_ACTIVATE_DELAY); - - REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); + ath9k_hw_rfbus_done(ah); if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) ath9k_hw_set_delta_slope(ah, chan); - ah->ath9k_hw_spur_mitigate_freq(ah, chan); + ath9k_hw_spur_mitigate_freq(ah, chan); if (!chan->oneTimeCalsDone) chan->oneTimeCalsDone = true; @@ -1902,17 +1188,33 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, return true; } -static void ath9k_enable_rfkill(struct ath_hw *ah) +bool ath9k_hw_check_alive(struct ath_hw *ah) { - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); + int count = 50; + u32 reg; + + if (AR_SREV_9285_10_OR_LATER(ah)) + return true; + + do { + reg = REG_READ(ah, AR_OBS_BUS_1); - REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, - AR_GPIO_INPUT_MUX2_RFSILENT); + if ((reg & 0x7E7FFFEF) == 0x00702400) + continue; - ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio); - REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); + switch (reg & 0x7E000B00) { + case 0x1E000000: + case 0x52000B00: + case 0x18000B00: + continue; + default: + return true; + } + } while (count-- > 0); + + return false; } +EXPORT_SYMBOL(ath9k_hw_check_alive); int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, bool bChannelChange) @@ -1923,11 +1225,18 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u32 saveDefAntenna; u32 macStaId1; u64 tsf = 0; - int i, rx_chainmask, r; + int i, r; ah->txchainmask = common->tx_chainmask; ah->rxchainmask = common->rx_chainmask; + if (!ah->chip_fullsleep) { + ath9k_hw_abortpcurecv(ah); + if (!ath9k_hw_stopdmarecv(ah)) + ath_print(common, ATH_DBG_XMIT, + "Failed to stop receive dma\n"); + } + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; @@ -1940,8 +1249,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, (chan->channel != ah->curchan->channel) && ((chan->channelFlags & CHANNEL_ALL) == (ah->curchan->channelFlags & CHANNEL_ALL)) && - !(AR_SREV_9280(ah) || IS_CHAN_A_5MHZ_SPACED(chan) || - IS_CHAN_A_5MHZ_SPACED(ah->curchan))) { + !AR_SREV_9280(ah)) { if (ath9k_hw_channel_change(ah, chan)) { ath9k_hw_loadnf(ah, ah->curchan); @@ -1966,6 +1274,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_mark_phy_inactive(ah); + /* Only required on the first reset */ if (AR_SREV_9271(ah) && ah->htc_reset_init) { REG_WRITE(ah, AR9271_RESET_POWER_DOWN_CONTROL, @@ -1978,6 +1287,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, return -EINVAL; } + /* Only required on the first reset */ if (AR_SREV_9271(ah) && ah->htc_reset_init) { ah->htc_reset_init = false; REG_WRITE(ah, @@ -1993,16 +1303,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (AR_SREV_9280_10_OR_LATER(ah)) REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); - if (AR_SREV_9287_12_OR_LATER(ah)) { - /* Enable ASYNC FIFO */ - REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, - AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL); - REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO); - REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, - AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET); - REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3, - AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET); - } r = ath9k_hw_process_ini(ah, chan); if (r) return r; @@ -2027,9 +1327,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) ath9k_hw_set_delta_slope(ah, chan); - ah->ath9k_hw_spur_mitigate_freq(ah, chan); + ath9k_hw_spur_mitigate_freq(ah, chan); ah->eep_ops->set_board_values(ah, chan); + ath9k_hw_set_operating_mode(ah, ah->opmode); + + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr)); REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4) | macStaId1 @@ -2037,25 +1341,27 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | (ah->config. ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0) | ah->sta_id1_defaults); - ath9k_hw_set_operating_mode(ah, ah->opmode); - ath_hw_setbssidmask(common); - REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna); - ath9k_hw_write_associd(ah); - REG_WRITE(ah, AR_ISR, ~0); - REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); - r = ah->ath9k_hw_rf_set_freq(ah, chan); + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + + r = ath9k_hw_rf_set_freq(ah, chan); if (r) return r; + ENABLE_REGWRITE_BUFFER(ah); + for (i = 0; i < AR_NUM_DCU; i++) REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + ah->intr_txqs = 0; for (i = 0; i < ah->caps.total_queues; i++) ath9k_hw_resettxqueue(ah, i); @@ -2068,25 +1374,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_init_global_settings(ah); - if (AR_SREV_9287_12_OR_LATER(ah)) { - REG_WRITE(ah, AR_D_GBL_IFS_SIFS, - AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR); - REG_WRITE(ah, AR_D_GBL_IFS_SLOT, - AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR); - REG_WRITE(ah, AR_D_GBL_IFS_EIFS, - AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR); - - REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR); - REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR); - - REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER, - AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768); - REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN, - AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL); - } - if (AR_SREV_9287_12_OR_LATER(ah)) { - REG_SET_BIT(ah, AR_PCU_MISC_MODE2, - AR_PCU_MISC_MODE2_ENABLE_AGGWEP); + if (!AR_SREV_9300_20_OR_LATER(ah)) { + ar9002_hw_enable_async_fifo(ah); + ar9002_hw_enable_wep_aggregation(ah); } REG_WRITE(ah, AR_STA_ID1, @@ -2101,19 +1391,24 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); } + if (ah->config.tx_intr_mitigation) { + REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, 300); + REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, 750); + } + ath9k_hw_init_bb(ah, chan); if (!ath9k_hw_init_cal(ah, chan)) return -EIO; - rx_chainmask = ah->rxchainmask; - if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { - REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); - REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); - } + ENABLE_REGWRITE_BUFFER(ah); + ath9k_hw_restore_chainmask(ah); REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ); + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + /* * For big endian systems turn on swapping for descriptors */ @@ -2143,6 +1438,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (ah->btcoex_hw.enabled) ath9k_hw_btcoex_enable(ah); + if (AR_SREV_9300_20_OR_LATER(ah)) { + ath9k_hw_loadnf(ah, curchan); + ath9k_hw_start_nfcal(ah); + } + return 0; } EXPORT_SYMBOL(ath9k_hw_reset); @@ -2429,21 +1729,35 @@ EXPORT_SYMBOL(ath9k_hw_keyisvalid); /* Power Management (Chipset) */ /******************************/ +/* + * Notify Power Mgt is disabled in self-generated frames. + * If requested, force chip to sleep. + */ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) { REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); if (setChip) { + /* + * Clear the RTC force wake bit to allow the + * mac to go to sleep. + */ REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); - if (!AR_SREV_9100(ah)) + if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah)) REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - if(!AR_SREV_5416(ah)) + /* Shutdown chip. Active low */ + if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) REG_CLR_BIT(ah, (AR_RTC_RESET), AR_RTC_RESET_EN); } } +/* + * Notify Power Management is enabled in self-generating + * frames. If request, set power mode of chip to + * auto/normal. Duration in units of 128us (1/8 TU). + */ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip) { REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); @@ -2451,9 +1765,14 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip) struct ath9k_hw_capabilities *pCap = &ah->caps; if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + /* Set WakeOnInterrupt bit; clear ForceWake bit */ REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); } else { + /* + * Clear the RTC force wake bit to allow the + * mac to go to sleep. + */ REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); } @@ -2472,7 +1791,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip) ATH9K_RESET_POWER_ON) != true) { return false; } - ath9k_hw_init_pll(ah, NULL); + if (!AR_SREV_9300_20_OR_LATER(ah)) + ath9k_hw_init_pll(ah, NULL); } if (AR_SREV_9100(ah)) REG_SET_BIT(ah, AR_RTC_RESET, @@ -2542,424 +1862,6 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) } EXPORT_SYMBOL(ath9k_hw_setpower); -/* - * Helper for ASPM support. - * - * Disable PLL when in L0s as well as receiver clock when in L1. - * This power saving option must be enabled through the SerDes. - * - * Programming the SerDes must go through the same 288 bit serial shift - * register as the other analog registers. Hence the 9 writes. - */ -void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off) -{ - u8 i; - u32 val; - - if (ah->is_pciexpress != true) - return; - - /* Do not touch SerDes registers */ - if (ah->config.pcie_powersave_enable == 2) - return; - - /* Nothing to do on restore for 11N */ - if (!restore) { - if (AR_SREV_9280_20_OR_LATER(ah)) { - /* - * AR9280 2.0 or later chips use SerDes values from the - * initvals.h initialized depending on chipset during - * ath9k_hw_init() - */ - for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) { - REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0), - INI_RA(&ah->iniPcieSerdes, i, 1)); - } - } else if (AR_SREV_9280(ah) && - (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) { - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - - /* RX shut off when elecidle is asserted */ - REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); - REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); - REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); - - /* Shut off CLKREQ active in L1 */ - if (ah->config.pcie_clock_req) - REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); - else - REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); - - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); - - /* Load the new settings */ - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); - - } else { - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - - /* RX shut off when elecidle is asserted */ - REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); - REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); - REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); - - /* - * Ignore ah->ah_config.pcie_clock_req setting for - * pre-AR9280 11n - */ - REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); - - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); - - /* Load the new settings */ - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); - } - - udelay(1000); - - /* set bit 19 to allow forcing of pcie core into L1 state */ - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); - - /* Several PCIe massages to ensure proper behaviour */ - if (ah->config.pcie_waen) { - val = ah->config.pcie_waen; - if (!power_off) - val &= (~AR_WA_D3_L1_DISABLE); - } else { - if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || - AR_SREV_9287(ah)) { - val = AR9285_WA_DEFAULT; - if (!power_off) - val &= (~AR_WA_D3_L1_DISABLE); - } else if (AR_SREV_9280(ah)) { - /* - * On AR9280 chips bit 22 of 0x4004 needs to be - * set otherwise card may disappear. - */ - val = AR9280_WA_DEFAULT; - if (!power_off) - val &= (~AR_WA_D3_L1_DISABLE); - } else - val = AR_WA_DEFAULT; - } - - REG_WRITE(ah, AR_WA, val); - } - - if (power_off) { - /* - * Set PCIe workaround bits - * bit 14 in WA register (disable L1) should only - * be set when device enters D3 and be cleared - * when device comes back to D0. - */ - if (ah->config.pcie_waen) { - if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE) - REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE); - } else { - if (((AR_SREV_9285(ah) || AR_SREV_9271(ah) || - AR_SREV_9287(ah)) && - (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) || - (AR_SREV_9280(ah) && - (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) { - REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE); - } - } - } -} -EXPORT_SYMBOL(ath9k_hw_configpcipowersave); - -/**********************/ -/* Interrupt Handling */ -/**********************/ - -bool ath9k_hw_intrpend(struct ath_hw *ah) -{ - u32 host_isr; - - if (AR_SREV_9100(ah)) - return true; - - host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE); - if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS)) - return true; - - host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE); - if ((host_isr & AR_INTR_SYNC_DEFAULT) - && (host_isr != AR_INTR_SPURIOUS)) - return true; - - return false; -} -EXPORT_SYMBOL(ath9k_hw_intrpend); - -bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) -{ - u32 isr = 0; - u32 mask2 = 0; - struct ath9k_hw_capabilities *pCap = &ah->caps; - u32 sync_cause = 0; - bool fatal_int = false; - struct ath_common *common = ath9k_hw_common(ah); - - if (!AR_SREV_9100(ah)) { - if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { - if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) - == AR_RTC_STATUS_ON) { - isr = REG_READ(ah, AR_ISR); - } - } - - sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & - AR_INTR_SYNC_DEFAULT; - - *masked = 0; - - if (!isr && !sync_cause) - return false; - } else { - *masked = 0; - isr = REG_READ(ah, AR_ISR); - } - - if (isr) { - if (isr & AR_ISR_BCNMISC) { - u32 isr2; - isr2 = REG_READ(ah, AR_ISR_S2); - if (isr2 & AR_ISR_S2_TIM) - mask2 |= ATH9K_INT_TIM; - if (isr2 & AR_ISR_S2_DTIM) - mask2 |= ATH9K_INT_DTIM; - if (isr2 & AR_ISR_S2_DTIMSYNC) - mask2 |= ATH9K_INT_DTIMSYNC; - if (isr2 & (AR_ISR_S2_CABEND)) - mask2 |= ATH9K_INT_CABEND; - if (isr2 & AR_ISR_S2_GTT) - mask2 |= ATH9K_INT_GTT; - if (isr2 & AR_ISR_S2_CST) - mask2 |= ATH9K_INT_CST; - if (isr2 & AR_ISR_S2_TSFOOR) - mask2 |= ATH9K_INT_TSFOOR; - } - - isr = REG_READ(ah, AR_ISR_RAC); - if (isr == 0xffffffff) { - *masked = 0; - return false; - } - - *masked = isr & ATH9K_INT_COMMON; - - if (ah->config.rx_intr_mitigation) { - if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) - *masked |= ATH9K_INT_RX; - } - - if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) - *masked |= ATH9K_INT_RX; - if (isr & - (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | - AR_ISR_TXEOL)) { - u32 s0_s, s1_s; - - *masked |= ATH9K_INT_TX; - - s0_s = REG_READ(ah, AR_ISR_S0_S); - ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK); - ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); - - s1_s = REG_READ(ah, AR_ISR_S1_S); - ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR); - ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL); - } - - if (isr & AR_ISR_RXORN) { - ath_print(common, ATH_DBG_INTERRUPT, - "receive FIFO overrun interrupt\n"); - } - - if (!AR_SREV_9100(ah)) { - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - u32 isr5 = REG_READ(ah, AR_ISR_S5_S); - if (isr5 & AR_ISR_S5_TIM_TIMER) - *masked |= ATH9K_INT_TIM_TIMER; - } - } - - *masked |= mask2; - } - - if (AR_SREV_9100(ah)) - return true; - - if (isr & AR_ISR_GENTMR) { - u32 s5_s; - - s5_s = REG_READ(ah, AR_ISR_S5_S); - if (isr & AR_ISR_GENTMR) { - ah->intr_gen_timer_trigger = - MS(s5_s, AR_ISR_S5_GENTIMER_TRIG); - - ah->intr_gen_timer_thresh = - MS(s5_s, AR_ISR_S5_GENTIMER_THRESH); - - if (ah->intr_gen_timer_trigger) - *masked |= ATH9K_INT_GENTIMER; - - } - } - - if (sync_cause) { - fatal_int = - (sync_cause & - (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) - ? true : false; - - if (fatal_int) { - if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { - ath_print(common, ATH_DBG_ANY, - "received PCI FATAL interrupt\n"); - } - if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { - ath_print(common, ATH_DBG_ANY, - "received PCI PERR interrupt\n"); - } - *masked |= ATH9K_INT_FATAL; - } - if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { - ath_print(common, ATH_DBG_INTERRUPT, - "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); - REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); - REG_WRITE(ah, AR_RC, 0); - *masked |= ATH9K_INT_FATAL; - } - if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { - ath_print(common, ATH_DBG_INTERRUPT, - "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); - } - - REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); - (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); - } - - return true; -} -EXPORT_SYMBOL(ath9k_hw_getisr); - -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) -{ - u32 omask = ah->mask_reg; - u32 mask, mask2; - struct ath9k_hw_capabilities *pCap = &ah->caps; - struct ath_common *common = ath9k_hw_common(ah); - - ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); - - if (omask & ATH9K_INT_GLOBAL) { - ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n"); - REG_WRITE(ah, AR_IER, AR_IER_DISABLE); - (void) REG_READ(ah, AR_IER); - if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); - (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE); - - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); - (void) REG_READ(ah, AR_INTR_SYNC_ENABLE); - } - } - - mask = ints & ATH9K_INT_COMMON; - mask2 = 0; - - if (ints & ATH9K_INT_TX) { - if (ah->txok_interrupt_mask) - mask |= AR_IMR_TXOK; - if (ah->txdesc_interrupt_mask) - mask |= AR_IMR_TXDESC; - if (ah->txerr_interrupt_mask) - mask |= AR_IMR_TXERR; - if (ah->txeol_interrupt_mask) - mask |= AR_IMR_TXEOL; - } - if (ints & ATH9K_INT_RX) { - mask |= AR_IMR_RXERR; - if (ah->config.rx_intr_mitigation) - mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; - else - mask |= AR_IMR_RXOK | AR_IMR_RXDESC; - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) - mask |= AR_IMR_GENTMR; - } - - if (ints & (ATH9K_INT_BMISC)) { - mask |= AR_IMR_BCNMISC; - if (ints & ATH9K_INT_TIM) - mask2 |= AR_IMR_S2_TIM; - if (ints & ATH9K_INT_DTIM) - mask2 |= AR_IMR_S2_DTIM; - if (ints & ATH9K_INT_DTIMSYNC) - mask2 |= AR_IMR_S2_DTIMSYNC; - if (ints & ATH9K_INT_CABEND) - mask2 |= AR_IMR_S2_CABEND; - if (ints & ATH9K_INT_TSFOOR) - mask2 |= AR_IMR_S2_TSFOOR; - } - - if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) { - mask |= AR_IMR_BCNMISC; - if (ints & ATH9K_INT_GTT) - mask2 |= AR_IMR_S2_GTT; - if (ints & ATH9K_INT_CST) - mask2 |= AR_IMR_S2_CST; - } - - ath_print(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); - REG_WRITE(ah, AR_IMR, mask); - mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM | - AR_IMR_S2_DTIM | - AR_IMR_S2_DTIMSYNC | - AR_IMR_S2_CABEND | - AR_IMR_S2_CABTO | - AR_IMR_S2_TSFOOR | - AR_IMR_S2_GTT | AR_IMR_S2_CST); - REG_WRITE(ah, AR_IMR_S2, mask | mask2); - ah->mask_reg = ints; - - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - if (ints & ATH9K_INT_TIM_TIMER) - REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); - else - REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); - } - - if (ints & ATH9K_INT_GLOBAL) { - ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n"); - REG_WRITE(ah, AR_IER, AR_IER_ENABLE); - if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, - AR_INTR_MAC_IRQ); - REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); - - - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, - AR_INTR_SYNC_DEFAULT); - REG_WRITE(ah, AR_INTR_SYNC_MASK, - AR_INTR_SYNC_DEFAULT); - } - ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", - REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); - } - - return omask; -} -EXPORT_SYMBOL(ath9k_hw_set_interrupts); - /*******************/ /* Beacon Handling */ /*******************/ @@ -2970,6 +1872,8 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) ah->beacon_interval = beacon_period; + ENABLE_REGWRITE_BUFFER(ah); + switch (ah->opmode) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_MONITOR: @@ -3013,6 +1917,9 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period)); REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period)); + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + beacon_period &= ~ATH9K_BEACON_ENA; if (beacon_period & ATH9K_BEACON_RESET_TSF) { ath9k_hw_reset_tsf(ah); @@ -3029,6 +1936,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt)); REG_WRITE(ah, AR_BEACON_PERIOD, @@ -3036,6 +1945,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD)); + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold); @@ -3058,6 +1970,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, ath_print(common, ATH_DBG_BEACON, "beacon period %d\n", beaconintval); ath_print(common, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod); + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); @@ -3077,6 +1991,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + REG_SET_BIT(ah, AR_TIMER_MODE, AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | AR_DTIM_TIMER_EN); @@ -3219,7 +2136,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - if (AR_SREV_9285_10_OR_LATER(ah)) + if (AR_SREV_9271(ah)) + pCap->num_gpio_pins = AR9271_NUM_GPIO; + else if (AR_SREV_9285_10_OR_LATER(ah)) pCap->num_gpio_pins = AR9285_NUM_GPIO; else if (AR_SREV_9280_10_OR_LATER(ah)) pCap->num_gpio_pins = AR928X_NUM_GPIO; @@ -3246,8 +2165,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; } #endif - - pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; + if (AR_SREV_9271(ah)) + pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; + else + pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; if (AR_SREV_9280(ah) || AR_SREV_9285(ah)) pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS; @@ -3291,6 +2212,26 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE; } + if (AR_SREV_9300_20_OR_LATER(ah)) { + pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_LDPC | + ATH9K_HW_CAP_FASTCLOCK; + pCap->rx_hp_qdepth = ATH9K_HW_RX_HP_QDEPTH; + pCap->rx_lp_qdepth = ATH9K_HW_RX_LP_QDEPTH; + pCap->rx_status_len = sizeof(struct ar9003_rxs); + pCap->tx_desc_len = sizeof(struct ar9003_txc); + pCap->txs_len = sizeof(struct ar9003_txs); + } else { + pCap->tx_desc_len = sizeof(struct ath_desc); + if (AR_SREV_9280_20(ah) && + ((ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) <= + AR5416_EEP_MINOR_VER_16) || + ah->eep_ops->get_eeprom(ah, EEP_FSTCLK_5G))) + pCap->hw_caps |= ATH9K_HW_CAP_FASTCLOCK; + } + + if (AR_SREV_9300_20_OR_LATER(ah)) + pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED; + return 0; } @@ -3323,10 +2264,6 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, case ATH9K_CAP_TKIP_SPLIT: return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ? false : true; - case ATH9K_CAP_DIVERSITY: - return (REG_READ(ah, AR_PHY_CCK_DETECT) & - AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? - true : false; case ATH9K_CAP_MCAST_KEYSRCH: switch (capability) { case 0: @@ -3369,8 +2306,6 @@ EXPORT_SYMBOL(ath9k_hw_getcapability); bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 setting, int *status) { - u32 v; - switch (type) { case ATH9K_CAP_TKIP_MIC: if (setting) @@ -3380,14 +2315,6 @@ bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, ah->sta_id1_defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; return true; - case ATH9K_CAP_DIVERSITY: - v = REG_READ(ah, AR_PHY_CCK_DETECT); - if (setting) - v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - else - v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - REG_WRITE(ah, AR_PHY_CCK_DETECT, v); - return true; case ATH9K_CAP_MCAST_KEYSRCH: if (setting) ah->sta_id1_defaults |= AR_STA_ID1_MCAST_KSRCH; @@ -3455,7 +2382,11 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) if (gpio >= ah->caps.num_gpio_pins) return 0xffffffff; - if (AR_SREV_9287_10_OR_LATER(ah)) + if (AR_SREV_9300_20_OR_LATER(ah)) + return MS_REG_READ(AR9300, gpio) != 0; + else if (AR_SREV_9271(ah)) + return MS_REG_READ(AR9271, gpio) != 0; + else if (AR_SREV_9287_10_OR_LATER(ah)) return MS_REG_READ(AR9287, gpio) != 0; else if (AR_SREV_9285_10_OR_LATER(ah)) return MS_REG_READ(AR9285, gpio) != 0; @@ -3484,6 +2415,9 @@ EXPORT_SYMBOL(ath9k_hw_cfg_output); void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) { + if (AR_SREV_9271(ah)) + val = ~val; + REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), AR_GPIO_BIT(gpio)); } @@ -3523,6 +2457,8 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) { u32 phybits; + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_RX_FILTER, bits); phybits = 0; @@ -3538,6 +2474,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) else REG_WRITE(ah, AR_RXCFG, REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); } EXPORT_SYMBOL(ath9k_hw_setrxfilter); @@ -3610,14 +2549,25 @@ void ath9k_hw_write_associd(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_write_associd); +#define ATH9K_MAX_TSF_READ 10 + u64 ath9k_hw_gettsf64(struct ath_hw *ah) { - u64 tsf; + u32 tsf_lower, tsf_upper1, tsf_upper2; + int i; + + tsf_upper1 = REG_READ(ah, AR_TSF_U32); + for (i = 0; i < ATH9K_MAX_TSF_READ; i++) { + tsf_lower = REG_READ(ah, AR_TSF_L32); + tsf_upper2 = REG_READ(ah, AR_TSF_U32); + if (tsf_upper2 == tsf_upper1) + break; + tsf_upper1 = tsf_upper2; + } - tsf = REG_READ(ah, AR_TSF_U32); - tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32); + WARN_ON( i == ATH9K_MAX_TSF_READ ); - return tsf; + return (((u64)tsf_upper1 << 32) | tsf_lower); } EXPORT_SYMBOL(ath9k_hw_gettsf64); @@ -3868,6 +2818,16 @@ void ath_gen_timer_isr(struct ath_hw *ah) } EXPORT_SYMBOL(ath_gen_timer_isr); +/********/ +/* HTC */ +/********/ + +void ath9k_hw_htc_resetinit(struct ath_hw *ah) +{ + ah->htc_reset_init = true; +} +EXPORT_SYMBOL(ath9k_hw_htc_resetinit); + static struct { u32 version; const char * name; @@ -3882,6 +2842,7 @@ static struct { { AR_SREV_VERSION_9285, "9285" }, { AR_SREV_VERSION_9287, "9287" }, { AR_SREV_VERSION_9271, "9271" }, + { AR_SREV_VERSION_9300, "9300" }, }; /* For devices with external radios */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index dbbf7ca5f97..77245dff599 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2009 Atheros Communications Inc. + * Copyright (c) 2008-2010 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 @@ -41,18 +41,16 @@ #define AR9280_DEVID_PCIE 0x002a #define AR9285_DEVID_PCIE 0x002b #define AR2427_DEVID_PCIE 0x002c +#define AR9287_DEVID_PCI 0x002d +#define AR9287_DEVID_PCIE 0x002e +#define AR9300_DEVID_PCIE 0x0030 #define AR5416_AR9100_DEVID 0x000b -#define AR9271_USB 0x9271 - #define AR_SUBVENDOR_ID_NOG 0x0e11 #define AR_SUBVENDOR_ID_NEW_A 0x7065 #define AR5416_MAGIC 0x19641014 -#define AR5416_DEVID_AR9287_PCI 0x002D -#define AR5416_DEVID_AR9287_PCIE 0x002E - #define AR9280_COEX2WIRE_SUBSYSID 0x309b #define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa #define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab @@ -70,6 +68,24 @@ #define REG_READ(_ah, _reg) \ ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) +#define ENABLE_REGWRITE_BUFFER(_ah) \ + do { \ + if (AR_SREV_9271(_ah)) \ + ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \ + } while (0) + +#define DISABLE_REGWRITE_BUFFER(_ah) \ + do { \ + if (AR_SREV_9271(_ah)) \ + ath9k_hw_common(_ah)->ops->disable_write_buffer((_ah)); \ + } while (0) + +#define REGWRITE_BUFFER_FLUSH(_ah) \ + do { \ + if (AR_SREV_9271(_ah)) \ + ath9k_hw_common(_ah)->ops->write_flush((_ah)); \ + } while (0) + #define SM(_v, _f) (((_v) << _f##_S) & _f) #define MS(_v, _f) (((_v) & _f) >> _f##_S) #define REG_RMW(_a, _r, _set, _clr) \ @@ -77,6 +93,8 @@ #define REG_RMW_FIELD(_a, _r, _f, _v) \ REG_WRITE(_a, _r, \ (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f)) +#define REG_READ_FIELD(_a, _r, _f) \ + (((REG_READ(_a, _r) & _f) >> _f##_S)) #define REG_SET_BIT(_a, _r, _f) \ REG_WRITE(_a, _r, REG_READ(_a, _r) | _f) #define REG_CLR_BIT(_a, _r, _f) \ @@ -137,6 +155,16 @@ #define TU_TO_USEC(_tu) ((_tu) << 10) +#define ATH9K_HW_RX_HP_QDEPTH 16 +#define ATH9K_HW_RX_LP_QDEPTH 128 + +enum ath_ini_subsys { + ATH_INI_PRE = 0, + ATH_INI_CORE, + ATH_INI_POST, + ATH_INI_NUM_SPLIT, +}; + enum wireless_mode { ATH9K_MODE_11A = 0, ATH9K_MODE_11G, @@ -167,13 +195,16 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_ENHANCEDPM = BIT(14), ATH9K_HW_CAP_AUTOSLEEP = BIT(15), ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16), + ATH9K_HW_CAP_EDMA = BIT(17), + ATH9K_HW_CAP_RAC_SUPPORTED = BIT(18), + ATH9K_HW_CAP_LDPC = BIT(19), + ATH9K_HW_CAP_FASTCLOCK = BIT(20), }; enum ath9k_capability_type { ATH9K_CAP_CIPHER = 0, ATH9K_CAP_TKIP_MIC, ATH9K_CAP_TKIP_SPLIT, - ATH9K_CAP_DIVERSITY, ATH9K_CAP_TXPOW, ATH9K_CAP_MCAST_KEYSRCH, ATH9K_CAP_DS @@ -194,6 +225,11 @@ struct ath9k_hw_capabilities { u8 num_gpio_pins; u8 num_antcfg_2ghz; u8 num_antcfg_5ghz; + u8 rx_hp_qdepth; + u8 rx_lp_qdepth; + u8 rx_status_len; + u8 tx_desc_len; + u8 txs_len; }; struct ath9k_ops_config { @@ -214,6 +250,7 @@ struct ath9k_ops_config { u32 enable_ani; int serialize_regmode; bool rx_intr_mitigation; + bool tx_intr_mitigation; #define SPUR_DISABLE 0 #define SPUR_ENABLE_IOCTL 1 #define SPUR_ENABLE_EEPROM 2 @@ -225,6 +262,7 @@ struct ath9k_ops_config { #define AR_BASE_FREQ_5GHZ 4900 #define AR_SPUR_FEEQ_BOUND_HT40 19 #define AR_SPUR_FEEQ_BOUND_HT20 10 + bool tx_iq_calibration; /* Only available for >= AR9003 */ int spurmode; u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; u8 max_txtrig_level; @@ -233,6 +271,8 @@ struct ath9k_ops_config { enum ath9k_int { ATH9K_INT_RX = 0x00000001, ATH9K_INT_RXDESC = 0x00000002, + ATH9K_INT_RXHP = 0x00000001, + ATH9K_INT_RXLP = 0x00000002, ATH9K_INT_RXNOFRM = 0x00000008, ATH9K_INT_RXEOL = 0x00000010, ATH9K_INT_RXORN = 0x00000020, @@ -329,10 +369,9 @@ struct ath9k_channel { #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) #define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0) #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) -#define IS_CHAN_A_5MHZ_SPACED(_c) \ +#define IS_CHAN_A_FAST_CLOCK(_ah, _c) \ ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) && \ - (((_c)->channel % 20) != 0) && \ - (((_c)->channel % 10) != 0)) + ((_ah)->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)) /* These macros check chanmode and not channelFlags */ #define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B) @@ -365,6 +404,12 @@ enum ser_reg_mode { SER_REG_MODE_AUTO = 2, }; +enum ath9k_rx_qtype { + ATH9K_RX_QUEUE_HP, + ATH9K_RX_QUEUE_LP, + ATH9K_RX_QUEUE_MAX, +}; + struct ath9k_beacon_state { u32 bs_nexttbtt; u32 bs_nextdtim; @@ -442,6 +487,124 @@ struct ath_gen_timer_table { } timer_mask; }; +/** + * struct ath_hw_private_ops - callbacks used internally by hardware code + * + * This structure contains private callbacks designed to only be used internally + * by the hardware core. + * + * @init_cal_settings: setup types of calibrations supported + * @init_cal: starts actual calibration + * + * @init_mode_regs: Initializes mode registers + * @init_mode_gain_regs: Initialize TX/RX gain registers + * @macversion_supported: If this specific mac revision is supported + * + * @rf_set_freq: change frequency + * @spur_mitigate_freq: spur mitigation + * @rf_alloc_ext_banks: + * @rf_free_ext_banks: + * @set_rf_regs: + * @compute_pll_control: compute the PLL control value to use for + * AR_RTC_PLL_CONTROL for a given channel + * @setup_calibration: set up calibration + * @iscal_supported: used to query if a type of calibration is supported + * @loadnf: load noise floor read from each chain on the CCA registers + */ +struct ath_hw_private_ops { + /* Calibration ops */ + void (*init_cal_settings)(struct ath_hw *ah); + bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan); + + void (*init_mode_regs)(struct ath_hw *ah); + void (*init_mode_gain_regs)(struct ath_hw *ah); + bool (*macversion_supported)(u32 macversion); + void (*setup_calibration)(struct ath_hw *ah, + struct ath9k_cal_list *currCal); + bool (*iscal_supported)(struct ath_hw *ah, + enum ath9k_cal_types calType); + + /* PHY ops */ + int (*rf_set_freq)(struct ath_hw *ah, + struct ath9k_channel *chan); + void (*spur_mitigate_freq)(struct ath_hw *ah, + struct ath9k_channel *chan); + int (*rf_alloc_ext_banks)(struct ath_hw *ah); + void (*rf_free_ext_banks)(struct ath_hw *ah); + bool (*set_rf_regs)(struct ath_hw *ah, + struct ath9k_channel *chan, + u16 modesIndex); + void (*set_channel_regs)(struct ath_hw *ah, struct ath9k_channel *chan); + void (*init_bb)(struct ath_hw *ah, + struct ath9k_channel *chan); + int (*process_ini)(struct ath_hw *ah, struct ath9k_channel *chan); + void (*olc_init)(struct ath_hw *ah); + void (*set_rfmode)(struct ath_hw *ah, struct ath9k_channel *chan); + void (*mark_phy_inactive)(struct ath_hw *ah); + void (*set_delta_slope)(struct ath_hw *ah, struct ath9k_channel *chan); + bool (*rfbus_req)(struct ath_hw *ah); + void (*rfbus_done)(struct ath_hw *ah); + void (*enable_rfkill)(struct ath_hw *ah); + void (*restore_chainmask)(struct ath_hw *ah); + void (*set_diversity)(struct ath_hw *ah, bool value); + u32 (*compute_pll_control)(struct ath_hw *ah, + struct ath9k_channel *chan); + bool (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd, + int param); + void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]); + void (*loadnf)(struct ath_hw *ah, struct ath9k_channel *chan); +}; + +/** + * struct ath_hw_ops - callbacks used by hardware code and driver code + * + * This structure contains callbacks designed to to be used internally by + * hardware code and also by the lower level driver. + * + * @config_pci_powersave: + * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC + */ +struct ath_hw_ops { + void (*config_pci_powersave)(struct ath_hw *ah, + int restore, + int power_off); + void (*rx_enable)(struct ath_hw *ah); + void (*set_desc_link)(void *ds, u32 link); + void (*get_desc_link)(void *ds, u32 **link); + bool (*calibrate)(struct ath_hw *ah, + struct ath9k_channel *chan, + u8 rxchainmask, + bool longcal); + bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked); + void (*fill_txdesc)(struct ath_hw *ah, void *ds, u32 seglen, + bool is_firstseg, bool is_is_lastseg, + const void *ds0, dma_addr_t buf_addr, + unsigned int qcu); + int (*proc_txdesc)(struct ath_hw *ah, void *ds, + struct ath_tx_status *ts); + void (*set11n_txdesc)(struct ath_hw *ah, void *ds, + u32 pktLen, enum ath9k_pkt_type type, + u32 txPower, u32 keyIx, + enum ath9k_key_type keyType, + u32 flags); + void (*set11n_ratescenario)(struct ath_hw *ah, void *ds, + void *lastds, + u32 durUpdateEn, u32 rtsctsRate, + u32 rtsctsDuration, + struct ath9k_11n_rate_series series[], + u32 nseries, u32 flags); + void (*set11n_aggr_first)(struct ath_hw *ah, void *ds, + u32 aggrLen); + void (*set11n_aggr_middle)(struct ath_hw *ah, void *ds, + u32 numDelims); + void (*set11n_aggr_last)(struct ath_hw *ah, void *ds); + void (*clr11n_aggr)(struct ath_hw *ah, void *ds); + void (*set11n_burstduration)(struct ath_hw *ah, void *ds, + u32 burstDuration); + void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds, + u32 vmf); +}; + struct ath_hw { struct ieee80211_hw *hw; struct ath_common common; @@ -455,13 +618,18 @@ struct ath_hw { struct ar5416_eeprom_def def; struct ar5416_eeprom_4k map4k; struct ar9287_eeprom map9287; + struct ar9300_eeprom ar9300_eep; } eeprom; const struct eeprom_ops *eep_ops; - enum ath9k_eep_map eep_map; bool sw_mgmt_crypto; bool is_pciexpress; + bool need_an_top2_fixup; u16 tx_trig_level; + s16 nf_2g_max; + s16 nf_2g_min; + s16 nf_5g_max; + s16 nf_5g_min; u16 rfsilent; u32 rfkill_gpio; u32 rfkill_polarity; @@ -478,7 +646,8 @@ struct ath_hw { struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES]; int16_t curchan_rad_index; - u32 mask_reg; + enum ath9k_int imask; + u32 imrs2_reg; u32 txok_interrupt_mask; u32 txerr_interrupt_mask; u32 txdesc_interrupt_mask; @@ -493,6 +662,7 @@ struct ath_hw { struct ath9k_cal_list adcgain_caldata; struct ath9k_cal_list adcdc_calinitdata; struct ath9k_cal_list adcdc_caldata; + struct ath9k_cal_list tempCompCalData; struct ath9k_cal_list *cal_list; struct ath9k_cal_list *cal_list_last; struct ath9k_cal_list *cal_list_curr; @@ -533,12 +703,10 @@ struct ath_hw { DONT_USE_32KHZ, } enable_32kHz_clock; - /* Callback for radio frequency change */ - int (*ath9k_hw_rf_set_freq)(struct ath_hw *ah, struct ath9k_channel *chan); - - /* Callback for baseband spur frequency */ - void (*ath9k_hw_spur_mitigate_freq)(struct ath_hw *ah, - struct ath9k_channel *chan); + /* Private to hardware code */ + struct ath_hw_private_ops private_ops; + /* Accessed by the lower level driver */ + struct ath_hw_ops ops; /* Used to program the radio on non single-chip devices */ u32 *analogBank0Data; @@ -551,6 +719,7 @@ struct ath_hw { u32 *addac5416_21; u32 *bank6Temp; + u8 txpower_limit; int16_t txpower_indexoffset; int coverage_class; u32 beacon_interval; @@ -592,16 +761,34 @@ struct ath_hw { struct ar5416IniArray iniBank7; struct ar5416IniArray iniAddac; struct ar5416IniArray iniPcieSerdes; + struct ar5416IniArray iniPcieSerdesLowPower; struct ar5416IniArray iniModesAdditional; struct ar5416IniArray iniModesRxGain; struct ar5416IniArray iniModesTxGain; struct ar5416IniArray iniModes_9271_1_0_only; struct ar5416IniArray iniCckfirNormal; struct ar5416IniArray iniCckfirJapan2484; + struct ar5416IniArray iniCommon_normal_cck_fir_coeff_9271; + struct ar5416IniArray iniCommon_japan_2484_cck_fir_coeff_9271; + struct ar5416IniArray iniModes_9271_ANI_reg; + struct ar5416IniArray iniModes_high_power_tx_gain_9271; + struct ar5416IniArray iniModes_normal_power_tx_gain_9271; + + struct ar5416IniArray iniMac[ATH_INI_NUM_SPLIT]; + struct ar5416IniArray iniBB[ATH_INI_NUM_SPLIT]; + struct ar5416IniArray iniRadio[ATH_INI_NUM_SPLIT]; + struct ar5416IniArray iniSOC[ATH_INI_NUM_SPLIT]; u32 intr_gen_timer_trigger; u32 intr_gen_timer_thresh; struct ath_gen_timer_table hw_gen_timers; + + struct ar9003_txs *ts_ring; + void *ts_start; + u32 ts_paddr_start; + u32 ts_paddr_end; + u16 ts_tail; + u8 ts_size; }; static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) @@ -614,6 +801,16 @@ static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) return &(ath9k_hw_common(ah)->regulatory); } +static inline struct ath_hw_private_ops *ath9k_hw_private_ops(struct ath_hw *ah) +{ + return &ah->private_ops; +} + +static inline struct ath_hw_ops *ath9k_hw_ops(struct ath_hw *ah) +{ + return &ah->ops; +} + /* Initialization, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_deinit(struct ath_hw *ah); @@ -625,6 +822,7 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 *result); bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, u32 capability, u32 setting, int *status); +u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan); /* Key Cache Management */ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry); @@ -673,16 +871,10 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, const struct ath9k_beacon_state *bs); +bool ath9k_hw_check_alive(struct ath_hw *ah); bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); -void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off); - -/* Interrupt Handling */ -bool ath9k_hw_intrpend(struct ath_hw *ah); -bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); - /* Generic hw timer primitives */ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, void (*trigger)(void *), @@ -701,6 +893,39 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len); +/* HTC */ +void ath9k_hw_htc_resetinit(struct ath_hw *ah); + +/* PHY */ +void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, + u32 *coef_mantissa, u32 *coef_exponent); + +/* + * Code Specific to AR5008, AR9001 or AR9002, + * we stuff these here to avoid callbacks for AR9003. + */ +void ar9002_hw_cck_chan14_spread(struct ath_hw *ah); +int ar9002_hw_rf_claim(struct ath_hw *ah); +void ar9002_hw_enable_async_fifo(struct ath_hw *ah); +void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah); + +/* + * Code specifric to AR9003, we stuff these here to avoid callbacks + * for older families + */ +void ar9003_hw_set_nf_limits(struct ath_hw *ah); + +/* Hardware family op attach helpers */ +void ar5008_hw_attach_phy_ops(struct ath_hw *ah); +void ar9002_hw_attach_phy_ops(struct ath_hw *ah); +void ar9003_hw_attach_phy_ops(struct ath_hw *ah); + +void ar9002_hw_attach_calib_ops(struct ath_hw *ah); +void ar9003_hw_attach_calib_ops(struct ath_hw *ah); + +void ar9002_hw_attach_ops(struct ath_hw *ah); +void ar9003_hw_attach_ops(struct ath_hw *ah); + #define ATH_PCIE_CAP_LINK_CTRL 0x70 #define ATH_PCIE_CAP_LINK_L0S 1 #define ATH_PCIE_CAP_LINK_L1 2 diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 3d4d897add6..d457cb3bd77 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -175,6 +175,18 @@ static const struct ath_ops ath9k_common_ops = { .write = ath9k_iowrite32, }; +static int count_streams(unsigned int chainmask, int max) +{ + int streams = 0; + + do { + if (++streams == max) + break; + } while ((chainmask = chainmask & (chainmask - 1))); + + return streams; +} + /**************************/ /* Initialization */ /**************************/ @@ -182,8 +194,10 @@ static const struct ath_ops ath9k_common_ops = { static void setup_ht_cap(struct ath_softc *sc, struct ieee80211_sta_ht_cap *ht_info) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); u8 tx_streams, rx_streams; + int i, max_streams; ht_info->ht_supported = true; ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | @@ -191,28 +205,40 @@ static void setup_ht_cap(struct ath_softc *sc, IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_DSSSCCK40; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; + if (AR_SREV_9300_20_OR_LATER(ah)) + max_streams = 3; + else + max_streams = 2; + + if (AR_SREV_9280_10_OR_LATER(ah)) { + if (max_streams >= 2) + ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; + ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + } + /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ? - 1 : 2; - rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ? - 1 : 2; + tx_streams = count_streams(common->tx_chainmask, max_streams); + rx_streams = count_streams(common->rx_chainmask, max_streams); + + ath_print(common, ATH_DBG_CONFIG, + "TX streams %d, RX streams: %d\n", + tx_streams, rx_streams); if (tx_streams != rx_streams) { - ath_print(common, ATH_DBG_CONFIG, - "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; ht_info->mcs.tx_params |= ((tx_streams - 1) << IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); } - ht_info->mcs.rx_mask[0] = 0xff; - if (rx_streams >= 2) - ht_info->mcs.rx_mask[1] = 0xff; + for (i = 0; i < rx_streams; i++) + ht_info->mcs.rx_mask[i] = 0xff; ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; } @@ -235,31 +261,37 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, */ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, struct list_head *head, const char *name, - int nbuf, int ndesc) + int nbuf, int ndesc, bool is_tx) { #define DS2PHYS(_dd, _ds) \ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) #define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) #define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_desc *ds; + u8 *ds; struct ath_buf *bf; - int i, bsize, error; + int i, bsize, error, desc_len; ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", name, nbuf, ndesc); INIT_LIST_HEAD(head); + + if (is_tx) + desc_len = sc->sc_ah->caps.tx_desc_len; + else + desc_len = sizeof(struct ath_desc); + /* ath_desc must be a multiple of DWORDs */ - if ((sizeof(struct ath_desc) % 4) != 0) { + if ((desc_len % 4) != 0) { ath_print(common, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); - BUG_ON((sizeof(struct ath_desc) % 4) != 0); + BUG_ON((desc_len % 4) != 0); error = -ENOMEM; goto fail; } - dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; + dd->dd_desc_len = desc_len * nbuf * ndesc; /* * Need additional DMA memory because we can't use @@ -272,11 +304,11 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, u32 dma_len; while (ndesc_skipped) { - dma_len = ndesc_skipped * sizeof(struct ath_desc); + dma_len = ndesc_skipped * desc_len; dd->dd_desc_len += dma_len; ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); - }; + } } /* allocate descriptors */ @@ -286,7 +318,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, error = -ENOMEM; goto fail; } - ds = dd->dd_desc; + ds = (u8 *) dd->dd_desc; ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", name, ds, (u32) dd->dd_desc_len, ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); @@ -300,7 +332,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, } dd->dd_bufptr = bf; - for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { + for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { bf->bf_desc = ds; bf->bf_daddr = DS2PHYS(dd, ds); @@ -316,7 +348,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, ((caddr_t) dd->dd_desc + dd->dd_desc_len)); - ds += ndesc; + ds += (desc_len * ndesc); bf->bf_desc = ds; bf->bf_daddr = DS2PHYS(dd, ds); } @@ -514,7 +546,7 @@ static void ath9k_init_misc(struct ath_softc *sc) common->tx_chainmask = sc->sc_ah->caps.tx_chainmask; common->rx_chainmask = sc->sc_ah->caps.rx_chainmask; - ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); + ath9k_hw_set_diversity(sc->sc_ah, true); sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) @@ -568,13 +600,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, ath_read_cachesize(common, &csz); common->cachelsz = csz << 2; /* convert to bytes */ + /* Initializes the hardware for all supported chipsets */ ret = ath9k_hw_init(ah); - if (ret) { - ath_print(common, ATH_DBG_FATAL, - "Unable to initialize hardware; " - "initialization status: %d\n", ret); + if (ret) goto err_hw; - } ret = ath9k_init_debug(ah); if (ret) { @@ -760,6 +789,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc) tasklet_kill(&sc->intr_tq); tasklet_kill(&sc->bcon_tasklet); + + kfree(sc->sc_ah); + sc->sc_ah = NULL; } void ath9k_deinit_device(struct ath_softc *sc) diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index efc420cd42b..0e425cb4bbb 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -25,14 +25,21 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah, ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask, ah->txurn_interrupt_mask); + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_IMR_S0, SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK) | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC)); REG_WRITE(ah, AR_IMR_S1, SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR) | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL)); - REG_RMW_FIELD(ah, AR_IMR_S2, - AR_IMR_S2_QCU_TXURN, ah->txurn_interrupt_mask); + + ah->imrs2_reg &= ~AR_IMR_S2_QCU_TXURN; + ah->imrs2_reg |= (ah->txurn_interrupt_mask & AR_IMR_S2_QCU_TXURN); + REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); } u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q) @@ -55,6 +62,18 @@ void ath9k_hw_txstart(struct ath_hw *ah, u32 q) } EXPORT_SYMBOL(ath9k_hw_txstart); +void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_txstatus0 = ads->ds_txstatus1 = 0; + ads->ds_txstatus2 = ads->ds_txstatus3 = 0; + ads->ds_txstatus4 = ads->ds_txstatus5 = 0; + ads->ds_txstatus6 = ads->ds_txstatus7 = 0; + ads->ds_txstatus8 = ads->ds_txstatus9 = 0; +} +EXPORT_SYMBOL(ath9k_hw_cleartxdesc); + u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) { u32 npend; @@ -103,7 +122,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) if (ah->tx_trig_level >= ah->config.max_txtrig_level) return false; - omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL); + omask = ath9k_hw_set_interrupts(ah, ah->imask & ~ATH9K_INT_GLOBAL); txcfg = REG_READ(ah, AR_TXCFG); curLevel = MS(txcfg, AR_FTRIG); @@ -205,280 +224,6 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) } EXPORT_SYMBOL(ath9k_hw_stoptxdma); -void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 segLen, bool firstSeg, - bool lastSeg, const struct ath_desc *ds0) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (firstSeg) { - ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); - } else if (lastSeg) { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = segLen; - ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; - ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; - } else { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = segLen | AR_TxMore; - ads->ds_ctl2 = 0; - ads->ds_ctl3 = 0; - } - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; -} -EXPORT_SYMBOL(ath9k_hw_filltxdesc); - -void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; -} -EXPORT_SYMBOL(ath9k_hw_cleartxdesc); - -int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if ((ads->ds_txstatus9 & AR_TxDone) == 0) - return -EINPROGRESS; - - ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); - ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp; - ds->ds_txstat.ts_status = 0; - ds->ds_txstat.ts_flags = 0; - - if (ads->ds_txstatus1 & AR_FrmXmitOK) - ds->ds_txstat.ts_status |= ATH9K_TX_ACKED; - if (ads->ds_txstatus1 & AR_ExcessiveRetries) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; - if (ads->ds_txstatus1 & AR_Filtered) - ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; - if (ads->ds_txstatus1 & AR_FIFOUnderrun) { - ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus9 & AR_TxOpExceeded) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; - if (ads->ds_txstatus1 & AR_TxTimerExpired) - ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED; - - if (ads->ds_txstatus1 & AR_DescCfgErr) - ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR; - if (ads->ds_txstatus1 & AR_TxDataUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus0 & AR_TxBaStatus) { - ds->ds_txstat.ts_flags |= ATH9K_TX_BA; - ds->ds_txstat.ba_low = ads->AR_BaBitmapLow; - ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh; - } - - ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); - switch (ds->ds_txstat.ts_rateindex) { - case 0: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); - break; - case 1: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); - break; - case 2: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); - break; - case 3: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); - break; - } - - ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); - ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); - ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); - ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); - ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); - ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); - ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); - ds->ds_txstat.evm0 = ads->AR_TxEVM0; - ds->ds_txstat.evm1 = ads->AR_TxEVM1; - ds->ds_txstat.evm2 = ads->AR_TxEVM2; - ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); - ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); - ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); - ds->ds_txstat.ts_antenna = 0; - - return 0; -} -EXPORT_SYMBOL(ath9k_hw_txprocdesc); - -void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 pktLen, enum ath9k_pkt_type type, u32 txPower, - u32 keyIx, enum ath9k_key_type keyType, u32 flags) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - txPower += ah->txpower_indexoffset; - if (txPower > 63) - txPower = 63; - - ads->ds_ctl0 = (pktLen & AR_FrameLen) - | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) - | SM(txPower, AR_XmitPower) - | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) - | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) - | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) - | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); - - ads->ds_ctl1 = - (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) - | SM(type, AR_FrameType) - | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) - | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) - | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); - - ads->ds_ctl6 = SM(keyType, AR_EncrType); - - if (AR_SREV_9285(ah)) { - ads->ds_ctl8 = 0; - ads->ds_ctl9 = 0; - ads->ds_ctl10 = 0; - ads->ds_ctl11 = 0; - } -} -EXPORT_SYMBOL(ath9k_hw_set11n_txdesc); - -void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds, - struct ath_desc *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - struct ar5416_desc *last_ads = AR5416DESC(lastds); - u32 ds_ctl0; - - if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { - ds_ctl0 = ads->ds_ctl0; - - if (flags & ATH9K_TXDESC_RTSENA) { - ds_ctl0 &= ~AR_CTSEnable; - ds_ctl0 |= AR_RTSEnable; - } else { - ds_ctl0 &= ~AR_RTSEnable; - ds_ctl0 |= AR_CTSEnable; - } - - ads->ds_ctl0 = ds_ctl0; - } else { - ads->ds_ctl0 = - (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); - } - - ads->ds_ctl2 = set11nTries(series, 0) - | set11nTries(series, 1) - | set11nTries(series, 2) - | set11nTries(series, 3) - | (durUpdateEn ? AR_DurUpdateEna : 0) - | SM(0, AR_BurstDur); - - ads->ds_ctl3 = set11nRate(series, 0) - | set11nRate(series, 1) - | set11nRate(series, 2) - | set11nRate(series, 3); - - ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) - | set11nPktDurRTSCTS(series, 1); - - ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) - | set11nPktDurRTSCTS(series, 3); - - ads->ds_ctl7 = set11nRateFlags(series, 0) - | set11nRateFlags(series, 1) - | set11nRateFlags(series, 2) - | set11nRateFlags(series, 3) - | SM(rtsctsRate, AR_RTSCTSRate); - last_ads->ds_ctl2 = ads->ds_ctl2; - last_ads->ds_ctl3 = ads->ds_ctl3; -} -EXPORT_SYMBOL(ath9k_hw_set11n_ratescenario); - -void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds, - u32 aggrLen) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); - ads->ds_ctl6 &= ~AR_AggrLen; - ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); -} -EXPORT_SYMBOL(ath9k_hw_set11n_aggr_first); - -void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds, - u32 numDelims) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - unsigned int ctl6; - - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); - - ctl6 = ads->ds_ctl6; - ctl6 &= ~AR_PadDelim; - ctl6 |= SM(numDelims, AR_PadDelim); - ads->ds_ctl6 = ctl6; -} -EXPORT_SYMBOL(ath9k_hw_set11n_aggr_middle); - -void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 |= AR_IsAggr; - ads->ds_ctl1 &= ~AR_MoreAggr; - ads->ds_ctl6 &= ~AR_PadDelim; -} -EXPORT_SYMBOL(ath9k_hw_set11n_aggr_last); - -void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); -} -EXPORT_SYMBOL(ath9k_hw_clr11n_aggr); - -void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds, - u32 burstDuration) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl2 &= ~AR_BurstDur; - ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); -} -EXPORT_SYMBOL(ath9k_hw_set11n_burstduration); - -void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds, - u32 vmf) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (vmf) - ads->ds_ctl0 |= AR_VirtMoreFrag; - else - ads->ds_ctl0 &= ~AR_VirtMoreFrag; -} - void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs) { *txqs &= ah->intr_txqs; @@ -730,6 +475,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) } else cwMin = qi->tqi_cwmin; + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_DLCL_IFS(q), SM(cwMin, AR_D_LCL_IFS_CWMIN) | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) | @@ -744,6 +491,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) REG_WRITE(ah, AR_DMISC(q), AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); + REGWRITE_BUFFER_FLUSH(ah); + if (qi->tqi_cbrPeriod) { REG_WRITE(ah, AR_QCBRCFG(q), SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | @@ -759,6 +508,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) AR_Q_RDYTIMECFG_EN); } + REGWRITE_BUFFER_FLUSH(ah); + REG_WRITE(ah, AR_DCHNTIME(q), SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); @@ -776,6 +527,10 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) REG_READ(ah, AR_DMISC(q)) | AR_D_MISC_POST_FR_BKOFF_DIS); } + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | @@ -783,6 +538,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) } switch (qi->tqi_type) { case ATH9K_TX_QUEUE_BEACON: + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_BEACON_USE @@ -793,8 +550,20 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) AR_D_MISC_ARB_LOCKOUT_CNTRL_S) | AR_D_MISC_BEACON_USE | AR_D_MISC_POST_FR_BKOFF_DIS); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + + /* cwmin and cwmax should be 0 for beacon queue */ + if (AR_SREV_9300_20_OR_LATER(ah)) { + REG_WRITE(ah, AR_DLCL_IFS(q), SM(0, AR_D_LCL_IFS_CWMIN) + | SM(0, AR_D_LCL_IFS_CWMAX) + | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); + } break; case ATH9K_TX_QUEUE_CAB: + ENABLE_REGWRITE_BUFFER(ah); + REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_CBR_INCR_DIS1 @@ -808,6 +577,10 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); + + REGWRITE_BUFFER_FLUSH(ah); + DISABLE_REGWRITE_BUFFER(ah); + break; case ATH9K_TX_QUEUE_PSPOLL: REG_WRITE(ah, AR_QMISC(q), @@ -829,6 +602,9 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) AR_D_MISC_POST_FR_BKOFF_DIS); } + if (AR_SREV_9300_20_OR_LATER(ah)) + REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN); + if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) ah->txok_interrupt_mask |= 1 << q; else @@ -856,7 +632,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) EXPORT_SYMBOL(ath9k_hw_resettxqueue); int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 pa, struct ath_desc *nds, u64 tsf) + struct ath_rx_status *rs, u64 tsf) { struct ar5416_desc ads; struct ar5416_desc *adsp = AR5416DESC(ds); @@ -867,92 +643,76 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, ads.u.rx = adsp->u.rx; - ds->ds_rxstat.rs_status = 0; - ds->ds_rxstat.rs_flags = 0; + rs->rs_status = 0; + rs->rs_flags = 0; - ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; - ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; + rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen; + rs->rs_tstamp = ads.AR_RcvTimestamp; if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) { - ds->ds_rxstat.rs_rssi = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ctl0 = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ctl1 = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ctl2 = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ext0 = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ext1 = ATH9K_RSSI_BAD; - ds->ds_rxstat.rs_rssi_ext2 = ATH9K_RSSI_BAD; + rs->rs_rssi = ATH9K_RSSI_BAD; + rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD; + rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD; + rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD; + rs->rs_rssi_ext0 = ATH9K_RSSI_BAD; + rs->rs_rssi_ext1 = ATH9K_RSSI_BAD; + rs->rs_rssi_ext2 = ATH9K_RSSI_BAD; } else { - ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); - ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, + rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); + rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); - ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, + rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); - ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, + rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); - ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, + rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); - ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, + rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); - ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, + rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); } if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) - ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); + rs->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); else - ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID; + rs->rs_keyix = ATH9K_RXKEYIX_INVALID; - ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads)); - ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; + rs->rs_rate = RXSTATUS_RATE(ah, (&ads)); + rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; - ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; - ds->ds_rxstat.rs_moreaggr = + rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; + rs->rs_moreaggr = (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; - ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); - ds->ds_rxstat.rs_flags = + rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); + rs->rs_flags = (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; - ds->ds_rxstat.rs_flags |= + rs->rs_flags |= (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE; + rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE; if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST; + rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST; if (ads.ds_rxstatus8 & AR_DecryptBusyErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY; + rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY; if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { if (ads.ds_rxstatus8 & AR_CRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC; + rs->rs_status |= ATH9K_RXERR_CRC; else if (ads.ds_rxstatus8 & AR_PHYErr) { - ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY; + rs->rs_status |= ATH9K_RXERR_PHY; phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); - ds->ds_rxstat.rs_phyerr = phyerr; + rs->rs_phyerr = phyerr; } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT; + rs->rs_status |= ATH9K_RXERR_DECRYPT; else if (ads.ds_rxstatus8 & AR_MichaelErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC; + rs->rs_status |= ATH9K_RXERR_MIC; } return 0; } EXPORT_SYMBOL(ath9k_hw_rxprocdesc); -void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 size, u32 flags) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - struct ath9k_hw_capabilities *pCap = &ah->caps; - - ads->ds_ctl1 = size & AR_BufLen; - if (flags & ATH9K_RXDESC_INTREQ) - ads->ds_ctl1 |= AR_RxIntrReq; - - ads->ds_rxstatus8 &= ~AR_RxDone; - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) - memset(&(ads->u), 0, sizeof(ads->u)); -} -EXPORT_SYMBOL(ath9k_hw_setuprxdesc); - /* * This can stop or re-enables RX. * @@ -996,12 +756,6 @@ void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp) } EXPORT_SYMBOL(ath9k_hw_putrxbuf); -void ath9k_hw_rxena(struct ath_hw *ah) -{ - REG_WRITE(ah, AR_CR, AR_CR_RXE); -} -EXPORT_SYMBOL(ath9k_hw_rxena); - void ath9k_hw_startpcureceive(struct ath_hw *ah) { ath9k_enable_mib_counters(ah); @@ -1020,6 +774,14 @@ void ath9k_hw_stoppcurecv(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_stoppcurecv); +void ath9k_hw_abortpcurecv(struct ath_hw *ah) +{ + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS); + + ath9k_hw_disable_mib_counters(ah); +} +EXPORT_SYMBOL(ath9k_hw_abortpcurecv); + bool ath9k_hw_stopdmarecv(struct ath_hw *ah) { #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ @@ -1065,3 +827,142 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah) return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); } EXPORT_SYMBOL(ath9k_hw_beaconq_setup); + +bool ath9k_hw_intrpend(struct ath_hw *ah) +{ + u32 host_isr; + + if (AR_SREV_9100(ah)) + return true; + + host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE); + if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS)) + return true; + + host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE); + if ((host_isr & AR_INTR_SYNC_DEFAULT) + && (host_isr != AR_INTR_SPURIOUS)) + return true; + + return false; +} +EXPORT_SYMBOL(ath9k_hw_intrpend); + +enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, + enum ath9k_int ints) +{ + enum ath9k_int omask = ah->imask; + u32 mask, mask2; + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_common *common = ath9k_hw_common(ah); + + ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); + + if (omask & ATH9K_INT_GLOBAL) { + ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n"); + REG_WRITE(ah, AR_IER, AR_IER_DISABLE); + (void) REG_READ(ah, AR_IER); + if (!AR_SREV_9100(ah)) { + REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); + (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE); + + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + (void) REG_READ(ah, AR_INTR_SYNC_ENABLE); + } + } + + /* TODO: global int Ref count */ + mask = ints & ATH9K_INT_COMMON; + mask2 = 0; + + if (ints & ATH9K_INT_TX) { + if (ah->config.tx_intr_mitigation) + mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM; + else { + if (ah->txok_interrupt_mask) + mask |= AR_IMR_TXOK; + if (ah->txdesc_interrupt_mask) + mask |= AR_IMR_TXDESC; + } + if (ah->txerr_interrupt_mask) + mask |= AR_IMR_TXERR; + if (ah->txeol_interrupt_mask) + mask |= AR_IMR_TXEOL; + } + if (ints & ATH9K_INT_RX) { + if (AR_SREV_9300_20_OR_LATER(ah)) { + mask |= AR_IMR_RXERR | AR_IMR_RXOK_HP; + if (ah->config.rx_intr_mitigation) { + mask &= ~AR_IMR_RXOK_LP; + mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; + } else { + mask |= AR_IMR_RXOK_LP; + } + } else { + if (ah->config.rx_intr_mitigation) + mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; + else + mask |= AR_IMR_RXOK | AR_IMR_RXDESC; + } + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) + mask |= AR_IMR_GENTMR; + } + + if (ints & (ATH9K_INT_BMISC)) { + mask |= AR_IMR_BCNMISC; + if (ints & ATH9K_INT_TIM) + mask2 |= AR_IMR_S2_TIM; + if (ints & ATH9K_INT_DTIM) + mask2 |= AR_IMR_S2_DTIM; + if (ints & ATH9K_INT_DTIMSYNC) + mask2 |= AR_IMR_S2_DTIMSYNC; + if (ints & ATH9K_INT_CABEND) + mask2 |= AR_IMR_S2_CABEND; + if (ints & ATH9K_INT_TSFOOR) + mask2 |= AR_IMR_S2_TSFOOR; + } + + if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) { + mask |= AR_IMR_BCNMISC; + if (ints & ATH9K_INT_GTT) + mask2 |= AR_IMR_S2_GTT; + if (ints & ATH9K_INT_CST) + mask2 |= AR_IMR_S2_CST; + } + + ath_print(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); + REG_WRITE(ah, AR_IMR, mask); + ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC | + AR_IMR_S2_CABEND | AR_IMR_S2_CABTO | + AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST); + ah->imrs2_reg |= mask2; + REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); + + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + if (ints & ATH9K_INT_TIM_TIMER) + REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); + else + REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); + } + + if (ints & ATH9K_INT_GLOBAL) { + ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n"); + REG_WRITE(ah, AR_IER, AR_IER_ENABLE); + if (!AR_SREV_9100(ah)) { + REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, + AR_INTR_MAC_IRQ); + REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); + + + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, + AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_MASK, + AR_INTR_SYNC_DEFAULT); + } + ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", + REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); + } + + return omask; +} +EXPORT_SYMBOL(ath9k_hw_set_interrupts); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 29851e6376a..00f3e0c7528 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -37,6 +37,8 @@ AR_2040_##_index : 0) \ |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \ AR_GI##_index : 0) \ + |((_series)[_index].RateFlags & ATH9K_RATESERIES_STBC ? \ + AR_STBC##_index : 0) \ |SM((_series)[_index].ChSel, AR_ChainSel##_index)) #define CCK_SIFS_TIME 10 @@ -86,7 +88,6 @@ #define ATH9K_TX_DESC_CFG_ERR 0x04 #define ATH9K_TX_DATA_UNDERRUN 0x08 #define ATH9K_TX_DELIM_UNDERRUN 0x10 -#define ATH9K_TX_SW_ABORTED 0x40 #define ATH9K_TX_SW_FILTERED 0x80 /* 64 bytes */ @@ -117,7 +118,10 @@ struct ath_tx_status { int8_t ts_rssi_ext0; int8_t ts_rssi_ext1; int8_t ts_rssi_ext2; - u8 pad[3]; + u8 qid; + u16 desc_id; + u8 tid; + u8 pad[2]; u32 ba_low; u32 ba_high; u32 evm0; @@ -148,6 +152,34 @@ struct ath_rx_status { u32 evm0; u32 evm1; u32 evm2; + u32 evm3; + u32 evm4; +}; + +struct ath_htc_rx_status { + __be64 rs_tstamp; + __be16 rs_datalen; + u8 rs_status; + u8 rs_phyerr; + int8_t rs_rssi; + int8_t rs_rssi_ctl0; + int8_t rs_rssi_ctl1; + int8_t rs_rssi_ctl2; + int8_t rs_rssi_ext0; + int8_t rs_rssi_ext1; + int8_t rs_rssi_ext2; + u8 rs_keyix; + u8 rs_rate; + u8 rs_antenna; + u8 rs_more; + u8 rs_isaggr; + u8 rs_moreaggr; + u8 rs_num_delims; + u8 rs_flags; + u8 rs_dummy; + __be32 evm0; + __be32 evm1; + __be32 evm2; }; #define ATH9K_RXERR_CRC 0x01 @@ -207,18 +239,9 @@ struct ath_desc { u32 ds_ctl0; u32 ds_ctl1; u32 ds_hw[20]; - union { - struct ath_tx_status tx; - struct ath_rx_status rx; - void *stats; - } ds_us; void *ds_vdata; } __packed; -#define ds_txstat ds_us.tx -#define ds_rxstat ds_us.rx -#define ds_stat ds_us.stats - #define ATH9K_TXDESC_CLRDMASK 0x0001 #define ATH9K_TXDESC_NOACK 0x0002 #define ATH9K_TXDESC_RTSENA 0x0004 @@ -242,7 +265,8 @@ struct ath_desc { #define ATH9K_TXDESC_EXT_AND_CTL 0x0080 #define ATH9K_TXDESC_VMF 0x0100 #define ATH9K_TXDESC_FRAG_IS_ON 0x0200 -#define ATH9K_TXDESC_CAB 0x0400 +#define ATH9K_TXDESC_LOWRXCHAIN 0x0400 +#define ATH9K_TXDESC_LDPC 0x00010000 #define ATH9K_RXDESC_INTREQ 0x0020 @@ -336,7 +360,6 @@ struct ar5416_desc { #define AR_DestIdxValid 0x40000000 #define AR_CTSEnable 0x80000000 -#define AR_BufLen 0x00000fff #define AR_TxMore 0x00001000 #define AR_DestIdx 0x000fe000 #define AR_DestIdx_S 13 @@ -393,6 +416,7 @@ struct ar5416_desc { #define AR_EncrType 0x0c000000 #define AR_EncrType_S 26 #define AR_TxCtlRsvd61 0xf0000000 +#define AR_LDPC 0x80000000 #define AR_2040_0 0x00000001 #define AR_GI0 0x00000002 @@ -412,7 +436,10 @@ struct ar5416_desc { #define AR_ChainSel3_S 17 #define AR_RTSCTSRate 0x0ff00000 #define AR_RTSCTSRate_S 20 -#define AR_TxCtlRsvd70 0xf0000000 +#define AR_STBC0 0x10000000 +#define AR_STBC1 0x20000000 +#define AR_STBC2 0x40000000 +#define AR_STBC3 0x80000000 #define AR_TxRSSIAnt00 0x000000ff #define AR_TxRSSIAnt00_S 0 @@ -476,7 +503,6 @@ struct ar5416_desc { #define AR_RxCTLRsvd00 0xffffffff -#define AR_BufLen 0x00000fff #define AR_RxCtlRsvd00 0x00001000 #define AR_RxIntrReq 0x00002000 #define AR_RxCtlRsvd01 0xffffc000 @@ -626,6 +652,7 @@ enum ath9k_rx_filter { #define ATH9K_RATESERIES_RTS_CTS 0x0001 #define ATH9K_RATESERIES_2040 0x0002 #define ATH9K_RATESERIES_HALFGI 0x0004 +#define ATH9K_RATESERIES_STBC 0x0008 struct ath9k_11n_rate_series { u32 Tries; @@ -669,33 +696,10 @@ struct ath9k_channel; u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); void ath9k_hw_txstart(struct ath_hw *ah, u32 q); +void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds); u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q); -void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 segLen, bool firstSeg, - bool lastSeg, const struct ath_desc *ds0); -void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds); -int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds); -void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 pktLen, enum ath9k_pkt_type type, u32 txPower, - u32 keyIx, enum ath9k_key_type keyType, u32 flags); -void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds, - struct ath_desc *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags); -void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds, - u32 aggrLen); -void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds, - u32 numDelims); -void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds); -void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds); -void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds, - u32 burstDuration); -void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds, - u32 vmf); void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs); bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, const struct ath9k_tx_queue_info *qinfo); @@ -706,15 +710,22 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q); bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q); int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, - u32 pa, struct ath_desc *nds, u64 tsf); + struct ath_rx_status *rs, u64 tsf); void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags); bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); -void ath9k_hw_rxena(struct ath_hw *ah); void ath9k_hw_startpcureceive(struct ath_hw *ah); void ath9k_hw_stoppcurecv(struct ath_hw *ah); +void ath9k_hw_abortpcurecv(struct ath_hw *ah); bool ath9k_hw_stopdmarecv(struct ath_hw *ah); int ath9k_hw_beaconq_setup(struct ath_hw *ah); +/* Interrupt Handling */ +bool ath9k_hw_intrpend(struct ath_hw *ah); +enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, + enum ath9k_int ints); + +void ar9002_hw_attach_mac_ops(struct ath_hw *ah); + #endif /* MAC_H */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 115e1aeedb5..893b552981a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -225,7 +225,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath_cache_conf_rate(sc, &hw->conf); ath_update_txpow(sc); - ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); ps_restore: ath9k_ps_restore(sc); @@ -401,23 +401,41 @@ void ath9k_tasklet(unsigned long data) struct ath_common *common = ath9k_hw_common(ah); u32 status = sc->intrstatus; + u32 rxmask; ath9k_ps_wakeup(sc); - if (status & ATH9K_INT_FATAL) { + if ((status & ATH9K_INT_FATAL) || + !ath9k_hw_check_alive(ah)) { ath_reset(sc, false); ath9k_ps_restore(sc); return; } - if (status & (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL | + ATH9K_INT_RXORN); + else + rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); + + if (status & rxmask) { spin_lock_bh(&sc->rx.rxflushlock); - ath_rx_tasklet(sc, 0); + + /* Check for high priority Rx first */ + if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && + (status & ATH9K_INT_RXHP)) + ath_rx_tasklet(sc, 0, true); + + ath_rx_tasklet(sc, 0, false); spin_unlock_bh(&sc->rx.rxflushlock); } - if (status & ATH9K_INT_TX) - ath_tx_tasklet(sc); + if (status & ATH9K_INT_TX) { + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + ath_tx_edma_tasklet(sc); + else + ath_tx_tasklet(sc); + } if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { /* @@ -434,7 +452,7 @@ void ath9k_tasklet(unsigned long data) ath_gen_timer_isr(sc->sc_ah); /* re-enable hardware interrupt */ - ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); ath9k_ps_restore(sc); } @@ -445,6 +463,8 @@ irqreturn_t ath_isr(int irq, void *dev) ATH9K_INT_RXORN | \ ATH9K_INT_RXEOL | \ ATH9K_INT_RX | \ + ATH9K_INT_RXLP | \ + ATH9K_INT_RXHP | \ ATH9K_INT_TX | \ ATH9K_INT_BMISS | \ ATH9K_INT_CST | \ @@ -477,7 +497,7 @@ irqreturn_t ath_isr(int irq, void *dev) * value to insure we only process bits we requested. */ ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ - status &= sc->imask; /* discard unasked-for bits */ + status &= ah->imask; /* discard unasked-for bits */ /* * If there are no status bits set, then this interrupt was not @@ -496,7 +516,8 @@ irqreturn_t ath_isr(int irq, void *dev) * If a FATAL or RXORN interrupt is received, we have to reset the * chip immediately. */ - if (status & (ATH9K_INT_FATAL | ATH9K_INT_RXORN)) + if ((status & ATH9K_INT_FATAL) || ((status & ATH9K_INT_RXORN) && + !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))) goto chip_reset; if (status & ATH9K_INT_SWBA) @@ -505,6 +526,13 @@ irqreturn_t ath_isr(int irq, void *dev) if (status & ATH9K_INT_TXURN) ath9k_hw_updatetxtriglevel(ah, true); + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + if (status & ATH9K_INT_RXEOL) { + ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN); + ath9k_hw_set_interrupts(ah, ah->imask); + } + } + if (status & ATH9K_INT_MIB) { /* * Disable interrupts until we service the MIB @@ -518,7 +546,7 @@ irqreturn_t ath_isr(int irq, void *dev) * the interrupt. */ ath9k_hw_procmibevent(ah); - ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); } if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) @@ -536,7 +564,7 @@ chip_reset: if (sched) { /* turn off every interrupt except SWBA */ - ath9k_hw_set_interrupts(ah, (sc->imask & ATH9K_INT_SWBA)); + ath9k_hw_set_interrupts(ah, (ah->imask & ATH9K_INT_SWBA)); tasklet_schedule(&sc->intr_tq); } @@ -724,6 +752,7 @@ static int ath_key_config(struct ath_common *common, struct ath_hw *ah = common->ah; struct ath9k_keyval hk; const u8 *mac = NULL; + u8 gmac[ETH_ALEN]; int ret = 0; int idx; @@ -747,9 +776,30 @@ static int ath_key_config(struct ath_common *common, memcpy(hk.kv_val, key->key, key->keylen); if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { - /* For now, use the default keys for broadcast keys. This may - * need to change with virtual interfaces. */ - idx = key->keyidx; + + if (key->ap_addr) { + /* + * Group keys on hardware that supports multicast frame + * key search use a mac that is the sender's address with + * the high bit set instead of the app-specified address. + */ + memcpy(gmac, key->ap_addr, ETH_ALEN); + gmac[0] |= 0x80; + mac = gmac; + + if (key->alg == ALG_TKIP) + idx = ath_reserve_key_cache_slot_tkip(common); + else + idx = ath_reserve_key_cache_slot(common); + if (idx < 0) + mac = NULL; /* no free key cache entries */ + } + + if (!mac) { + /* For now, use the default keys for broadcast keys. This may + * need to change with virtual interfaces. */ + idx = key->keyidx; + } } else if (key->keyidx) { if (WARN_ON(!sta)) return -EOPNOTSUPP; @@ -887,7 +937,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) ath_beacon_config(sc, NULL); /* restart beacons */ /* Re-Enable interrupts */ - ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); /* Enable LED */ ath9k_hw_cfg_output(ah, ah->led_pin, @@ -977,7 +1027,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, NULL); /* restart beacons */ - ath9k_hw_set_interrupts(ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); if (retry_tx) { int i; @@ -1162,23 +1212,28 @@ static int ath9k_start(struct ieee80211_hw *hw) } /* Setup our intr mask. */ - sc->imask = ATH9K_INT_RX | ATH9K_INT_TX - | ATH9K_INT_RXEOL | ATH9K_INT_RXORN - | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; + ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | + ATH9K_INT_RXORN | ATH9K_INT_FATAL | + ATH9K_INT_GLOBAL; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + ah->imask |= ATH9K_INT_RXHP | ATH9K_INT_RXLP; + else + ah->imask |= ATH9K_INT_RX; if (ah->caps.hw_caps & ATH9K_HW_CAP_GTT) - sc->imask |= ATH9K_INT_GTT; + ah->imask |= ATH9K_INT_GTT; if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) - sc->imask |= ATH9K_INT_CST; + ah->imask |= ATH9K_INT_CST; ath_cache_conf_rate(sc, &hw->conf); sc->sc_flags &= ~SC_OP_INVALID; /* Disable BMISS interrupt when we're not associated */ - sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - ath9k_hw_set_interrupts(ah, sc->imask); + ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + ath9k_hw_set_interrupts(ah, ah->imask); ieee80211_wake_queues(hw); @@ -1372,14 +1427,15 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, { struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_vif *avp = (void *)vif->drv_priv; enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; int ret = 0; mutex_lock(&sc->mutex); - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) && + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) && sc->nvifs > 0) { ret = -ENOBUFS; goto out; @@ -1414,19 +1470,19 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, sc->nvifs++; - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) + if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) ath9k_set_bssid_mask(hw); if (sc->nvifs > 1) goto out; /* skip global settings for secondary vif */ if (ic_opmode == NL80211_IFTYPE_AP) { - ath9k_hw_set_tsfadjust(sc->sc_ah, 1); + ath9k_hw_set_tsfadjust(ah, 1); sc->sc_flags |= SC_OP_TSF_RESET; } /* Set the device opmode */ - sc->sc_ah->opmode = ic_opmode; + ah->opmode = ic_opmode; /* * Enable MIB interrupts when there are hardware phy counters. @@ -1435,11 +1491,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, if ((vif->type == NL80211_IFTYPE_STATION) || (vif->type == NL80211_IFTYPE_ADHOC) || (vif->type == NL80211_IFTYPE_MESH_POINT)) { - sc->imask |= ATH9K_INT_MIB; - sc->imask |= ATH9K_INT_TSFOOR; + if (ah->config.enable_ani) + ah->imask |= ATH9K_INT_MIB; + ah->imask |= ATH9K_INT_TSFOOR; } - ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); + ath9k_hw_set_interrupts(ah, ah->imask); if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC || @@ -1495,15 +1552,16 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, void ath9k_enable_ps(struct ath_softc *sc) { + struct ath_hw *ah = sc->sc_ah; + sc->ps_enabled = true; - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { - sc->imask |= ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) { + ah->imask |= ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(ah, ah->imask); } } - ath9k_hw_setrxabort(sc->sc_ah, 1); + ath9k_hw_setrxabort(ah, 1); } static int ath9k_config(struct ieee80211_hw *hw, u32 changed) @@ -1579,10 +1637,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA | PS_WAIT_FOR_TX_ACK); - if (sc->imask & ATH9K_INT_TIM_TIMER) { - sc->imask &= ~ATH9K_INT_TIM_TIMER; + if (ah->imask & ATH9K_INT_TIM_TIMER) { + ah->imask &= ~ATH9K_INT_TIM_TIMER; ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); + ah->imask); } } } @@ -1986,6 +2044,25 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, return ret; } +static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct ath_wiphy *aphy = hw->priv; + struct ath_softc *sc = aphy->sc; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &hw->conf; + + if (idx != 0) + return -ENOENT; + + survey->channel = conf->channel; + survey->filled = SURVEY_INFO_NOISE_DBM; + survey->noise = common->ani.noise_floor; + + return 0; +} + static void ath9k_sw_scan_start(struct ieee80211_hw *hw) { struct ath_wiphy *aphy = hw->priv; @@ -2057,6 +2134,7 @@ struct ieee80211_ops ath9k_ops = { .set_tsf = ath9k_set_tsf, .reset_tsf = ath9k_reset_tsf, .ampdu_action = ath9k_ampdu_action, + .get_survey = ath9k_get_survey, .sw_scan_start = ath9k_sw_scan_start, .sw_scan_complete = ath9k_sw_scan_complete, .rfkill_poll = ath9k_rfkill_poll_state, diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 9441c6718a3..257b10ba6f5 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -28,6 +28,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */ { 0 } }; @@ -88,6 +89,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common) } static const struct ath_bus_ops ath_pci_bus_ops = { + .ath_bus_type = ATH_PCI, .read_cachesize = ath_pci_read_cachesize, .eeprom_read = ath_pci_eeprom_read, .bt_coex_prep = ath_pci_bt_coex_prep, diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c deleted file mode 100644 index 2547b3c4a26..00000000000 --- a/drivers/net/wireless/ath/ath9k/phy.c +++ /dev/null @@ -1,978 +0,0 @@ -/* - * Copyright (c) 2008-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. - */ - -/** - * DOC: Programming Atheros 802.11n analog front end radios - * - * AR5416 MAC based PCI devices and AR518 MAC based PCI-Express - * devices have either an external AR2133 analog front end radio for single - * band 2.4 GHz communication or an AR5133 analog front end radio for dual - * band 2.4 GHz / 5 GHz communication. - * - * All devices after the AR5416 and AR5418 family starting with the AR9280 - * have their analog front radios, MAC/BB and host PCIe/USB interface embedded - * into a single-chip and require less programming. - * - * The following single-chips exist with a respective embedded radio: - * - * AR9280 - 11n dual-band 2x2 MIMO for PCIe - * AR9281 - 11n single-band 1x2 MIMO for PCIe - * AR9285 - 11n single-band 1x1 for PCIe - * AR9287 - 11n single-band 2x2 MIMO for PCIe - * - * AR9220 - 11n dual-band 2x2 MIMO for PCI - * AR9223 - 11n single-band 2x2 MIMO for PCI - * - * AR9287 - 11n single-band 1x1 MIMO for USB - */ - -#include <linux/slab.h> - -#include "hw.h" - -/** - * ath9k_hw_write_regs - ?? - * - * @ah: atheros hardware structure - * @freqIndex: - * @regWrites: - * - * Used for both the chipsets with an external AR2133/AR5133 radios and - * single-chip devices. - */ -void ath9k_hw_write_regs(struct ath_hw *ah, u32 freqIndex, int regWrites) -{ - REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); -} - -/** - * ath9k_hw_ar9280_set_channel - set channel on single-chip device - * @ah: atheros hardware structure - * @chan: - * - * This is the function to change channel on single-chip devices, that is - * all devices after ar9280. - * - * This function takes the channel value in MHz and sets - * hardware channel value. Assumes writes have been enabled to analog bus. - * - * Actual Expression, - * - * For 2GHz channel, - * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17) - * (freq_ref = 40MHz) - * - * For 5GHz channel, - * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10) - * (freq_ref = 40MHz/(24>>amodeRefSel)) - */ -int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) -{ - u16 bMode, fracMode, aModeRefSel = 0; - u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0; - struct chan_centers centers; - u32 refDivA = 24; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = centers.synth_center; - - reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL); - reg32 &= 0xc0000000; - - if (freq < 4800) { /* 2 GHz, fractional mode */ - u32 txctl; - int regWrites = 0; - - bMode = 1; - fracMode = 1; - aModeRefSel = 0; - channelSel = (freq * 0x10000) / 15; - - if (AR_SREV_9287_11_OR_LATER(ah)) { - if (freq == 2484) { - /* Enable channel spreading for channel 14 */ - REG_WRITE_ARRAY(&ah->iniCckfirJapan2484, - 1, regWrites); - } else { - REG_WRITE_ARRAY(&ah->iniCckfirNormal, - 1, regWrites); - } - } else { - txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); - if (freq == 2484) { - /* Enable channel spreading for channel 14 */ - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl | AR_PHY_CCK_TX_CTRL_JAPAN); - } else { - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); - } - } - } else { - bMode = 0; - fracMode = 0; - - switch(ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) { - case 0: - if ((freq % 20) == 0) { - aModeRefSel = 3; - } else if ((freq % 10) == 0) { - aModeRefSel = 2; - } - if (aModeRefSel) - break; - case 1: - default: - aModeRefSel = 0; - /* - * Enable 2G (fractional) mode for channels - * which are 5MHz spaced. - */ - fracMode = 1; - refDivA = 1; - channelSel = (freq * 0x8000) / 15; - - /* RefDivA setting */ - REG_RMW_FIELD(ah, AR_AN_SYNTH9, - AR_AN_SYNTH9_REFDIVA, refDivA); - - } - - if (!fracMode) { - ndiv = (freq * (refDivA >> aModeRefSel)) / 60; - channelSel = ndiv & 0x1ff; - channelFrac = (ndiv & 0xfffffe00) * 2; - channelSel = (channelSel << 17) | channelFrac; - } - } - - reg32 = reg32 | - (bMode << 29) | - (fracMode << 28) | (aModeRefSel << 26) | (channelSel); - - REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); - - ah->curchan = chan; - ah->curchan_rad_index = -1; - - return 0; -} - -/** - * ath9k_hw_9280_spur_mitigate - convert baseband spur frequency - * @ah: atheros hardware structure - * @chan: - * - * For single-chip solutions. Converts to baseband spur frequency given the - * input channel frequency and compute register settings below. - */ -void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int freq; - int bin, cur_bin; - int bb_spur_off, spur_subchannel_sd; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, newVal; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - struct chan_centers centers; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = centers.synth_center; - - ah->config.spurmode = SPUR_ENABLE_EEPROM; - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); - - if (is2GHz) - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; - else - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; - - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - freq; - - if (IS_CHAN_HT40(chan)) { - if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { - bb_spur = cur_bb_spur; - break; - } - } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - return; - } else { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - } - - bin = bb_spur * 320; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - - newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); - - newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); - - if (IS_CHAN_HT40(chan)) { - if (bb_spur < 0) { - spur_subchannel_sd = 1; - bb_spur_off = bb_spur + 10; - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur - 10; - } - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur; - } - - if (IS_CHAN_HT40(chan)) - spur_delta_phase = - ((bb_spur * 262144) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - else - spur_delta_phase = - ((bb_spur * 524288) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; - spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; - - newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, newVal); - - newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; - REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp_v = abs(cur_vit_mask - bin); - - if (tmp_v < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); -} - -/* All code below is for non single-chip solutions */ - -/** - * ath9k_phy_modify_rx_buffer() - perform analog swizzling of parameters - * @rfbuf: - * @reg32: - * @numBits: - * @firstBit: - * @column: - * - * Performs analog "swizzling" of parameters into their location. - * Used on external AR2133/AR5133 radios. - */ -static void ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, - u32 numBits, u32 firstBit, - u32 column) -{ - u32 tmp32, mask, arrayEntry, lastBit; - int32_t bitPosition, bitsLeft; - - tmp32 = ath9k_hw_reverse_bits(reg32, numBits); - arrayEntry = (firstBit - 1) / 8; - bitPosition = (firstBit - 1) % 8; - bitsLeft = numBits; - while (bitsLeft > 0) { - lastBit = (bitPosition + bitsLeft > 8) ? - 8 : bitPosition + bitsLeft; - mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) << - (column * 8); - rfBuf[arrayEntry] &= ~mask; - rfBuf[arrayEntry] |= ((tmp32 << bitPosition) << - (column * 8)) & mask; - bitsLeft -= 8 - bitPosition; - tmp32 = tmp32 >> (8 - bitPosition); - bitPosition = 0; - arrayEntry++; - } -} - -/* - * Fix on 2.4 GHz band for orientation sensitivity issue by increasing - * rf_pwd_icsyndiv. - * - * Theoretical Rules: - * if 2 GHz band - * if forceBiasAuto - * if synth_freq < 2412 - * bias = 0 - * else if 2412 <= synth_freq <= 2422 - * bias = 1 - * else // synth_freq > 2422 - * bias = 2 - * else if forceBias > 0 - * bias = forceBias & 7 - * else - * no change, use value from ini file - * else - * no change, invalid band - * - * 1st Mod: - * 2422 also uses value of 2 - * <approved> - * - * 2nd Mod: - * Less than 2412 uses value of 0, 2412 and above uses value of 2 - */ -static void ath9k_hw_force_bias(struct ath_hw *ah, u16 synth_freq) -{ - struct ath_common *common = ath9k_hw_common(ah); - u32 tmp_reg; - int reg_writes = 0; - u32 new_bias = 0; - - if (!AR_SREV_5416(ah) || synth_freq >= 3000) { - return; - } - - BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); - - if (synth_freq < 2412) - new_bias = 0; - else if (synth_freq < 2422) - new_bias = 1; - else - new_bias = 2; - - /* pre-reverse this field */ - tmp_reg = ath9k_hw_reverse_bits(new_bias, 3); - - ath_print(common, ATH_DBG_CONFIG, - "Force rf_pwd_icsyndiv to %1d on %4d\n", - new_bias, synth_freq); - - /* swizzle rf_pwd_icsyndiv */ - ath9k_phy_modify_rx_buffer(ah->analogBank6Data, tmp_reg, 3, 181, 3); - - /* write Bank 6 with new params */ - REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes); -} - -/** - * ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios - * @ah: atheros hardware stucture - * @chan: - * - * For the external AR2133/AR5133 radios, takes the MHz channel value and set - * the channel value. Assumes writes enabled to analog bus and bank6 register - * cache in ah->analogBank6Data. - */ -int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) -{ - struct ath_common *common = ath9k_hw_common(ah); - u32 channelSel = 0; - u32 bModeSynth = 0; - u32 aModeRefSel = 0; - u32 reg32 = 0; - u16 freq; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = centers.synth_center; - - if (freq < 4800) { - u32 txctl; - - if (((freq - 2192) % 5) == 0) { - channelSel = ((freq - 672) * 2 - 3040) / 10; - bModeSynth = 0; - } else if (((freq - 2224) % 5) == 0) { - channelSel = ((freq - 704) * 2 - 3040) / 10; - bModeSynth = 1; - } else { - ath_print(common, ATH_DBG_FATAL, - "Invalid channel %u MHz\n", freq); - return -EINVAL; - } - - channelSel = (channelSel << 2) & 0xff; - channelSel = ath9k_hw_reverse_bits(channelSel, 8); - - txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); - if (freq == 2484) { - - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl | AR_PHY_CCK_TX_CTRL_JAPAN); - } else { - REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, - txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); - } - - } else if ((freq % 20) == 0 && freq >= 5120) { - channelSel = - ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8); - aModeRefSel = ath9k_hw_reverse_bits(1, 2); - } else if ((freq % 10) == 0) { - channelSel = - ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8); - if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) - aModeRefSel = ath9k_hw_reverse_bits(2, 2); - else - aModeRefSel = ath9k_hw_reverse_bits(1, 2); - } else if ((freq % 5) == 0) { - channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8); - aModeRefSel = ath9k_hw_reverse_bits(1, 2); - } else { - ath_print(common, ATH_DBG_FATAL, - "Invalid channel %u MHz\n", freq); - return -EINVAL; - } - - ath9k_hw_force_bias(ah, freq); - - reg32 = - (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | - (1 << 5) | 0x1; - - REG_WRITE(ah, AR_PHY(0x37), reg32); - - ah->curchan = chan; - ah->curchan_rad_index = -1; - - return 0; -} - -/** - * ath9k_hw_spur_mitigate - convert baseband spur frequency for external radios - * @ah: atheros hardware structure - * @chan: - * - * For non single-chip solutions. Converts to baseband spur frequency given the - * input channel frequency and compute register settings below. - */ -void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int bin, cur_bin; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, new; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - (chan->channel * 10); - if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) - return; - - bin = bb_spur * 32; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); - - new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, new); - - spur_delta_phase = ((bb_spur * 524288) / 100) & - AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; - spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; - - new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, new); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp_v = abs(cur_vit_mask - bin); - - if (tmp_v < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); -} - -/** - * ath9k_hw_rf_alloc_ext_banks - allocates banks for external radio programming - * @ah: atheros hardware structure - * - * Only required for older devices with external AR2133/AR5133 radios. - */ -int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah) -{ -#define ATH_ALLOC_BANK(bank, size) do { \ - bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \ - if (!bank) { \ - ath_print(common, ATH_DBG_FATAL, \ - "Cannot allocate RF banks\n"); \ - return -ENOMEM; \ - } \ - } while (0); - - struct ath_common *common = ath9k_hw_common(ah); - - BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); - - ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows); - ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows); - ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows); - ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows); - ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows); - ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows); - ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows); - ATH_ALLOC_BANK(ah->addac5416_21, - ah->iniAddac.ia_rows * ah->iniAddac.ia_columns); - ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows); - - return 0; -#undef ATH_ALLOC_BANK -} - - -/** - * ath9k_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers - * @ah: atheros hardware struture - * For the external AR2133/AR5133 radios banks. - */ -void -ath9k_hw_rf_free_ext_banks(struct ath_hw *ah) -{ -#define ATH_FREE_BANK(bank) do { \ - kfree(bank); \ - bank = NULL; \ - } while (0); - - BUG_ON(AR_SREV_9280_10_OR_LATER(ah)); - - ATH_FREE_BANK(ah->analogBank0Data); - ATH_FREE_BANK(ah->analogBank1Data); - ATH_FREE_BANK(ah->analogBank2Data); - ATH_FREE_BANK(ah->analogBank3Data); - ATH_FREE_BANK(ah->analogBank6Data); - ATH_FREE_BANK(ah->analogBank6TPCData); - ATH_FREE_BANK(ah->analogBank7Data); - ATH_FREE_BANK(ah->addac5416_21); - ATH_FREE_BANK(ah->bank6Temp); - -#undef ATH_FREE_BANK -} - -/* * - * ath9k_hw_set_rf_regs - programs rf registers based on EEPROM - * @ah: atheros hardware structure - * @chan: - * @modesIndex: - * - * Used for the external AR2133/AR5133 radios. - * - * Reads the EEPROM header info from the device structure and programs - * all rf registers. This routine requires access to the analog - * rf device. This is not required for single-chip devices. - */ -bool ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, - u16 modesIndex) -{ - u32 eepMinorRev; - u32 ob5GHz = 0, db5GHz = 0; - u32 ob2GHz = 0, db2GHz = 0; - int regWrites = 0; - - /* - * Software does not need to program bank data - * for single chip devices, that is AR9280 or anything - * after that. - */ - if (AR_SREV_9280_10_OR_LATER(ah)) - return true; - - /* Setup rf parameters */ - eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); - - /* Setup Bank 0 Write */ - RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); - - /* Setup Bank 1 Write */ - RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); - - /* Setup Bank 2 Write */ - RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); - - /* Setup Bank 6 Write */ - RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, - modesIndex); - { - int i; - for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) { - ah->analogBank6Data[i] = - INI_RA(&ah->iniBank6TPC, i, modesIndex); - } - } - - /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ - if (eepMinorRev >= 2) { - if (IS_CHAN_2GHZ(chan)) { - ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2); - db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2); - ath9k_phy_modify_rx_buffer(ah->analogBank6Data, - ob2GHz, 3, 197, 0); - ath9k_phy_modify_rx_buffer(ah->analogBank6Data, - db2GHz, 3, 194, 0); - } else { - ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5); - db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5); - ath9k_phy_modify_rx_buffer(ah->analogBank6Data, - ob5GHz, 3, 203, 0); - ath9k_phy_modify_rx_buffer(ah->analogBank6Data, - db5GHz, 3, 200, 0); - } - } - - /* Setup Bank 7 Setup */ - RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); - - /* Write Analog registers */ - REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, - regWrites); - REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data, - regWrites); - REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data, - regWrites); - REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data, - regWrites); - REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data, - regWrites); - REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data, - regWrites); - - return true; -} diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 0999a495fd4..e724c2c1ae2 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -17,589 +17,25 @@ #ifndef PHY_H #define PHY_H -/* Common between single chip and non single-chip solutions */ -void ath9k_hw_write_regs(struct ath_hw *ah, u32 freqIndex, int regWrites); - -/* Single chip radio settings */ -int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); -void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); - -/* Routines below are for non single-chip solutions */ -int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan); -void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan); - -int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah); -void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah); - -bool ath9k_hw_set_rf_regs(struct ath_hw *ah, - struct ath9k_channel *chan, - u16 modesIndex); +#define CHANSEL_DIV 15 +#define CHANSEL_2G(_freq) (((_freq) * 0x10000) / CHANSEL_DIV) +#define CHANSEL_5G(_freq) (((_freq) * 0x8000) / CHANSEL_DIV) #define AR_PHY_BASE 0x9800 #define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) -#define AR_PHY_TEST 0x9800 -#define PHY_AGC_CLR 0x10000000 -#define RFSILENT_BB 0x00002000 - -#define AR_PHY_TURBO 0x9804 -#define AR_PHY_FC_TURBO_MODE 0x00000001 -#define AR_PHY_FC_TURBO_SHORT 0x00000002 -#define AR_PHY_FC_DYN2040_EN 0x00000004 -#define AR_PHY_FC_DYN2040_PRI_ONLY 0x00000008 -#define AR_PHY_FC_DYN2040_PRI_CH 0x00000010 -/* For 25 MHz channel spacing -- not used but supported by hw */ -#define AR_PHY_FC_DYN2040_EXT_CH 0x00000020 -#define AR_PHY_FC_HT_EN 0x00000040 -#define AR_PHY_FC_SHORT_GI_40 0x00000080 -#define AR_PHY_FC_WALSH 0x00000100 -#define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200 -#define AR_PHY_FC_ENABLE_DAC_FIFO 0x00000800 - -#define AR_PHY_TEST2 0x9808 - -#define AR_PHY_TIMING2 0x9810 -#define AR_PHY_TIMING3 0x9814 -#define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 -#define AR_PHY_TIMING3_DSC_MAN_S 17 -#define AR_PHY_TIMING3_DSC_EXP 0x0001E000 -#define AR_PHY_TIMING3_DSC_EXP_S 13 - -#define AR_PHY_CHIP_ID 0x9818 -#define AR_PHY_CHIP_ID_REV_0 0x80 -#define AR_PHY_CHIP_ID_REV_1 0x81 -#define AR_PHY_CHIP_ID_9160_REV_0 0xb0 - -#define AR_PHY_ACTIVE 0x981C -#define AR_PHY_ACTIVE_EN 0x00000001 -#define AR_PHY_ACTIVE_DIS 0x00000000 - -#define AR_PHY_RF_CTL2 0x9824 -#define AR_PHY_TX_END_DATA_START 0x000000FF -#define AR_PHY_TX_END_DATA_START_S 0 -#define AR_PHY_TX_END_PA_ON 0x0000FF00 -#define AR_PHY_TX_END_PA_ON_S 8 - -#define AR_PHY_RF_CTL3 0x9828 -#define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000 -#define AR_PHY_TX_END_TO_A2_RX_ON_S 16 - -#define AR_PHY_ADC_CTL 0x982C -#define AR_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003 -#define AR_PHY_ADC_CTL_OFF_INBUFGAIN_S 0 -#define AR_PHY_ADC_CTL_OFF_PWDDAC 0x00002000 -#define AR_PHY_ADC_CTL_OFF_PWDBANDGAP 0x00004000 -#define AR_PHY_ADC_CTL_OFF_PWDADC 0x00008000 -#define AR_PHY_ADC_CTL_ON_INBUFGAIN 0x00030000 -#define AR_PHY_ADC_CTL_ON_INBUFGAIN_S 16 - -#define AR_PHY_ADC_SERIAL_CTL 0x9830 -#define AR_PHY_SEL_INTERNAL_ADDAC 0x00000000 -#define AR_PHY_SEL_EXTERNAL_RADIO 0x00000001 - -#define AR_PHY_RF_CTL4 0x9834 -#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF 0xFF000000 -#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF_S 24 -#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF 0x00FF0000 -#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF_S 16 -#define AR_PHY_RF_CTL4_FRAME_XPAB_ON 0x0000FF00 -#define AR_PHY_RF_CTL4_FRAME_XPAB_ON_S 8 -#define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF -#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0 - -#define AR_PHY_TSTDAC_CONST 0x983c - -#define AR_PHY_SETTLING 0x9844 -#define AR_PHY_SETTLING_SWITCH 0x00003F80 -#define AR_PHY_SETTLING_SWITCH_S 7 - -#define AR_PHY_RXGAIN 0x9848 -#define AR_PHY_RXGAIN_TXRX_ATTEN 0x0003F000 -#define AR_PHY_RXGAIN_TXRX_ATTEN_S 12 -#define AR_PHY_RXGAIN_TXRX_RF_MAX 0x007C0000 -#define AR_PHY_RXGAIN_TXRX_RF_MAX_S 18 -#define AR9280_PHY_RXGAIN_TXRX_ATTEN 0x00003F80 -#define AR9280_PHY_RXGAIN_TXRX_ATTEN_S 7 -#define AR9280_PHY_RXGAIN_TXRX_MARGIN 0x001FC000 -#define AR9280_PHY_RXGAIN_TXRX_MARGIN_S 14 - -#define AR_PHY_DESIRED_SZ 0x9850 -#define AR_PHY_DESIRED_SZ_ADC 0x000000FF -#define AR_PHY_DESIRED_SZ_ADC_S 0 -#define AR_PHY_DESIRED_SZ_PGA 0x0000FF00 -#define AR_PHY_DESIRED_SZ_PGA_S 8 -#define AR_PHY_DESIRED_SZ_TOT_DES 0x0FF00000 -#define AR_PHY_DESIRED_SZ_TOT_DES_S 20 - -#define AR_PHY_FIND_SIG 0x9858 -#define AR_PHY_FIND_SIG_FIRSTEP 0x0003F000 -#define AR_PHY_FIND_SIG_FIRSTEP_S 12 -#define AR_PHY_FIND_SIG_FIRPWR 0x03FC0000 -#define AR_PHY_FIND_SIG_FIRPWR_S 18 - -#define AR_PHY_AGC_CTL1 0x985C -#define AR_PHY_AGC_CTL1_COARSE_LOW 0x00007F80 -#define AR_PHY_AGC_CTL1_COARSE_LOW_S 7 -#define AR_PHY_AGC_CTL1_COARSE_HIGH 0x003F8000 -#define AR_PHY_AGC_CTL1_COARSE_HIGH_S 15 - -#define AR_PHY_AGC_CONTROL 0x9860 -#define AR_PHY_AGC_CONTROL_CAL 0x00000001 -#define AR_PHY_AGC_CONTROL_NF 0x00000002 -#define AR_PHY_AGC_CONTROL_ENABLE_NF 0x00008000 -#define AR_PHY_AGC_CONTROL_FLTR_CAL 0x00010000 -#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000 - -#define AR_PHY_CCA 0x9864 -#define AR_PHY_MINCCA_PWR 0x0FF80000 -#define AR_PHY_MINCCA_PWR_S 19 -#define AR_PHY_CCA_THRESH62 0x0007F000 -#define AR_PHY_CCA_THRESH62_S 12 -#define AR9280_PHY_MINCCA_PWR 0x1FF00000 -#define AR9280_PHY_MINCCA_PWR_S 20 -#define AR9280_PHY_CCA_THRESH62 0x000FF000 -#define AR9280_PHY_CCA_THRESH62_S 12 - -#define AR_PHY_SFCORR_LOW 0x986C -#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW 0x00000001 -#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW 0x00003F00 -#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S 8 -#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW 0x001FC000 -#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S 14 -#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW 0x0FE00000 -#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S 21 - -#define AR_PHY_SFCORR 0x9868 -#define AR_PHY_SFCORR_M2COUNT_THR 0x0000001F -#define AR_PHY_SFCORR_M2COUNT_THR_S 0 -#define AR_PHY_SFCORR_M1_THRESH 0x00FE0000 -#define AR_PHY_SFCORR_M1_THRESH_S 17 -#define AR_PHY_SFCORR_M2_THRESH 0x7F000000 -#define AR_PHY_SFCORR_M2_THRESH_S 24 - -#define AR_PHY_SLEEP_CTR_CONTROL 0x9870 -#define AR_PHY_SLEEP_CTR_LIMIT 0x9874 -#define AR_PHY_SYNTH_CONTROL 0x9874 -#define AR_PHY_SLEEP_SCAL 0x9878 - -#define AR_PHY_PLL_CTL 0x987c -#define AR_PHY_PLL_CTL_40 0xaa -#define AR_PHY_PLL_CTL_40_5413 0x04 -#define AR_PHY_PLL_CTL_44 0xab -#define AR_PHY_PLL_CTL_44_2133 0xeb -#define AR_PHY_PLL_CTL_40_2133 0xea - -#define AR_PHY_SPECTRAL_SCAN 0x9910 /* AR9280 spectral scan configuration register */ -#define AR_PHY_SPECTRAL_SCAN_ENABLE 0x1 -#define AR_PHY_SPECTRAL_SCAN_ENA 0x00000001 /* Enable spectral scan, reg 68, bit 0 */ -#define AR_PHY_SPECTRAL_SCAN_ENA_S 0 /* Enable spectral scan, reg 68, bit 0 */ -#define AR_PHY_SPECTRAL_SCAN_ACTIVE 0x00000002 /* Activate spectral scan reg 68, bit 1*/ -#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S 1 /* Activate spectral scan reg 68, bit 1*/ -#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD 0x000000F0 /* Interval for FFT reports, reg 68, bits 4-7*/ -#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S 4 -#define AR_PHY_SPECTRAL_SCAN_PERIOD 0x0000FF00 /* Interval for FFT reports, reg 68, bits 8-15*/ -#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8 -#define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 /* Number of reports, reg 68, bits 16-23*/ -#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16 -#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 /* Short repeat, reg 68, bit 24*/ -#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 /* Short repeat, reg 68, bit 24*/ - -#define AR_PHY_RX_DELAY 0x9914 -#define AR_PHY_SEARCH_START_DELAY 0x9918 -#define AR_PHY_RX_DELAY_DELAY 0x00003FFF - -#define AR_PHY_TIMING_CTRL4(_i) (0x9920 + ((_i) << 12)) -#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01F -#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S 0 -#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7E0 -#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5 -#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x800 -#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xF000 -#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12 -#define AR_PHY_TIMING_CTRL4_DO_CAL 0x10000 - -#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI 0x80000000 -#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER 0x40000000 -#define AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK 0x20000000 -#define AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK 0x10000000 - -#define AR_PHY_TIMING5 0x9924 -#define AR_PHY_TIMING5_CYCPWR_THR1 0x000000FE -#define AR_PHY_TIMING5_CYCPWR_THR1_S 1 - -#define AR_PHY_POWER_TX_RATE1 0x9934 -#define AR_PHY_POWER_TX_RATE2 0x9938 -#define AR_PHY_POWER_TX_RATE_MAX 0x993c -#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040 - -#define AR_PHY_FRAME_CTL 0x9944 -#define AR_PHY_FRAME_CTL_TX_CLIP 0x00000038 -#define AR_PHY_FRAME_CTL_TX_CLIP_S 3 - -#define AR_PHY_TXPWRADJ 0x994C -#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA 0x00000FC0 -#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA_S 6 -#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX 0x00FC0000 -#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX_S 18 - -#define AR_PHY_RADAR_EXT 0x9940 -#define AR_PHY_RADAR_EXT_ENA 0x00004000 - -#define AR_PHY_RADAR_0 0x9954 -#define AR_PHY_RADAR_0_ENA 0x00000001 -#define AR_PHY_RADAR_0_FFT_ENA 0x80000000 -#define AR_PHY_RADAR_0_INBAND 0x0000003e -#define AR_PHY_RADAR_0_INBAND_S 1 -#define AR_PHY_RADAR_0_PRSSI 0x00000FC0 -#define AR_PHY_RADAR_0_PRSSI_S 6 -#define AR_PHY_RADAR_0_HEIGHT 0x0003F000 -#define AR_PHY_RADAR_0_HEIGHT_S 12 -#define AR_PHY_RADAR_0_RRSSI 0x00FC0000 -#define AR_PHY_RADAR_0_RRSSI_S 18 -#define AR_PHY_RADAR_0_FIRPWR 0x7F000000 -#define AR_PHY_RADAR_0_FIRPWR_S 24 - -#define AR_PHY_RADAR_1 0x9958 -#define AR_PHY_RADAR_1_RELPWR_ENA 0x00800000 -#define AR_PHY_RADAR_1_USE_FIR128 0x00400000 -#define AR_PHY_RADAR_1_RELPWR_THRESH 0x003F0000 -#define AR_PHY_RADAR_1_RELPWR_THRESH_S 16 -#define AR_PHY_RADAR_1_BLOCK_CHECK 0x00008000 -#define AR_PHY_RADAR_1_MAX_RRSSI 0x00004000 -#define AR_PHY_RADAR_1_RELSTEP_CHECK 0x00002000 -#define AR_PHY_RADAR_1_RELSTEP_THRESH 0x00001F00 -#define AR_PHY_RADAR_1_RELSTEP_THRESH_S 8 -#define AR_PHY_RADAR_1_MAXLEN 0x000000FF -#define AR_PHY_RADAR_1_MAXLEN_S 0 - -#define AR_PHY_SWITCH_CHAIN_0 0x9960 -#define AR_PHY_SWITCH_COM 0x9964 - -#define AR_PHY_SIGMA_DELTA 0x996C -#define AR_PHY_SIGMA_DELTA_ADC_SEL 0x00000003 -#define AR_PHY_SIGMA_DELTA_ADC_SEL_S 0 -#define AR_PHY_SIGMA_DELTA_FILT2 0x000000F8 -#define AR_PHY_SIGMA_DELTA_FILT2_S 3 -#define AR_PHY_SIGMA_DELTA_FILT1 0x00001F00 -#define AR_PHY_SIGMA_DELTA_FILT1_S 8 -#define AR_PHY_SIGMA_DELTA_ADC_CLIP 0x01FFE000 -#define AR_PHY_SIGMA_DELTA_ADC_CLIP_S 13 - -#define AR_PHY_RESTART 0x9970 -#define AR_PHY_RESTART_DIV_GC 0x001C0000 -#define AR_PHY_RESTART_DIV_GC_S 18 - -#define AR_PHY_RFBUS_REQ 0x997C -#define AR_PHY_RFBUS_REQ_EN 0x00000001 - -#define AR_PHY_TIMING7 0x9980 -#define AR_PHY_TIMING8 0x9984 -#define AR_PHY_TIMING8_PILOT_MASK_2 0x000FFFFF -#define AR_PHY_TIMING8_PILOT_MASK_2_S 0 - -#define AR_PHY_BIN_MASK2_1 0x9988 -#define AR_PHY_BIN_MASK2_2 0x998c -#define AR_PHY_BIN_MASK2_3 0x9990 -#define AR_PHY_BIN_MASK2_4 0x9994 - -#define AR_PHY_BIN_MASK_1 0x9900 -#define AR_PHY_BIN_MASK_2 0x9904 -#define AR_PHY_BIN_MASK_3 0x9908 - -#define AR_PHY_MASK_CTL 0x990c - -#define AR_PHY_BIN_MASK2_4_MASK_4 0x00003FFF -#define AR_PHY_BIN_MASK2_4_MASK_4_S 0 - -#define AR_PHY_TIMING9 0x9998 -#define AR_PHY_TIMING10 0x999c -#define AR_PHY_TIMING10_PILOT_MASK_2 0x000FFFFF -#define AR_PHY_TIMING10_PILOT_MASK_2_S 0 - -#define AR_PHY_TIMING11 0x99a0 -#define AR_PHY_TIMING11_SPUR_DELTA_PHASE 0x000FFFFF -#define AR_PHY_TIMING11_SPUR_DELTA_PHASE_S 0 -#define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 -#define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 -#define AR_PHY_TIMING11_USE_SPUR_IN_AGC 0x40000000 -#define AR_PHY_TIMING11_USE_SPUR_IN_SELFCOR 0x80000000 - -#define AR_PHY_RX_CHAINMASK 0x99a4 -#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12)) -#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000 -#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000 - -#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac -#define AR_PHY_9285_ANT_DIV_CTL_ALL 0x7f000000 -#define AR_PHY_9285_ANT_DIV_CTL 0x01000000 -#define AR_PHY_9285_ANT_DIV_CTL_S 24 -#define AR_PHY_9285_ANT_DIV_ALT_LNACONF 0x06000000 -#define AR_PHY_9285_ANT_DIV_ALT_LNACONF_S 25 -#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF 0x18000000 -#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S 27 -#define AR_PHY_9285_ANT_DIV_ALT_GAINTB 0x20000000 -#define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S 29 -#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000 -#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30 -#define AR_PHY_9285_ANT_DIV_LNA1 2 -#define AR_PHY_9285_ANT_DIV_LNA2 1 -#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3 -#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0 -#define AR_PHY_9285_ANT_DIV_GAINTB_0 0 -#define AR_PHY_9285_ANT_DIV_GAINTB_1 1 +#define AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX 0x0007E000 +#define AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX_S 13 +#define AR_PHY_TX_GAIN_CLC 0x0000001E +#define AR_PHY_TX_GAIN_CLC_S 1 +#define AR_PHY_TX_GAIN 0x0007F000 +#define AR_PHY_TX_GAIN_S 12 -#define AR_PHY_EXT_CCA0 0x99b8 -#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF -#define AR_PHY_EXT_CCA0_THRESH62_S 0 - -#define AR_PHY_EXT_CCA 0x99bc -#define AR_PHY_EXT_CCA_CYCPWR_THR1 0x0000FE00 -#define AR_PHY_EXT_CCA_CYCPWR_THR1_S 9 -#define AR_PHY_EXT_CCA_THRESH62 0x007F0000 -#define AR_PHY_EXT_CCA_THRESH62_S 16 -#define AR_PHY_EXT_MINCCA_PWR 0xFF800000 -#define AR_PHY_EXT_MINCCA_PWR_S 23 -#define AR9280_PHY_EXT_MINCCA_PWR 0x01FF0000 -#define AR9280_PHY_EXT_MINCCA_PWR_S 16 - -#define AR_PHY_SFCORR_EXT 0x99c0 -#define AR_PHY_SFCORR_EXT_M1_THRESH 0x0000007F -#define AR_PHY_SFCORR_EXT_M1_THRESH_S 0 -#define AR_PHY_SFCORR_EXT_M2_THRESH 0x00003F80 -#define AR_PHY_SFCORR_EXT_M2_THRESH_S 7 -#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW 0x001FC000 -#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14 -#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW 0x0FE00000 -#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21 -#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28 - -#define AR_PHY_HALFGI 0x99D0 -#define AR_PHY_HALFGI_DSC_MAN 0x0007FFF0 -#define AR_PHY_HALFGI_DSC_MAN_S 4 -#define AR_PHY_HALFGI_DSC_EXP 0x0000000F -#define AR_PHY_HALFGI_DSC_EXP_S 0 - -#define AR_PHY_CHAN_INFO_MEMORY 0x99DC -#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001 - -#define AR_PHY_HEAVY_CLIP_ENABLE 0x99E0 - -#define AR_PHY_HEAVY_CLIP_FACTOR_RIFS 0x99EC -#define AR_PHY_RIFS_INIT_DELAY 0x03ff0000 - -#define AR_PHY_M_SLEEP 0x99f0 -#define AR_PHY_REFCLKDLY 0x99f4 -#define AR_PHY_REFCLKPD 0x99f8 - -#define AR_PHY_CALMODE 0x99f0 - -#define AR_PHY_CALMODE_IQ 0x00000000 -#define AR_PHY_CALMODE_ADC_GAIN 0x00000001 -#define AR_PHY_CALMODE_ADC_DC_PER 0x00000002 -#define AR_PHY_CALMODE_ADC_DC_INIT 0x00000003 - -#define AR_PHY_CAL_MEAS_0(_i) (0x9c10 + ((_i) << 12)) -#define AR_PHY_CAL_MEAS_1(_i) (0x9c14 + ((_i) << 12)) -#define AR_PHY_CAL_MEAS_2(_i) (0x9c18 + ((_i) << 12)) -#define AR_PHY_CAL_MEAS_3(_i) (0x9c1c + ((_i) << 12)) - -#define AR_PHY_CURRENT_RSSI 0x9c1c -#define AR9280_PHY_CURRENT_RSSI 0x9c3c - -#define AR_PHY_RFBUS_GRANT 0x9C20 -#define AR_PHY_RFBUS_GRANT_EN 0x00000001 - -#define AR_PHY_CHAN_INFO_GAIN_DIFF 0x9CF4 -#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320 - -#define AR_PHY_CHAN_INFO_GAIN 0x9CFC - -#define AR_PHY_MODE 0xA200 -#define AR_PHY_MODE_ASYNCFIFO 0x80 -#define AR_PHY_MODE_AR2133 0x08 -#define AR_PHY_MODE_AR5111 0x00 -#define AR_PHY_MODE_AR5112 0x08 -#define AR_PHY_MODE_DYNAMIC 0x04 -#define AR_PHY_MODE_RF2GHZ 0x02 -#define AR_PHY_MODE_RF5GHZ 0x00 -#define AR_PHY_MODE_CCK 0x01 -#define AR_PHY_MODE_OFDM 0x00 -#define AR_PHY_MODE_DYN_CCK_DISABLE 0x100 - -#define AR_PHY_CCK_TX_CTRL 0xA204 -#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010 -#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK 0x0000000C -#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S 2 - -#define AR_PHY_CCK_DETECT 0xA208 -#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F -#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0 -/* [12:6] settling time for antenna switch */ -#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0 -#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6 -#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 -#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S 13 - -#define AR_PHY_GAIN_2GHZ 0xA20C -#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000 -#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN_S 18 -#define AR_PHY_GAIN_2GHZ_BSW_MARGIN 0x00003C00 -#define AR_PHY_GAIN_2GHZ_BSW_MARGIN_S 10 -#define AR_PHY_GAIN_2GHZ_BSW_ATTEN 0x0000001F -#define AR_PHY_GAIN_2GHZ_BSW_ATTEN_S 0 - -#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN 0x003E0000 -#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN_S 17 -#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN 0x0001F000 -#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN_S 12 -#define AR_PHY_GAIN_2GHZ_XATTEN2_DB 0x00000FC0 -#define AR_PHY_GAIN_2GHZ_XATTEN2_DB_S 6 -#define AR_PHY_GAIN_2GHZ_XATTEN1_DB 0x0000003F -#define AR_PHY_GAIN_2GHZ_XATTEN1_DB_S 0 - -#define AR_PHY_CCK_RXCTRL4 0xA21C -#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT 0x01F80000 -#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19 - -#define AR_PHY_DAG_CTRLCCK 0xA228 -#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR 0x00000200 -#define AR_PHY_DAG_CTRLCCK_RSSI_THR 0x0001FC00 -#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S 10 - -#define AR_PHY_FORCE_CLKEN_CCK 0xA22C -#define AR_PHY_FORCE_CLKEN_CCK_MRC_MUX 0x00000040 - -#define AR_PHY_POWER_TX_RATE3 0xA234 -#define AR_PHY_POWER_TX_RATE4 0xA238 - -#define AR_PHY_SCRM_SEQ_XR 0xA23C -#define AR_PHY_HEADER_DETECT_XR 0xA240 -#define AR_PHY_CHIRP_DETECTED_XR 0xA244 -#define AR_PHY_BLUETOOTH 0xA254 - -#define AR_PHY_TPCRG1 0xA258 -#define AR_PHY_TPCRG1_NUM_PD_GAIN 0x0000c000 -#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14 - -#define AR_PHY_TPCRG1_PD_GAIN_1 0x00030000 -#define AR_PHY_TPCRG1_PD_GAIN_1_S 16 -#define AR_PHY_TPCRG1_PD_GAIN_2 0x000C0000 -#define AR_PHY_TPCRG1_PD_GAIN_2_S 18 -#define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000 -#define AR_PHY_TPCRG1_PD_GAIN_3_S 20 - -#define AR_PHY_TPCRG1_PD_CAL_ENABLE 0x00400000 -#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22 - -#define AR_PHY_TX_PWRCTRL4 0xa264 -#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID 0x00000001 -#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID_S 0 -#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT 0x000001FE -#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT_S 1 - -#define AR_PHY_TX_PWRCTRL6_0 0xa270 -#define AR_PHY_TX_PWRCTRL6_1 0xb270 -#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE 0x03000000 -#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S 24 - -#define AR_PHY_TX_PWRCTRL7 0xa274 -#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000 -#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19 - -#define AR_PHY_TX_PWRCTRL9 0xa27C -#define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 -#define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 -#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000 -#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31 - -#define AR_PHY_TX_GAIN_TBL1 0xa300 -#define AR_PHY_TX_GAIN 0x0007F000 -#define AR_PHY_TX_GAIN_S 12 - -#define AR_PHY_CH0_TX_PWRCTRL11 0xa398 -#define AR_PHY_CH1_TX_PWRCTRL11 0xb398 -#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00 -#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10 - -#define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 -#define AR_PHY_MASK2_M_31_45 0xa3a4 -#define AR_PHY_MASK2_M_16_30 0xa3a8 -#define AR_PHY_MASK2_M_00_15 0xa3ac -#define AR_PHY_MASK2_P_15_01 0xa3b8 -#define AR_PHY_MASK2_P_30_16 0xa3bc -#define AR_PHY_MASK2_P_45_31 0xa3c0 -#define AR_PHY_MASK2_P_61_45 0xa3c4 -#define AR_PHY_SPUR_REG 0x994c - -#define AR_PHY_SPUR_REG_MASK_RATE_CNTL (0xFF << 18) -#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S 18 - -#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM 0x20000 -#define AR_PHY_SPUR_REG_MASK_RATE_SELECT (0xFF << 9) -#define AR_PHY_SPUR_REG_MASK_RATE_SELECT_S 9 -#define AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100 -#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH 0x7F -#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S 0 - -#define AR_PHY_PILOT_MASK_01_30 0xa3b0 -#define AR_PHY_PILOT_MASK_31_60 0xa3b4 - -#define AR_PHY_CHANNEL_MASK_01_30 0x99d4 -#define AR_PHY_CHANNEL_MASK_31_60 0x99d8 - -#define AR_PHY_ANALOG_SWAP 0xa268 -#define AR_PHY_SWAP_ALT_CHAIN 0x00000040 - -#define AR_PHY_TPCRG5 0xA26C -#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP 0x0000000F -#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S 0 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1 0x000003F0 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S 4 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2 0x0000FC00 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S 10 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3 0x003F0000 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S 16 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0FC00000 -#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22 - -/* Carrier leak calibration control, do it after AGC calibration */ -#define AR_PHY_CL_CAL_CTL 0xA358 -#define AR_PHY_CL_CAL_ENABLE 0x00000002 -#define AR_PHY_PARALLEL_CAL_ENABLE 0x00000001 - -#define AR_PHY_POWER_TX_RATE5 0xA38C -#define AR_PHY_POWER_TX_RATE6 0xA390 - -#define AR_PHY_CAL_CHAINMASK 0xA39C - -#define AR_PHY_POWER_TX_SUB 0xA3C8 -#define AR_PHY_POWER_TX_RATE7 0xA3CC -#define AR_PHY_POWER_TX_RATE8 0xA3D0 -#define AR_PHY_POWER_TX_RATE9 0xA3D4 - -#define AR_PHY_XPA_CFG 0xA3D8 -#define AR_PHY_FORCE_XPA_CFG 0x000000001 -#define AR_PHY_FORCE_XPA_CFG_S 0 - -#define AR_PHY_CH1_CCA 0xa864 -#define AR_PHY_CH1_MINCCA_PWR 0x0FF80000 -#define AR_PHY_CH1_MINCCA_PWR_S 19 -#define AR9280_PHY_CH1_MINCCA_PWR 0x1FF00000 -#define AR9280_PHY_CH1_MINCCA_PWR_S 20 - -#define AR_PHY_CH2_CCA 0xb864 -#define AR_PHY_CH2_MINCCA_PWR 0x0FF80000 -#define AR_PHY_CH2_MINCCA_PWR_S 19 - -#define AR_PHY_CH1_EXT_CCA 0xa9bc -#define AR_PHY_CH1_EXT_MINCCA_PWR 0xFF800000 -#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23 -#define AR9280_PHY_CH1_EXT_MINCCA_PWR 0x01FF0000 -#define AR9280_PHY_CH1_EXT_MINCCA_PWR_S 16 - -#define AR_PHY_CH2_EXT_CCA 0xb9bc -#define AR_PHY_CH2_EXT_MINCCA_PWR 0xFF800000 -#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23 +#define AR_PHY_CLC_TBL1 0xa35c +#define AR_PHY_CLC_I0 0x07ff0000 +#define AR_PHY_CLC_I0_S 16 +#define AR_PHY_CLC_Q0 0x0000ffd0 +#define AR_PHY_CLC_Q0_S 5 #define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do { \ int r; \ @@ -615,6 +51,7 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah, #define ANTSWAP_AB 0x0001 #define REDUCE_CHAIN_0 0x00000050 #define REDUCE_CHAIN_1 0x00000051 +#define AR_PHY_CHIP_ID 0x9818 #define RF_BANK_SETUP(_bank, _iniarray, _col) do { \ int i; \ @@ -622,4 +59,7 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah, (_bank)[i] = INI_RA((_iniarray), i, _col);; \ } while (0) +#define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 +#define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 + #endif diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 244e1c62917..8519452c95f 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -691,6 +691,19 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, rate_table = sc->cur_rate_table; rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe); + /* + * If we're in HT mode and both us and our peer supports LDPC. + * We don't need to check our own device's capabilities as our own + * ht capabilities would have already been intersected with our peer's. + */ + if (conf_is_ht(&sc->hw->conf) && + (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) + tx_info->flags |= IEEE80211_TX_CTL_LDPC; + + if (conf_is_ht(&sc->hw->conf) && + (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) + tx_info->flags |= (1 << IEEE80211_TX_CTL_STBC_SHIFT); + if (is_probe) { /* set one try for probe rates. For the * probes don't enable rts */ @@ -1228,8 +1241,12 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, long_retry = rate->count - 1; } - if (!priv_sta || !ieee80211_is_data(fc) || - !(tx_info->pad[0] & ATH_TX_INFO_UPDATE_RC)) + if (!priv_sta || !ieee80211_is_data(fc)) + return; + + /* This packet was aggregated but doesn't carry status info */ + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && + !(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) return; if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 4f6d6fd442f..3d8d40cdc99 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -110,8 +110,8 @@ struct ath_rate_table { int rate_cnt; int mcs_start; struct { - int valid; - int valid_single_stream; + u8 valid; + u8 valid_single_stream; u8 phy; u32 ratekbps; u32 user_ratekbps; @@ -172,14 +172,13 @@ struct ath_rate_priv { #define ATH_TX_INFO_FRAME_TYPE_INTERNAL (1 << 0) #define ATH_TX_INFO_FRAME_TYPE_PAUSE (1 << 1) -#define ATH_TX_INFO_UPDATE_RC (1 << 2) #define ATH_TX_INFO_XRETRY (1 << 3) #define ATH_TX_INFO_UNDERRUN (1 << 4) enum ath9k_internal_frame_type { - ATH9K_NOT_INTERNAL, - ATH9K_INT_PAUSE, - ATH9K_INT_UNPAUSE + ATH9K_IFT_NOT_INTERNAL, + ATH9K_IFT_PAUSE, + ATH9K_IFT_UNPAUSE }; int ath_rate_control_register(void); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 1ca42e5148c..ba139132c85 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -15,6 +15,9 @@ */ #include "ath9k.h" +#include "ar9003_mac.h" + +#define SKB_CB_ATHBUF(__skb) (*((struct ath_buf **)__skb->cb)) static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc, struct ieee80211_hdr *hdr) @@ -115,56 +118,244 @@ static void ath_opmode_init(struct ath_softc *sc) ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); } -int ath_rx_init(struct ath_softc *sc, int nbufs) +static bool ath_rx_edma_buf_link(struct ath_softc *sc, + enum ath9k_rx_qtype qtype) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_rx_edma *rx_edma; struct sk_buff *skb; struct ath_buf *bf; - int error = 0; - spin_lock_init(&sc->rx.rxflushlock); - sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_lock_init(&sc->rx.rxbuflock); + rx_edma = &sc->rx.rx_edma[qtype]; + if (skb_queue_len(&rx_edma->rx_fifo) >= rx_edma->rx_fifo_hwsize) + return false; - common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN, - min(common->cachelsz, (u16)64)); + bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); + list_del_init(&bf->list); - ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", - common->cachelsz, common->rx_bufsize); + skb = bf->bf_mpdu; + + ATH_RXBUF_RESET(bf); + memset(skb->data, 0, ah->caps.rx_status_len); + dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, + ah->caps.rx_status_len, DMA_TO_DEVICE); - /* Initialize rx descriptors */ + SKB_CB_ATHBUF(skb) = bf; + ath9k_hw_addrxbuf_edma(ah, bf->bf_buf_addr, qtype); + skb_queue_tail(&rx_edma->rx_fifo, skb); - error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, - "rx", nbufs, 1); - if (error != 0) { - ath_print(common, ATH_DBG_FATAL, - "failed to allocate rx descriptors: %d\n", error); - goto err; + return true; +} + +static void ath_rx_addbuffer_edma(struct ath_softc *sc, + enum ath9k_rx_qtype qtype, int size) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + u32 nbuf = 0; + + if (list_empty(&sc->rx.rxbuf)) { + ath_print(common, ATH_DBG_QUEUE, "No free rx buf available\n"); + return; } + while (!list_empty(&sc->rx.rxbuf)) { + nbuf++; + + if (!ath_rx_edma_buf_link(sc, qtype)) + break; + + if (nbuf >= size) + break; + } +} + +static void ath_rx_remove_buffer(struct ath_softc *sc, + enum ath9k_rx_qtype qtype) +{ + struct ath_buf *bf; + struct ath_rx_edma *rx_edma; + struct sk_buff *skb; + + rx_edma = &sc->rx.rx_edma[qtype]; + + while ((skb = skb_dequeue(&rx_edma->rx_fifo)) != NULL) { + bf = SKB_CB_ATHBUF(skb); + BUG_ON(!bf); + list_add_tail(&bf->list, &sc->rx.rxbuf); + } +} + +static void ath_rx_edma_cleanup(struct ath_softc *sc) +{ + struct ath_buf *bf; + + ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); + ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); + list_for_each_entry(bf, &sc->rx.rxbuf, list) { + if (bf->bf_mpdu) + dev_kfree_skb_any(bf->bf_mpdu); + } + + INIT_LIST_HEAD(&sc->rx.rxbuf); + + kfree(sc->rx.rx_bufptr); + sc->rx.rx_bufptr = NULL; +} + +static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size) +{ + skb_queue_head_init(&rx_edma->rx_fifo); + skb_queue_head_init(&rx_edma->rx_buffers); + rx_edma->rx_fifo_hwsize = size; +} + +static int ath_rx_edma_init(struct ath_softc *sc, int nbufs) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct sk_buff *skb; + struct ath_buf *bf; + int error = 0, i; + u32 size; + + + common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN + + ah->caps.rx_status_len, + min(common->cachelsz, (u16)64)); + + ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize - + ah->caps.rx_status_len); + + ath_rx_edma_init_queue(&sc->rx.rx_edma[ATH9K_RX_QUEUE_LP], + ah->caps.rx_lp_qdepth); + ath_rx_edma_init_queue(&sc->rx.rx_edma[ATH9K_RX_QUEUE_HP], + ah->caps.rx_hp_qdepth); + + size = sizeof(struct ath_buf) * nbufs; + bf = kzalloc(size, GFP_KERNEL); + if (!bf) + return -ENOMEM; + + INIT_LIST_HEAD(&sc->rx.rxbuf); + sc->rx.rx_bufptr = bf; + + for (i = 0; i < nbufs; i++, bf++) { skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL); - if (skb == NULL) { + if (!skb) { error = -ENOMEM; - goto err; + goto rx_init_fail; } + memset(skb->data, 0, common->rx_bufsize); bf->bf_mpdu = skb; + bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, common->rx_bufsize, - DMA_FROM_DEVICE); + DMA_BIDIRECTIONAL); if (unlikely(dma_mapping_error(sc->dev, - bf->bf_buf_addr))) { - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; + bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + ath_print(common, ATH_DBG_FATAL, + "dma_mapping_error() on RX init\n"); + error = -ENOMEM; + goto rx_init_fail; + } + + list_add_tail(&bf->list, &sc->rx.rxbuf); + } + + return 0; + +rx_init_fail: + ath_rx_edma_cleanup(sc); + return error; +} + +static void ath_edma_start_recv(struct ath_softc *sc) +{ + spin_lock_bh(&sc->rx.rxbuflock); + + ath9k_hw_rxena(sc->sc_ah); + + ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP, + sc->rx.rx_edma[ATH9K_RX_QUEUE_HP].rx_fifo_hwsize); + + ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP, + sc->rx.rx_edma[ATH9K_RX_QUEUE_LP].rx_fifo_hwsize); + + spin_unlock_bh(&sc->rx.rxbuflock); + + ath_opmode_init(sc); + + ath9k_hw_startpcureceive(sc->sc_ah); +} + +static void ath_edma_stop_recv(struct ath_softc *sc) +{ + spin_lock_bh(&sc->rx.rxbuflock); + ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); + ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); + spin_unlock_bh(&sc->rx.rxbuflock); +} + +int ath_rx_init(struct ath_softc *sc, int nbufs) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct sk_buff *skb; + struct ath_buf *bf; + int error = 0; + + spin_lock_init(&sc->rx.rxflushlock); + sc->sc_flags &= ~SC_OP_RXFLUSH; + spin_lock_init(&sc->rx.rxbuflock); + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + return ath_rx_edma_init(sc, nbufs); + } else { + 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, common->rx_bufsize); + + /* Initialize rx descriptors */ + + error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, + "rx", nbufs, 1, 0); + if (error != 0) { ath_print(common, ATH_DBG_FATAL, - "dma_mapping_error() on RX init\n"); - error = -ENOMEM; + "failed to allocate rx descriptors: %d\n", + error); goto err; } - bf->bf_dmacontext = bf->bf_buf_addr; + + list_for_each_entry(bf, &sc->rx.rxbuf, list) { + skb = ath_rxbuf_alloc(common, common->rx_bufsize, + GFP_KERNEL); + if (skb == NULL) { + error = -ENOMEM; + goto err; + } + + bf->bf_mpdu = skb; + bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, + common->rx_bufsize, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(sc->dev, + bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + ath_print(common, ATH_DBG_FATAL, + "dma_mapping_error() on RX init\n"); + error = -ENOMEM; + goto err; + } + bf->bf_dmacontext = bf->bf_buf_addr; + } + sc->rx.rxlink = NULL; } - sc->rx.rxlink = NULL; err: if (error) @@ -180,17 +371,23 @@ void ath_rx_cleanup(struct ath_softc *sc) struct sk_buff *skb; struct ath_buf *bf; - list_for_each_entry(bf, &sc->rx.rxbuf, list) { - skb = bf->bf_mpdu; - if (skb) { - dma_unmap_single(sc->dev, bf->bf_buf_addr, - common->rx_bufsize, DMA_FROM_DEVICE); - dev_kfree_skb(skb); + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + ath_rx_edma_cleanup(sc); + return; + } else { + list_for_each_entry(bf, &sc->rx.rxbuf, list) { + skb = bf->bf_mpdu; + if (skb) { + dma_unmap_single(sc->dev, bf->bf_buf_addr, + common->rx_bufsize, + DMA_FROM_DEVICE); + dev_kfree_skb(skb); + } } - } - if (sc->rx.rxdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf); + if (sc->rx.rxdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf); + } } /* @@ -273,6 +470,11 @@ int ath_startrecv(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; struct ath_buf *bf, *tbf; + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + ath_edma_start_recv(sc); + return 0; + } + spin_lock_bh(&sc->rx.rxbuflock); if (list_empty(&sc->rx.rxbuf)) goto start_recv; @@ -306,7 +508,11 @@ bool ath_stoprecv(struct ath_softc *sc) ath9k_hw_stoppcurecv(ah); ath9k_hw_setrxfilter(ah, 0); stopped = ath9k_hw_stopdmarecv(ah); - sc->rx.rxlink = NULL; + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + ath_edma_stop_recv(sc); + else + sc->rx.rxlink = NULL; return stopped; } @@ -315,7 +521,9 @@ void ath_flushrecv(struct ath_softc *sc) { spin_lock_bh(&sc->rx.rxflushlock); sc->sc_flags |= SC_OP_RXFLUSH; - ath_rx_tasklet(sc, 1); + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + ath_rx_tasklet(sc, 1, true); + ath_rx_tasklet(sc, 1, false); sc->sc_flags &= ~SC_OP_RXFLUSH; spin_unlock_bh(&sc->rx.rxflushlock); } @@ -469,15 +677,148 @@ static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw, ieee80211_rx(hw, skb); } -int ath_rx_tasklet(struct ath_softc *sc, int flush) +static bool ath_edma_get_buffers(struct ath_softc *sc, + enum ath9k_rx_qtype qtype) { -#define PA2DESC(_sc, _pa) \ - ((struct ath_desc *)((caddr_t)(_sc)->rx.rxdma.dd_desc + \ - ((_pa) - (_sc)->rx.rxdma.dd_desc_paddr))) + struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype]; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct sk_buff *skb; + struct ath_buf *bf; + int ret; + + skb = skb_peek(&rx_edma->rx_fifo); + if (!skb) + return false; + + bf = SKB_CB_ATHBUF(skb); + BUG_ON(!bf); + + dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, + common->rx_bufsize, DMA_FROM_DEVICE); + + ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data); + if (ret == -EINPROGRESS) + return false; + + __skb_unlink(skb, &rx_edma->rx_fifo); + if (ret == -EINVAL) { + /* corrupt descriptor, skip this one and the following one */ + list_add_tail(&bf->list, &sc->rx.rxbuf); + ath_rx_edma_buf_link(sc, qtype); + skb = skb_peek(&rx_edma->rx_fifo); + if (!skb) + return true; + + bf = SKB_CB_ATHBUF(skb); + BUG_ON(!bf); + + __skb_unlink(skb, &rx_edma->rx_fifo); + list_add_tail(&bf->list, &sc->rx.rxbuf); + ath_rx_edma_buf_link(sc, qtype); + return true; + } + skb_queue_tail(&rx_edma->rx_buffers, skb); + + return true; +} +static struct ath_buf *ath_edma_get_next_rx_buf(struct ath_softc *sc, + struct ath_rx_status *rs, + enum ath9k_rx_qtype qtype) +{ + struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype]; + struct sk_buff *skb; struct ath_buf *bf; + + while (ath_edma_get_buffers(sc, qtype)); + skb = __skb_dequeue(&rx_edma->rx_buffers); + if (!skb) + return NULL; + + bf = SKB_CB_ATHBUF(skb); + ath9k_hw_process_rxdesc_edma(sc->sc_ah, rs, skb->data); + return bf; +} + +static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, + struct ath_rx_status *rs) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_desc *ds; - struct ath_rx_status *rx_stats; + struct ath_buf *bf; + int ret; + + if (list_empty(&sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; + return NULL; + } + + bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); + ds = bf->bf_desc; + + /* + * Must provide the virtual address of the current + * descriptor, the physical address, and the virtual + * address of the next descriptor in the h/w chain. + * This allows the HAL to look ahead to see if the + * hardware is done with a descriptor by checking the + * done bit in the following descriptor and the address + * of the current descriptor the DMA engine is working + * on. All this is necessary because of our use of + * a self-linked list to avoid rx overruns. + */ + ret = ath9k_hw_rxprocdesc(ah, ds, rs, 0); + if (ret == -EINPROGRESS) { + struct ath_rx_status trs; + struct ath_buf *tbf; + struct ath_desc *tds; + + memset(&trs, 0, sizeof(trs)); + if (list_is_last(&bf->list, &sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; + return NULL; + } + + tbf = list_entry(bf->list.next, struct ath_buf, list); + + /* + * On some hardware the descriptor status words could + * get corrupted, including the done bit. Because of + * this, check if the next descriptor's done bit is + * set or not. + * + * If the next descriptor's done bit is set, the current + * descriptor has been corrupted. Force s/w to discard + * this descriptor and continue... + */ + + tds = tbf->bf_desc; + ret = ath9k_hw_rxprocdesc(ah, tds, &trs, 0); + if (ret == -EINPROGRESS) + return NULL; + } + + if (!bf->bf_mpdu) + return bf; + + /* + * Synchronize the DMA transfer with CPU before + * 1. accessing the frame + * 2. requeueing the same buffer to h/w + */ + dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, + common->rx_bufsize, + DMA_FROM_DEVICE); + + return bf; +} + + +int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) +{ + struct ath_buf *bf; struct sk_buff *skb = NULL, *requeue_skb; struct ieee80211_rx_status *rxs; struct ath_hw *ah = sc->sc_ah; @@ -491,7 +832,17 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ieee80211_hdr *hdr; int retval; bool decrypt_error = false; + struct ath_rx_status rs; + enum ath9k_rx_qtype qtype; + bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); + int dma_type; + if (edma) + dma_type = DMA_FROM_DEVICE; + else + dma_type = DMA_BIDIRECTIONAL; + + qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP; spin_lock_bh(&sc->rx.rxbuflock); do { @@ -499,79 +850,25 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) break; - if (list_empty(&sc->rx.rxbuf)) { - sc->rx.rxlink = NULL; - break; - } - - bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); - ds = bf->bf_desc; - - /* - * Must provide the virtual address of the current - * descriptor, the physical address, and the virtual - * address of the next descriptor in the h/w chain. - * This allows the HAL to look ahead to see if the - * hardware is done with a descriptor by checking the - * done bit in the following descriptor and the address - * of the current descriptor the DMA engine is working - * on. All this is necessary because of our use of - * a self-linked list to avoid rx overruns. - */ - retval = ath9k_hw_rxprocdesc(ah, ds, - bf->bf_daddr, - PA2DESC(sc, ds->ds_link), - 0); - if (retval == -EINPROGRESS) { - struct ath_buf *tbf; - struct ath_desc *tds; - - if (list_is_last(&bf->list, &sc->rx.rxbuf)) { - sc->rx.rxlink = NULL; - break; - } + memset(&rs, 0, sizeof(rs)); + if (edma) + bf = ath_edma_get_next_rx_buf(sc, &rs, qtype); + else + bf = ath_get_next_rx_buf(sc, &rs); - tbf = list_entry(bf->list.next, struct ath_buf, list); - - /* - * On some hardware the descriptor status words could - * get corrupted, including the done bit. Because of - * this, check if the next descriptor's done bit is - * set or not. - * - * If the next descriptor's done bit is set, the current - * descriptor has been corrupted. Force s/w to discard - * this descriptor and continue... - */ - - tds = tbf->bf_desc; - retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr, - PA2DESC(sc, tds->ds_link), 0); - if (retval == -EINPROGRESS) { - break; - } - } + if (!bf) + break; skb = bf->bf_mpdu; if (!skb) continue; - /* - * Synchronize the DMA transfer with CPU before - * 1. accessing the frame - * 2. requeueing the same buffer to h/w - */ - dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr, - 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; - ath_debug_stat_rx(sc, bf); + ath_debug_stat_rx(sc, &rs); /* * If we're asked to flush receive queue, directly @@ -580,7 +877,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) if (flush) goto requeue; - retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, rx_stats, + retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, &rs, rxs, &decrypt_error); if (retval) goto requeue; @@ -599,18 +896,20 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) /* Unmap the frame */ dma_unmap_single(sc->dev, bf->bf_buf_addr, common->rx_bufsize, - DMA_FROM_DEVICE); + dma_type); - skb_put(skb, rx_stats->rs_datalen); + skb_put(skb, rs.rs_datalen + ah->caps.rx_status_len); + if (ah->caps.rx_status_len) + skb_pull(skb, ah->caps.rx_status_len); - ath9k_cmn_rx_skb_postprocess(common, skb, rx_stats, + ath9k_cmn_rx_skb_postprocess(common, skb, &rs, 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, common->rx_bufsize, - DMA_FROM_DEVICE); + dma_type); if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(requeue_skb); @@ -626,9 +925,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * change the default rx antenna if rx diversity chooses the * other antenna 3 times in a row. */ - if (sc->rx.defant != ds->ds_rxstat.rs_antenna) { + if (sc->rx.defant != rs.rs_antenna) { if (++sc->rx.rxotherant >= 3) - ath_setdefantenna(sc, rx_stats->rs_antenna); + ath_setdefantenna(sc, rs.rs_antenna); } else { sc->rx.rxotherant = 0; } @@ -641,12 +940,16 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) ath_rx_send_to_mac80211(hw, sc, skb, rxs); requeue: - list_move_tail(&bf->list, &sc->rx.rxbuf); - ath_rx_buf_link(sc, bf); + if (edma) { + list_add_tail(&bf->list, &sc->rx.rxbuf); + ath_rx_edma_buf_link(sc, qtype); + } else { + list_move_tail(&bf->list, &sc->rx.rxbuf); + ath_rx_buf_link(sc, bf); + } } while (1); spin_unlock_bh(&sc->rx.rxbuflock); return 0; -#undef PA2DESC } diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 72cfa8ebd9a..d4371a43bda 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -20,7 +20,7 @@ #include "../reg.h" #define AR_CR 0x0008 -#define AR_CR_RXE 0x00000004 +#define AR_CR_RXE (AR_SREV_9300_20_OR_LATER(ah) ? 0x0000000c : 0x00000004) #define AR_CR_RXD 0x00000020 #define AR_CR_SWI 0x00000040 @@ -39,6 +39,12 @@ #define AR_CFG_PCI_MASTER_REQ_Q_THRESH 0x00060000 #define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17 +#define AR_RXBP_THRESH 0x0018 +#define AR_RXBP_THRESH_HP 0x0000000f +#define AR_RXBP_THRESH_HP_S 0 +#define AR_RXBP_THRESH_LP 0x00003f00 +#define AR_RXBP_THRESH_LP_S 8 + #define AR_MIRT 0x0020 #define AR_MIRT_VAL 0x0000ffff #define AR_MIRT_VAL_S 16 @@ -144,6 +150,9 @@ #define AR_MACMISC_MISC_OBS_BUS_MSB_S 15 #define AR_MACMISC_MISC_OBS_BUS_1 1 +#define AR_DATABUF_SIZE 0x0060 +#define AR_DATABUF_SIZE_MASK 0x00000FFF + #define AR_GTXTO 0x0064 #define AR_GTXTO_TIMEOUT_COUNTER 0x0000FFFF #define AR_GTXTO_TIMEOUT_LIMIT 0xFFFF0000 @@ -160,9 +169,14 @@ #define AR_CST_TIMEOUT_LIMIT 0xFFFF0000 #define AR_CST_TIMEOUT_LIMIT_S 16 +#define AR_HP_RXDP 0x0074 +#define AR_LP_RXDP 0x0078 + #define AR_ISR 0x0080 #define AR_ISR_RXOK 0x00000001 #define AR_ISR_RXDESC 0x00000002 +#define AR_ISR_HP_RXOK 0x00000001 +#define AR_ISR_LP_RXOK 0x00000002 #define AR_ISR_RXERR 0x00000004 #define AR_ISR_RXNOPKT 0x00000008 #define AR_ISR_RXEOL 0x00000010 @@ -232,7 +246,6 @@ #define AR_ISR_S5_TIMER_THRESH 0x0007FE00 #define AR_ISR_S5_TIM_TIMER 0x00000010 #define AR_ISR_S5_DTIM_TIMER 0x00000020 -#define AR_ISR_S5_S 0x00d8 #define AR_IMR_S5 0x00b8 #define AR_IMR_S5_TIM_TIMER 0x00000010 #define AR_IMR_S5_DTIM_TIMER 0x00000020 @@ -240,7 +253,6 @@ #define AR_ISR_S5_GENTIMER_TRIG_S 0 #define AR_ISR_S5_GENTIMER_THRESH 0xFF800000 #define AR_ISR_S5_GENTIMER_THRESH_S 16 -#define AR_ISR_S5_S 0x00d8 #define AR_IMR_S5_GENTIMER_TRIG 0x0000FF80 #define AR_IMR_S5_GENTIMER_TRIG_S 0 #define AR_IMR_S5_GENTIMER_THRESH 0xFF800000 @@ -249,6 +261,8 @@ #define AR_IMR 0x00a0 #define AR_IMR_RXOK 0x00000001 #define AR_IMR_RXDESC 0x00000002 +#define AR_IMR_RXOK_HP 0x00000001 +#define AR_IMR_RXOK_LP 0x00000002 #define AR_IMR_RXERR 0x00000004 #define AR_IMR_RXNOPKT 0x00000008 #define AR_IMR_RXEOL 0x00000010 @@ -332,10 +346,10 @@ #define AR_ISR_S1_QCU_TXEOL 0x03FF0000 #define AR_ISR_S1_QCU_TXEOL_S 16 -#define AR_ISR_S2_S 0x00cc -#define AR_ISR_S3_S 0x00d0 -#define AR_ISR_S4_S 0x00d4 -#define AR_ISR_S5_S 0x00d8 +#define AR_ISR_S2_S (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d0 : 0x00cc) +#define AR_ISR_S3_S (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d4 : 0x00d0) +#define AR_ISR_S4_S (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d8 : 0x00d4) +#define AR_ISR_S5_S (AR_SREV_9300_20_OR_LATER(ah) ? 0x00dc : 0x00d8) #define AR_DMADBG_0 0x00e0 #define AR_DMADBG_1 0x00e4 #define AR_DMADBG_2 0x00e8 @@ -369,6 +383,9 @@ #define AR_Q9_TXDP 0x0824 #define AR_QTXDP(_i) (AR_Q0_TXDP + ((_i)<<2)) +#define AR_Q_STATUS_RING_START 0x830 +#define AR_Q_STATUS_RING_END 0x834 + #define AR_Q_TXE 0x0840 #define AR_Q_TXE_M 0x000003FF @@ -461,6 +478,10 @@ #define AR_Q_RDYTIMESHDN 0x0a40 #define AR_Q_RDYTIMESHDN_M 0x000003FF +/* MAC Descriptor CRC check */ +#define AR_Q_DESC_CRCCHK 0xa44 +/* Enable CRC check on the descriptor fetched from host */ +#define AR_Q_DESC_CRCCHK_EN 1 #define AR_NUM_DCU 10 #define AR_DCU_0 0x0001 @@ -679,7 +700,7 @@ #define AR_WA 0x4004 #define AR_WA_D3_L1_DISABLE (1 << 14) -#define AR9285_WA_DEFAULT 0x004a05cb +#define AR9285_WA_DEFAULT 0x004a050b #define AR9280_WA_DEFAULT 0x0040073b #define AR_WA_DEFAULT 0x0000073f @@ -759,6 +780,8 @@ #define AR_SREV_VERSION_9271 0x140 #define AR_SREV_REVISION_9271_10 0 #define AR_SREV_REVISION_9271_11 1 +#define AR_SREV_VERSION_9300 0x1c0 +#define AR_SREV_REVISION_9300_20 2 /* 2.0 and 2.1 */ #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -844,6 +867,19 @@ #define AR_SREV_9271_11(_ah) \ (AR_SREV_9271(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11)) +#define AR_SREV_9300(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300)) +#define AR_SREV_9300_20(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9300_20)) +#define AR_SREV_9300_20_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9300) || \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9300_20))) + +#define AR_SREV_9285E_20(_ah) \ + (AR_SREV_9285_12_OR_LATER(_ah) && \ + ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1)) #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 @@ -940,6 +976,8 @@ enum { #define AR928X_NUM_GPIO 10 #define AR9285_NUM_GPIO 12 #define AR9287_NUM_GPIO 11 +#define AR9271_NUM_GPIO 16 +#define AR9300_NUM_GPIO 17 #define AR_GPIO_IN_OUT 0x4048 #define AR_GPIO_IN_VAL 0x0FFFC000 @@ -950,19 +988,23 @@ enum { #define AR9285_GPIO_IN_VAL_S 12 #define AR9287_GPIO_IN_VAL 0x003FF800 #define AR9287_GPIO_IN_VAL_S 11 +#define AR9271_GPIO_IN_VAL 0xFFFF0000 +#define AR9271_GPIO_IN_VAL_S 16 +#define AR9300_GPIO_IN_VAL 0x0001FFFF +#define AR9300_GPIO_IN_VAL_S 0 -#define AR_GPIO_OE_OUT 0x404c +#define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c) #define AR_GPIO_OE_OUT_DRV 0x3 #define AR_GPIO_OE_OUT_DRV_NO 0x0 #define AR_GPIO_OE_OUT_DRV_LOW 0x1 #define AR_GPIO_OE_OUT_DRV_HI 0x2 #define AR_GPIO_OE_OUT_DRV_ALL 0x3 -#define AR_GPIO_INTR_POL 0x4050 -#define AR_GPIO_INTR_POL_VAL 0x00001FFF +#define AR_GPIO_INTR_POL (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050) +#define AR_GPIO_INTR_POL_VAL 0x0001FFFF #define AR_GPIO_INTR_POL_VAL_S 0 -#define AR_GPIO_INPUT_EN_VAL 0x4054 +#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054) #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF 0x00000004 #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S 2 #define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF 0x00000008 @@ -980,13 +1022,13 @@ enum { #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 #define AR_GPIO_JTAG_DISABLE 0x00020000 -#define AR_GPIO_INPUT_MUX1 0x4058 +#define AR_GPIO_INPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058) #define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8 -#define AR_GPIO_INPUT_MUX2 0x405c +#define AR_GPIO_INPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c) #define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f #define AR_GPIO_INPUT_MUX2_CLK25_S 0 #define AR_GPIO_INPUT_MUX2_RFSILENT 0x000000f0 @@ -994,13 +1036,13 @@ enum { #define AR_GPIO_INPUT_MUX2_RTC_RESET 0x00000f00 #define AR_GPIO_INPUT_MUX2_RTC_RESET_S 8 -#define AR_GPIO_OUTPUT_MUX1 0x4060 -#define AR_GPIO_OUTPUT_MUX2 0x4064 -#define AR_GPIO_OUTPUT_MUX3 0x4068 +#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060) +#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064) +#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068) -#define AR_INPUT_STATE 0x406c +#define AR_INPUT_STATE (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c) -#define AR_EEPROM_STATUS_DATA 0x407c +#define AR_EEPROM_STATUS_DATA (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c) #define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff #define AR_EEPROM_STATUS_DATA_VAL_S 0 #define AR_EEPROM_STATUS_DATA_BUSY 0x00010000 @@ -1008,13 +1050,24 @@ enum { #define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000 #define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000 -#define AR_OBS 0x4080 +#define AR_OBS (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080) -#define AR_GPIO_PDPU 0x4088 +#define AR_GPIO_PDPU (AR_SREV_9300_20_OR_LATER(ah) ? 0x4090 : 0x4088) -#define AR_PCIE_MSI 0x4094 +#define AR_PCIE_MSI (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094) #define AR_PCIE_MSI_ENABLE 0x00000001 +#define AR_INTR_PRIO_SYNC_ENABLE 0x40c4 +#define AR_INTR_PRIO_ASYNC_MASK 0x40c8 +#define AR_INTR_PRIO_SYNC_MASK 0x40cc +#define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4 + +#define AR_RTC_9300_PLL_DIV 0x000003ff +#define AR_RTC_9300_PLL_DIV_S 0 +#define AR_RTC_9300_PLL_REFDIV 0x00003C00 +#define AR_RTC_9300_PLL_REFDIV_S 10 +#define AR_RTC_9300_PLL_CLKSEL 0x0000C000 +#define AR_RTC_9300_PLL_CLKSEL_S 14 #define AR_RTC_9160_PLL_DIV 0x000003ff #define AR_RTC_9160_PLL_DIV_S 0 @@ -1032,6 +1085,16 @@ enum { #define AR_RTC_RC_COLD_RESET 0x00000004 #define AR_RTC_RC_WARM_RESET 0x00000008 +/* Crystal Control */ +#define AR_RTC_XTAL_CONTROL 0x7004 + +/* Reg Control 0 */ +#define AR_RTC_REG_CONTROL0 0x7008 + +/* Reg Control 1 */ +#define AR_RTC_REG_CONTROL1 0x700c +#define AR_RTC_REG_CONTROL1_SWREG_PROGRAM 0x00000001 + #define AR_RTC_PLL_CONTROL \ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0014) : 0x7014) @@ -1062,6 +1125,7 @@ enum { #define AR_RTC_SLEEP_CLK \ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0048) : 0x7048) #define AR_RTC_FORCE_DERIVED_CLK 0x2 +#define AR_RTC_FORCE_SWREG_PRD 0x00000004 #define AR_RTC_FORCE_WAKE \ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x004c) : 0x704c) @@ -1178,6 +1242,13 @@ enum { #define AR9285_AN_RF2G4_DB2_4 0x00003800 #define AR9285_AN_RF2G4_DB2_4_S 11 +#define AR9285_RF2G5 0x7830 +#define AR9285_RF2G5_IC50TX 0xfffff8ff +#define AR9285_RF2G5_IC50TX_SET 0x00000400 +#define AR9285_RF2G5_IC50TX_XE_SET 0x00000500 +#define AR9285_RF2G5_IC50TX_CLEAR 0x00000700 +#define AR9285_RF2G5_IC50TX_CLEAR_S 8 + /* AR9271 : 0x7828, 0x782c different setting from AR9285 */ #define AR9271_AN_RF2G3_OB_cck 0x001C0000 #define AR9271_AN_RF2G3_OB_cck_S 18 @@ -1519,7 +1590,7 @@ enum { #define AR_TSFOOR_THRESHOLD 0x813c #define AR_TSFOOR_THRESHOLD_VAL 0x0000FFFF -#define AR_PHY_ERR_EIFS_MASK 8144 +#define AR_PHY_ERR_EIFS_MASK 0x8144 #define AR_PHY_ERR_3 0x8168 #define AR_PHY_ERR_3_COUNT 0x00FFFFFF @@ -1585,24 +1656,26 @@ enum { #define AR_FIRST_NDP_TIMER 7 #define AR_NDP2_PERIOD 0x81a0 #define AR_NDP2_TIMER_MODE 0x81c0 -#define AR_NEXT_TBTT_TIMER 0x8200 -#define AR_NEXT_DMA_BEACON_ALERT 0x8204 -#define AR_NEXT_SWBA 0x8208 -#define AR_NEXT_CFP 0x8208 -#define AR_NEXT_HCF 0x820C -#define AR_NEXT_TIM 0x8210 -#define AR_NEXT_DTIM 0x8214 -#define AR_NEXT_QUIET_TIMER 0x8218 -#define AR_NEXT_NDP_TIMER 0x821C - -#define AR_BEACON_PERIOD 0x8220 -#define AR_DMA_BEACON_PERIOD 0x8224 -#define AR_SWBA_PERIOD 0x8228 -#define AR_HCF_PERIOD 0x822C -#define AR_TIM_PERIOD 0x8230 -#define AR_DTIM_PERIOD 0x8234 -#define AR_QUIET_PERIOD 0x8238 -#define AR_NDP_PERIOD 0x823C + +#define AR_GEN_TIMERS(_i) (0x8200 + ((_i) << 2)) +#define AR_NEXT_TBTT_TIMER AR_GEN_TIMERS(0) +#define AR_NEXT_DMA_BEACON_ALERT AR_GEN_TIMERS(1) +#define AR_NEXT_SWBA AR_GEN_TIMERS(2) +#define AR_NEXT_CFP AR_GEN_TIMERS(2) +#define AR_NEXT_HCF AR_GEN_TIMERS(3) +#define AR_NEXT_TIM AR_GEN_TIMERS(4) +#define AR_NEXT_DTIM AR_GEN_TIMERS(5) +#define AR_NEXT_QUIET_TIMER AR_GEN_TIMERS(6) +#define AR_NEXT_NDP_TIMER AR_GEN_TIMERS(7) + +#define AR_BEACON_PERIOD AR_GEN_TIMERS(8) +#define AR_DMA_BEACON_PERIOD AR_GEN_TIMERS(9) +#define AR_SWBA_PERIOD AR_GEN_TIMERS(10) +#define AR_HCF_PERIOD AR_GEN_TIMERS(11) +#define AR_TIM_PERIOD AR_GEN_TIMERS(12) +#define AR_DTIM_PERIOD AR_GEN_TIMERS(13) +#define AR_QUIET_PERIOD AR_GEN_TIMERS(14) +#define AR_NDP_PERIOD AR_GEN_TIMERS(15) #define AR_TIMER_MODE 0x8240 #define AR_TBTT_TIMER_EN 0x00000001 @@ -1716,4 +1789,32 @@ enum { #define AR9271_CORE_CLOCK 117 /* clock to 117Mhz */ #define AR9271_TARGET_BAUD_RATE 19200 /* 115200 */ +#define AR_AGG_WEP_ENABLE_FIX 0x00000008 /* This allows the use of AR_AGG_WEP_ENABLE */ +#define AR_ADHOC_MCAST_KEYID_ENABLE 0x00000040 /* This bit enables the Multicast search + * based on both MAC Address and Key ID. + * If bit is 0, then Multicast search is + * based on MAC address only. + * For Merlin and above only. + */ +#define AR_AGG_WEP_ENABLE 0x00020000 /* This field enables AGG_WEP feature, + * when it is enable, AGG_WEP would takes + * charge of the encryption interface of + * pcu_txsm. + */ + +#define AR9300_SM_BASE 0xa200 +#define AR9002_PHY_AGC_CONTROL 0x9860 +#define AR9003_PHY_AGC_CONTROL AR9300_SM_BASE + 0xc4 +#define AR_PHY_AGC_CONTROL (AR_SREV_9300_20_OR_LATER(ah) ? AR9003_PHY_AGC_CONTROL : AR9002_PHY_AGC_CONTROL) +#define AR_PHY_AGC_CONTROL_CAL 0x00000001 /* do internal calibration */ +#define AR_PHY_AGC_CONTROL_NF 0x00000002 /* do noise-floor calibration */ +#define AR_PHY_AGC_CONTROL_OFFSET_CAL 0x00000800 /* allow offset calibration */ +#define AR_PHY_AGC_CONTROL_ENABLE_NF 0x00008000 /* enable noise floor calibration to happen */ +#define AR_PHY_AGC_CONTROL_FLTR_CAL 0x00010000 /* allow tx filter calibration */ +#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000 /* don't update noise floor automatically */ +#define AR_PHY_AGC_CONTROL_EXT_NF_PWR_MEAS 0x00040000 /* extend noise floor power measurement */ +#define AR_PHY_AGC_CONTROL_CLC_SUCCESS 0x00080000 /* carrier leak calibration done */ +#define AR_PHY_AGC_CONTROL_YCOK_MAX 0x000003c0 +#define AR_PHY_AGC_CONTROL_YCOK_MAX_S 6 + #endif diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index 00c0e21a4af..105ad40968f 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -220,7 +220,7 @@ static int ath9k_send_nullfunc(struct ath_wiphy *aphy, memset(&txctl, 0, sizeof(struct ath_tx_control)); txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]]; - txctl.frame_type = ps ? ATH9K_INT_PAUSE : ATH9K_INT_UNPAUSE; + txctl.frame_type = ps ? ATH9K_IFT_PAUSE : ATH9K_IFT_UNPAUSE; if (ath_tx_start(aphy->hw, skb, &txctl) != 0) goto exit; diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c new file mode 100644 index 00000000000..e23172c9caa --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2010 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 "htc.h" + +static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) +{ + switch (wmi_cmd) { + case WMI_ECHO_CMDID: + return "WMI_ECHO_CMDID"; + case WMI_ACCESS_MEMORY_CMDID: + return "WMI_ACCESS_MEMORY_CMDID"; + case WMI_DISABLE_INTR_CMDID: + return "WMI_DISABLE_INTR_CMDID"; + case WMI_ENABLE_INTR_CMDID: + return "WMI_ENABLE_INTR_CMDID"; + case WMI_RX_LINK_CMDID: + return "WMI_RX_LINK_CMDID"; + case WMI_ATH_INIT_CMDID: + return "WMI_ATH_INIT_CMDID"; + case WMI_ABORT_TXQ_CMDID: + return "WMI_ABORT_TXQ_CMDID"; + case WMI_STOP_TX_DMA_CMDID: + return "WMI_STOP_TX_DMA_CMDID"; + case WMI_STOP_DMA_RECV_CMDID: + return "WMI_STOP_DMA_RECV_CMDID"; + case WMI_ABORT_TX_DMA_CMDID: + return "WMI_ABORT_TX_DMA_CMDID"; + case WMI_DRAIN_TXQ_CMDID: + return "WMI_DRAIN_TXQ_CMDID"; + case WMI_DRAIN_TXQ_ALL_CMDID: + return "WMI_DRAIN_TXQ_ALL_CMDID"; + case WMI_START_RECV_CMDID: + return "WMI_START_RECV_CMDID"; + case WMI_STOP_RECV_CMDID: + return "WMI_STOP_RECV_CMDID"; + case WMI_FLUSH_RECV_CMDID: + return "WMI_FLUSH_RECV_CMDID"; + case WMI_SET_MODE_CMDID: + return "WMI_SET_MODE_CMDID"; + case WMI_RESET_CMDID: + return "WMI_RESET_CMDID"; + case WMI_NODE_CREATE_CMDID: + return "WMI_NODE_CREATE_CMDID"; + case WMI_NODE_REMOVE_CMDID: + return "WMI_NODE_REMOVE_CMDID"; + case WMI_VAP_REMOVE_CMDID: + return "WMI_VAP_REMOVE_CMDID"; + case WMI_VAP_CREATE_CMDID: + return "WMI_VAP_CREATE_CMDID"; + case WMI_BEACON_UPDATE_CMDID: + return "WMI_BEACON_UPDATE_CMDID"; + case WMI_REG_READ_CMDID: + return "WMI_REG_READ_CMDID"; + case WMI_REG_WRITE_CMDID: + return "WMI_REG_WRITE_CMDID"; + case WMI_RC_STATE_CHANGE_CMDID: + return "WMI_RC_STATE_CHANGE_CMDID"; + case WMI_RC_RATE_UPDATE_CMDID: + return "WMI_RC_RATE_UPDATE_CMDID"; + case WMI_DEBUG_INFO_CMDID: + return "WMI_DEBUG_INFO_CMDID"; + case WMI_HOST_ATTACH: + return "WMI_HOST_ATTACH"; + case WMI_TARGET_IC_UPDATE_CMDID: + return "WMI_TARGET_IC_UPDATE_CMDID"; + case WMI_TGT_STATS_CMDID: + return "WMI_TGT_STATS_CMDID"; + case WMI_TX_AGGR_ENABLE_CMDID: + return "WMI_TX_AGGR_ENABLE_CMDID"; + case WMI_TGT_DETACH_CMDID: + return "WMI_TGT_DETACH_CMDID"; + case WMI_TGT_TXQ_ENABLE_CMDID: + return "WMI_TGT_TXQ_ENABLE_CMDID"; + } + + return "Bogus"; +} + +struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv) +{ + struct wmi *wmi; + + wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL); + if (!wmi) + return NULL; + + wmi->drv_priv = priv; + wmi->stopped = false; + mutex_init(&wmi->op_mutex); + mutex_init(&wmi->multi_write_mutex); + init_completion(&wmi->cmd_wait); + + return wmi; +} + +void ath9k_deinit_wmi(struct ath9k_htc_priv *priv) +{ + struct wmi *wmi = priv->wmi; + + mutex_lock(&wmi->op_mutex); + wmi->stopped = true; + mutex_unlock(&wmi->op_mutex); + + kfree(priv->wmi); +} + +void ath9k_wmi_tasklet(unsigned long data) +{ + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct wmi_cmd_hdr *hdr; + struct wmi_swba *swba_hdr; + enum wmi_event_id event; + struct sk_buff *skb; + void *wmi_event; + unsigned long flags; +#ifdef CONFIG_ATH9K_HTC_DEBUGFS + __be32 txrate; +#endif + + spin_lock_irqsave(&priv->wmi->wmi_lock, flags); + skb = priv->wmi->wmi_skb; + spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); + + hdr = (struct wmi_cmd_hdr *) skb->data; + event = be16_to_cpu(hdr->command_id); + wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); + + ath_print(common, ATH_DBG_WMI, + "WMI Event: 0x%x\n", event); + + switch (event) { + case WMI_TGT_RDY_EVENTID: + break; + case WMI_SWBA_EVENTID: + swba_hdr = (struct wmi_swba *) wmi_event; + ath9k_htc_swba(priv, swba_hdr->beacon_pending); + break; + case WMI_FATAL_EVENTID: + break; + case WMI_TXTO_EVENTID: + break; + case WMI_BMISS_EVENTID: + break; + case WMI_WLAN_TXCOMP_EVENTID: + break; + case WMI_DELBA_EVENTID: + break; + case WMI_TXRATE_EVENTID: +#ifdef CONFIG_ATH9K_HTC_DEBUGFS + txrate = ((struct wmi_event_txrate *)wmi_event)->txrate; + priv->debug.txrate = be32_to_cpu(txrate); +#endif + break; + default: + break; + } + + kfree_skb(skb); +} + +static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb) +{ + skb_pull(skb, sizeof(struct wmi_cmd_hdr)); + + if (wmi->cmd_rsp_buf != NULL && wmi->cmd_rsp_len != 0) + memcpy(wmi->cmd_rsp_buf, skb->data, wmi->cmd_rsp_len); + + complete(&wmi->cmd_wait); +} + +static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, + enum htc_endpoint_id epid) +{ + struct wmi *wmi = (struct wmi *) priv; + struct wmi_cmd_hdr *hdr; + u16 cmd_id; + + if (unlikely(wmi->stopped)) + goto free_skb; + + hdr = (struct wmi_cmd_hdr *) skb->data; + cmd_id = be16_to_cpu(hdr->command_id); + + if (cmd_id & 0x1000) { + spin_lock(&wmi->wmi_lock); + wmi->wmi_skb = skb; + spin_unlock(&wmi->wmi_lock); + tasklet_schedule(&wmi->drv_priv->wmi_tasklet); + return; + } + + /* Check if there has been a timeout. */ + spin_lock(&wmi->wmi_lock); + if (cmd_id != wmi->last_cmd_id) { + spin_unlock(&wmi->wmi_lock); + goto free_skb; + } + spin_unlock(&wmi->wmi_lock); + + /* WMI command response */ + ath9k_wmi_rsp_callback(wmi, skb); + +free_skb: + kfree_skb(skb); +} + +static void ath9k_wmi_ctrl_tx(void *priv, struct sk_buff *skb, + enum htc_endpoint_id epid, bool txok) +{ + kfree_skb(skb); +} + +int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi, + enum htc_endpoint_id *wmi_ctrl_epid) +{ + struct htc_service_connreq connect; + int ret; + + wmi->htc = htc; + + memset(&connect, 0, sizeof(connect)); + + connect.ep_callbacks.priv = wmi; + connect.ep_callbacks.tx = ath9k_wmi_ctrl_tx; + connect.ep_callbacks.rx = ath9k_wmi_ctrl_rx; + connect.service_id = WMI_CONTROL_SVC; + + ret = htc_connect_service(htc, &connect, &wmi->ctrl_epid); + if (ret) + return ret; + + *wmi_ctrl_epid = wmi->ctrl_epid; + + return 0; +} + +static int ath9k_wmi_cmd_issue(struct wmi *wmi, + struct sk_buff *skb, + enum wmi_cmd_id cmd, u16 len) +{ + struct wmi_cmd_hdr *hdr; + + hdr = (struct wmi_cmd_hdr *) skb_push(skb, sizeof(struct wmi_cmd_hdr)); + hdr->command_id = cpu_to_be16(cmd); + hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); + + return htc_send(wmi->htc, skb, wmi->ctrl_epid, NULL); +} + +int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, + u8 *cmd_buf, u32 cmd_len, + u8 *rsp_buf, u32 rsp_len, + u32 timeout) +{ + struct ath_hw *ah = wmi->drv_priv->ah; + struct ath_common *common = ath9k_hw_common(ah); + u16 headroom = sizeof(struct htc_frame_hdr) + + sizeof(struct wmi_cmd_hdr); + struct sk_buff *skb; + u8 *data; + int time_left, ret = 0; + unsigned long flags; + + if (wmi->drv_priv->op_flags & OP_UNPLUGGED) + return 0; + + if (!wmi) + return -EINVAL; + + skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, headroom); + + if (cmd_len != 0 && cmd_buf != NULL) { + data = (u8 *) skb_put(skb, cmd_len); + memcpy(data, cmd_buf, cmd_len); + } + + mutex_lock(&wmi->op_mutex); + + /* check if wmi stopped flag is set */ + if (unlikely(wmi->stopped)) { + ret = -EPROTO; + goto out; + } + + /* record the rsp buffer and length */ + wmi->cmd_rsp_buf = rsp_buf; + wmi->cmd_rsp_len = rsp_len; + + spin_lock_irqsave(&wmi->wmi_lock, flags); + wmi->last_cmd_id = cmd_id; + spin_unlock_irqrestore(&wmi->wmi_lock, flags); + + ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len); + if (ret) + goto out; + + time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout); + if (!time_left) { + ath_print(common, ATH_DBG_WMI, + "Timeout waiting for WMI command: %s\n", + wmi_cmd_to_name(cmd_id)); + mutex_unlock(&wmi->op_mutex); + return -ETIMEDOUT; + } + + mutex_unlock(&wmi->op_mutex); + + return 0; + +out: + ath_print(common, ATH_DBG_WMI, + "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id)); + mutex_unlock(&wmi->op_mutex); + kfree_skb(skb); + + return ret; +} diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h new file mode 100644 index 00000000000..765db5faa2d --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2010 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. + */ + +#ifndef WMI_H +#define WMI_H + + +struct wmi_event_txrate { + __be32 txrate; + struct { + u8 rssi_thresh; + u8 per; + } rc_stats; +} __packed; + +struct wmi_cmd_hdr { + __be16 command_id; + __be16 seq_no; +} __packed; + +struct wmi_swba { + u8 beacon_pending; +} __packed; + +enum wmi_cmd_id { + WMI_ECHO_CMDID = 0x0001, + WMI_ACCESS_MEMORY_CMDID, + + /* Commands to Target */ + WMI_DISABLE_INTR_CMDID, + WMI_ENABLE_INTR_CMDID, + WMI_RX_LINK_CMDID, + WMI_ATH_INIT_CMDID, + WMI_ABORT_TXQ_CMDID, + WMI_STOP_TX_DMA_CMDID, + WMI_STOP_DMA_RECV_CMDID, + WMI_ABORT_TX_DMA_CMDID, + WMI_DRAIN_TXQ_CMDID, + WMI_DRAIN_TXQ_ALL_CMDID, + WMI_START_RECV_CMDID, + WMI_STOP_RECV_CMDID, + WMI_FLUSH_RECV_CMDID, + WMI_SET_MODE_CMDID, + WMI_RESET_CMDID, + WMI_NODE_CREATE_CMDID, + WMI_NODE_REMOVE_CMDID, + WMI_VAP_REMOVE_CMDID, + WMI_VAP_CREATE_CMDID, + WMI_BEACON_UPDATE_CMDID, + WMI_REG_READ_CMDID, + WMI_REG_WRITE_CMDID, + WMI_RC_STATE_CHANGE_CMDID, + WMI_RC_RATE_UPDATE_CMDID, + WMI_DEBUG_INFO_CMDID, + WMI_HOST_ATTACH, + WMI_TARGET_IC_UPDATE_CMDID, + WMI_TGT_STATS_CMDID, + WMI_TX_AGGR_ENABLE_CMDID, + WMI_TGT_DETACH_CMDID, + WMI_TGT_TXQ_ENABLE_CMDID, +}; + +enum wmi_event_id { + WMI_TGT_RDY_EVENTID = 0x1001, + WMI_SWBA_EVENTID, + WMI_FATAL_EVENTID, + WMI_TXTO_EVENTID, + WMI_BMISS_EVENTID, + WMI_WLAN_TXCOMP_EVENTID, + WMI_DELBA_EVENTID, + WMI_TXRATE_EVENTID, +}; + +#define MAX_CMD_NUMBER 62 + +struct register_write { + __be32 reg; + __be32 val; +}; + +struct wmi { + struct ath9k_htc_priv *drv_priv; + struct htc_target *htc; + enum htc_endpoint_id ctrl_epid; + struct mutex op_mutex; + struct completion cmd_wait; + enum wmi_cmd_id last_cmd_id; + u16 tx_seq_id; + u8 *cmd_rsp_buf; + u32 cmd_rsp_len; + bool stopped; + + struct sk_buff *wmi_skb; + spinlock_t wmi_lock; + + atomic_t mwrite_cnt; + struct register_write multi_write[MAX_CMD_NUMBER]; + u32 multi_write_idx; + struct mutex multi_write_mutex; +}; + +struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv); +void ath9k_deinit_wmi(struct ath9k_htc_priv *priv); +int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi, + enum htc_endpoint_id *wmi_ctrl_epid); +int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, + u8 *cmd_buf, u32 cmd_len, + u8 *rsp_buf, u32 rsp_len, + u32 timeout); +void ath9k_wmi_tasklet(unsigned long data); + +#define WMI_CMD(_wmi_cmd) \ + do { \ + ret = ath9k_wmi_cmd(priv->wmi, _wmi_cmd, NULL, 0, \ + (u8 *) &cmd_rsp, \ + sizeof(cmd_rsp), HZ*2); \ + } while (0) + +#define WMI_CMD_BUF(_wmi_cmd, _buf) \ + do { \ + ret = ath9k_wmi_cmd(priv->wmi, _wmi_cmd, \ + (u8 *) _buf, sizeof(*_buf), \ + &cmd_rsp, sizeof(cmd_rsp), HZ*2); \ + } while (0) + +#endif /* WMI_H */ diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 294b486bc3e..3db19172b43 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -15,10 +15,11 @@ */ #include "ath9k.h" +#include "ar9003_mac.h" #define BITS_PER_BYTE 8 #define OFDM_PLCP_BITS 22 -#define HT_RC_2_MCS(_rc) ((_rc) & 0x0f) +#define HT_RC_2_MCS(_rc) ((_rc) & 0x1f) #define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) #define L_STF 8 #define L_LTF 8 @@ -33,7 +34,7 @@ #define OFDM_SIFS_TIME 16 -static u32 bits_per_symbol[][2] = { +static u16 bits_per_symbol[][2] = { /* 20MHz 40MHz */ { 26, 54 }, /* 0: BPSK */ { 52, 108 }, /* 1: QPSK 1/2 */ @@ -43,14 +44,6 @@ static u32 bits_per_symbol[][2] = { { 208, 432 }, /* 5: 64-QAM 2/3 */ { 234, 486 }, /* 6: 64-QAM 3/4 */ { 260, 540 }, /* 7: 64-QAM 5/6 */ - { 52, 108 }, /* 8: BPSK */ - { 104, 216 }, /* 9: QPSK 1/2 */ - { 156, 324 }, /* 10: QPSK 3/4 */ - { 208, 432 }, /* 11: 16-QAM 1/2 */ - { 312, 648 }, /* 12: 16-QAM 3/4 */ - { 416, 864 }, /* 13: 64-QAM 2/3 */ - { 468, 972 }, /* 14: 64-QAM 3/4 */ - { 520, 1080 }, /* 15: 64-QAM 5/6 */ }; #define IS_HT_RATE(_rate) ((_rate) & 0x80) @@ -59,40 +52,50 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_head); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, - struct ath_txq *txq, - struct list_head *bf_q, - int txok, int sendbar); + struct ath_txq *txq, struct list_head *bf_q, + struct ath_tx_status *ts, int txok, int sendbar); static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, struct list_head *head); static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf); static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, - int txok); -static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, + struct ath_tx_status *ts, int txok); +static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, int nbad, int txok, bool update_rc); enum { - MCS_DEFAULT, + MCS_HT20, + MCS_HT20_SGI, MCS_HT40, MCS_HT40_SGI, }; -static int ath_max_4ms_framelen[3][16] = { - [MCS_DEFAULT] = { - 3216, 6434, 9650, 12868, 19304, 25740, 28956, 32180, - 6430, 12860, 19300, 25736, 38600, 51472, 57890, 64320, +static int ath_max_4ms_framelen[4][32] = { + [MCS_HT20] = { + 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172, + 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280, + 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532, + 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532, + }, + [MCS_HT20_SGI] = { + 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744, + 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532, + 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532, + 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532, }, [MCS_HT40] = { - 6684, 13368, 20052, 26738, 40104, 53476, 60156, 66840, - 13360, 26720, 40080, 53440, 80160, 106880, 120240, 133600, + 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532, + 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532, + 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532, + 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532, }, [MCS_HT40_SGI] = { - /* TODO: Only MCS 7 and 15 updated, recalculate the rest */ - 6684, 13368, 20052, 26738, 40104, 53476, 60156, 74200, - 13360, 26720, 40080, 53440, 80160, 106880, 120240, 148400, + 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532, + 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532, + 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532, + 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532, } }; - /*********************/ /* Aggregation logic */ /*********************/ @@ -223,6 +226,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, { struct ath_buf *bf; struct list_head bf_head; + struct ath_tx_status ts; + + memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); for (;;) { @@ -236,7 +242,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, ath_tx_update_baw(sc, tid, bf->bf_seqno); spin_unlock(&txq->axq_lock); - ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); spin_lock(&txq->axq_lock); } @@ -259,25 +265,46 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); } -static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) +static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) { - struct ath_buf *tbf; + struct ath_buf *bf = NULL; spin_lock_bh(&sc->tx.txbuflock); - if (WARN_ON(list_empty(&sc->tx.txbuf))) { + + if (unlikely(list_empty(&sc->tx.txbuf))) { spin_unlock_bh(&sc->tx.txbuflock); return NULL; } - tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); - list_del(&tbf->list); + + bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); + list_del(&bf->list); + spin_unlock_bh(&sc->tx.txbuflock); + return bf; +} + +static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf) +{ + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); +} + +static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) +{ + struct ath_buf *tbf; + + tbf = ath_tx_get_buffer(sc); + if (WARN_ON(!tbf)) + return NULL; + ATH_TXBUF_RESET(tbf); tbf->aphy = bf->aphy; tbf->bf_mpdu = bf->bf_mpdu; tbf->bf_buf_addr = bf->bf_buf_addr; - *(tbf->bf_desc) = *(bf->bf_desc); + memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len); tbf->bf_state = bf->bf_state; tbf->bf_dmacontext = bf->bf_dmacontext; @@ -286,7 +313,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf, struct list_head *bf_q, - int txok) + struct ath_tx_status *ts, int txok) { struct ath_node *an = NULL; struct sk_buff *skb; @@ -296,7 +323,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ieee80211_tx_info *tx_info; struct ath_atx_tid *tid = NULL; struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; - struct ath_desc *ds = bf_last->bf_desc; struct list_head bf_head, bf_pending; u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; @@ -325,10 +351,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, memset(ba, 0, WME_BA_BMP_SIZE >> 3); if (isaggr && txok) { - if (ATH_DS_TX_BA(ds)) { - seq_st = ATH_DS_BA_SEQ(ds); - memcpy(ba, ATH_DS_BA_BITMAP(ds), - WME_BA_BMP_SIZE >> 3); + if (ts->ts_flags & ATH9K_TX_BA) { + seq_st = ts->ts_seqnum; + memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); } else { /* * AR5416 can become deaf/mute when BA @@ -345,7 +370,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&bf_pending); INIT_LIST_HEAD(&bf_head); - nbad = ath_tx_num_badfrms(sc, bf, txok); + nbad = ath_tx_num_badfrms(sc, bf, ts, txok); while (bf) { txfail = txpending = 0; bf_next = bf->bf_next; @@ -359,7 +384,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, acked_cnt++; } else { if (!(tid->state & AGGR_CLEANUP) && - ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { + !bf_last->bf_tx_aborted) { if (bf->bf_retries < ATH_MAX_SW_RETRIES) { ath_tx_set_retry(sc, txq, bf); txpending = 1; @@ -378,7 +403,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } } - if (bf_next == NULL) { + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && + bf_next == NULL) { /* * Make sure the last desc is reclaimed if it * not a holding desc. @@ -402,45 +428,53 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, spin_unlock_bh(&txq->axq_lock); if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { - ath_tx_rc_status(bf, ds, nbad, txok, true); + ath_tx_rc_status(bf, ts, nbad, txok, true); rc_update = false; } else { - ath_tx_rc_status(bf, ds, nbad, txok, false); + ath_tx_rc_status(bf, ts, nbad, txok, false); } - ath_tx_complete_buf(sc, bf, txq, &bf_head, !txfail, sendbar); + ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, + !txfail, sendbar); } else { /* retry the un-acked ones */ - if (bf->bf_next == NULL && bf_last->bf_stale) { - struct ath_buf *tbf; - - tbf = ath_clone_txbuf(sc, bf_last); - /* - * Update tx baw and complete the frame with - * failed status if we run out of tx buf - */ - if (!tbf) { - spin_lock_bh(&txq->axq_lock); - ath_tx_update_baw(sc, tid, - bf->bf_seqno); - spin_unlock_bh(&txq->axq_lock); - - bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, ds, nbad, - 0, false); - ath_tx_complete_buf(sc, bf, txq, - &bf_head, 0, 0); - break; + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { + if (bf->bf_next == NULL && bf_last->bf_stale) { + struct ath_buf *tbf; + + tbf = ath_clone_txbuf(sc, bf_last); + /* + * Update tx baw and complete the + * frame with failed status if we + * run out of tx buf. + */ + if (!tbf) { + spin_lock_bh(&txq->axq_lock); + ath_tx_update_baw(sc, tid, + bf->bf_seqno); + spin_unlock_bh(&txq->axq_lock); + + bf->bf_state.bf_type |= + BUF_XRETRY; + ath_tx_rc_status(bf, ts, nbad, + 0, false); + ath_tx_complete_buf(sc, bf, txq, + &bf_head, + ts, 0, 0); + break; + } + + ath9k_hw_cleartxdesc(sc->sc_ah, + tbf->bf_desc); + list_add_tail(&tbf->list, &bf_head); + } else { + /* + * Clear descriptor status words for + * software retry + */ + ath9k_hw_cleartxdesc(sc->sc_ah, + bf->bf_desc); } - - ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc); - list_add_tail(&tbf->list, &bf_head); - } else { - /* - * Clear descriptor status words for - * software retry - */ - ath9k_hw_cleartxdesc(sc->sc_ah, bf->bf_desc); } /* @@ -508,12 +542,13 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, break; } - if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) - modeidx = MCS_HT40_SGI; - else if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) modeidx = MCS_HT40; else - modeidx = MCS_DEFAULT; + modeidx = MCS_HT20; + + if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) + modeidx++; frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx]; max_4ms_framelen = min(max_4ms_framelen, frmlen); @@ -558,7 +593,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, u32 nsymbits, nsymbols; u16 minlen; u8 flags, rix; - int width, half_gi, ndelim, mindelim; + int width, streams, half_gi, ndelim, mindelim; /* Select standard number of delimiters based on frame length alone */ ndelim = ATH_AGGR_GET_NDELIM(frmlen); @@ -598,7 +633,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, if (nsymbols == 0) nsymbols = 1; - nsymbits = bits_per_symbol[rix][width]; + streams = HT_RC_2_STREAMS(rix); + nsymbits = bits_per_symbol[rix % 8][width] * streams; minlen = (nsymbols * nsymbits) / BITS_PER_BYTE; if (frmlen < minlen) { @@ -664,7 +700,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, bpad = PADBYTES(al_delta) + (ndelim << 2); bf->bf_next = NULL; - bf->bf_desc->ds_link = 0; + ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0); /* link buffers of this frame to the aggregate */ ath_tx_addto_baw(sc, tid, bf); @@ -672,7 +708,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, list_move_tail(&bf->list, bf_q); if (bf_prev) { bf_prev->bf_next = bf; - bf_prev->bf_desc->ds_link = bf->bf_daddr; + ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc, + bf->bf_daddr); } bf_prev = bf; @@ -752,8 +789,11 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; + struct ath_tx_status ts; struct ath_buf *bf; struct list_head bf_head; + + memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); if (txtid->state & AGGR_CLEANUP) @@ -780,7 +820,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) } list_move_tail(&bf->list, &bf_head); ath_tx_update_baw(sc, txtid, bf->bf_seqno); - ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); } spin_unlock_bh(&txq->axq_lock); @@ -849,7 +889,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info qi; - int qnum; + int qnum, i; memset(&qi, 0, sizeof(qi)); qi.tqi_subtype = subtype; @@ -873,11 +913,16 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) * The UAPSD queue is an exception, since we take a desc- * based intr on the EOSP frames. */ - if (qtype == ATH9K_TX_QUEUE_UAPSD) - qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE; - else - qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | - TXQ_FLAG_TXDESCINT_ENABLE; + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE | + TXQ_FLAG_TXERRINT_ENABLE; + } else { + if (qtype == ATH9K_TX_QUEUE_UAPSD) + qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE; + else + qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | + TXQ_FLAG_TXDESCINT_ENABLE; + } qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi); if (qnum == -1) { /* @@ -904,6 +949,11 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_depth = 0; txq->axq_tx_inprogress = false; sc->tx.txqsetup |= 1<<qnum; + + txq->txq_headidx = txq->txq_tailidx = 0; + for (i = 0; i < ATH_TXFIFO_DEPTH; i++) + INIT_LIST_HEAD(&txq->txq_fifo[i]); + INIT_LIST_HEAD(&txq->txq_fifo_pending); } return &sc->tx.txq[qnum]; } @@ -1028,45 +1078,63 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) { struct ath_buf *bf, *lastbf; struct list_head bf_head; + struct ath_tx_status ts; + memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); for (;;) { spin_lock_bh(&txq->axq_lock); - if (list_empty(&txq->axq_q)) { - txq->axq_link = NULL; - spin_unlock_bh(&txq->axq_lock); - break; - } - - bf = list_first_entry(&txq->axq_q, struct ath_buf, list); + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { + txq->txq_headidx = txq->txq_tailidx = 0; + spin_unlock_bh(&txq->axq_lock); + break; + } else { + bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx], + struct ath_buf, list); + } + } else { + if (list_empty(&txq->axq_q)) { + txq->axq_link = NULL; + spin_unlock_bh(&txq->axq_lock); + break; + } + bf = list_first_entry(&txq->axq_q, struct ath_buf, + list); - if (bf->bf_stale) { - list_del(&bf->list); - spin_unlock_bh(&txq->axq_lock); + if (bf->bf_stale) { + list_del(&bf->list); + spin_unlock_bh(&txq->axq_lock); - spin_lock_bh(&sc->tx.txbuflock); - list_add_tail(&bf->list, &sc->tx.txbuf); - spin_unlock_bh(&sc->tx.txbuflock); - continue; + ath_tx_return_buffer(sc, bf); + continue; + } } lastbf = bf->bf_lastbf; if (!retry_tx) - lastbf->bf_desc->ds_txstat.ts_flags = - ATH9K_TX_SW_ABORTED; + lastbf->bf_tx_aborted = true; + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + list_cut_position(&bf_head, + &txq->txq_fifo[txq->txq_tailidx], + &lastbf->list); + INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH); + } else { + /* remove ath_buf's of the same mpdu from txq */ + list_cut_position(&bf_head, &txq->axq_q, &lastbf->list); + } - /* remove ath_buf's of the same mpdu from txq */ - list_cut_position(&bf_head, &txq->axq_q, &lastbf->list); txq->axq_depth--; spin_unlock_bh(&txq->axq_lock); if (bf_isampdu(bf)) - ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0); + ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0); else - ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); } spin_lock_bh(&txq->axq_lock); @@ -1081,6 +1149,27 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx) spin_unlock_bh(&txq->axq_lock); } } + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + spin_lock_bh(&txq->axq_lock); + while (!list_empty(&txq->txq_fifo_pending)) { + bf = list_first_entry(&txq->txq_fifo_pending, + struct ath_buf, list); + list_cut_position(&bf_head, + &txq->txq_fifo_pending, + &bf->bf_lastbf->list); + spin_unlock_bh(&txq->axq_lock); + + if (bf_isampdu(bf)) + ath_tx_complete_aggr(sc, txq, bf, &bf_head, + &ts, 0); + else + ath_tx_complete_buf(sc, bf, txq, &bf_head, + &ts, 0, 0); + spin_lock_bh(&txq->axq_lock); + } + spin_unlock_bh(&txq->axq_lock); + } } void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) @@ -1218,44 +1307,47 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, bf = list_first_entry(head, struct ath_buf, list); - list_splice_tail_init(head, &txq->axq_q); - txq->axq_depth++; - ath_print(common, ATH_DBG_QUEUE, "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); - if (txq->axq_link == NULL) { + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + if (txq->axq_depth >= ATH_TXFIFO_DEPTH) { + list_splice_tail_init(head, &txq->txq_fifo_pending); + return; + } + if (!list_empty(&txq->txq_fifo[txq->txq_headidx])) + ath_print(common, ATH_DBG_XMIT, + "Initializing tx fifo %d which " + "is non-empty\n", + txq->txq_headidx); + INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]); + list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]); + INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH); ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); ath_print(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n", txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); } else { - *txq->axq_link = bf->bf_daddr; - ath_print(common, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", - txq->axq_qnum, txq->axq_link, - ito64(bf->bf_daddr), bf->bf_desc); - } - txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link); - ath9k_hw_txstart(ah, txq->axq_qnum); -} + list_splice_tail_init(head, &txq->axq_q); -static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) -{ - struct ath_buf *bf = NULL; - - spin_lock_bh(&sc->tx.txbuflock); - - if (unlikely(list_empty(&sc->tx.txbuf))) { - spin_unlock_bh(&sc->tx.txbuflock); - return NULL; + if (txq->axq_link == NULL) { + ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); + ath_print(common, ATH_DBG_XMIT, + "TXDP[%u] = %llx (%p)\n", + txq->axq_qnum, ito64(bf->bf_daddr), + bf->bf_desc); + } else { + *txq->axq_link = bf->bf_daddr; + ath_print(common, ATH_DBG_XMIT, + "link[%u] (%p)=%llx (%p)\n", + txq->axq_qnum, txq->axq_link, + ito64(bf->bf_daddr), bf->bf_desc); + } + ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc, + &txq->axq_link); + ath9k_hw_txstart(ah, txq->axq_qnum); } - - bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); - list_del(&bf->list); - - spin_unlock_bh(&sc->tx.txbuflock); - - return bf; + txq->axq_depth++; } static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, @@ -1402,8 +1494,7 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb, INCR(tid->seq_next, IEEE80211_SEQ_MAX); } -static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, - struct ath_txq *txq) +static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); int flags = 0; @@ -1414,6 +1505,9 @@ static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) flags |= ATH9K_TXDESC_NOACK; + if (use_ldpc) + flags |= ATH9K_TXDESC_LDPC; + return flags; } @@ -1432,8 +1526,9 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; /* find number of symbols: PLCP + data */ + streams = HT_RC_2_STREAMS(rix); nbits = (pktlen << 3) + OFDM_PLCP_BITS; - nsymbits = bits_per_symbol[rix][width]; + nsymbits = bits_per_symbol[rix % 8][width] * streams; nsymbols = (nbits + nsymbits - 1) / nsymbits; if (!half_gi) @@ -1442,7 +1537,6 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, duration = SYMBOL_TIME_HALFGI(nsymbols); /* addup duration for legacy/ht training and signal fields */ - streams = HT_RC_2_STREAMS(rix); duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); return duration; @@ -1513,6 +1607,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) series[i].Rate = rix | 0x80; series[i].PktDuration = ath_pkt_duration(sc, rix, bf, is_40, is_sgi, is_sp); + if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) + series[i].RateFlags |= ATH9K_RATESERIES_STBC; continue; } @@ -1565,15 +1661,16 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, int hdrlen; __le16 fc; int padpos, padsize; + bool use_ldpc = false; tx_info->pad[0] = 0; switch (txctl->frame_type) { - case ATH9K_NOT_INTERNAL: + case ATH9K_IFT_NOT_INTERNAL: break; - case ATH9K_INT_PAUSE: + case ATH9K_IFT_PAUSE: tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE; /* fall through */ - case ATH9K_INT_UNPAUSE: + case ATH9K_IFT_UNPAUSE: tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL; break; } @@ -1591,10 +1688,13 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, bf->bf_frmlen -= padsize; } - if (conf_is_ht(&hw->conf)) + if (conf_is_ht(&hw->conf)) { bf->bf_state.bf_type |= BUF_HT; + if (tx_info->flags & IEEE80211_TX_CTL_LDPC) + use_ldpc = true; + } - bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); + bf->bf_flags = setup_tx_flags(skb, use_ldpc); bf->bf_keytype = get_hw_crypto_keytype(skb); if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { @@ -1653,8 +1753,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, list_add_tail(&bf->list, &bf_head); ds = bf->bf_desc; - ds->ds_link = 0; - ds->ds_data = bf->bf_buf_addr; + ath9k_hw_set_desc_link(ah, ds, 0); ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, bf->bf_keyix, bf->bf_keytype, bf->bf_flags); @@ -1663,7 +1762,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, skb->len, /* segment length */ true, /* first segment */ true, /* last segment */ - ds); /* first descriptor */ + ds, /* first descriptor */ + bf->bf_buf_addr, + txctl->txq->axq_qnum); spin_lock_bh(&txctl->txq->axq_lock); @@ -1732,9 +1833,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, } spin_unlock_bh(&txq->axq_lock); - spin_lock_bh(&sc->tx.txbuflock); - list_add_tail(&bf->list, &sc->tx.txbuf); - spin_unlock_bh(&sc->tx.txbuflock); + ath_tx_return_buffer(sc, bf); return r; } @@ -1852,9 +1951,8 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, } static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, - struct ath_txq *txq, - struct list_head *bf_q, - int txok, int sendbar) + struct ath_txq *txq, struct list_head *bf_q, + struct ath_tx_status *ts, int txok, int sendbar) { struct sk_buff *skb = bf->bf_mpdu; unsigned long flags; @@ -1872,7 +1970,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); ath_tx_complete(sc, skb, bf->aphy, tx_flags); - ath_debug_stat_tx(sc, txq, bf); + ath_debug_stat_tx(sc, txq, bf, ts); /* * Return the list of ath_buf of this mpdu to free queue @@ -1883,23 +1981,21 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, } static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, - int txok) + struct ath_tx_status *ts, int txok) { - struct ath_buf *bf_last = bf->bf_lastbf; - struct ath_desc *ds = bf_last->bf_desc; u16 seq_st = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; int ba_index; int nbad = 0; int isaggr = 0; - if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) + if (bf->bf_tx_aborted) return 0; isaggr = bf_isaggr(bf); if (isaggr) { - seq_st = ATH_DS_BA_SEQ(ds); - memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3); + seq_st = ts->ts_seqnum; + memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); } while (bf) { @@ -1913,7 +2009,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, return nbad; } -static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, +static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, int nbad, int txok, bool update_rc) { struct sk_buff *skb = bf->bf_mpdu; @@ -1923,24 +2019,24 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, u8 i, tx_rateindex; if (txok) - tx_info->status.ack_signal = ds->ds_txstat.ts_rssi; + tx_info->status.ack_signal = ts->ts_rssi; - tx_rateindex = ds->ds_txstat.ts_rateindex; + tx_rateindex = ts->ts_rateindex; WARN_ON(tx_rateindex >= hw->max_rates); - if (update_rc) - tx_info->pad[0] |= ATH_TX_INFO_UPDATE_RC; - if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) + if (ts->ts_status & ATH9K_TXERR_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) + tx_info->flags |= IEEE80211_TX_STAT_AMPDU; - if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && + if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { if (ieee80211_is_data(hdr->frame_control)) { - if (ds->ds_txstat.ts_flags & + if (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN)) tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN; - if ((ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) || - (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO)) + if ((ts->ts_status & ATH9K_TXERR_XRETRY) || + (ts->ts_status & ATH9K_TXERR_FIFO)) tx_info->pad[0] |= ATH_TX_INFO_XRETRY; tx_info->status.ampdu_len = bf->bf_nframes; tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad; @@ -1978,6 +2074,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) struct ath_buf *bf, *lastbf, *bf_held = NULL; struct list_head bf_head; struct ath_desc *ds; + struct ath_tx_status ts; int txok; int status; @@ -2017,7 +2114,8 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) lastbf = bf->bf_lastbf; ds = lastbf->bf_desc; - status = ath9k_hw_txprocdesc(ah, ds); + memset(&ts, 0, sizeof(ts)); + status = ath9k_hw_txprocdesc(ah, ds, &ts); if (status == -EINPROGRESS) { spin_unlock_bh(&txq->axq_lock); break; @@ -2028,7 +2126,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) * can disable RX. */ if (bf->bf_isnullfunc && - (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { + (ts.ts_status & ATH9K_TX_ACKED)) { if ((sc->ps_flags & PS_ENABLED)) ath9k_enable_ps(sc); else @@ -2047,31 +2145,30 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) &txq->axq_q, lastbf->list.prev); txq->axq_depth--; - txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_MASK); + txok = !(ts.ts_status & ATH9K_TXERR_MASK); txq->axq_tx_inprogress = false; + if (bf_held) + list_del(&bf_held->list); spin_unlock_bh(&txq->axq_lock); - if (bf_held) { - spin_lock_bh(&sc->tx.txbuflock); - list_move_tail(&bf_held->list, &sc->tx.txbuf); - spin_unlock_bh(&sc->tx.txbuflock); - } + if (bf_held) + ath_tx_return_buffer(sc, bf_held); if (!bf_isampdu(bf)) { /* * This frame is sent out as a single frame. * Use hardware retry status for this frame. */ - bf->bf_retries = ds->ds_txstat.ts_longretry; - if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) + bf->bf_retries = ts.ts_longretry; + if (ts.ts_status & ATH9K_TXERR_XRETRY) bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, ds, 0, txok, true); + ath_tx_rc_status(bf, &ts, 0, txok, true); } if (bf_isampdu(bf)) - ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok); + ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok); else - ath_tx_complete_buf(sc, bf, txq, &bf_head, txok, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0); ath_wake_mac80211_queue(sc, txq); @@ -2133,10 +2230,121 @@ void ath_tx_tasklet(struct ath_softc *sc) } } +void ath_tx_edma_tasklet(struct ath_softc *sc) +{ + struct ath_tx_status txs; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_txq *txq; + struct ath_buf *bf, *lastbf; + struct list_head bf_head; + int status; + int txok; + + for (;;) { + status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs); + if (status == -EINPROGRESS) + break; + if (status == -EIO) { + ath_print(common, ATH_DBG_XMIT, + "Error processing tx status\n"); + break; + } + + /* Skip beacon completions */ + if (txs.qid == sc->beacon.beaconq) + continue; + + txq = &sc->tx.txq[txs.qid]; + + spin_lock_bh(&txq->axq_lock); + if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) { + spin_unlock_bh(&txq->axq_lock); + return; + } + + bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx], + struct ath_buf, list); + lastbf = bf->bf_lastbf; + + INIT_LIST_HEAD(&bf_head); + list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx], + &lastbf->list); + INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH); + txq->axq_depth--; + txq->axq_tx_inprogress = false; + spin_unlock_bh(&txq->axq_lock); + + txok = !(txs.ts_status & ATH9K_TXERR_MASK); + + if (!bf_isampdu(bf)) { + bf->bf_retries = txs.ts_longretry; + if (txs.ts_status & ATH9K_TXERR_XRETRY) + bf->bf_state.bf_type |= BUF_XRETRY; + ath_tx_rc_status(bf, &txs, 0, txok, true); + } + + if (bf_isampdu(bf)) + ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok); + else + ath_tx_complete_buf(sc, bf, txq, &bf_head, + &txs, txok, 0); + + ath_wake_mac80211_queue(sc, txq); + + spin_lock_bh(&txq->axq_lock); + if (!list_empty(&txq->txq_fifo_pending)) { + INIT_LIST_HEAD(&bf_head); + bf = list_first_entry(&txq->txq_fifo_pending, + struct ath_buf, list); + list_cut_position(&bf_head, &txq->txq_fifo_pending, + &bf->bf_lastbf->list); + ath_tx_txqaddbuf(sc, txq, &bf_head); + } else if (sc->sc_flags & SC_OP_TXAGGR) + ath_txq_schedule(sc, txq); + spin_unlock_bh(&txq->axq_lock); + } +} + /*****************/ /* Init, Cleanup */ /*****************/ +static int ath_txstatus_setup(struct ath_softc *sc, int size) +{ + struct ath_descdma *dd = &sc->txsdma; + u8 txs_len = sc->sc_ah->caps.txs_len; + + dd->dd_desc_len = size * txs_len; + dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, + &dd->dd_desc_paddr, GFP_KERNEL); + if (!dd->dd_desc) + return -ENOMEM; + + return 0; +} + +static int ath_tx_edma_init(struct ath_softc *sc) +{ + int err; + + err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE); + if (!err) + ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc, + sc->txsdma.dd_desc_paddr, + ATH_TXSTATUS_RING_SIZE); + + return err; +} + +static void ath_tx_edma_cleanup(struct ath_softc *sc) +{ + struct ath_descdma *dd = &sc->txsdma; + + dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, + dd->dd_desc_paddr); +} + int ath_tx_init(struct ath_softc *sc, int nbufs) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -2145,7 +2353,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) spin_lock_init(&sc->tx.txbuflock); error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, - "tx", nbufs, 1); + "tx", nbufs, 1, 1); if (error != 0) { ath_print(common, ATH_DBG_FATAL, "Failed to allocate tx descriptors: %d\n", error); @@ -2153,7 +2361,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) } error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, - "beacon", ATH_BCBUF, 1); + "beacon", ATH_BCBUF, 1, 1); if (error != 0) { ath_print(common, ATH_DBG_FATAL, "Failed to allocate beacon descriptors: %d\n", error); @@ -2162,6 +2370,12 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + error = ath_tx_edma_init(sc); + if (error) + goto err; + } + err: if (error != 0) ath_tx_cleanup(sc); @@ -2176,6 +2390,9 @@ void ath_tx_cleanup(struct ath_softc *sc) if (sc->tx.txdma.dd_desc_len != 0) ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); + + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + ath_tx_edma_cleanup(sc); } void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h index 8263633c003..873bf526e11 100644 --- a/drivers/net/wireless/ath/debug.h +++ b/drivers/net/wireless/ath/debug.h @@ -59,6 +59,7 @@ enum ATH_DEBUG { ATH_DBG_PS = 0x00000800, ATH_DBG_HWTIMER = 0x00001000, ATH_DBG_BTCOEX = 0x00002000, + ATH_DBG_WMI = 0x00004000, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c index ecc9eb01f4f..a8f81ea09f1 100644 --- a/drivers/net/wireless/ath/hw.c +++ b/drivers/net/wireless/ath/hw.c @@ -19,8 +19,8 @@ #include "ath.h" #include "reg.h" -#define REG_READ common->ops->read -#define REG_WRITE common->ops->write +#define REG_READ (common->ops->read) +#define REG_WRITE (common->ops->write) /** * ath_hw_set_bssid_mask - filter out bssids we listen diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 00489c40be0..3f4244f56ce 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -50,6 +50,7 @@ #define ATH9K_5GHZ_ALL ATH9K_5GHZ_5150_5350, \ ATH9K_5GHZ_5470_5850 + /* This one skips what we call "mid band" */ #define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \ ATH9K_5GHZ_5725_5850 @@ -332,7 +333,6 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy, ath_reg_apply_active_scan_flags(wiphy, initiator); break; } - return; } int ath_reg_notifier_apply(struct wiphy *wiphy, @@ -360,7 +360,7 @@ EXPORT_SYMBOL(ath_reg_notifier_apply); static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) { - u16 rd = ath_regd_get_eepromRD(reg); + u16 rd = ath_regd_get_eepromRD(reg); int i; if (rd & COUNTRY_ERD_FLAG) { |