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

Conflicts:
	drivers/net/wireless/ath/ar9170/main.c
This commit is contained in:
John W. Linville 2010-05-11 14:24:55 -04:00
commit cc755896a4
63 changed files with 1367 additions and 1510 deletions

View File

@ -5,6 +5,7 @@
menuconfig WLAN
bool "Wireless LAN"
depends on !S390
depends on NET
select WIRELESS
default y
---help---

View File

@ -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;
};

View File

@ -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;
@ -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,
@ -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:
@ -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;
@ -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;
@ -2326,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)
{
@ -2419,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 */
@ -2493,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,
};
@ -2527,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]);
@ -2536,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];
@ -2549,16 +2019,8 @@ void *ar9170_alloc(size_t priv_size)
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_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;
}
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;

View File

@ -73,7 +73,7 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
const s8 hi[] = { -14, -12 };
const s8 fr[] = { -78, -80 };
#endif
if (level < 0 || level > ARRAY_SIZE(sz)) {
if (level < 0 || level >= ARRAY_SIZE(sz)) {
ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
"level out of range %d", level);
return;
@ -104,7 +104,7 @@ 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) ||
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);
@ -129,7 +129,7 @@ ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level)
{
const int val[] = { 0, 4, 8 };
if (level < 0 || level > ARRAY_SIZE(val)) {
if (level < 0 || level >= ARRAY_SIZE(val)) {
ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
"level out of range %d", level);
return;

View File

@ -541,7 +541,7 @@ static const u32 ar9300_2p0_mac_postamble[][5] = {
static const u32 ar9300_2p0_soc_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00007010, 0x00000023, 0x00000023, 0x00000022, 0x00000022},
{0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
};
static const u32 ar9200_merlin_2p0_radio_core[][2] = {
@ -588,12 +588,12 @@ static const u32 ar9200_merlin_2p0_radio_core[][2] = {
static const u32 ar9300_2p0_baseband_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005},
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a800b},
{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
{0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
{0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x00000b9c},
{0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044},
{0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
{0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
@ -744,7 +744,7 @@ static const u32 ar9300_2p0_baseband_core[][2] = {
{0x0000a408, 0x0e79e5c6},
{0x0000a40c, 0x00820820},
{0x0000a414, 0x1ce739ce},
{0x0000a418, 0x7d001dce},
{0x0000a418, 0x2d001dce},
{0x0000a41c, 0x1ce739ce},
{0x0000a420, 0x000001ce},
{0x0000a424, 0x1ce739ce},
@ -756,7 +756,7 @@ static const u32 ar9300_2p0_baseband_core[][2] = {
{0x0000a43c, 0x00000000},
{0x0000a440, 0x00000000},
{0x0000a444, 0x00000000},
{0x0000a448, 0x07000080},
{0x0000a448, 0x04000080},
{0x0000a44c, 0x00000001},
{0x0000a450, 0x00010000},
{0x0000a458, 0x00000000},
@ -777,7 +777,7 @@ static const u32 ar9300_2p0_baseband_core[][2] = {
{0x0000a638, 0x00000000},
{0x0000a63c, 0x00000000},
{0x0000a640, 0x00000000},
{0x0000a644, 0x3ffd9d74},
{0x0000a644, 0x3fad9d74},
{0x0000a648, 0x0048060a},
{0x0000a64c, 0x00000637},
{0x0000a670, 0x03020100},
@ -835,9 +835,9 @@ static const u32 ar9300_2p0_baseband_core[][2] = {
static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x0000a410, 0x000050db, 0x000050db, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00020220, 0x00020220, 0x00000000, 0x00000000},
{0x0000a504, 0x06020223, 0x06020223, 0x04000002, 0x04000002},
{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},
@ -848,28 +848,28 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
{0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
{0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
{0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
{0x0000a530, 0x34043643, 0x34043643, 0x2a000e20, 0x2a000e20},
{0x0000a534, 0x38043a44, 0x38043a44, 0x2e000e22, 0x2e000e22},
{0x0000a538, 0x3b043e45, 0x3b043e45, 0x31000e24, 0x31000e24},
{0x0000a53c, 0x40063e46, 0x40063e46, 0x34001640, 0x34001640},
{0x0000a540, 0x44083e46, 0x44083e46, 0x38001660, 0x38001660},
{0x0000a544, 0x46083e66, 0x46083e66, 0x3b001861, 0x3b001861},
{0x0000a548, 0x4b0a3e69, 0x4b0a3e69, 0x3e001a81, 0x3e001a81},
{0x0000a54c, 0x4f0a5e66, 0x4f0a5e66, 0x42001a83, 0x42001a83},
{0x0000a550, 0x540a7e66, 0x540a7e66, 0x44001c84, 0x44001c84},
{0x0000a554, 0x570a7e89, 0x570a7e89, 0x48001ce3, 0x48001ce3},
{0x0000a558, 0x5c0e7e8a, 0x5c0e7e8a, 0x4c001ce5, 0x4c001ce5},
{0x0000a55c, 0x60127e8b, 0x60127e8b, 0x50001ce9, 0x50001ce9},
{0x0000a560, 0x65127ecc, 0x65127ecc, 0x54001ceb, 0x54001ceb},
{0x0000a564, 0x6b169ecd, 0x6b169ecd, 0x56001eec, 0x56001eec},
{0x0000a568, 0x70169f0e, 0x70169f0e, 0x56001eec, 0x56001eec},
{0x0000a56c, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
{0x0000a570, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
{0x0000a574, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
{0x0000a578, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
{0x0000a57c, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
{0x0000a580, 0x00820220, 0x00820220, 0x00800000, 0x00800000},
{0x0000a584, 0x06820223, 0x06820223, 0x04800002, 0x04800002},
{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},
@ -880,42 +880,42 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
{0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
{0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
{0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
{0x0000a5b0, 0x34843643, 0x34843643, 0x2a800e20, 0x2a800e20},
{0x0000a5b4, 0x38843a44, 0x38843a44, 0x2e800e22, 0x2e800e22},
{0x0000a5b8, 0x3b843e45, 0x3b843e45, 0x31800e24, 0x31800e24},
{0x0000a5bc, 0x40863e46, 0x40863e46, 0x34801640, 0x34801640},
{0x0000a5c0, 0x4c8a3065, 0x44883e46, 0x44883e46, 0x38801660},
{0x0000a5c4, 0x46883e66, 0x46883e66, 0x3b801861, 0x3b801861},
{0x0000a5c8, 0x4b8a3e69, 0x4b8a3e69, 0x3e801a81, 0x3e801a81},
{0x0000a5cc, 0x4f8a5e66, 0x4f8a5e66, 0x42801a83, 0x42801a83},
{0x0000a5d0, 0x548a7e66, 0x548a7e66, 0x44801c84, 0x44801c84},
{0x0000a5d4, 0x578a7e89, 0x578a7e89, 0x48801ce3, 0x48801ce3},
{0x0000a5d8, 0x5c8e7e8a, 0x5c8e7e8a, 0x4c801ce5, 0x4c801ce5},
{0x0000a5dc, 0x60927e8b, 0x60927e8b, 0x50801ce9, 0x50801ce9},
{0x0000a5e0, 0x65927ecc, 0x65927ecc, 0x54801ceb, 0x54801ceb},
{0x0000a5e4, 0x6b969ecd, 0x6b969ecd, 0x56801eec, 0x56801eec},
{0x0000a5e8, 0x70969f0e, 0x70969f0e, 0x56801eec, 0x56801eec},
{0x0000a5ec, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
{0x0000a5f0, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
{0x0000a5f4, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
{0x0000a5f8, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
{0x0000a5fc, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
{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, 0xad241a61, 0xad241a61, 0xad241a61, 0xad241a61},
{0x00016048, 0xae481a61, 0xae481a61, 0xae481a61, 0xae481a61},
{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
{0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
{0x00016448, 0xad241a61, 0xad241a61, 0xad241a61, 0xad241a61},
{0x00016448, 0xae481a61, 0xae481a61, 0xae481a61, 0xae481a61},
{0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
{0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
{0x00016848, 0xad241a61, 0xad241a61, 0xad241a61, 0xad241a61},
{0x00016848, 0xae481a61, 0xae481a61, 0xae481a61, 0xae481a61},
{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, 0x000050db, 0x000050db, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00020220, 0x00020220, 0x00000000, 0x00000000},
{0x0000a504, 0x06020223, 0x06020223, 0x04000002, 0x04000002},
{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},
@ -926,28 +926,28 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p0[][5] = {
{0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
{0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
{0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
{0x0000a530, 0x34043643, 0x34043643, 0x2a000e20, 0x2a000e20},
{0x0000a534, 0x38043a44, 0x38043a44, 0x2e000e22, 0x2e000e22},
{0x0000a538, 0x3b043e45, 0x3b043e45, 0x31000e24, 0x31000e24},
{0x0000a53c, 0x40063e46, 0x40063e46, 0x34001640, 0x34001640},
{0x0000a540, 0x44083e46, 0x44083e46, 0x38001660, 0x38001660},
{0x0000a544, 0x46083e66, 0x46083e66, 0x3b001861, 0x3b001861},
{0x0000a548, 0x4b0a3e69, 0x4b0a3e69, 0x3e001a81, 0x3e001a81},
{0x0000a54c, 0x4f0a5e66, 0x4f0a5e66, 0x42001a83, 0x42001a83},
{0x0000a550, 0x540a7e66, 0x540a7e66, 0x44001c84, 0x44001c84},
{0x0000a554, 0x570a7e89, 0x570a7e89, 0x48001ce3, 0x48001ce3},
{0x0000a558, 0x5c0e7e8a, 0x5c0e7e8a, 0x4c001ce5, 0x4c001ce5},
{0x0000a55c, 0x60127e8b, 0x60127e8b, 0x50001ce9, 0x50001ce9},
{0x0000a560, 0x65127ecc, 0x65127ecc, 0x54001ceb, 0x54001ceb},
{0x0000a564, 0x6b169ecd, 0x6b169ecd, 0x56001eec, 0x56001eec},
{0x0000a568, 0x70169f0e, 0x70169f0e, 0x56001eec, 0x56001eec},
{0x0000a56c, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
{0x0000a570, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
{0x0000a574, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
{0x0000a578, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
{0x0000a57c, 0x75169f4f, 0x75169f4f, 0x56001eec, 0x56001eec},
{0x0000a580, 0x00820220, 0x00820220, 0x00800000, 0x00800000},
{0x0000a584, 0x06820223, 0x06820223, 0x04800002, 0x04800002},
{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},
@ -958,34 +958,34 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p0[][5] = {
{0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
{0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
{0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
{0x0000a5b0, 0x34843643, 0x34843643, 0x2a800e20, 0x2a800e20},
{0x0000a5b4, 0x38843a44, 0x38843a44, 0x2e800e22, 0x2e800e22},
{0x0000a5b8, 0x3b843e45, 0x3b843e45, 0x31800e24, 0x31800e24},
{0x0000a5bc, 0x40863e46, 0x40863e46, 0x34801640, 0x34801640},
{0x0000a5c0, 0x44883e46, 0x44883e46, 0x38801660, 0x38801660},
{0x0000a5c4, 0x46883e66, 0x46883e66, 0x3b801861, 0x3b801861},
{0x0000a5c8, 0x4b8a3e69, 0x4b8a3e69, 0x3e801a81, 0x3e801a81},
{0x0000a5cc, 0x4f8a5e66, 0x4f8a5e66, 0x42801a83, 0x42801a83},
{0x0000a5d0, 0x548a7e66, 0x548a7e66, 0x44801c84, 0x44801c84},
{0x0000a5d4, 0x578a7e89, 0x578a7e89, 0x48801ce3, 0x48801ce3},
{0x0000a5d8, 0x5c8e7e8a, 0x5c8e7e8a, 0x4c801ce5, 0x4c801ce5},
{0x0000a5dc, 0x60927e8b, 0x60927e8b, 0x50801ce9, 0x50801ce9},
{0x0000a5e0, 0x65927ecc, 0x65927ecc, 0x54801ceb, 0x54801ceb},
{0x0000a5e4, 0x6b969ecd, 0x6b969ecd, 0x56801eec, 0x56801eec},
{0x0000a5e8, 0x70969f0e, 0x70969f0e, 0x56801eec, 0x56801eec},
{0x0000a5ec, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
{0x0000a5f0, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
{0x0000a5f4, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
{0x0000a5f8, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
{0x0000a5fc, 0x75969f4f, 0x75969f4f, 0x56801eec, 0x56801eec},
{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, 0x8c001a61, 0x8c001a61, 0x8c001a61, 0x8c001a61},
{0x00016048, 0x8e481a61, 0x8e481a61, 0x8e481a61, 0x8e481a61},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
{0x00016448, 0x8c001a61, 0x8c001a61, 0x8c001a61, 0x8c001a61},
{0x00016448, 0x8e481a61, 0x8e481a61, 0x8e481a61, 0x8e481a61},
{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
{0x00016848, 0x8c001a61, 0x8c001a61, 0x8c001a61, 0x8c001a61},
{0x00016848, 0x8e481a61, 0x8e481a61, 0x8e481a61, 0x8e481a61},
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};

View File

@ -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,13 +215,19 @@ 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;

View File

@ -356,7 +356,6 @@ struct ath9k_htc_priv {
u16 seq_no;
u32 bmiss_cnt;
struct sk_buff *beacon;
spinlock_t beacon_lock;
bool tx_queues_stop;
@ -408,13 +407,13 @@ static inline void ath_read_cachesize(struct ath_common *common, int *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_beacon_update(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif);
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);

View File

@ -165,22 +165,10 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
}
void ath9k_htc_beacon_update(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif)
void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
enum htc_endpoint_id ep_id, bool txok)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
spin_lock_bh(&priv->beacon_lock);
if (priv->beacon)
dev_kfree_skb_any(priv->beacon);
priv->beacon = ieee80211_beacon_get(priv->hw, vif);
if (!priv->beacon)
ath_print(common, ATH_DBG_BEACON,
"Unable to allocate beacon\n");
spin_unlock_bh(&priv->beacon_lock);
dev_kfree_skb_any(skb);
}
void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
@ -189,6 +177,7 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
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));
@ -207,25 +196,17 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
return;
}
if (unlikely(priv->beacon == NULL)) {
spin_unlock_bh(&priv->beacon_lock);
return;
}
/* Free the old SKB first */
dev_kfree_skb_any(priv->beacon);
/* Get a new beacon */
priv->beacon = ieee80211_beacon_get(priv->hw, priv->vif);
if (!priv->beacon) {
beacon = ieee80211_beacon_get(priv->hw, priv->vif);
if (!beacon) {
spin_unlock_bh(&priv->beacon_lock);
return;
}
info = IEEE80211_SKB_CB(priv->beacon);
info = IEEE80211_SKB_CB(beacon);
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *) priv->beacon->data;
(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);
@ -233,10 +214,10 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
tx_ctl.type = ATH9K_HTC_NORMAL;
beacon_hdr.vif_index = avp->index;
tx_fhdr = skb_push(priv->beacon, sizeof(beacon_hdr));
tx_fhdr = skb_push(beacon, sizeof(beacon_hdr));
memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr));
htc_send(priv->htc, priv->beacon, priv->beacon_ep, &tx_ctl);
htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl);
spin_unlock_bh(&priv->beacon_lock);
}

View File

@ -144,7 +144,7 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv)
goto err;
/* Beacon */
ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, NULL,
ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, ath9k_htc_beaconep,
&priv->beacon_ep);
if (ret)
goto err;

View File

@ -461,11 +461,11 @@ static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
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 = (struct ath9k_htc_sta *) sta->drv_priv;
struct ath9k_htc_sta *ista;
int ret = 0;
u8 cmd_rsp;
if (tid > ATH9K_HTC_MAX_TID)
if (tid >= ATH9K_HTC_MAX_TID)
return -EINVAL;
memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
@ -1099,7 +1099,7 @@ fail_tx:
return 0;
}
static int ath9k_htc_radio_enable(struct ieee80211_hw *hw)
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;
@ -1147,6 +1147,13 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw)
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;
@ -1158,13 +1165,13 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
int ret = 0;
mutex_lock(&priv->mutex);
ret = ath9k_htc_radio_enable(hw);
ret = ath9k_htc_radio_enable(hw, false);
mutex_unlock(&priv->mutex);
return ret;
}
static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
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;
@ -1177,6 +1184,12 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
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);
@ -1217,7 +1230,7 @@ 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);
ath9k_htc_radio_disable(hw, false);
mutex_unlock(&priv->mutex);
}
@ -1313,15 +1326,6 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
priv->nvifs--;
ath9k_htc_remove_station(priv, vif, NULL);
if (vif->type == NL80211_IFTYPE_ADHOC) {
spin_lock_bh(&priv->beacon_lock);
if (priv->beacon)
dev_kfree_skb_any(priv->beacon);
priv->beacon = NULL;
spin_unlock_bh(&priv->beacon_lock);
}
priv->vif = NULL;
mutex_unlock(&priv->mutex);
@ -1346,7 +1350,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
if (enable_radio) {
ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
ath9k_htc_radio_enable(hw);
ath9k_htc_radio_enable(hw, true);
ath_print(common, ATH_DBG_CONFIG,
"not-idle: enabling radio\n");
}
@ -1398,10 +1402,9 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
if (priv->ps_idle) {
ath_print(common, ATH_DBG_CONFIG,
"idle: disabling radio\n");
ath9k_htc_radio_disable(hw);
ath9k_htc_radio_disable(hw, true);
}
mutex_unlock(&priv->mutex);
return 0;
@ -1590,9 +1593,6 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
ath9k_htc_beacon_config(priv, vif);
}
if (changed & BSS_CHANGED_BEACON)
ath9k_htc_beacon_update(priv, vif);
if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
!bss_conf->enable_beacon) {
priv->op_flags &= ~OP_ENABLE_BEACON;

View File

@ -574,6 +574,26 @@ static int __ath9k_hw_init(struct ath_hw *ah)
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

View File

@ -2483,7 +2483,6 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
&priv->_3945.shared_phys, GFP_KERNEL);
if (!priv->_3945.shared_virt) {
IWL_ERR(priv, "failed to allocate pci memory\n");
mutex_unlock(&priv->mutex);
return -ENOMEM;
}

View File

@ -79,6 +79,7 @@ static const u32 cipher_suites[] = {
static int lbs_cfg_set_channel(struct wiphy *wiphy,
struct net_device *netdev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{

View File

@ -652,17 +652,17 @@ static void mac80211_hwsim_beacon(unsigned long arg)
add_timer(&data->beacon_timer);
}
static const char *hwsim_chantypes[] = {
[NL80211_CHAN_NO_HT] = "noht",
[NL80211_CHAN_HT20] = "ht20",
[NL80211_CHAN_HT40MINUS] = "ht40-",
[NL80211_CHAN_HT40PLUS] = "ht40+",
};
static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
{
struct mac80211_hwsim_data *data = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
static const char *chantypes[4] = {
[NL80211_CHAN_NO_HT] = "noht",
[NL80211_CHAN_HT20] = "ht20",
[NL80211_CHAN_HT40MINUS] = "ht40-",
[NL80211_CHAN_HT40PLUS] = "ht40+",
};
static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
[IEEE80211_SMPS_AUTOMATIC] = "auto",
[IEEE80211_SMPS_OFF] = "off",
@ -673,7 +673,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
wiphy_name(hw->wiphy), __func__,
conf->channel->center_freq,
chantypes[conf->channel_type],
hwsim_chantypes[conf->channel_type],
!!(conf->flags & IEEE80211_CONF_IDLE),
!!(conf->flags & IEEE80211_CONF_PS),
smps_modes[conf->smps_mode]);
@ -761,9 +761,10 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_HT) {
printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n",
printk(KERN_DEBUG " %s: HT: op_mode=0x%x, chantype=%s\n",
wiphy_name(hw->wiphy),
info->ht_operation_mode);
info->ht_operation_mode,
hwsim_chantypes[info->channel_type]);
}
if (changed & BSS_CHANGED_BASIC_RATES) {

View File

@ -159,6 +159,7 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
}
static int orinoco_set_channel(struct wiphy *wiphy,
struct net_device *netdev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{

View File

@ -340,18 +340,109 @@ EXPORT_SYMBOL(orinoco_change_mtu);
/* Tx path */
/********************************************************************/
/* Add encapsulation and MIC to the existing SKB.
* The main xmit routine will then send the whole lot to the card.
* Need 8 bytes headroom
* Need 8 bytes tailroom
*
* With encapsulated ethernet II frame
* --------
* 803.3 header (14 bytes)
* dst[6]
* -------- src[6]
* 803.3 header (14 bytes) len[2]
* dst[6] 803.2 header (8 bytes)
* src[6] encaps[6]
* len[2] <- leave alone -> len[2]
* -------- -------- <-- 0
* Payload Payload
* ... ...
*
* -------- --------
* MIC (8 bytes)
* --------
*
* returns 0 on success, -ENOMEM on error.
*/
int orinoco_process_xmit_skb(struct sk_buff *skb,
struct net_device *dev,
struct orinoco_private *priv,
int *tx_control,
u8 *mic_buf)
{
struct orinoco_tkip_key *key;
struct ethhdr *eh;
int do_mic;
key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
(key != NULL));
if (do_mic)
*tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
HERMES_TXCTRL_MIC;
eh = (struct ethhdr *)skb->data;
/* Encapsulate Ethernet-II frames */
if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
struct header_struct {
struct ethhdr eth; /* 802.3 header */
u8 encap[6]; /* 802.2 header */
} __attribute__ ((packed)) hdr;
int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
if (net_ratelimit())
printk(KERN_ERR
"%s: Not enough headroom for 802.2 headers %d\n",
dev->name, skb_headroom(skb));
return -ENOMEM;
}
/* Fill in new header */
memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
hdr.eth.h_proto = htons(len);
memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
/* Make room for the new header, and copy it in */
eh = (struct ethhdr *) skb_push(skb, ENCAPS_OVERHEAD);
memcpy(eh, &hdr, sizeof(hdr));
}
/* Calculate Michael MIC */
if (do_mic) {
size_t len = skb->len - ETH_HLEN;
u8 *mic = &mic_buf[0];
/* Have to write to an even address, so copy the spare
* byte across */
if (skb->len % 2) {
*mic = skb->data[skb->len - 1];
mic++;
}
orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
eh->h_dest, eh->h_source, 0 /* priority */,
skb->data + ETH_HLEN,
len, mic);
}
return 0;
}
EXPORT_SYMBOL(orinoco_process_xmit_skb);
static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct orinoco_tkip_key *key;
hermes_t *hw = &priv->hw;
int err = 0;
u16 txfid = priv->txfid;
struct ethhdr *eh;
int tx_control;
unsigned long flags;
int do_mic;
u8 mic_buf[MICHAEL_MIC_LEN+1];
if (!netif_running(dev)) {
printk(KERN_ERR "%s: Tx on stopped device!\n",
@ -383,16 +474,12 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < ETH_HLEN)
goto drop;
key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
(key != NULL));
tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
if (do_mic)
tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
HERMES_TXCTRL_MIC;
err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
&mic_buf[0]);
if (err)
goto drop;
if (priv->has_alt_txcntl) {
/* WPA enabled firmwares have tx_cntl at the end of
@ -435,34 +522,6 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
}
eh = (struct ethhdr *)skb->data;
/* Encapsulate Ethernet-II frames */
if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
struct header_struct {
struct ethhdr eth; /* 802.3 header */
u8 encap[6]; /* 802.2 header */
} __attribute__ ((packed)) hdr;
/* Strip destination and source from the data */
skb_pull(skb, 2 * ETH_ALEN);
/* And move them to a separate header */
memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
/* Insert the SNAP header */
if (skb_headroom(skb) < sizeof(hdr)) {
printk(KERN_ERR
"%s: Not enough headroom for 802.2 headers %d\n",
dev->name, skb_headroom(skb));
goto drop;
}
eh = (struct ethhdr *) skb_push(skb, sizeof(hdr));
memcpy(eh, &hdr, sizeof(hdr));
}
err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len,
txfid, HERMES_802_3_OFFSET);
if (err) {
@ -471,32 +530,16 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
goto busy;
}
/* Calculate Michael MIC */
if (do_mic) {
u8 mic_buf[MICHAEL_MIC_LEN + 1];
u8 *mic;
size_t offset;
size_t len;
if (tx_control & HERMES_TXCTRL_MIC) {
size_t offset = HERMES_802_3_OFFSET + skb->len;
size_t len = MICHAEL_MIC_LEN;
if (skb->len % 2) {
/* MIC start is on an odd boundary */
mic_buf[0] = skb->data[skb->len - 1];
mic = &mic_buf[1];
offset = skb->len - 1;
len = MICHAEL_MIC_LEN + 1;
} else {
mic = &mic_buf[0];
offset = skb->len;
len = MICHAEL_MIC_LEN;
if (offset % 2) {
offset--;
len++;
}
orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
eh->h_dest, eh->h_source, 0 /* priority */,
skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
/* Write the MIC */
err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
txfid, HERMES_802_3_OFFSET + offset);
txfid, offset);
if (err) {
printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
dev->name, err);
@ -2234,7 +2277,7 @@ int orinoco_if_add(struct orinoco_private *priv,
/* we use the default eth_mac_addr for setting the MAC addr */
/* Reserve space in skb for the SNAP header */
dev->hard_header_len += ENCAPS_OVERHEAD;
dev->needed_headroom = ENCAPS_OVERHEAD;
netif_carrier_off(dev);

View File

@ -200,6 +200,12 @@ extern irqreturn_t orinoco_interrupt(int irq, void *dev_id);
extern void __orinoco_ev_info(struct net_device *dev, hermes_t *hw);
extern void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw);
int orinoco_process_xmit_skb(struct sk_buff *skb,
struct net_device *dev,
struct orinoco_private *priv,
int *tx_control,
u8 *mic);
/* Common ndo functions exported for reuse by orinoco_usb */
int orinoco_open(struct net_device *dev);
int orinoco_stop(struct net_device *dev);

View File

@ -67,6 +67,7 @@
#include <linux/wireless.h>
#include <linux/firmware.h>
#include "mic.h"
#include "orinoco.h"
#ifndef URB_ASYNC_UNLINK
@ -1198,11 +1199,9 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct ezusb_priv *upriv = priv->card;
u8 mic[MICHAEL_MIC_LEN+1];
int err = 0;
char *p;
struct ethhdr *eh;
int len, data_len, data_off;
__le16 tx_control;
int tx_control;
unsigned long flags;
struct request_context *ctx;
u8 *buf;
@ -1222,7 +1221,7 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
if (orinoco_lock(priv, &flags) != 0) {
printk(KERN_ERR
"%s: orinoco_xmit() called while hw_unavailable\n",
"%s: ezusb_xmit() called while hw_unavailable\n",
dev->name);
return NETDEV_TX_BUSY;
}
@ -1232,53 +1231,46 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
/* Oops, the firmware hasn't established a connection,
silently drop the packet (this seems to be the
safest approach). */
stats->tx_errors++;
orinoco_unlock(priv, &flags);
dev_kfree_skb(skb);
return NETDEV_TX_OK;
goto drop;
}
/* Check packet length */
if (skb->len < ETH_HLEN)
goto drop;
ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0);
if (!ctx)
goto fail;
goto busy;
memset(ctx->buf, 0, BULK_BUF_SIZE);
buf = ctx->buf->data;
/* Length of the packet body */
/* FIXME: what if the skb is smaller than this? */
len = max_t(int, skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN);
tx_control = 0;
eh = (struct ethhdr *) skb->data;
err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
&mic[0]);
if (err)
goto drop;
tx_control = cpu_to_le16(0);
memcpy(buf, &tx_control, sizeof(tx_control));
buf += sizeof(tx_control);
/* Encapsulate Ethernet-II frames */
if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
struct header_struct *hdr = (void *) buf;
buf += sizeof(*hdr);
data_len = len;
data_off = sizeof(tx_control) + sizeof(*hdr);
p = skb->data + ETH_HLEN;
/* 802.3 header */
memcpy(hdr->dest, eh->h_dest, ETH_ALEN);
memcpy(hdr->src, eh->h_source, ETH_ALEN);
hdr->len = htons(data_len + ENCAPS_OVERHEAD);
/* 802.2 header */
memcpy(&hdr->dsap, &encaps_hdr, sizeof(encaps_hdr));
hdr->ethertype = eh->h_proto;
} else { /* IEEE 802.3 frame */
data_len = len + ETH_HLEN;
data_off = sizeof(tx_control);
p = skb->data;
{
__le16 *tx_cntl = (__le16 *)buf;
*tx_cntl = cpu_to_le16(tx_control);
buf += sizeof(*tx_cntl);
}
memcpy(buf, p, data_len);
buf += data_len;
memcpy(buf, skb->data, skb->len);
buf += skb->len;
if (tx_control & HERMES_TXCTRL_MIC) {
u8 *m = mic;
/* Mic has been offset so it can be copied to an even
* address. We're copying eveything anyway, so we
* don't need to copy that first byte. */
if (skb->len % 2)
m++;
memcpy(buf, m, MICHAEL_MIC_LEN);
buf += MICHAEL_MIC_LEN;
}
/* Finally, we actually initiate the send */
netif_stop_queue(dev);
@ -1294,20 +1286,23 @@ static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
if (net_ratelimit())
printk(KERN_ERR "%s: Error %d transmitting packet\n",
dev->name, err);
stats->tx_errors++;
goto fail;
goto busy;
}
dev->trans_start = jiffies;
stats->tx_bytes += data_off + data_len;
stats->tx_bytes += skb->len;
goto ok;
drop:
stats->tx_errors++;
stats->tx_dropped++;
ok:
orinoco_unlock(priv, &flags);
dev_kfree_skb(skb);
return NETDEV_TX_OK;
fail:
busy:
orinoco_unlock(priv, &flags);
return NETDEV_TX_BUSY;
}

View File

@ -535,7 +535,7 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev);
static int rndis_set_channel(struct wiphy *wiphy,
static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
@ -2291,7 +2291,7 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return deauthenticate(usbdev);
}
static int rndis_set_channel(struct wiphy *wiphy,
static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev,
struct ieee80211_channel *chan, enum nl80211_channel_type channel_type)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);

View File

@ -1060,7 +1060,8 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* TX data initialization
*/
static void rt2400pci_write_beacon(struct queue_entry *entry)
static void rt2400pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
@ -1090,6 +1091,14 @@ static void rt2400pci_write_beacon(struct queue_entry *entry)
rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 1, word);
/*
* Enable beaconing again.
*/
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
rt2x00_set_field32(&reg, CSR14_TBCN, 1);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
@ -1097,17 +1106,6 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
if (queue == QID_BEACON) {
rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
rt2x00_set_field32(&reg, CSR14_TBCN, 1);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
return;
}
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));

View File

@ -1217,7 +1217,8 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* TX data initialization
*/
static void rt2500pci_write_beacon(struct queue_entry *entry)
static void rt2500pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
@ -1247,6 +1248,14 @@ static void rt2500pci_write_beacon(struct queue_entry *entry)
rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
rt2x00_desc_write(entry_priv->desc, 1, word);
/*
* Enable beaconing again.
*/
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
rt2x00_set_field32(&reg, CSR14_TBCN, 1);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
@ -1254,17 +1263,6 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
if (queue == QID_BEACON) {
rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
rt2x00_set_field32(&reg, CSR14_TBCN, 1);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
return;
}
rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));

View File

@ -1083,7 +1083,8 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
*/
static void rt2500usb_beacondone(struct urb *urb);
static void rt2500usb_write_beacon(struct queue_entry *entry)
static void rt2500usb_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
@ -1091,7 +1092,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint);
int length;
u16 reg;
u16 reg, reg0;
/*
* Add the descriptor in front of the skb.
@ -1133,6 +1134,26 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
* Send out the guardian byte.
*/
usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
/*
* Enable beaconing again.
*/
rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
reg0 = reg;
rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
/*
* Beacon generation will fail initially.
* To prevent this we need to change the TXRX_CSR19
* register several times (reg0 is the same as reg
* except for TXRX_CSR19_BEACON_GEN, which is 0 in reg0
* and 1 in reg).
*/
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
}
static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
@ -1149,37 +1170,6 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
return length;
}
static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
u16 reg, reg0;
if (queue != QID_BEACON) {
rt2x00usb_kick_tx_queue(rt2x00dev, queue);
return;
}
rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) {
rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
reg0 = reg;
rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
/*
* Beacon generation will fail initially.
* To prevent this we need to change the TXRX_CSR19
* register several times (reg0 is the same as reg
* except for TXRX_CSR19_BEACON_GEN, which is 0 in reg0
* and 1 in reg).
*/
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
}
}
/*
* RX control handlers
*/
@ -1214,11 +1204,9 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC;
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER);
if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY;
}
rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER);
if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY;
if (rxdesc->cipher != CIPHER_NONE) {
_rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]);
@ -1780,7 +1768,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.write_tx_data = rt2x00usb_write_tx_data,
.write_beacon = rt2500usb_write_beacon,
.get_tx_data_len = rt2500usb_get_tx_data_len,
.kick_tx_queue = rt2500usb_kick_tx_queue,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
.kill_tx_queue = rt2x00usb_kill_tx_queue,
.fill_rxdone = rt2500usb_fill_rxdone,
.config_shared_key = rt2500usb_config_key,

View File

@ -282,6 +282,104 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc)
{
__le32 *txwi = (__le32 *)(skb->data - TXWI_DESC_SIZE);
u32 word;
/*
* Initialize TX Info descriptor
*/
rt2x00_desc_read(txwi, 0, &word);
rt2x00_set_field32(&word, TXWI_W0_FRAG,
test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
rt2x00_set_field32(&word, TXWI_W0_TS,
test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_AMPDU,
test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density);
rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->txop);
rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs);
rt2x00_set_field32(&word, TXWI_W0_BW,
test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc);
rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
rt2x00_desc_write(txwi, 0, word);
rt2x00_desc_read(txwi, 1, &word);
rt2x00_set_field32(&word, TXWI_W1_ACK,
test_bit(ENTRY_TXD_ACK, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W1_NSEQ,
test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
txdesc->key_idx : 0xff);
rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
txdesc->length);
rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->queue + 1);
rt2x00_desc_write(txwi, 1, word);
/*
* Always write 0 to IV/EIV fields, hardware will insert the IV
* from the IVEIV register when TXD_W3_WIV is set to 0.
* When TXD_W3_WIV is set to 1 it will use the IV data
* from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
* crypto entry in the registers should be used to encrypt the frame.
*/
_rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
_rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
}
EXPORT_SYMBOL_GPL(rt2800_write_txwi);
void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc)
{
__le32 *rxwi = (__le32 *) skb->data;
u32 word;
rt2x00_desc_read(rxwi, 0, &word);
rxdesc->cipher = rt2x00_get_field32(word, RXWI_W0_UDF);
rxdesc->size = rt2x00_get_field32(word, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
rt2x00_desc_read(rxwi, 1, &word);
if (rt2x00_get_field32(word, RXWI_W1_SHORT_GI))
rxdesc->flags |= RX_FLAG_SHORT_GI;
if (rt2x00_get_field32(word, RXWI_W1_BW))
rxdesc->flags |= RX_FLAG_40MHZ;
/*
* Detect RX rate, always use MCS as signal type.
*/
rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
rxdesc->signal = rt2x00_get_field32(word, RXWI_W1_MCS);
rxdesc->rate_mode = rt2x00_get_field32(word, RXWI_W1_PHYMODE);
/*
* Mask of 0x8 bit to remove the short preamble flag.
*/
if (rxdesc->rate_mode == RATE_MODE_CCK)
rxdesc->signal &= ~0x8;
rt2x00_desc_read(rxwi, 2, &word);
rxdesc->rssi =
(rt2x00_get_field32(word, RXWI_W2_RSSI0) +
rt2x00_get_field32(word, RXWI_W2_RSSI1)) / 2;
/*
* Remove RXWI descriptor from start of buffer.
*/
skb_pull(skb, RXWI_DESC_SIZE);
}
EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
const struct rt2x00debug rt2800_rt2x00debug = {
.owner = THIS_MODULE,
@ -640,8 +738,6 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp)
rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs);
rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs);
rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, erp->eifs);
rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
@ -1415,9 +1511,16 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca);
/*
* Usually the CCK SIFS time should be set to 10 and the OFDM SIFS
* time should be set to 16. However, the original Ralink driver uses
* 16 for both and indeed using a value of 10 for CCK SIFS results in
* connection problems with 11g + CTS protection. Hence, use the same
* defaults as the Ralink driver: 16 for both, CCK and OFDM SIFS.
*/
rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, 32);
rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, 32);
rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, 16);
rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, 16);
rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4);
rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, 314);
rt2x00_set_field32(&reg, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1);
@ -2219,7 +2322,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
EXPORT_SYMBOL_GPL(rt2800_init_eeprom);
/*
* RF value list for rt28x0
* RF value list for rt28xx
* Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750)
*/
static const struct rf_channel rf_vals[] = {
@ -2294,10 +2397,10 @@ static const struct rf_channel rf_vals[] = {
};
/*
* RF value list for rt3070
* Supports: 2.4 GHz
* RF value list for rt3xxx
* Supports: 2.4 GHz (all) & 5.2 GHz (RF3052)
*/
static const struct rf_channel rf_vals_302x[] = {
static const struct rf_channel rf_vals_3x[] = {
{1, 241, 2, 2 },
{2, 241, 2, 7 },
{3, 242, 2, 2 },
@ -2312,6 +2415,51 @@ static const struct rf_channel rf_vals_302x[] = {
{12, 246, 2, 7 },
{13, 247, 2, 2 },
{14, 248, 2, 4 },
/* 802.11 UNI / HyperLan 2 */
{36, 0x56, 0, 4},
{38, 0x56, 0, 6},
{40, 0x56, 0, 8},
{44, 0x57, 0, 0},
{46, 0x57, 0, 2},
{48, 0x57, 0, 4},
{52, 0x57, 0, 8},
{54, 0x57, 0, 10},
{56, 0x58, 0, 0},
{60, 0x58, 0, 4},
{62, 0x58, 0, 6},
{64, 0x58, 0, 8},
/* 802.11 HyperLan 2 */
{100, 0x5b, 0, 8},
{102, 0x5b, 0, 10},
{104, 0x5c, 0, 0},
{108, 0x5c, 0, 4},
{110, 0x5c, 0, 6},
{112, 0x5c, 0, 8},
{116, 0x5d, 0, 0},
{118, 0x5d, 0, 2},
{120, 0x5d, 0, 4},
{124, 0x5d, 0, 8},
{126, 0x5d, 0, 10},
{128, 0x5e, 0, 0},
{132, 0x5e, 0, 4},
{134, 0x5e, 0, 6},
{136, 0x5e, 0, 8},
{140, 0x5f, 0, 0},
/* 802.11 UNII */
{149, 0x5f, 0, 9},
{151, 0x5f, 0, 11},
{153, 0x60, 0, 1},
{157, 0x60, 0, 5},
{159, 0x60, 0, 7},
{161, 0x60, 0, 9},
{165, 0x61, 0, 1},
{167, 0x61, 0, 3},
{169, 0x61, 0, 5},
{171, 0x61, 0, 7},
{173, 0x61, 0, 9},
};
int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
@ -2352,11 +2500,11 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
if (rt2x00_rf(rt2x00dev, RF2820) ||
rt2x00_rf(rt2x00dev, RF2720) ||
rt2x00_rf(rt2x00dev, RF3052)) {
rt2x00_rf(rt2x00dev, RF2720)) {
spec->num_channels = 14;
spec->channels = rf_vals;
} else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) {
} else if (rt2x00_rf(rt2x00dev, RF2850) ||
rt2x00_rf(rt2x00dev, RF2750)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals);
spec->channels = rf_vals;
@ -2364,8 +2512,12 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
rt2x00_rf(rt2x00dev, RF2020) ||
rt2x00_rf(rt2x00dev, RF3021) ||
rt2x00_rf(rt2x00dev, RF3022)) {
spec->num_channels = ARRAY_SIZE(rf_vals_302x);
spec->channels = rf_vals_302x;
spec->num_channels = 14;
spec->channels = rf_vals_3x;
} else if (rt2x00_rf(rt2x00dev, RF3052)) {
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_3x);
spec->channels = rf_vals_3x;
}
/*

View File

@ -111,6 +111,9 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc);
void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *txdesc);
extern const struct rt2x00debug rt2800_rt2x00debug;
int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev);

View File

@ -616,67 +616,13 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
static int rt2800pci_write_tx_data(struct queue_entry* entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct sk_buff *skb = entry->skb;
struct skb_frame_desc *skbdesc;
int ret;
__le32 *txwi;
u32 word;
ret = rt2x00pci_write_tx_data(entry, txdesc);
if (ret)
return ret;
skbdesc = get_skb_frame_desc(skb);
txwi = (__le32 *)(skb->data - rt2x00dev->ops->extra_tx_headroom);
/*
* Initialize TX Info descriptor
*/
rt2x00_desc_read(txwi, 0, &word);
rt2x00_set_field32(&word, TXWI_W0_FRAG,
test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
rt2x00_set_field32(&word, TXWI_W0_TS,
test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_AMPDU,
test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density);
rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->ifs);
rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs);
rt2x00_set_field32(&word, TXWI_W0_BW,
test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc);
rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
rt2x00_desc_write(txwi, 0, word);
rt2x00_desc_read(txwi, 1, &word);
rt2x00_set_field32(&word, TXWI_W1_ACK,
test_bit(ENTRY_TXD_ACK, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W1_NSEQ,
test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
txdesc->key_idx : 0xff);
rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
txdesc->length);
rt2x00_set_field32(&word, TXWI_W1_PACKETID,
skbdesc->entry->queue->qid + 1);
rt2x00_desc_write(txwi, 1, word);
/*
* Always write 0 to IV/EIV fields, hardware will insert the IV
* from the IVEIV register when TXD_W3_WIV is set to 0.
* When TXD_W3_WIV is set to 1 it will use the IV data
* from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
* crypto entry in the registers should be used to encrypt the frame.
*/
_rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
_rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
rt2800_write_txwi(entry->skb, txdesc);
return 0;
}
@ -732,10 +678,10 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* TX data initialization
*/
static void rt2800pci_write_beacon(struct queue_entry *entry)
static void rt2800pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
unsigned int beacon_base;
u32 reg;
@ -748,15 +694,25 @@ static void rt2800pci_write_beacon(struct queue_entry *entry)
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
/*
* Write entire beacon with descriptor to register.
* Add the TXWI for the beacon to the skb.
*/
rt2800_write_txwi(entry->skb, txdesc);
skb_push(entry->skb, TXWI_DESC_SIZE);
/*
* Write entire beacon with TXWI to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
rt2800_register_multiwrite(rt2x00dev,
beacon_base,
skbdesc->desc, skbdesc->desc_len);
rt2800_register_multiwrite(rt2x00dev,
beacon_base + skbdesc->desc_len,
entry->skb->data, entry->skb->len);
rt2800_register_multiwrite(rt2x00dev, beacon_base,
entry->skb->data, entry->skb->len);
/*
* Enable beaconing again.
*/
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
/*
* Clean up beacon skb.
@ -770,18 +726,6 @@ static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
{
struct data_queue *queue;
unsigned int idx, qidx = 0;
u32 reg;
if (queue_idx == QID_BEACON) {
rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) {
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
}
return;
}
if (queue_idx > QID_HCCA && queue_idx != QID_MGMT)
return;
@ -824,34 +768,21 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
__le32 *rxd = entry_priv->desc;
__le32 *rxwi = (__le32 *)entry->skb->data;
u32 rxd3;
u32 rxwi0;
u32 rxwi1;
u32 rxwi2;
u32 rxwi3;
u32 word;
rt2x00_desc_read(rxd, 3, &rxd3);
rt2x00_desc_read(rxwi, 0, &rxwi0);
rt2x00_desc_read(rxwi, 1, &rxwi1);
rt2x00_desc_read(rxwi, 2, &rxwi2);
rt2x00_desc_read(rxwi, 3, &rxwi3);
rt2x00_desc_read(rxd, 3, &word);
if (rt2x00_get_field32(rxd3, RXD_W3_CRC_ERROR))
if (rt2x00_get_field32(word, RXD_W3_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
/*
* Unfortunately we don't know the cipher type used during
* decryption. This prevents us from correct providing
* correct statistics through debugfs.
*/
rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
rxdesc->cipher_status =
rt2x00_get_field32(rxd3, RXD_W3_CIPHER_ERROR);
}
/*
* Unfortunately we don't know the cipher type used during
* decryption. This prevents us from correct providing
* correct statistics through debugfs.
*/
rxdesc->cipher_status = rt2x00_get_field32(word, RXD_W3_CIPHER_ERROR);
if (rt2x00_get_field32(rxd3, RXD_W3_DECRYPTED)) {
if (rt2x00_get_field32(word, RXD_W3_DECRYPTED)) {
/*
* Hardware has stripped IV/EIV data from 802.11 frame during
* decryption. Unfortunately the descriptor doesn't contain
@ -866,47 +797,22 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
rxdesc->flags |= RX_FLAG_MMIC_ERROR;
}
if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS))
if (rt2x00_get_field32(word, RXD_W3_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD))
if (rt2x00_get_field32(word, RXD_W3_L2PAD))
rxdesc->dev_flags |= RXDONE_L2PAD;
if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
rxdesc->flags |= RX_FLAG_SHORT_GI;
if (rt2x00_get_field32(rxwi1, RXWI_W1_BW))
rxdesc->flags |= RX_FLAG_40MHZ;
/*
* Detect RX rate, always use MCS as signal type.
* Process the RXWI structure that is at the start of the buffer.
*/
rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
rxdesc->rate_mode = rt2x00_get_field32(rxwi1, RXWI_W1_PHYMODE);
rxdesc->signal = rt2x00_get_field32(rxwi1, RXWI_W1_MCS);
/*
* Mask of 0x8 bit to remove the short preamble flag.
*/
if (rxdesc->rate_mode == RATE_MODE_CCK)
rxdesc->signal &= ~0x8;
rxdesc->rssi =
(rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) +
rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2;
rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
rt2800_process_rxwi(entry->skb, rxdesc);
/*
* Set RX IDX in register to inform hardware that we have handled
* this entry and it is available for reuse again.
*/
rt2800_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx);
/*
* Remove TXWI descriptor from start of buffer.
*/
skb_pull(entry->skb, RXWI_DESC_SIZE);
}
/*

View File

@ -401,59 +401,15 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txi = skbdesc->desc;
__le32 *txwi = &txi[TXINFO_DESC_SIZE / sizeof(__le32)];
u32 word;
/*
* Initialize TX Info descriptor
* Initialize TXWI descriptor
*/
rt2x00_desc_read(txwi, 0, &word);
rt2x00_set_field32(&word, TXWI_W0_FRAG,
test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
rt2x00_set_field32(&word, TXWI_W0_TS,
test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_AMPDU,
test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density);
rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->ifs);
rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs);
rt2x00_set_field32(&word, TXWI_W0_BW,
test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc);
rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
rt2x00_desc_write(txwi, 0, word);
rt2x00_desc_read(txwi, 1, &word);
rt2x00_set_field32(&word, TXWI_W1_ACK,
test_bit(ENTRY_TXD_ACK, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W1_NSEQ,
test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
txdesc->key_idx : 0xff);
rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
txdesc->length);
rt2x00_set_field32(&word, TXWI_W1_PACKETID,
skbdesc->entry->queue->qid + 1);
rt2x00_desc_write(txwi, 1, word);
rt2800_write_txwi(skb, txdesc);
/*
* Always write 0 to IV/EIV fields, hardware will insert the IV
* from the IVEIV register when TXINFO_W0_WIV is set to 0.
* When TXINFO_W0_WIV is set to 1 it will use the IV data
* from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
* crypto entry in the registers should be used to encrypt the frame.
*/
_rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
_rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
/*
* Initialize TX descriptor
* Initialize TXINFO descriptor
*/
rt2x00_desc_read(txi, 0, &word);
rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
@ -471,20 +427,13 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* TX data initialization
*/
static void rt2800usb_write_beacon(struct queue_entry *entry)
static void rt2800usb_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
unsigned int beacon_base;
u32 reg;
/*
* Add the descriptor in front of the skb.
*/
skb_push(entry->skb, entry->queue->desc_size);
memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
skbdesc->desc = entry->skb->data;
/*
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
@ -493,6 +442,12 @@ static void rt2800usb_write_beacon(struct queue_entry *entry)
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
/*
* Add the TXWI for the beacon to the skb.
*/
rt2800_write_txwi(entry->skb, txdesc);
skb_push(entry->skb, TXWI_DESC_SIZE);
/*
* Write entire beacon with descriptor to register.
*/
@ -502,6 +457,14 @@ static void rt2800usb_write_beacon(struct queue_entry *entry)
entry->skb->data, entry->skb->len,
REGISTER_TIMEOUT32(entry->skb->len));
/*
* Enable beaconing again.
*/
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
/*
* Clean up the beacon skb.
*/
@ -524,84 +487,53 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
return length;
}
static void rt2800usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
u32 reg;
if (queue != QID_BEACON) {
rt2x00usb_kick_tx_queue(rt2x00dev, queue);
return;
}
rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) {
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
}
}
/*
* RX control handlers
*/
static void rt2800usb_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
__le32 *rxi = (__le32 *)entry->skb->data;
__le32 *rxwi;
__le32 *rxd;
u32 rxi0;
u32 rxwi0;
u32 rxwi1;
u32 rxwi2;
u32 rxwi3;
u32 rxd0;
u32 word;
int rx_pkt_len;
/*
* RX frame format is :
* | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad |
* |<------------ rx_pkt_len -------------->|
*/
rt2x00_desc_read(rxi, 0, &rxi0);
rx_pkt_len = rt2x00_get_field32(rxi0, RXINFO_W0_USB_DMA_RX_PKT_LEN);
rxwi = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE);
/*
* FIXME : we need to check for rx_pkt_len validity
*/
rxd = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE + rx_pkt_len);
/*
* Copy descriptor to the skbdesc->desc buffer, making it safe from
* moving of frame data in rt2x00usb.
*/
memcpy(skbdesc->desc, rxi, skbdesc->desc_len);
/*
* RX frame format is :
* | RXINFO | RXWI | header | L2 pad | payload | pad | RXD | USB pad |
* |<------------ rx_pkt_len -------------->|
*/
rt2x00_desc_read(rxi, 0, &word);
rx_pkt_len = rt2x00_get_field32(word, RXINFO_W0_USB_DMA_RX_PKT_LEN);
/*
* Remove the RXINFO structure from the sbk.
*/
skb_pull(entry->skb, RXINFO_DESC_SIZE);
/*
* FIXME: we need to check for rx_pkt_len validity
*/
rxd = (__le32 *)(entry->skb->data + rx_pkt_len);
/*
* It is now safe to read the descriptor on all architectures.
*/
rt2x00_desc_read(rxwi, 0, &rxwi0);
rt2x00_desc_read(rxwi, 1, &rxwi1);
rt2x00_desc_read(rxwi, 2, &rxwi2);
rt2x00_desc_read(rxwi, 3, &rxwi3);
rt2x00_desc_read(rxd, 0, &rxd0);
rt2x00_desc_read(rxd, 0, &word);
if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR))
if (rt2x00_get_field32(word, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
rxdesc->cipher_status =
rt2x00_get_field32(rxd0, RXD_W0_CIPHER_ERROR);
}
rxdesc->cipher_status = rt2x00_get_field32(word, RXD_W0_CIPHER_ERROR);
if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) {
if (rt2x00_get_field32(word, RXD_W0_DECRYPTED)) {
/*
* Hardware has stripped IV/EIV data from 802.11 frame during
* decryption. Unfortunately the descriptor doesn't contain
@ -616,41 +548,21 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
rxdesc->flags |= RX_FLAG_MMIC_ERROR;
}
if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS))
if (rt2x00_get_field32(word, RXD_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD))
if (rt2x00_get_field32(word, RXD_W0_L2PAD))
rxdesc->dev_flags |= RXDONE_L2PAD;
if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
rxdesc->flags |= RX_FLAG_SHORT_GI;
if (rt2x00_get_field32(rxwi1, RXWI_W1_BW))
rxdesc->flags |= RX_FLAG_40MHZ;
/*
* Remove RXD descriptor from end of buffer.
*/
skb_trim(entry->skb, rx_pkt_len);
/*
* Detect RX rate, always use MCS as signal type.
* Process the RXWI structure.
*/
rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
rxdesc->rate_mode = rt2x00_get_field32(rxwi1, RXWI_W1_PHYMODE);
rxdesc->signal = rt2x00_get_field32(rxwi1, RXWI_W1_MCS);
/*
* Mask of 0x8 bit to remove the short preamble flag.
*/
if (rxdesc->rate_mode == RATE_MODE_CCK)
rxdesc->signal &= ~0x8;
rxdesc->rssi =
(rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) +
rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2;
rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
/*
* Remove RXWI descriptor from start of buffer.
*/
skb_pull(entry->skb, skbdesc->desc_len);
rt2800_process_rxwi(entry->skb, rxdesc);
}
/*
@ -743,7 +655,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.write_tx_data = rt2x00usb_write_tx_data,
.write_beacon = rt2800usb_write_beacon,
.get_tx_data_len = rt2800usb_get_tx_data_len,
.kick_tx_queue = rt2800usb_kick_tx_queue,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
.kill_tx_queue = rt2x00usb_kill_tx_queue,
.fill_rxdone = rt2800usb_fill_rxdone,
.config_shared_key = rt2800_config_shared_key,
@ -841,7 +753,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
/* EnGenius */
{ USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Gigabyte */
{ USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) },

View File

@ -79,8 +79,6 @@
*/
#define TXINFO_DESC_SIZE ( 1 * sizeof(__le32) )
#define RXINFO_DESC_SIZE ( 1 * sizeof(__le32) )
#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) )
#define RXD_DESC_SIZE ( 1 * sizeof(__le32) )
/*
* TX Info structure
@ -112,44 +110,6 @@
#define RXINFO_W0_USB_DMA_RX_PKT_LEN FIELD32(0x0000ffff)
/*
* RX WI structure
*/
/*
* Word0
*/
#define RXWI_W0_WIRELESS_CLI_ID FIELD32(0x000000ff)
#define RXWI_W0_KEY_INDEX FIELD32(0x00000300)
#define RXWI_W0_BSSID FIELD32(0x00001c00)
#define RXWI_W0_UDF FIELD32(0x0000e000)
#define RXWI_W0_MPDU_TOTAL_BYTE_COUNT FIELD32(0x0fff0000)
#define RXWI_W0_TID FIELD32(0xf0000000)
/*
* Word1
*/
#define RXWI_W1_FRAG FIELD32(0x0000000f)
#define RXWI_W1_SEQUENCE FIELD32(0x0000fff0)
#define RXWI_W1_MCS FIELD32(0x007f0000)
#define RXWI_W1_BW FIELD32(0x00800000)
#define RXWI_W1_SHORT_GI FIELD32(0x01000000)
#define RXWI_W1_STBC FIELD32(0x06000000)
#define RXWI_W1_PHYMODE FIELD32(0xc0000000)
/*
* Word2
*/
#define RXWI_W2_RSSI0 FIELD32(0x000000ff)
#define RXWI_W2_RSSI1 FIELD32(0x0000ff00)
#define RXWI_W2_RSSI2 FIELD32(0x00ff0000)
/*
* Word3
*/
#define RXWI_W3_SNR0 FIELD32(0x000000ff)
#define RXWI_W3_SNR1 FIELD32(0x0000ff00)
/*
* RX descriptor format for RX Ring.
*/

View File

@ -551,7 +551,8 @@ struct rt2x00lib_ops {
struct txentry_desc *txdesc);
int (*write_tx_data) (struct queue_entry *entry,
struct txentry_desc *txdesc);
void (*write_beacon) (struct queue_entry *entry);
void (*write_beacon) (struct queue_entry *entry,
struct txentry_desc *txdesc);
int (*get_tx_data_len) (struct queue_entry *entry);
void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue);

View File

@ -128,6 +128,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
/* Pull buffer to correct size */
skb_pull(skb, txdesc->iv_len);
txdesc->length -= txdesc->iv_len;
/* IV/EIV data has officially been stripped */
skbdesc->flags |= SKBDESC_IV_STRIPPED;

View File

@ -35,6 +35,7 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
if (tx_info->control.sta)
txdesc->mpdu_density =
@ -66,4 +67,20 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
__set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
__set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags);
/*
* Determine IFS values
* - Use TXOP_BACKOFF for management frames
* - Use TXOP_SIFS for fragment bursts
* - Use TXOP_HTTXOP for everything else
*
* Note: rt2800 devices won't use CTS protection (if used)
* for frames not transmitted with TXOP_HTTXOP
*/
if (ieee80211_is_mgmt(hdr->frame_control))
txdesc->txop = TXOP_BACKOFF;
else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT))
txdesc->txop = TXOP_SIFS;
else
txdesc->txop = TXOP_HTTXOP;
}

View File

@ -429,20 +429,23 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
* it is now ready to be dumped to userspace through debugfs.
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
}
static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct data_queue *queue = entry->queue;
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
/*
* Check if we need to kick the queue, there are however a few rules
* 1) Don't kick beacon queue
* 2) Don't kick unless this is the last in frame in a burst.
* 1) Don't kick unless this is the last in frame in a burst.
* When the burst flag is set, this frame is always followed
* by another frame which in some way are related to eachother.
* This is true for fragments, RTS or CTS-to-self frames.
* 3) Rule 2 can be broken when the available entries
* 2) Rule 1 can be broken when the available entries
* in the queue are less then a certain threshold.
*/
if (entry->queue->qid == QID_BEACON)
return;
if (rt2x00queue_threshold(queue) ||
!test_bit(ENTRY_TXD_BURST, &txdesc->flags))
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
@ -538,6 +541,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
rt2x00queue_index_inc(queue, Q_INDEX);
rt2x00queue_write_tx_descriptor(entry, &txdesc);
rt2x00queue_kick_tx_queue(entry, &txdesc);
return 0;
}
@ -603,12 +607,9 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
/*
* Send beacon to hardware.
* Also enable beacon generation, which might have been disabled
* by the driver during the config_beacon() callback function.
* Send beacon to hardware and enable beacon genaration..
*/
rt2x00dev->ops->lib->write_beacon(intf->beacon);
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
mutex_unlock(&intf->beacon_skb_mutex);

View File

@ -299,6 +299,7 @@ enum txentry_desc_flags {
* @retry_limit: Max number of retries.
* @aifs: AIFS value.
* @ifs: IFS value.
* @txop: IFS value for 11n capable chips.
* @cw_min: cwmin value.
* @cw_max: cwmax value.
* @cipher: Cipher type used for encryption.
@ -328,6 +329,7 @@ struct txentry_desc {
short retry_limit;
short aifs;
short ifs;
short txop;
short cw_min;
short cw_max;

View File

@ -100,6 +100,16 @@ enum ifs {
IFS_NONE = 3,
};
/*
* IFS backoff values for HT devices
*/
enum txop {
TXOP_HTTXOP = 0,
TXOP_PIFS = 1,
TXOP_SIFS = 2,
TXOP_BACKOFF = 3,
};
/*
* Cipher types for hardware encryption
*/

View File

@ -1843,7 +1843,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* TX data initialization
*/
static void rt61pci_write_beacon(struct queue_entry *entry)
static void rt61pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
@ -1869,6 +1870,19 @@ static void rt61pci_write_beacon(struct queue_entry *entry)
beacon_base + skbdesc->desc_len,
entry->skb->data, entry->skb->len);
/*
* Enable beaconing again.
*
* For Wi-Fi faily generated beacons between participating
* stations. Set TBTT phase adaptive adjustment step to 8us.
*/
rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
* Clean up beacon skb.
*/
@ -1881,23 +1895,6 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
if (queue == QID_BEACON) {
/*
* For Wi-Fi faily generated beacons between participating
* stations. Set TBTT phase adaptive adjustment step to 8us.
*/
rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
}
return;
}
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE));
rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK));
@ -1969,12 +1966,8 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
rxdesc->cipher =
rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
rxdesc->cipher_status =
rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
}
rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
if (rxdesc->cipher != CIPHER_NONE) {
_rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv[0]);

View File

@ -1505,7 +1505,8 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* TX data initialization
*/
static void rt73usb_write_beacon(struct queue_entry *entry)
static void rt73usb_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
@ -1536,6 +1537,19 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
entry->skb->data, entry->skb->len,
REGISTER_TIMEOUT32(entry->skb->len));
/*
* Enable beaconing again.
*
* For Wi-Fi faily generated beacons between participating stations.
* Set TBTT phase adaptive adjustment step to 8us (default 16us)
*/
rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
* Clean up the beacon skb.
*/
@ -1557,31 +1571,6 @@ static int rt73usb_get_tx_data_len(struct queue_entry *entry)
return length;
}
static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
u32 reg;
if (queue != QID_BEACON) {
rt2x00usb_kick_tx_queue(rt2x00dev, queue);
return;
}
/*
* For Wi-Fi faily generated beacons between participating stations.
* Set TBTT phase adaptive adjustment step to 8us (default 16us)
*/
rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
}
}
/*
* RX control handlers
*/
@ -1645,12 +1634,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
rxdesc->cipher =
rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
rxdesc->cipher_status =
rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
}
rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
if (rxdesc->cipher != CIPHER_NONE) {
_rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]);
@ -2266,7 +2251,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.write_tx_data = rt2x00usb_write_tx_data,
.write_beacon = rt73usb_write_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,
.kick_tx_queue = rt73usb_kick_tx_queue,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
.kill_tx_queue = rt2x00usb_kill_tx_queue,
.fill_rxdone = rt73usb_fill_rxdone,
.config_shared_key = rt73usb_config_shared_key,

View File

@ -55,6 +55,14 @@ struct rtl8180_tx_ring {
struct sk_buff_head queue;
};
struct rtl8180_vif {
struct ieee80211_hw *dev;
/* beaconing */
struct delayed_work beacon_work;
bool enable_beacon;
};
struct rtl8180_priv {
/* common between rtl818x drivers */
struct rtl818x_csr __iomem *map;
@ -78,6 +86,9 @@ struct rtl8180_priv {
u32 anaparam;
u16 rfparam;
u8 csthreshold;
/* sequence # */
u16 seqno;
};
void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);

View File

@ -234,6 +234,7 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct rtl8180_priv *priv = dev->priv;
struct rtl8180_tx_ring *ring;
struct rtl8180_tx_desc *entry;
@ -285,6 +286,14 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
}
spin_lock_irqsave(&priv->lock, flags);
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
priv->seqno += 0x10;
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
}
idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
entry = &ring->desc[idx];
@ -299,6 +308,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
__skb_queue_tail(&ring->queue, skb);
if (ring->entries - skb_queue_len(&ring->queue) < 2)
ieee80211_stop_queue(dev, prio);
spin_unlock_irqrestore(&priv->lock, flags);
rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
@ -653,10 +663,59 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
rtl8180_free_tx_ring(dev, i);
}
static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
{
struct rtl8180_priv *priv = dev->priv;
return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
(u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
}
void rtl8180_beacon_work(struct work_struct *work)
{
struct rtl8180_vif *vif_priv =
container_of(work, struct rtl8180_vif, beacon_work.work);
struct ieee80211_vif *vif =
container_of((void *)vif_priv, struct ieee80211_vif, drv_priv);
struct ieee80211_hw *dev = vif_priv->dev;
struct ieee80211_mgmt *mgmt;
struct sk_buff *skb;
int err = 0;
/* don't overflow the tx ring */
if (ieee80211_queue_stopped(dev, 0))
goto resched;
/* grab a fresh beacon */
skb = ieee80211_beacon_get(dev, vif);
/*
* update beacon timestamp w/ TSF value
* TODO: make hardware update beacon timestamp
*/
mgmt = (struct ieee80211_mgmt *)skb->data;
mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev));
/* TODO: use actual beacon queue */
skb_set_queue_mapping(skb, 0);
err = rtl8180_tx(dev, skb);
WARN_ON(err);
resched:
/*
* schedule next beacon
* TODO: use hardware support for beacon timing
*/
schedule_delayed_work(&vif_priv->beacon_work,
usecs_to_jiffies(1024 * vif->bss_conf.beacon_int));
}
static int rtl8180_add_interface(struct ieee80211_hw *dev,
struct ieee80211_vif *vif)
{
struct rtl8180_priv *priv = dev->priv;
struct rtl8180_vif *vif_priv;
/*
* We only support one active interface at a time.
@ -666,6 +725,7 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
break;
default:
return -EOPNOTSUPP;
@ -673,6 +733,12 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev,
priv->vif = vif;
/* Initialize driver private area */
vif_priv = (struct rtl8180_vif *)&vif->drv_priv;
vif_priv->dev = dev;
INIT_DELAYED_WORK(&vif_priv->beacon_work, rtl8180_beacon_work);
vif_priv->enable_beacon = false;
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0],
le32_to_cpu(*(__le32 *)vif->addr));
@ -706,8 +772,11 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
u32 changed)
{
struct rtl8180_priv *priv = dev->priv;
struct rtl8180_vif *vif_priv;
int i;
vif_priv = (struct rtl8180_vif *)&vif->drv_priv;
if (changed & BSS_CHANGED_BSSID) {
for (i = 0; i < ETH_ALEN; i++)
rtl818x_iowrite8(priv, &priv->map->BSSID[i],
@ -722,7 +791,16 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
}
if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp)
priv->rf->conf_erp(dev, info);
priv->rf->conf_erp(dev, info);
if (changed & BSS_CHANGED_BEACON_ENABLED)
vif_priv->enable_beacon = info->enable_beacon;
if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON)) {
cancel_delayed_work_sync(&vif_priv->beacon_work);
if (vif_priv->enable_beacon)
schedule_work(&vif_priv->beacon_work.work);
}
}
static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev,
@ -763,14 +841,6 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev,
rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf);
}
static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
{
struct rtl8180_priv *priv = dev->priv;
return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
(u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
}
static const struct ieee80211_ops rtl8180_ops = {
.tx = rtl8180_tx,
.start = rtl8180_start,
@ -857,8 +927,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
goto err_free_reg;
}
if ((err = pci_set_dma_mask(pdev, 0xFFFFFF00ULL)) ||
(err = pci_set_consistent_dma_mask(pdev, 0xFFFFFF00ULL))) {
if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) ||
(err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))) {
printk(KERN_ERR "%s (rtl8180): No suitable DMA available\n",
pci_name(pdev));
goto err_free_reg;
@ -907,7 +977,9 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SIGNAL_UNSPEC;
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
dev->vif_data_size = sizeof(struct rtl8180_vif);
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
dev->queues = 1;
dev->max_signal = 65;

View File

@ -388,6 +388,8 @@ struct wl1271 {
size_t fw_len;
struct wl1271_nvs_file *nvs;
s8 hw_pg_ver;
u8 bssid[ETH_ALEN];
u8 mac_addr[ETH_ALEN];
u8 bss_type;
@ -479,7 +481,7 @@ struct wl1271 {
struct wl1271_stats stats;
struct wl1271_debugfs debugfs;
u32 buffer_32;
__le32 buffer_32;
u32 buffer_cmd;
u32 buffer_busyword[WL1271_BUSY_WORD_CNT];

View File

@ -441,11 +441,23 @@ static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
return 0;
}
static void wl1271_boot_hw_version(struct wl1271 *wl)
{
u32 fuse;
fuse = wl1271_top_reg_read(wl, REG_FUSE_DATA_2_1);
fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET;
wl->hw_pg_ver = (s8)fuse;
}
int wl1271_boot(struct wl1271 *wl)
{
int ret = 0;
u32 tmp, clk, pause;
wl1271_boot_hw_version(wl);
if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4)
/* ref clk: 19.2/38.4/38.4-XTAL */
clk = 0x3;

View File

@ -55,6 +55,9 @@ struct wl1271_static_data {
#define OCP_REG_CLK_POLARITY 0x0cb2
#define OCP_REG_CLK_PULL 0x0cb4
#define REG_FUSE_DATA_2_1 0x050a
#define PG_VER_MASK 0x3c
#define PG_VER_OFFSET 2
#define CMD_MBOX_ADDRESS 0x407B4

View File

@ -516,7 +516,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
ps_params->ps_mode = ps_mode;
ps_params->send_null_data = send;
ps_params->retries = 5;
ps_params->hang_over_period = 128;
ps_params->hang_over_period = 1;
ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,

View File

@ -129,7 +129,7 @@ enum cmd_templ {
/* unit ms */
#define WL1271_COMMAND_TIMEOUT 2000
#define WL1271_CMD_TEMPL_MAX_SIZE 252
#define WL1271_EVENT_TIMEOUT 100
#define WL1271_EVENT_TIMEOUT 750
struct wl1271_cmd_header {
__le16 id;

View File

@ -74,12 +74,12 @@ static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
wl1271_raw_read(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
return wl->buffer_32;
return le32_to_cpu(wl->buffer_32);
}
static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
{
wl->buffer_32 = val;
wl->buffer_32 = cpu_to_le32(val);
wl1271_raw_write(wl, addr, &wl->buffer_32,
sizeof(wl->buffer_32), false);
}

View File

@ -1140,10 +1140,25 @@ out:
return ret;
}
static int wl1271_join(struct wl1271 *wl)
static int wl1271_join(struct wl1271 *wl, bool set_assoc)
{
int ret;
/*
* One of the side effects of the JOIN command is that is clears
* WPA/WPA2 keys from the chipset. Performing a JOIN while associated
* to a WPA/WPA2 access point will therefore kill the data-path.
* Currently there is no supported scenario for JOIN during
* association - if it becomes a supported scenario, the WPA/WPA2 keys
* must be handled somehow.
*
*/
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
wl1271_info("JOIN while associated.");
if (set_assoc)
set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
ret = wl1271_cmd_join(wl, wl->set_bss_type);
if (ret < 0)
goto out;
@ -1190,7 +1205,6 @@ static int wl1271_unjoin(struct wl1271 *wl)
goto out;
clear_bit(WL1271_FLAG_JOINED, &wl->flags);
wl->channel = 0;
memset(wl->bssid, 0, ETH_ALEN);
/* stop filterting packets based on bssid */
@ -1250,7 +1264,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
goto out;
/* if the channel changes while joined, join again */
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
((wl->band != conf->channel->band) ||
(wl->channel != channel))) {
wl->band = conf->channel->band;
wl->channel = channel;
@ -1270,7 +1286,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
"failed %d", ret);
if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
ret = wl1271_join(wl);
ret = wl1271_join(wl, false);
if (ret < 0)
wl1271_warning("cmd join to update channel "
"failed %d", ret);
@ -1647,6 +1663,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
enum wl1271_cmd_ps_mode mode;
struct wl1271 *wl = hw->priv;
bool do_join = false;
bool set_assoc = false;
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
@ -1756,7 +1773,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (bss_conf->assoc) {
u32 rates;
wl->aid = bss_conf->aid;
set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
set_assoc = true;
/*
* use basic rates from AP, and determine lowest rate
@ -1856,7 +1873,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
}
if (do_join) {
ret = wl1271_join(wl);
ret = wl1271_join(wl, set_assoc);
if (ret < 0) {
wl1271_warning("cmd join failed %d", ret);
goto out_sleep;
@ -2228,6 +2245,29 @@ static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
wl1271_sysfs_show_bt_coex_state,
wl1271_sysfs_store_bt_coex_state);
static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl1271 *wl = dev_get_drvdata(dev);
ssize_t len;
/* FIXME: what's the maximum length of buf? page size?*/
len = 500;
mutex_lock(&wl->mutex);
if (wl->hw_pg_ver >= 0)
len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
else
len = snprintf(buf, len, "n/a\n");
mutex_unlock(&wl->mutex);
return len;
}
static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
wl1271_sysfs_show_hw_pg_ver, NULL);
int wl1271_register_hw(struct wl1271 *wl)
{
int ret;
@ -2347,6 +2387,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->vif = NULL;
wl->flags = 0;
wl->sg_enabled = true;
wl->hw_pg_ver = -1;
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
wl->tx_frames[i] = NULL;
@ -2376,8 +2417,18 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
goto err_platform;
}
/* Create sysfs file to get HW PG version */
ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
if (ret < 0) {
wl1271_error("failed to create sysfs file hw_pg_ver");
goto err_bt_coex_state;
}
return hw;
err_bt_coex_state:
device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
err_platform:
platform_device_unregister(wl->plat_dev);

View File

@ -52,6 +52,8 @@
* %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
* %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
* and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
* However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
* instead, the support here is for backward compatibility only.
* @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
* or rename notification. Has attributes %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
@ -329,6 +331,15 @@
* @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This
* command is used as an event to indicate the that a trigger level was
* reached.
* @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
* and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed
* by %NL80211_ATTR_IFINDEX) shall operate on.
* In case multiple channels are supported by the device, the mechanism
* with which it switches channels is implementation-defined.
* When a monitor interface is given, it can only switch channel while
* no other interfaces are operating to avoid disturbing the operation
* of any other interfaces, and other interfaces will again take
* precedence when they are used.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
@ -428,6 +439,8 @@ enum nl80211_commands {
NL80211_CMD_SET_CQM,
NL80211_CMD_NOTIFY_CQM,
NL80211_CMD_SET_CHANNEL,
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */

View File

@ -966,7 +966,11 @@ struct cfg80211_pmksa {
*
* @set_txq_params: Set TX queue parameters
*
* @set_channel: Set channel
* @set_channel: Set channel for a given wireless interface. Some devices
* may support multi-channel operation (by channel hopping) so cfg80211
* doesn't verify much. Note, however, that the passed netdev may be
* %NULL as well if the user requested changing the channel for the
* device itself, or for a monitor interface.
*
* @scan: Request to do a scan. If returning zero, the scan request is given
* the driver, and will be valid until passed to cfg80211_scan_done().
@ -1095,7 +1099,7 @@ struct cfg80211_ops {
int (*set_txq_params)(struct wiphy *wiphy,
struct ieee80211_txq_params *params);
int (*set_channel)(struct wiphy *wiphy,
int (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type);
@ -1461,6 +1465,8 @@ struct cfg80211_cached_keys;
* @list: (private) Used to collect the interfaces
* @netdev: (private) Used to reference back to the netdev
* @current_bss: (private) Used by the internal configuration code
* @channel: (private) Used by the internal configuration code to track
* user-set AP, monitor and WDS channels for wireless extensions
* @bssid: (private) Used by the internal configuration code
* @ssid: (private) Used by the internal configuration code
* @ssid_len: (private) Used by the internal configuration code
@ -1507,6 +1513,7 @@ struct wireless_dev {
struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES];
struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES];
struct cfg80211_internal_bss *current_bss; /* associated / joined */
struct ieee80211_channel *channel;
bool ps;
int ps_timeout;

View File

@ -160,6 +160,8 @@ enum ieee80211_bss_change {
BSS_CHANGED_BEACON_ENABLED = 1<<9,
BSS_CHANGED_CQM = 1<<10,
BSS_CHANGED_IBSS = 1<<11,
/* when adding here, make sure to change ieee80211_reconfig */
};
/**
@ -189,6 +191,9 @@ enum ieee80211_bss_change {
* the current band.
* @bssid: The BSSID for this BSS
* @enable_beacon: whether beaconing should be enabled or not
* @channel_type: Channel type for this BSS -- the hardware might be
* configured for HT40+ while this BSS only uses no-HT, for
* example.
* @ht_operation_mode: HT operation mode (like in &struct ieee80211_ht_info).
* This field is only valid when the channel type is one of the HT types.
* @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
@ -213,6 +218,7 @@ struct ieee80211_bss_conf {
u16 ht_operation_mode;
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
enum nl80211_channel_type channel_type;
};
/**

View File

@ -23,7 +23,8 @@ mac80211-y := \
key.o \
util.o \
wme.o \
event.o
event.o \
chan.o
mac80211-$(CONFIG_MAC80211_LEDS) += led.o
mac80211-$(CONFIG_MAC80211_DEBUGFS) += \

View File

@ -1162,15 +1162,39 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
}
static int ieee80211_set_channel(struct wiphy *wiphy,
struct net_device *netdev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = NULL;
if (netdev)
sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
switch (ieee80211_get_channel_mode(local, NULL)) {
case CHAN_MODE_HOPPING:
return -EBUSY;
case CHAN_MODE_FIXED:
if (local->oper_channel != chan)
return -EBUSY;
if (!sdata && local->_oper_channel_type == channel_type)
return 0;
break;
case CHAN_MODE_UNDEFINED:
break;
}
local->oper_channel = chan;
local->oper_channel_type = channel_type;
return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
if (!ieee80211_set_channel_type(local, sdata, channel_type))
return -EBUSY;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
return 0;
}
#ifdef CONFIG_PM
@ -1214,6 +1238,20 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_assoc_request *req)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
switch (ieee80211_get_channel_mode(local, sdata)) {
case CHAN_MODE_HOPPING:
return -EBUSY;
case CHAN_MODE_FIXED:
if (local->oper_channel == req->bss->channel)
break;
return -EBUSY;
case CHAN_MODE_UNDEFINED:
break;
}
return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
}
@ -1236,8 +1274,22 @@ static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ibss_params *params)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
switch (ieee80211_get_channel_mode(local, sdata)) {
case CHAN_MODE_HOPPING:
return -EBUSY;
case CHAN_MODE_FIXED:
if (!params->channel_fixed)
return -EBUSY;
if (local->oper_channel == params->channel)
break;
return -EBUSY;
case CHAN_MODE_UNDEFINED:
break;
}
return ieee80211_ibss_join(sdata, params);
}
@ -1366,7 +1418,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
* association, there's no need to send an action frame.
*/
if (!sdata->u.mgd.associated ||
sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) {
sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
mutex_lock(&sdata->local->iflist_mtx);
ieee80211_recalc_smps(sdata->local, sdata);
mutex_unlock(&sdata->local->iflist_mtx);

127
net/mac80211/chan.c Normal file
View File

@ -0,0 +1,127 @@
/*
* mac80211 - channel management
*/
#include <linux/nl80211.h>
#include "ieee80211_i.h"
enum ieee80211_chan_mode
__ieee80211_get_channel_mode(struct ieee80211_local *local,
struct ieee80211_sub_if_data *ignore)
{
struct ieee80211_sub_if_data *sdata;
WARN_ON(!mutex_is_locked(&local->iflist_mtx));
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata == ignore)
continue;
if (!ieee80211_sdata_running(sdata))
continue;
if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
continue;
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
!sdata->u.mgd.associated)
continue;
if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
if (!sdata->u.ibss.ssid_len)
continue;
if (!sdata->u.ibss.fixed_channel)
return CHAN_MODE_HOPPING;
}
if (sdata->vif.type == NL80211_IFTYPE_AP &&
!sdata->u.ap.beacon)
continue;
return CHAN_MODE_FIXED;
}
return CHAN_MODE_UNDEFINED;
}
enum ieee80211_chan_mode
ieee80211_get_channel_mode(struct ieee80211_local *local,
struct ieee80211_sub_if_data *ignore)
{
enum ieee80211_chan_mode mode;
mutex_lock(&local->iflist_mtx);
mode = __ieee80211_get_channel_mode(local, ignore);
mutex_unlock(&local->iflist_mtx);
return mode;
}
bool ieee80211_set_channel_type(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum nl80211_channel_type chantype)
{
struct ieee80211_sub_if_data *tmp;
enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
bool result;
mutex_lock(&local->iflist_mtx);
list_for_each_entry(tmp, &local->interfaces, list) {
if (tmp == sdata)
continue;
if (!ieee80211_sdata_running(tmp))
continue;
switch (tmp->vif.bss_conf.channel_type) {
case NL80211_CHAN_NO_HT:
case NL80211_CHAN_HT20:
superchan = tmp->vif.bss_conf.channel_type;
break;
case NL80211_CHAN_HT40PLUS:
WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
superchan = NL80211_CHAN_HT40PLUS;
break;
case NL80211_CHAN_HT40MINUS:
WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
superchan = NL80211_CHAN_HT40MINUS;
break;
}
}
switch (superchan) {
case NL80211_CHAN_NO_HT:
case NL80211_CHAN_HT20:
/*
* allow any change that doesn't go to no-HT
* (if it already is no-HT no change is needed)
*/
if (chantype == NL80211_CHAN_NO_HT)
break;
superchan = chantype;
break;
case NL80211_CHAN_HT40PLUS:
case NL80211_CHAN_HT40MINUS:
/* allow smaller bandwidth and same */
if (chantype == NL80211_CHAN_NO_HT)
break;
if (chantype == NL80211_CHAN_HT20)
break;
if (superchan == chantype)
break;
result = false;
goto out;
}
local->_oper_channel_type = superchan;
if (sdata)
sdata->vif.bss_conf.channel_type = chantype;
result = true;
out:
mutex_unlock(&local->iflist_mtx);
return result;
}

View File

@ -103,7 +103,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
local->oper_channel = chan;
local->oper_channel_type = NL80211_CHAN_NO_HT;
WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
sband = local->hw.wiphy->bands[chan->band];
@ -911,7 +911,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
/* fix ourselves to that channel now already */
if (params->channel_fixed) {
sdata->local->oper_channel = params->channel;
sdata->local->oper_channel_type = NL80211_CHAN_NO_HT;
WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata,
NL80211_CHAN_NO_HT));
}
if (params->ie) {

View File

@ -767,7 +767,7 @@ struct ieee80211_local {
enum mac80211_scan_state next_scan_state;
struct delayed_work scan_work;
struct ieee80211_sub_if_data *scan_sdata;
enum nl80211_channel_type oper_channel_type;
enum nl80211_channel_type _oper_channel_type;
struct ieee80211_channel *oper_channel, *csa_channel;
/* Temporary remain-on-channel for off-channel operations */
@ -1228,6 +1228,20 @@ int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
int ieee80211_wk_cancel_remain_on_channel(
struct ieee80211_sub_if_data *sdata, u64 cookie);
/* channel management */
enum ieee80211_chan_mode {
CHAN_MODE_UNDEFINED,
CHAN_MODE_HOPPING,
CHAN_MODE_FIXED,
};
enum ieee80211_chan_mode
ieee80211_get_channel_mode(struct ieee80211_local *local,
struct ieee80211_sub_if_data *ignore);
bool ieee80211_set_channel_type(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum nl80211_channel_type chantype);
#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
#else

View File

@ -111,7 +111,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
channel_type = local->tmp_channel_type;
} else {
chan = local->oper_channel;
channel_type = local->oper_channel_type;
channel_type = local->_oper_channel_type;
}
if (chan != local->hw.conf.channel ||

View File

@ -137,11 +137,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta;
u32 changed = 0;
u16 ht_opmode;
bool enable_ht = true, ht_changed;
bool enable_ht = true;
enum nl80211_channel_type prev_chantype;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
prev_chantype = sdata->vif.bss_conf.channel_type;
/* HT is not supported */
if (!sband->ht_cap.ht_supported)
enable_ht = false;
@ -172,38 +175,37 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
}
}
ht_changed = conf_is_ht(&local->hw.conf) != enable_ht ||
channel_type != local->hw.conf.channel_type;
if (local->tmp_channel)
local->tmp_channel_type = channel_type;
local->oper_channel_type = channel_type;
if (ht_changed) {
/* channel_type change automatically detected */
ieee80211_hw_config(local, 0);
if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
/* can only fail due to HT40+/- mismatch */
channel_type = NL80211_CHAN_HT20;
WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type));
}
/* channel_type change automatically detected */
ieee80211_hw_config(local, 0);
if (prev_chantype != channel_type) {
rcu_read_lock();
sta = sta_info_get(sdata, bssid);
if (sta)
rate_control_rate_update(local, sband, sta,
IEEE80211_RC_HT_CHANGED,
local->oper_channel_type);
channel_type);
rcu_read_unlock();
}
/* disable HT */
if (!enable_ht)
return 0;
}
ht_opmode = le16_to_cpu(hti->operation_mode);
/* if bss configuration changed store the new one */
if (!sdata->ht_opmode_valid ||
sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
if (sdata->ht_opmode_valid != enable_ht ||
sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
prev_chantype != channel_type) {
changed |= BSS_CHANGED_HT;
sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
sdata->ht_opmode_valid = true;
sdata->ht_opmode_valid = enable_ht;
}
return changed;
@ -866,7 +868,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_set_wmm_default(sdata);
/* channel(_type) changes are handled by ieee80211_hw_config */
local->oper_channel_type = NL80211_CHAN_NO_HT;
WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
/* on the next assoc, re-program HT parameters */
sdata->ht_opmode_valid = false;
@ -883,8 +885,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_hw_config(local, config_changed);
/* And the BSSID changed -- not very interesting here */
changed |= BSS_CHANGED_BSSID;
/* The BSSID (not really interesting) and HT changed */
changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
ieee80211_bss_info_change_notify(sdata, changed);
if (remove_sta)
@ -2266,7 +2268,7 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
if ((chan != local->tmp_channel ||
channel_type != local->tmp_channel_type) &&
(chan != local->oper_channel ||
channel_type != local->oper_channel_type))
channel_type != local->_oper_channel_type))
return -EBUSY;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);

View File

@ -2251,8 +2251,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
info->control.vif = vif;
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT |
IEEE80211_TX_CTL_ASSIGN_SEQ |
IEEE80211_TX_CTL_FIRST_FRAGMENT;
out:
rcu_read_unlock();
return skb;

View File

@ -1160,18 +1160,33 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* Finally also reconfigure all the BSS information */
list_for_each_entry(sdata, &local->interfaces, list) {
u32 changed = ~0;
u32 changed;
if (!ieee80211_sdata_running(sdata))
continue;
/* common change flags for all interface types */
changed = BSS_CHANGED_ERP_CTS_PROT |
BSS_CHANGED_ERP_PREAMBLE |
BSS_CHANGED_ERP_SLOT |
BSS_CHANGED_HT |
BSS_CHANGED_BASIC_RATES |
BSS_CHANGED_BEACON_INT |
BSS_CHANGED_BSSID |
BSS_CHANGED_CQM;
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
/* disable beacon change bits */
changed &= ~(BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED);
/* fall through */
changed |= BSS_CHANGED_ASSOC;
ieee80211_bss_info_change_notify(sdata, changed);
break;
case NL80211_IFTYPE_ADHOC:
changed |= BSS_CHANGED_IBSS;
/* fall through */
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
changed |= BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED;
ieee80211_bss_info_change_notify(sdata, changed);
break;
case NL80211_IFTYPE_WDS:

View File

@ -9,38 +9,6 @@
#include <net/cfg80211.h>
#include "core.h"
struct ieee80211_channel *
rdev_fixed_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *for_wdev)
{
struct wireless_dev *wdev;
struct ieee80211_channel *result = NULL;
WARN_ON(!mutex_is_locked(&rdev->devlist_mtx));
list_for_each_entry(wdev, &rdev->netdev_list, list) {
if (wdev == for_wdev)
continue;
/*
* Lock manually to tell lockdep about allowed
* nesting here if for_wdev->mtx is held already.
* This is ok as it's all under the rdev devlist
* mutex and as such can only be done once at any
* given time.
*/
mutex_lock_nested(&wdev->mtx, SINGLE_DEPTH_NESTING);
if (wdev->current_bss)
result = wdev->current_bss->pub.channel;
wdev_unlock(wdev);
if (result)
break;
}
return result;
}
struct ieee80211_channel *
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
int freq, enum nl80211_channel_type channel_type)
@ -75,15 +43,22 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
return chan;
}
int rdev_set_freq(struct cfg80211_registered_device *rdev,
struct wireless_dev *for_wdev,
int freq, enum nl80211_channel_type channel_type)
int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, int freq,
enum nl80211_channel_type channel_type)
{
struct ieee80211_channel *chan;
int result;
if (rdev_fixed_channel(rdev, for_wdev))
return -EBUSY;
if (wdev->iftype == NL80211_IFTYPE_MONITOR)
wdev = NULL;
if (wdev) {
ASSERT_WDEV_LOCK(wdev);
if (!netif_running(wdev->netdev))
return -ENETDOWN;
}
if (!rdev->ops->set_channel)
return -EOPNOTSUPP;
@ -92,11 +67,14 @@ int rdev_set_freq(struct cfg80211_registered_device *rdev,
if (!chan)
return -EINVAL;
result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type);
result = rdev->ops->set_channel(&rdev->wiphy,
wdev ? wdev->netdev : NULL,
chan, channel_type);
if (result)
return result;
rdev->channel = chan;
if (wdev)
wdev->channel = chan;
return 0;
}

View File

@ -70,9 +70,6 @@ struct cfg80211_registered_device {
struct work_struct conn_work;
struct work_struct event_work;
/* current channel */
struct ieee80211_channel *channel;
/* must be last because of the way we do wiphy_priv(),
* and it should at least be aligned to NETDEV_ALIGN */
struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
@ -387,15 +384,12 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
u32 *flags, struct vif_params *params);
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
struct ieee80211_channel *
rdev_fixed_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *for_wdev);
struct ieee80211_channel *
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
int freq, enum nl80211_channel_type channel_type);
int rdev_set_freq(struct cfg80211_registered_device *rdev,
struct wireless_dev *for_wdev,
int freq, enum nl80211_channel_type channel_type);
int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, int freq,
enum nl80211_channel_type channel_type);
u16 cfg80211_calculate_bitrate(struct rate_info *rate);

View File

@ -81,15 +81,10 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
struct cfg80211_cached_keys *connkeys)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct ieee80211_channel *chan;
int err;
ASSERT_WDEV_LOCK(wdev);
chan = rdev_fixed_channel(rdev, wdev);
if (chan && chan != params->channel)
return -EBUSY;
if (wdev->ssid_len)
return -EALREADY;

View File

@ -589,6 +589,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
i++;
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
}
CMD(set_channel, SET_CHANNEL);
#undef CMD
@ -689,10 +690,90 @@ static int parse_txq_params(struct nlattr *tb[],
return 0;
}
static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
{
/*
* You can only set the channel explicitly for AP, mesh
* and WDS type interfaces; all others have their channel
* managed via their respective "establish a connection"
* command (connect, join, ...)
*
* Monitors are special as they are normally slaved to
* whatever else is going on, so they behave as though
* you tried setting the wiphy channel itself.
*/
return !wdev ||
wdev->iftype == NL80211_IFTYPE_AP ||
wdev->iftype == NL80211_IFTYPE_WDS ||
wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
wdev->iftype == NL80211_IFTYPE_MONITOR;
}
static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct genl_info *info)
{
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
u32 freq;
int result;
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
if (!nl80211_can_set_dev_channel(wdev))
return -EOPNOTSUPP;
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
channel_type = nla_get_u32(info->attrs[
NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
if (channel_type != NL80211_CHAN_NO_HT &&
channel_type != NL80211_CHAN_HT20 &&
channel_type != NL80211_CHAN_HT40PLUS &&
channel_type != NL80211_CHAN_HT40MINUS)
return -EINVAL;
}
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
mutex_lock(&rdev->devlist_mtx);
if (wdev) {
wdev_lock(wdev);
result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
wdev_unlock(wdev);
} else {
result = cfg80211_set_freq(rdev, NULL, freq, channel_type);
}
mutex_unlock(&rdev->devlist_mtx);
return result;
}
static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
struct net_device *netdev;
int result;
rtnl_lock();
result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev);
if (result)
goto unlock;
result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
unlock:
rtnl_unlock();
return result;
}
static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
int result = 0, rem_txq_params = 0;
struct net_device *netdev = NULL;
struct wireless_dev *wdev;
int result, rem_txq_params = 0;
struct nlattr *nl_txq_params;
u32 changed;
u8 retry_short = 0, retry_long = 0;
@ -701,16 +782,50 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
rtnl_lock();
/*
* Try to find the wiphy and netdev. Normally this
* function shouldn't need the netdev, but this is
* done for backward compatibility -- previously
* setting the channel was done per wiphy, but now
* it is per netdev. Previous userland like hostapd
* also passed a netdev to set_wiphy, so that it is
* possible to let that go to the right netdev!
*/
mutex_lock(&cfg80211_mutex);
rdev = __cfg80211_rdev_from_info(info);
if (IS_ERR(rdev)) {
mutex_unlock(&cfg80211_mutex);
result = PTR_ERR(rdev);
goto unlock;
if (info->attrs[NL80211_ATTR_IFINDEX]) {
int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
netdev = dev_get_by_index(genl_info_net(info), ifindex);
if (netdev && netdev->ieee80211_ptr) {
rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy);
mutex_lock(&rdev->mtx);
} else
netdev = NULL;
}
mutex_lock(&rdev->mtx);
if (!netdev) {
rdev = __cfg80211_rdev_from_info(info);
if (IS_ERR(rdev)) {
mutex_unlock(&cfg80211_mutex);
result = PTR_ERR(rdev);
goto unlock;
}
wdev = NULL;
netdev = NULL;
result = 0;
mutex_lock(&rdev->mtx);
} else if (netif_running(netdev) &&
nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
wdev = netdev->ieee80211_ptr;
else
wdev = NULL;
/*
* end workaround code, by now the rdev is available
* and locked, and wdev may or may not be NULL.
*/
if (info->attrs[NL80211_ATTR_WIPHY_NAME])
result = cfg80211_dev_rename(
@ -749,26 +864,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
}
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
u32 freq;
result = -EINVAL;
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
channel_type = nla_get_u32(info->attrs[
NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
if (channel_type != NL80211_CHAN_NO_HT &&
channel_type != NL80211_CHAN_HT20 &&
channel_type != NL80211_CHAN_HT40PLUS &&
channel_type != NL80211_CHAN_HT40MINUS)
goto bad_res;
}
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
mutex_lock(&rdev->devlist_mtx);
result = rdev_set_freq(rdev, NULL, freq, channel_type);
mutex_unlock(&rdev->devlist_mtx);
result = __nl80211_set_channel(rdev, wdev, info);
if (result)
goto bad_res;
}
@ -865,6 +961,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
bad_res:
mutex_unlock(&rdev->mtx);
if (netdev)
dev_put(netdev);
unlock:
rtnl_unlock();
return result;
@ -3562,9 +3660,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
struct net_device *dev;
struct wireless_dev *wdev;
struct cfg80211_crypto_settings crypto;
struct ieee80211_channel *chan, *fixedchan;
struct ieee80211_channel *chan;
const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
int err, ssid_len, ie_len = 0;
bool use_mfp = false;
@ -3607,16 +3704,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
goto out;
}
mutex_lock(&rdev->devlist_mtx);
wdev = dev->ieee80211_ptr;
fixedchan = rdev_fixed_channel(rdev, wdev);
if (fixedchan && chan != fixedchan) {
err = -EBUSY;
mutex_unlock(&rdev->devlist_mtx);
goto out;
}
mutex_unlock(&rdev->devlist_mtx);
ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
@ -5186,6 +5273,12 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NL80211_CMD_SET_CHANNEL,
.doit = nl80211_set_channel,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {

View File

@ -741,7 +741,6 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
const u8 *prev_bssid)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct ieee80211_channel *chan;
struct cfg80211_bss *bss = NULL;
int err;
@ -750,10 +749,6 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
if (wdev->sme_state != CFG80211_SME_IDLE)
return -EALREADY;
chan = rdev_fixed_channel(rdev, wdev);
if (chan && chan != connect->channel)
return -EBUSY;
if (WARN_ON(wdev->connect_keys)) {
kfree(wdev->connect_keys);
wdev->connect_keys = NULL;

View File

@ -782,16 +782,22 @@ int cfg80211_wext_siwfreq(struct net_device *dev,
return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra);
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
default:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_MESH_POINT:
freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
if (freq < 0)
return freq;
if (freq == 0)
return -EINVAL;
wdev_lock(wdev);
mutex_lock(&rdev->devlist_mtx);
err = rdev_set_freq(rdev, NULL, freq, NL80211_CHAN_NO_HT);
err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
mutex_unlock(&rdev->devlist_mtx);
wdev_unlock(wdev);
return err;
default:
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
@ -801,7 +807,6 @@ int cfg80211_wext_giwfreq(struct net_device *dev,
struct iw_freq *freq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
@ -809,9 +814,9 @@ int cfg80211_wext_giwfreq(struct net_device *dev,
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
default:
if (!rdev->channel)
if (!wdev->channel)
return -EINVAL;
freq->m = rdev->channel->center_freq;
freq->m = wdev->channel->center_freq;
freq->e = 6;
return 0;
}

View File

@ -108,7 +108,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
/* SSID is not set, we just want to switch channel */
if (chan && !wdev->wext.connect.ssid_len) {
err = rdev_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
goto out;
}