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

This commit is contained in:
David S. Miller 2009-07-26 10:01:25 -07:00
commit c8b201ff86
134 changed files with 5003 additions and 3241 deletions

View File

@ -4984,7 +4984,7 @@ L: linux-wireless@vger.kernel.org
W: http://linuxwireless.org/ W: http://linuxwireless.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained S: Maintained
F: drivers/net/wireless/rtl818* F: drivers/net/wireless/rtl818x/rtl8180*
RTL8187 WIRELESS DRIVER RTL8187 WIRELESS DRIVER
P: Herton Ronaldo Krzesinski P: Herton Ronaldo Krzesinski
@ -6466,6 +6466,15 @@ M: mitr@volny.cz
S: Maintained S: Maintained
F: drivers/input/misc/wistron_btns.c F: drivers/input/misc/wistron_btns.c
WL1251 WIRELESS DRIVER
P: Kalle Valo
M: kalle.valo@nokia.com
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
S: Maintained
F: drivers/net/wireless/wl12xx/wl1251*
WL3501 WIRELESS PCMCIA CARD DRIVER WL3501 WIRELESS PCMCIA CARD DRIVER
P: Arnaldo Carvalho de Melo P: Arnaldo Carvalho de Melo
M: acme@ghostprotocols.net M: acme@ghostprotocols.net

View File

@ -428,10 +428,12 @@ config RTL8187
Micronet SP907GK V5 Micronet SP907GK V5
Encore ENUWI-G2 Encore ENUWI-G2
Trendnet TEW-424UB Trendnet TEW-424UB
ASUS P5B Deluxe ASUS P5B Deluxe/P5K Premium motherboards
Toshiba Satellite Pro series of laptops Toshiba Satellite Pro series of laptops
Asus Wireless Link Asus Wireless Link
Linksys WUSB54GC-EU Linksys WUSB54GC-EU v2
(v1 = rt73usb; v3 is rt2070-based,
use staging/rt3070 or try rt2800usb)
Thanks to Realtek for their support! Thanks to Realtek for their support!

View File

@ -1964,14 +1964,6 @@ static void __devexit adm8211_remove(struct pci_dev *pdev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
{ {
struct ieee80211_hw *dev = pci_get_drvdata(pdev);
struct adm8211_priv *priv = dev->priv;
if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
ieee80211_stop_queues(dev);
adm8211_stop(dev);
}
pci_save_state(pdev); pci_save_state(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state)); pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0; return 0;
@ -1979,17 +1971,8 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
static int adm8211_resume(struct pci_dev *pdev) static int adm8211_resume(struct pci_dev *pdev)
{ {
struct ieee80211_hw *dev = pci_get_drvdata(pdev);
struct adm8211_priv *priv = dev->priv;
pci_set_power_state(pdev, PCI_D0); pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev); pci_restore_state(pdev);
if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
adm8211_start(dev);
ieee80211_wake_queues(dev);
}
return 0; return 0;
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */

View File

@ -1022,7 +1022,7 @@ static int arlan_mac_addr(struct net_device *dev, void *p)
ARLAN_DEBUG_ENTRY("arlan_mac_addr"); ARLAN_DEBUG_ENTRY("arlan_mac_addr");
return -EINVAL; return -EINVAL;
if (!netif_running(dev)) if (netif_running(dev))
return -EBUSY; return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);

View File

@ -109,11 +109,52 @@ struct ar9170_rxstream_mpdu_merge {
bool has_plcp; bool has_plcp;
}; };
#define AR9170_NUM_MAX_BA_RETRY 5
#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;
u8 retry;
};
#define AR9170_QUEUE_TIMEOUT 64 #define AR9170_QUEUE_TIMEOUT 64
#define AR9170_TX_TIMEOUT 8 #define AR9170_TX_TIMEOUT 8
#define AR9170_BA_TIMEOUT 4
#define AR9170_JANITOR_DELAY 128 #define AR9170_JANITOR_DELAY 128
#define AR9170_TX_INVALID_RATE 0xffffffff #define AR9170_TX_INVALID_RATE 0xffffffff
#define AR9170_NUM_TX_STATUS 128
#define AR9170_NUM_TX_AGG_MAX 30
struct ar9170 { struct ar9170 {
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct mutex mutex; struct mutex mutex;
@ -187,14 +228,25 @@ struct ar9170 {
struct sk_buff_head tx_pending[__AR9170_NUM_TXQ]; struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
struct delayed_work tx_janitor; 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;
unsigned int tx_ampdu_pending;
/* rxstream mpdu merge */ /* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu; struct ar9170_rxstream_mpdu_merge rx_mpdu;
struct sk_buff *rx_failover; struct sk_buff *rx_failover;
int rx_failover_missing; int rx_failover_missing;
/* (cached) HW A-MPDU settings */
u8 global_ampdu_density;
u8 global_ampdu_factor;
}; };
struct ar9170_sta_info { struct ar9170_sta_info {
struct ar9170_sta_tid agg[AR9170_NUM_TID];
unsigned int ampdu_max_len;
}; };
#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0) #define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0)

View File

@ -49,6 +49,10 @@ static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); 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) { \ #define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \
.bitrate = (_bitrate), \ .bitrate = (_bitrate), \
.flags = (_flags), \ .flags = (_flags), \
@ -148,12 +152,15 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
.cap = IEEE80211_HT_CAP_MAX_AMSDU | \ .cap = IEEE80211_HT_CAP_MAX_AMSDU | \
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
IEEE80211_HT_CAP_SGI_40 | \ IEEE80211_HT_CAP_SGI_40 | \
IEEE80211_HT_CAP_GRN_FLD | \
IEEE80211_HT_CAP_DSSSCCK40 | \ IEEE80211_HT_CAP_DSSSCCK40 | \
IEEE80211_HT_CAP_SM_PS, \ IEEE80211_HT_CAP_SM_PS, \
.ampdu_factor = 3, \ .ampdu_factor = 3, \
.ampdu_density = 6, \ .ampdu_density = 6, \
.mcs = { \ .mcs = { \
.rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \ .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \
.rx_highest = cpu_to_le16(300), \
.tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
}, \ }, \
} }
@ -174,8 +181,31 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
}; };
static void ar9170_tx(struct ar9170 *ar); static void ar9170_tx(struct ar9170 *ar);
static bool ar9170_tx_ampdu(struct ar9170 *ar);
#ifdef AR9170_QUEUE_DEBUG static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
{
return le16_to_cpu(hdr->seq_ctrl) >> 4;
}
static inline u16 ar9170_get_seq(struct sk_buff *skb)
{
struct ar9170_tx_control *txc = (void *) skb->data;
return ar9170_get_seq_h((void *) txc->frame_data);
}
static inline u16 ar9170_get_tid(struct sk_buff *skb)
{
struct ar9170_tx_control *txc = (void *) skb->data;
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
}
#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)
static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
{ {
struct ar9170_tx_control *txc = (void *) skb->data; struct ar9170_tx_control *txc = (void *) skb->data;
@ -183,10 +213,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
struct ieee80211_hdr *hdr = (void *) txc->frame_data; struct ieee80211_hdr *hdr = (void *) txc->frame_data;
printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x " printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d "
"mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n", "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
ieee80211_get_DA(hdr), arinfo->flags, ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr),
le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control), le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
jiffies_to_msecs(arinfo->timeout - jiffies)); jiffies_to_msecs(arinfo->timeout - jiffies));
} }
@ -210,7 +240,9 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
"mismatch %d != %d\n", skb_queue_len(queue), i); "mismatch %d != %d\n", skb_queue_len(queue), i);
printk(KERN_DEBUG "---[ end ]---\n"); printk(KERN_DEBUG "---[ end ]---\n");
} }
#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */
#ifdef AR9170_QUEUE_DEBUG
static void ar9170_dump_txqueue(struct ar9170 *ar, static void ar9170_dump_txqueue(struct ar9170 *ar,
struct sk_buff_head *queue) struct sk_buff_head *queue)
{ {
@ -220,7 +252,9 @@ static void ar9170_dump_txqueue(struct ar9170 *ar,
__ar9170_dump_txqueue(ar, queue); __ar9170_dump_txqueue(ar, queue);
spin_unlock_irqrestore(&queue->lock, flags); spin_unlock_irqrestore(&queue->lock, flags);
} }
#endif /* AR9170_QUEUE_DEBUG */
#ifdef AR9170_QUEUE_STOP_DEBUG
static void __ar9170_dump_txstats(struct ar9170 *ar) static void __ar9170_dump_txstats(struct ar9170 *ar)
{ {
int i; int i;
@ -229,20 +263,27 @@ static void __ar9170_dump_txstats(struct ar9170 *ar)
wiphy_name(ar->hw->wiphy)); wiphy_name(ar->hw->wiphy));
for (i = 0; i < __AR9170_NUM_TXQ; i++) for (i = 0; i < __AR9170_NUM_TXQ; i++)
printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n", printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d "
wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit, " stopped:%d\n", wiphy_name(ar->hw->wiphy), i,
ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i])); ar->tx_stats[i].limit, ar->tx_stats[i].len,
skb_queue_len(&ar->tx_status[i]),
ieee80211_queue_stopped(ar->hw, i));
} }
#endif /* AR9170_QUEUE_STOP_DEBUG */
static void ar9170_dump_txstats(struct ar9170 *ar) #ifdef AR9170_TXAGG_DEBUG
static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ar->tx_stats_lock, flags); spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags);
__ar9170_dump_txstats(ar); printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n",
spin_unlock_irqrestore(&ar->tx_stats_lock, flags); wiphy_name(ar->hw->wiphy));
__ar9170_dump_txqueue(ar, &ar->tx_status_ampdu);
spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags);
} }
#endif /* AR9170_QUEUE_DEBUG */
#endif /* AR9170_TXAGG_DEBUG */
/* caller must guarantee exclusive access for _bin_ queue. */ /* caller must guarantee exclusive access for _bin_ queue. */
static void ar9170_recycle_expired(struct ar9170 *ar, static void ar9170_recycle_expired(struct ar9170 *ar,
@ -315,6 +356,70 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
ieee80211_tx_status_irqsafe(ar->hw, 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_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);
ar->tx_ampdu_pending--;
if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending)
ar9170_tx_ampdu(ar);
}
void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb) void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
{ {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@ -336,7 +441,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
spin_unlock_irqrestore(&ar->tx_stats_lock, flags); spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) { if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
dev_kfree_skb_any(skb); ar9170_tx_ampdu_callback(ar, skb);
} else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) { } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
arinfo->timeout = jiffies + arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT); msecs_to_jiffies(AR9170_TX_TIMEOUT);
@ -420,6 +525,38 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
return NULL; 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. * This worker tries to keeps an maintain tx_status queues.
* So we can guarantee that incoming tx_status reports are * So we can guarantee that incoming tx_status reports are
@ -456,6 +593,8 @@ static void ar9170_tx_janitor(struct work_struct *work)
resched = true; resched = true;
} }
ar9170_tx_fake_ampdu_status(ar);
if (resched) if (resched)
queue_delayed_work(ar->hw->workqueue, queue_delayed_work(ar->hw->workqueue,
&ar->tx_janitor, &ar->tx_janitor,
@ -528,8 +667,15 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
break; break;
case 0xc4: case 0xc4:
/* BlockACK bitmap */
break;
case 0xc5: case 0xc5:
/* BlockACK events */ /* 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; break;
case 0xc6: case 0xc6:
@ -1098,6 +1244,10 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */
AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */
/* set sane AMPDU defaults */
ar->global_ampdu_density = 6;
ar->global_ampdu_factor = 3;
ar->bad_hw_nagger = jiffies; ar->bad_hw_nagger = jiffies;
err = ar->open(ar); err = ar->open(ar);
@ -1143,6 +1293,7 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
flush_workqueue(ar->hw->workqueue); flush_workqueue(ar->hw->workqueue);
cancel_delayed_work_sync(&ar->tx_janitor); cancel_delayed_work_sync(&ar->tx_janitor);
cancel_delayed_work_sync(&ar->led_work);
cancel_work_sync(&ar->filter_config_work); cancel_work_sync(&ar->filter_config_work);
cancel_work_sync(&ar->beacon_work); cancel_work_sync(&ar->beacon_work);
mutex_lock(&ar->mutex); mutex_lock(&ar->mutex);
@ -1159,9 +1310,40 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
skb_queue_purge(&ar->tx_pending[i]); skb_queue_purge(&ar->tx_pending[i]);
skb_queue_purge(&ar->tx_status[i]); skb_queue_purge(&ar->tx_status[i]);
} }
skb_queue_purge(&ar->tx_status_ampdu);
mutex_unlock(&ar->mutex); 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) static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
{ {
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
@ -1230,6 +1412,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK; arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
goto out; goto out;
} }
@ -1360,6 +1543,159 @@ 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); 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.
*/
if (likely(skb_peek_tail(&agg)))
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) static void ar9170_tx(struct ar9170 *ar)
{ {
struct sk_buff *skb; struct sk_buff *skb;
@ -1384,11 +1720,17 @@ static void ar9170_tx(struct ar9170 *ar)
printk(KERN_DEBUG "%s: queue %d full\n", printk(KERN_DEBUG "%s: queue %d full\n",
wiphy_name(ar->hw->wiphy), i); wiphy_name(ar->hw->wiphy), i);
__ar9170_dump_txstats(ar); printk(KERN_DEBUG "%s: stuck frames: ===> \n",
printk(KERN_DEBUG "stuck frames: ===> \n"); wiphy_name(ar->hw->wiphy));
ar9170_dump_txqueue(ar, &ar->tx_pending[i]); ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
ar9170_dump_txqueue(ar, &ar->tx_status[i]); ar9170_dump_txqueue(ar, &ar->tx_status[i]);
#endif /* AR9170_QUEUE_DEBUG */ #endif /* AR9170_QUEUE_DEBUG */
#ifdef AR9170_QUEUE_STOP_DEBUG
printk(KERN_DEBUG "%s: stop queue %d\n",
wiphy_name(ar->hw->wiphy), i);
__ar9170_dump_txstats(ar);
#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_stop_queue(ar->hw, i); ieee80211_stop_queue(ar->hw, i);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags); spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
continue; continue;
@ -1403,8 +1745,6 @@ static void ar9170_tx(struct ar9170 *ar)
"remaining slots:%d, needed:%d\n", "remaining slots:%d, needed:%d\n",
wiphy_name(ar->hw->wiphy), i, remaining_space, wiphy_name(ar->hw->wiphy), i, remaining_space,
frames); frames);
ar9170_dump_txstats(ar);
#endif /* AR9170_QUEUE_DEBUG */ #endif /* AR9170_QUEUE_DEBUG */
frames = remaining_space; frames = remaining_space;
} }
@ -1432,6 +1772,9 @@ static void ar9170_tx(struct ar9170 *ar)
arinfo->timeout = jiffies + arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT); msecs_to_jiffies(AR9170_TX_TIMEOUT);
if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
ar->tx_ampdu_pending++;
#ifdef AR9170_QUEUE_DEBUG #ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: send frame q:%d =>\n", printk(KERN_DEBUG "%s: send frame q:%d =>\n",
wiphy_name(ar->hw->wiphy), i); wiphy_name(ar->hw->wiphy), i);
@ -1440,6 +1783,9 @@ static void ar9170_tx(struct ar9170 *ar)
err = ar->tx(ar, skb); err = ar->tx(ar, skb);
if (unlikely(err)) { if (unlikely(err)) {
if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
ar->tx_ampdu_pending--;
frames_failed++; frames_failed++;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} else { } else {
@ -1461,13 +1807,18 @@ static void ar9170_tx(struct ar9170 *ar)
if (unlikely(frames_failed)) { if (unlikely(frames_failed)) {
#ifdef AR9170_QUEUE_DEBUG #ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: frames failed =>\n", printk(KERN_DEBUG "%s: frames failed %d =>\n",
wiphy_name(ar->hw->wiphy), frames_failed); wiphy_name(ar->hw->wiphy), frames_failed);
#endif /* AR9170_QUEUE_DEBUG */ #endif /* AR9170_QUEUE_DEBUG */
spin_lock_irqsave(&ar->tx_stats_lock, flags); spin_lock_irqsave(&ar->tx_stats_lock, flags);
ar->tx_stats[i].len -= frames_failed; ar->tx_stats[i].len -= frames_failed;
ar->tx_stats[i].count -= frames_failed; ar->tx_stats[i].count -= frames_failed;
#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); ieee80211_wake_queue(ar->hw, i);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags); spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
} }
@ -1479,6 +1830,90 @@ static void ar9170_tx(struct ar9170 *ar)
msecs_to_jiffies(AR9170_JANITOR_DELAY)); 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) int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{ {
struct ar9170 *ar = hw->priv; struct ar9170 *ar = hw->priv;
@ -1492,8 +1927,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_AMPDU) { if (info->flags & IEEE80211_TX_CTL_AMPDU) {
/* drop frame, we do not allow TX A-MPDU aggregation yet. */ bool run = ar9170_tx_ampdu_queue(ar, skb);
goto err_free;
if (run || !ar->tx_ampdu_pending)
ar9170_tx_ampdu(ar);
} else { } else {
unsigned int queue = skb_get_queue_mapping(skb); unsigned int queue = skb_get_queue_mapping(skb);
@ -1931,6 +2368,53 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
enum sta_notify_cmd cmd, enum sta_notify_cmd cmd,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
struct ar9170 *ar = hw->priv;
struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
unsigned int i;
switch (cmd) {
case STA_NOTIFY_ADD:
memset(sta_info, 0, sizeof(*sta_info));
if (!sta->ht_cap.ht_supported)
break;
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].retry = 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);
break;
case STA_NOTIFY_REMOVE:
if (!sta->ht_cap.ht_supported)
break;
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);
}
break;
default:
break;
}
if (IS_STARTED(ar) && ar->filter_changed)
queue_work(ar->hw->workqueue, &ar->filter_config_work);
} }
static int ar9170_get_stats(struct ieee80211_hw *hw, static int ar9170_get_stats(struct ieee80211_hw *hw,
@ -1985,18 +2469,65 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn) 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) { 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(hw, 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(hw, 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_START:
case IEEE80211_AMPDU_RX_STOP: case IEEE80211_AMPDU_RX_STOP:
/* /* Handled by firmware */
* Something goes wrong -- RX locks up break;
* after a while of receiving aggregated
* frames -- not enabling for now.
*/
return -EOPNOTSUPP;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
return 0;
} }
static const struct ieee80211_ops ar9170_ops = { static const struct ieee80211_ops ar9170_ops = {
@ -2045,6 +2576,8 @@ void *ar9170_alloc(size_t priv_size)
mutex_init(&ar->mutex); mutex_init(&ar->mutex);
spin_lock_init(&ar->cmdlock); spin_lock_init(&ar->cmdlock);
spin_lock_init(&ar->tx_stats_lock); 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++) { for (i = 0; i < __AR9170_NUM_TXQ; i++) {
skb_queue_head_init(&ar->tx_status[i]); skb_queue_head_init(&ar->tx_status[i]);
skb_queue_head_init(&ar->tx_pending[i]); skb_queue_head_init(&ar->tx_pending[i]);
@ -2053,6 +2586,7 @@ void *ar9170_alloc(size_t priv_size)
INIT_WORK(&ar->filter_config_work, ar9170_set_filters); INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
INIT_WORK(&ar->beacon_work, ar9170_new_beacon); INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor); 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 */ /* all hw supports 2.4 GHz, so set channel to 1 by default */
ar->channel = &ar9170_2ghz_chantable[0]; ar->channel = &ar9170_2ghz_chantable[0];
@ -2066,6 +2600,13 @@ void *ar9170_alloc(size_t priv_size)
IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM; IEEE80211_HW_NOISE_DBM;
if (modparam_ht) {
ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
} else {
ar9170_band_2GHz.ht_cap.ht_supported = false;
ar9170_band_5GHz.ht_cap.ht_supported = false;
}
ar->hw->queues = __AR9170_NUM_TXQ; ar->hw->queues = __AR9170_NUM_TXQ;
ar->hw->extra_tx_headroom = 8; ar->hw->extra_tx_headroom = 8;
ar->hw->sta_data_size = sizeof(struct ar9170_sta_info); ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
@ -2087,10 +2628,10 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
{ {
#define RW 8 /* number of words to read at once */ #define RW 8 /* number of words to read at once */
#define RB (sizeof(u32) * RW) #define RB (sizeof(u32) * RW)
DECLARE_MAC_BUF(mbuf);
u8 *eeprom = (void *)&ar->eeprom; u8 *eeprom = (void *)&ar->eeprom;
u8 *addr = ar->eeprom.mac_address; u8 *addr = ar->eeprom.mac_address;
__le32 offsets[RW]; __le32 offsets[RW];
unsigned int rx_streams, tx_streams, tx_params = 0;
int i, j, err, bands = 0; int i, j, err, bands = 0;
BUILD_BUG_ON(sizeof(ar->eeprom) & 3); BUILD_BUG_ON(sizeof(ar->eeprom) & 3);
@ -2127,6 +2668,20 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz;
bands++; bands++;
} }
rx_streams = hweight8(ar->eeprom.rx_mask);
tx_streams = hweight8(ar->eeprom.tx_mask);
if (rx_streams != tx_streams)
tx_params = IEEE80211_HT_MCS_TX_RX_DIFF;
if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS)
tx_params = (tx_streams - 1) <<
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params;
/* /*
* I measured this, a bandswitch takes roughly * I measured this, a bandswitch takes roughly
* 135 ms and a frequency switch about 80. * 135 ms and a frequency switch about 80.

View File

@ -339,9 +339,9 @@
#define AR5K_SISR2 0x008c /* Register Address [5211+] */ #define AR5K_SISR2 0x008c /* Register Address [5211+] */
#define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ #define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
#define AR5K_SISR2_QCU_TXURN_S 0 #define AR5K_SISR2_QCU_TXURN_S 0
#define AR5K_SISR2_MCABT 0x00100000 /* Master Cycle Abort */ #define AR5K_SISR2_MCABT 0x00010000 /* Master Cycle Abort */
#define AR5K_SISR2_SSERR 0x00200000 /* Signaled System Error */ #define AR5K_SISR2_SSERR 0x00020000 /* Signaled System Error */
#define AR5K_SISR2_DPERR 0x00400000 /* Bus parity error */ #define AR5K_SISR2_DPERR 0x00040000 /* Bus parity error */
#define AR5K_SISR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SISR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */ #define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */
#define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */ #define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */
@ -430,9 +430,9 @@
#define AR5K_SIMR2 0x00ac /* Register Address [5211+] */ #define AR5K_SIMR2 0x00ac /* Register Address [5211+] */
#define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */ #define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
#define AR5K_SIMR2_QCU_TXURN_S 0 #define AR5K_SIMR2_QCU_TXURN_S 0
#define AR5K_SIMR2_MCABT 0x00100000 /* Master Cycle Abort */ #define AR5K_SIMR2_MCABT 0x00010000 /* Master Cycle Abort */
#define AR5K_SIMR2_SSERR 0x00200000 /* Signaled System Error */ #define AR5K_SIMR2_SSERR 0x00020000 /* Signaled System Error */
#define AR5K_SIMR2_DPERR 0x00400000 /* Bus parity error */ #define AR5K_SIMR2_DPERR 0x00040000 /* Bus parity error */
#define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */ #define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */ #define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */
#define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */ #define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */

View File

@ -164,7 +164,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define WME_NUM_TID 16 #define WME_NUM_TID 16
#define ATH_TXBUF 512 #define ATH_TXBUF 512
#define ATH_TXMAXTRY 13 #define ATH_TXMAXTRY 13
#define ATH_11N_TXMAXTRY 10
#define ATH_MGT_TXMAXTRY 4 #define ATH_MGT_TXMAXTRY 4
#define WME_BA_BMP_SIZE 64 #define WME_BA_BMP_SIZE 64
#define WME_MAX_BA WME_BA_BMP_SIZE #define WME_MAX_BA WME_BA_BMP_SIZE
@ -226,6 +225,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) #define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) #define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)])
#define ATH_TX_COMPLETE_POLL_INT 1000
enum ATH_AGGR_STATUS { enum ATH_AGGR_STATUS {
ATH_AGGR_DONE, ATH_AGGR_DONE,
ATH_AGGR_BAW_CLOSED, ATH_AGGR_BAW_CLOSED,
@ -241,6 +242,7 @@ struct ath_txq {
u8 axq_aggr_depth; u8 axq_aggr_depth;
u32 axq_totalqueued; u32 axq_totalqueued;
bool stopped; bool stopped;
bool axq_tx_inprogress;
struct ath_buf *axq_linkbuf; struct ath_buf *axq_linkbuf;
/* first desc of the last descriptor that contains CTS */ /* first desc of the last descriptor that contains CTS */
@ -291,12 +293,28 @@ struct ath_tx_control {
#define ATH_TX_XRETRY 0x02 #define ATH_TX_XRETRY 0x02
#define ATH_TX_BAR 0x04 #define ATH_TX_BAR 0x04
#define ATH_RSSI_LPF_LEN 10
#define RSSI_LPF_THRESHOLD -20
#define ATH9K_RSSI_BAD 0x80
#define ATH_RSSI_EP_MULTIPLIER (1<<7)
#define ATH_EP_MUL(x, mul) ((x) * (mul))
#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
#define ATH_LPF_RSSI(x, y, len) \
((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
#define ATH_RSSI_LPF(x, y) do { \
if ((y) >= RSSI_LPF_THRESHOLD) \
x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
} while (0)
#define ATH_EP_RND(x, mul) \
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
struct ath_node { struct ath_node {
struct ath_softc *an_sc; struct ath_softc *an_sc;
struct ath_atx_tid tid[WME_NUM_TID]; struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC]; struct ath_atx_ac ac[WME_NUM_AC];
u16 maxampdu; u16 maxampdu;
u8 mpdudensity; u8 mpdudensity;
int last_rssi;
}; };
struct ath_tx { struct ath_tx {
@ -541,6 +559,7 @@ struct ath_softc {
spinlock_t sc_resetlock; spinlock_t sc_resetlock;
spinlock_t sc_serial_rw; spinlock_t sc_serial_rw;
spinlock_t ani_lock; spinlock_t ani_lock;
spinlock_t sc_pm_lock;
struct mutex mutex; struct mutex mutex;
u8 curbssid[ETH_ALEN]; u8 curbssid[ETH_ALEN];
@ -557,7 +576,7 @@ struct ath_softc {
u32 keymax; u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX); DECLARE_BITMAP(keymap, ATH_KEYMAX);
u8 splitmic; u8 splitmic;
atomic_t ps_usecount; unsigned long ps_usecount;
enum ath9k_int imask; enum ath9k_int imask;
enum ath9k_ht_extprotspacing ht_extprotspacing; enum ath9k_ht_extprotspacing ht_extprotspacing;
enum ath9k_ht_macmode tx_chan_width; enum ath9k_ht_macmode tx_chan_width;
@ -590,6 +609,7 @@ struct ath_softc {
#endif #endif
struct ath_bus_ops *bus_ops; struct ath_bus_ops *bus_ops;
struct ath_beacon_config cur_beacon_conf; struct ath_beacon_config cur_beacon_conf;
struct delayed_work tx_complete_work;
}; };
struct ath_wiphy { struct ath_wiphy {
@ -654,27 +674,8 @@ static inline int ath_ahb_init(void) { return 0; };
static inline void ath_ahb_exit(void) {}; static inline void ath_ahb_exit(void) {};
#endif #endif
static inline void ath9k_ps_wakeup(struct ath_softc *sc) void ath9k_ps_wakeup(struct ath_softc *sc);
{ void ath9k_ps_restore(struct ath_softc *sc);
if (atomic_inc_return(&sc->ps_usecount) == 1)
if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
}
}
static inline void ath9k_ps_restore(struct ath_softc *sc)
{
if (atomic_dec_and_test(&sc->ps_usecount))
if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
!(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
SC_OP_WAIT_FOR_CAB |
SC_OP_WAIT_FOR_PSPOLL_DATA |
SC_OP_WAIT_FOR_TX_ACK)))
ath9k_hw_setpower(sc->sc_ah,
sc->sc_ah->restore_mode);
}
void ath9k_set_bssid_mask(struct ieee80211_hw *hw); void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
int ath9k_wiphy_add(struct ath_softc *sc); int ath9k_wiphy_add(struct ath_softc *sc);
@ -690,6 +691,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
struct ath_wiphy *selected); struct ath_wiphy *selected);
bool ath9k_wiphy_scanning(struct ath_softc *sc); bool ath9k_wiphy_scanning(struct ath_softc *sc);
void ath9k_wiphy_work(struct work_struct *work); void ath9k_wiphy_work(struct work_struct *work);
bool ath9k_all_wiphys_idle(struct ath_softc *sc);
void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val); void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val);
unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset); unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset);

View File

@ -691,15 +691,22 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah) void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
{ {
int i, j; int i, j;
s16 noise_floor;
if (AR_SREV_9280(ah))
noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
else if (AR_SREV_9285(ah))
noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
else
noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
for (i = 0; i < NUM_NF_READINGS; i++) { for (i = 0; i < NUM_NF_READINGS; i++) {
ah->nfCalHist[i].currIndex = 0; ah->nfCalHist[i].currIndex = 0;
ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; ah->nfCalHist[i].privNF = noise_floor;
ah->nfCalHist[i].invalidNFcount = ah->nfCalHist[i].invalidNFcount =
AR_PHY_CCA_FILTERWINDOW_LENGTH; AR_PHY_CCA_FILTERWINDOW_LENGTH;
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
ah->nfCalHist[i].nfCalBuffer[j] = ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
AR_PHY_CCA_MAX_GOOD_VALUE;
} }
} }
} }

View File

@ -25,7 +25,9 @@ extern const struct ath9k_percal_data adc_dc_cal_multi_sample;
extern const struct ath9k_percal_data adc_dc_cal_single_sample; extern const struct ath9k_percal_data adc_dc_cal_single_sample;
extern const struct ath9k_percal_data adc_init_dc_cal; extern const struct ath9k_percal_data adc_init_dc_cal;
#define AR_PHY_CCA_MAX_GOOD_VALUE -85 #define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE -85
#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE -112
#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE -118
#define AR_PHY_CCA_MAX_HIGH_VALUE -62 #define AR_PHY_CCA_MAX_HIGH_VALUE -62
#define AR_PHY_CCA_MIN_BAD_VALUE -140 #define AR_PHY_CCA_MIN_BAD_VALUE -140
#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 #define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3

View File

@ -1208,6 +1208,19 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
pModal->xatten2Margin[0]); pModal->xatten2Margin[0]);
REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
/* Set the block 1 value to block 0 value */
REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
pModal->bswMargin[0]);
REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
pModal->xatten2Margin[0]);
REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
AR_PHY_GAIN_2GHZ_XATTEN2_DB,
pModal->xatten2Db[0]);
} }
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
@ -1215,6 +1228,11 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
if (AR_SREV_9285_11(ah)) if (AR_SREV_9285_11(ah))
REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
} }
@ -1239,7 +1257,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0);
/* Initialize Ant Diversity settings from EEPROM */ /* Initialize Ant Diversity settings from EEPROM */
if (pModal->version == 3) { if (pModal->version >= 3) {
ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf);
ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf);
regVal = REG_READ(ah, 0x99ac); regVal = REG_READ(ah, 0x99ac);

View File

@ -2728,7 +2728,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
return true; return true;
} }
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
enum ath9k_power_mode mode)
{ {
int status = true, setChip = true; int status = true, setChip = true;
static const char *modes[] = { static const char *modes[] = {
@ -2762,6 +2763,55 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
return status; return status;
} }
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
{
unsigned long flags;
bool ret;
spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags);
ret = ath9k_hw_setpower_nolock(ah, mode);
spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags);
return ret;
}
void ath9k_ps_wakeup(struct ath_softc *sc)
{
unsigned long flags;
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if (++sc->ps_usecount != 1)
goto unlock;
if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
}
unlock:
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
}
void ath9k_ps_restore(struct ath_softc *sc)
{
unsigned long flags;
spin_lock_irqsave(&sc->sc_pm_lock, flags);
if (--sc->ps_usecount != 0)
goto unlock;
if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
!(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
SC_OP_WAIT_FOR_CAB |
SC_OP_WAIT_FOR_PSPOLL_DATA |
SC_OP_WAIT_FOR_TX_ACK)))
ath9k_hw_setpower_nolock(sc->sc_ah,
sc->sc_ah->restore_mode);
unlock:
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
}
/* /*
* Helper for ASPM support. * Helper for ASPM support.
* *
@ -3305,7 +3355,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
} }
if (eeval & AR5416_OPFLAGS_11G) { if (eeval & AR5416_OPFLAGS_11G) {
set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
set_bit(ATH9K_MODE_11G, pCap->wireless_modes); set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
if (ah->config.ht_enable) { if (ah->config.ht_enable) {
if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
@ -3791,19 +3840,14 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
void ath9k_hw_reset_tsf(struct ath_hw *ah) void ath9k_hw_reset_tsf(struct ath_hw *ah)
{ {
int count; ath9k_ps_wakeup(ah->ah_sc);
if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0,
AH_TSF_WRITE_TIMEOUT))
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
"AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
count = 0;
while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
count++;
if (count > 10) {
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
"AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
break;
}
udelay(10);
}
REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
ath9k_ps_restore(ah->ah_sc);
} }
bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)

View File

@ -95,6 +95,7 @@
#define MAX_RATE_POWER 63 #define MAX_RATE_POWER 63
#define AH_WAIT_TIMEOUT 100000 /* (us) */ #define AH_WAIT_TIMEOUT 100000 /* (us) */
#define AH_TSF_WRITE_TIMEOUT 100 /* (us) */
#define AH_TIME_QUANTUM 10 #define AH_TIME_QUANTUM 10
#define AR_KEYTABLE_SIZE 128 #define AR_KEYTABLE_SIZE 128
#define POWER_UP_TIME 200000 #define POWER_UP_TIME 200000
@ -113,15 +114,14 @@
enum wireless_mode { enum wireless_mode {
ATH9K_MODE_11A = 0, ATH9K_MODE_11A = 0,
ATH9K_MODE_11B = 2, ATH9K_MODE_11G,
ATH9K_MODE_11G = 3, ATH9K_MODE_11NA_HT20,
ATH9K_MODE_11NA_HT20 = 6, ATH9K_MODE_11NG_HT20,
ATH9K_MODE_11NG_HT20 = 7, ATH9K_MODE_11NA_HT40PLUS,
ATH9K_MODE_11NA_HT40PLUS = 8, ATH9K_MODE_11NA_HT40MINUS,
ATH9K_MODE_11NA_HT40MINUS = 9, ATH9K_MODE_11NG_HT40PLUS,
ATH9K_MODE_11NG_HT40PLUS = 10, ATH9K_MODE_11NG_HT40MINUS,
ATH9K_MODE_11NG_HT40MINUS = 11, ATH9K_MODE_MAX,
ATH9K_MODE_MAX
}; };
enum ath9k_hw_caps { enum ath9k_hw_caps {

View File

@ -2782,7 +2782,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008338, 0x00ff0000 }, { 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 }, { 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff }, { 0x00008340, 0x000107ff },
{ 0x00008344, 0x00581043 }, { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 }, { 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafa68e30 }, { 0x0000980c, 0xafa68e30 },
{ 0x00009810, 0xfd14e000 }, { 0x00009810, 0xfd14e000 },
@ -3439,7 +3439,7 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
{0x00004044, 0x00000000 }, {0x00004044, 0x00000000 },
}; };
/* AR9285 */ /* AR9285 Revsion 10*/
static const u_int32_t ar9285Modes_9285[][6] = { static const u_int32_t ar9285Modes_9285[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@ -3955,7 +3955,7 @@ static const u_int32_t ar9285Common_9285[][2] = {
{ 0x00008338, 0x00000000 }, { 0x00008338, 0x00000000 },
{ 0x0000833c, 0x00000000 }, { 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 }, { 0x00008340, 0x00010380 },
{ 0x00008344, 0x00581043 }, { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 }, { 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 }, { 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 }, { 0x00009810, 0xfd14e000 },
@ -4121,8 +4121,9 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
{0x00004044, 0x00000000 }, {0x00004044, 0x00000000 },
}; };
/* AR9285 v1_2 PCI Register Writes. Created: 03/04/09 */ /* AR9285 v1_2 PCI Register Writes. Created: 04/13/09 */
static const u_int32_t ar9285Modes_9285_1_2[][6] = { static const u_int32_t ar9285Modes_9285_1_2[][6] = {
/* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
{ 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
@ -4139,6 +4140,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
{ 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 }, { 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
{ 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 }, { 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
{ 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
{ 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
{ 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
{ 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e }, { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
@ -4419,6 +4421,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 }, { 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
{ 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
{ 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 }, { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
{ 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
{ 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
{ 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
{ 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
@ -4618,7 +4621,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00008338, 0x00ff0000 }, { 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 }, { 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 }, { 0x00008340, 0x00010380 },
{ 0x00008344, 0x00581043 }, { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 }, { 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 }, { 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 }, { 0x00009810, 0xfd14e000 },
@ -4752,18 +4755,18 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
/* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 }, { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
{ 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
{ 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 }, { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
{ 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 }, { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
{ 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 }, { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
{ 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 }, { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
{ 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 }, { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
{ 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 }, { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
{ 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 }, { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
{ 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 }, { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
{ 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 }, { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
{ 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 }, { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
{ 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 }, { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
{ 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
{ 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
@ -4776,13 +4779,13 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
{ 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 }, { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
{ 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe }, { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
{ 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
{ 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 }, { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
{ 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
{ 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
{ 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
{ 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
{ 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce }, { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
{ 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce }, { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
}; };
static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = { static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {

View File

@ -825,13 +825,29 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); ds->ds_rxstat.rs_rssi = ATH9K_RSSI_BAD;
ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); ds->ds_rxstat.rs_rssi_ctl0 = ATH9K_RSSI_BAD;
ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); ds->ds_rxstat.rs_rssi_ctl1 = ATH9K_RSSI_BAD;
ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); ds->ds_rxstat.rs_rssi_ctl2 = ATH9K_RSSI_BAD;
ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); ds->ds_rxstat.rs_rssi_ext0 = ATH9K_RSSI_BAD;
ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); ds->ds_rxstat.rs_rssi_ext1 = ATH9K_RSSI_BAD;
ds->ds_rxstat.rs_rssi_ext2 = ATH9K_RSSI_BAD;
} else {
ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
AR_RxRSSIAnt00);
ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
AR_RxRSSIAnt01);
ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
AR_RxRSSIAnt02);
ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4,
AR_RxRSSIAnt10);
ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4,
AR_RxRSSIAnt11);
ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4,
AR_RxRSSIAnt12);
}
if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
else else

View File

@ -465,6 +465,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
sta->ht_cap.ampdu_factor); sta->ht_cap.ampdu_factor);
an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
an->last_rssi = ATH_RSSI_DUMMY_MARKER;
} }
} }
@ -1258,6 +1259,7 @@ void ath_detach(struct ath_softc *sc)
ath_deinit_leds(sc); ath_deinit_leds(sc);
cancel_work_sync(&sc->chan_work); cancel_work_sync(&sc->chan_work);
cancel_delayed_work_sync(&sc->wiphy_work); cancel_delayed_work_sync(&sc->wiphy_work);
cancel_delayed_work_sync(&sc->tx_complete_work);
for (i = 0; i < sc->num_sec_wiphy; i++) { for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i]; struct ath_wiphy *aphy = sc->sec_wiphy[i];
@ -1284,7 +1286,6 @@ void ath_detach(struct ath_softc *sc)
ath9k_hw_detach(sc->sc_ah); ath9k_hw_detach(sc->sc_ah);
ath9k_exit_debug(sc); ath9k_exit_debug(sc);
ath9k_ps_restore(sc);
} }
static int ath9k_reg_notifier(struct wiphy *wiphy, static int ath9k_reg_notifier(struct wiphy *wiphy,
@ -1315,6 +1316,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
spin_lock_init(&sc->sc_resetlock); spin_lock_init(&sc->sc_resetlock);
spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_serial_rw);
spin_lock_init(&sc->ani_lock); spin_lock_init(&sc->ani_lock);
spin_lock_init(&sc->sc_pm_lock);
mutex_init(&sc->mutex); mutex_init(&sc->mutex);
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
@ -1540,7 +1542,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->max_rates = 4; hw->max_rates = 4;
hw->channel_change_time = 5000; hw->channel_change_time = 5000;
hw->max_listen_interval = 10; hw->max_listen_interval = 10;
hw->max_rate_tries = ATH_11N_TXMAXTRY; /* Hardware supports 10 but we use 4 */
hw->max_rate_tries = 4;
hw->sta_data_size = sizeof(struct ath_node); hw->sta_data_size = sizeof(struct ath_node);
hw->vif_data_size = sizeof(struct ath_vif); hw->vif_data_size = sizeof(struct ath_vif);
@ -1977,6 +1980,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
ieee80211_wake_queues(hw); ieee80211_wake_queues(hw);
queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0);
mutex_unlock: mutex_unlock:
mutex_unlock(&sc->mutex); mutex_unlock(&sc->mutex);
@ -2096,8 +2101,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
ieee80211_stop_queues(hw);
if (ath9k_wiphy_started(sc)) { if (ath9k_wiphy_started(sc)) {
mutex_unlock(&sc->mutex); mutex_unlock(&sc->mutex);
return; /* another wiphy still in use */ return; /* another wiphy still in use */
@ -2255,9 +2258,28 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
struct ath_softc *sc = aphy->sc; struct ath_softc *sc = aphy->sc;
struct ieee80211_conf *conf = &hw->conf; struct ieee80211_conf *conf = &hw->conf;
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
bool all_wiphys_idle = false, disable_radio = false;
mutex_lock(&sc->mutex); mutex_lock(&sc->mutex);
/* Leave this as the first check */
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
spin_lock_bh(&sc->wiphy_lock);
all_wiphys_idle = ath9k_all_wiphys_idle(sc);
spin_unlock_bh(&sc->wiphy_lock);
if (conf->flags & IEEE80211_CONF_IDLE){
if (all_wiphys_idle)
disable_radio = true;
}
else if (all_wiphys_idle) {
ath_radio_enable(sc);
DPRINTF(sc, ATH_DBG_CONFIG,
"not-idle: enabling radio\n");
}
}
if (changed & IEEE80211_CONF_CHANGE_PS) { if (changed & IEEE80211_CONF_CHANGE_PS) {
if (conf->flags & IEEE80211_CONF_PS) { if (conf->flags & IEEE80211_CONF_PS) {
if (!(ah->caps.hw_caps & if (!(ah->caps.hw_caps &
@ -2325,6 +2347,11 @@ skip_chan_change:
if (changed & IEEE80211_CONF_CHANGE_POWER) if (changed & IEEE80211_CONF_CHANGE_POWER)
sc->config.txpowlimit = 2 * conf->power_level; sc->config.txpowlimit = 2 * conf->power_level;
if (disable_radio) {
DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n");
ath_radio_disable(sc);
}
mutex_unlock(&sc->mutex); mutex_unlock(&sc->mutex);
return 0; return 0;

File diff suppressed because it is too large Load Diff

View File

@ -112,8 +112,6 @@ struct ath_rate_table {
u8 short_preamble; u8 short_preamble;
u8 dot11rate; u8 dot11rate;
u8 ctrl_rate; u8 ctrl_rate;
int8_t rssi_ack_validmin;
int8_t rssi_ack_deltamin;
u8 base_index; u8 base_index;
u8 cw40index; u8 cw40index;
u8 sgi_index; u8 sgi_index;
@ -121,15 +119,9 @@ struct ath_rate_table {
u32 max_4ms_framelen; u32 max_4ms_framelen;
} info[RATE_TABLE_SIZE]; } info[RATE_TABLE_SIZE];
u32 probe_interval; u32 probe_interval;
u32 rssi_reduce_interval;
u8 initial_ratemax; u8 initial_ratemax;
}; };
struct ath_tx_ratectrl_state {
int8_t rssi_thres; /* required rssi for this rate (dB) */
u8 per; /* recent estimate of packet error rate (%) */
};
struct ath_rateset { struct ath_rateset {
u8 rs_nrates; u8 rs_nrates;
u8 rs_rates[ATH_RATE_MAX]; u8 rs_rates[ATH_RATE_MAX];
@ -138,22 +130,14 @@ struct ath_rateset {
/** /**
* struct ath_rate_priv - Rate Control priv data * struct ath_rate_priv - Rate Control priv data
* @state: RC state * @state: RC state
* @rssi_last: last ACK rssi
* @rssi_last_lookup: last ACK rssi used for lookup
* @rssi_last_prev: previous last ACK rssi
* @rssi_last_prev2: 2nd previous last ACK rssi
* @rssi_sum_cnt: count of rssi_sum for averaging
* @rssi_sum_rate: rate that we are averaging
* @rssi_sum: running sum of rssi for averaging
* @probe_rate: rate we are probing at * @probe_rate: rate we are probing at
* @rssi_time: msec timestamp for last ack rssi
* @rssi_down_time: msec timestamp for last down step
* @probe_time: msec timestamp for last probe * @probe_time: msec timestamp for last probe
* @hw_maxretry_pktcnt: num of packets since we got HW max retry error * @hw_maxretry_pktcnt: num of packets since we got HW max retry error
* @max_valid_rate: maximum number of valid rate * @max_valid_rate: maximum number of valid rate
* @per_down_time: msec timestamp for last PER down step * @per_down_time: msec timestamp for last PER down step
* @valid_phy_ratecnt: valid rate count * @valid_phy_ratecnt: valid rate count
* @rate_max_phy: phy index for the max rate * @rate_max_phy: phy index for the max rate
* @per: PER for every valid rate in %
* @probe_interval: interval for ratectrl to probe for other rates * @probe_interval: interval for ratectrl to probe for other rates
* @prev_data_rix: rate idx of last data frame * @prev_data_rix: rate idx of last data frame
* @ht_cap: HT capabilities * @ht_cap: HT capabilities
@ -161,13 +145,6 @@ struct ath_rateset {
* @neg_ht_rates: Negotiated HT rates * @neg_ht_rates: Negotiated HT rates
*/ */
struct ath_rate_priv { struct ath_rate_priv {
int8_t rssi_last;
int8_t rssi_last_lookup;
int8_t rssi_last_prev;
int8_t rssi_last_prev2;
int32_t rssi_sum_cnt;
int32_t rssi_sum_rate;
int32_t rssi_sum;
u8 rate_table_size; u8 rate_table_size;
u8 probe_rate; u8 probe_rate;
u8 hw_maxretry_pktcnt; u8 hw_maxretry_pktcnt;
@ -177,14 +154,12 @@ struct ath_rate_priv {
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
u8 rate_max_phy; u8 rate_max_phy;
u32 rssi_time; u8 per[RATE_TABLE_SIZE];
u32 rssi_down_time;
u32 probe_time; u32 probe_time;
u32 per_down_time; u32 per_down_time;
u32 probe_interval; u32 probe_interval;
u32 prev_data_rix; u32 prev_data_rix;
u32 tx_triglevel_max; u32 tx_triglevel_max;
struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE];
struct ath_rateset neg_rates; struct ath_rateset neg_rates;
struct ath_rateset neg_ht_rates; struct ath_rateset neg_ht_rates;
struct ath_rate_softc *asc; struct ath_rate_softc *asc;

View File

@ -145,6 +145,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
u8 ratecode; u8 ratecode;
__le16 fc; __le16 fc;
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct ieee80211_sta *sta;
struct ath_node *an;
int last_rssi = ATH_RSSI_DUMMY_MARKER;
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control; fc = hdr->frame_control;
@ -229,11 +233,30 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
} }
} }
rcu_read_lock();
sta = ieee80211_find_sta(sc->hw, hdr->addr2);
if (sta) {
an = (struct ath_node *) sta->drv_priv;
if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
!ds->ds_rxstat.rs_moreaggr)
ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
last_rssi = an->last_rssi;
}
rcu_read_unlock();
if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi,
ATH_RSSI_EP_MULTIPLIER);
if (ds->ds_rxstat.rs_rssi < 0)
ds->ds_rxstat.rs_rssi = 0;
else if (ds->ds_rxstat.rs_rssi > 127)
ds->ds_rxstat.rs_rssi = 127;
rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
rx_status->band = hw->conf.channel->band; rx_status->band = hw->conf.channel->band;
rx_status->freq = hw->conf.channel->center_freq; rx_status->freq = hw->conf.channel->center_freq;
rx_status->noise = sc->ani.noise_floor; rx_status->noise = sc->ani.noise_floor;
rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi;
rx_status->antenna = ds->ds_rxstat.rs_antenna; rx_status->antenna = ds->ds_rxstat.rs_antenna;
/* /*

View File

@ -574,6 +574,7 @@
#define AR_D_GBL_IFS_SIFS 0x1030 #define AR_D_GBL_IFS_SIFS 0x1030
#define AR_D_GBL_IFS_SIFS_M 0x0000FFFF #define AR_D_GBL_IFS_SIFS_M 0x0000FFFF
#define AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR 0x000003AB
#define AR_D_GBL_IFS_SIFS_RESV0 0xFFFFFFFF #define AR_D_GBL_IFS_SIFS_RESV0 0xFFFFFFFF
#define AR_D_TXBLK_BASE 0x1038 #define AR_D_TXBLK_BASE 0x1038
@ -589,10 +590,12 @@
#define AR_D_GBL_IFS_SLOT 0x1070 #define AR_D_GBL_IFS_SLOT 0x1070
#define AR_D_GBL_IFS_SLOT_M 0x0000FFFF #define AR_D_GBL_IFS_SLOT_M 0x0000FFFF
#define AR_D_GBL_IFS_SLOT_RESV0 0xFFFF0000 #define AR_D_GBL_IFS_SLOT_RESV0 0xFFFF0000
#define AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR 0x00000420
#define AR_D_GBL_IFS_EIFS 0x10b0 #define AR_D_GBL_IFS_EIFS 0x10b0
#define AR_D_GBL_IFS_EIFS_M 0x0000FFFF #define AR_D_GBL_IFS_EIFS_M 0x0000FFFF
#define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000 #define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000
#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR 0x0000A5EB
#define AR_D_GBL_IFS_MISC 0x10f0 #define AR_D_GBL_IFS_MISC 0x10f0
#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007 #define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007
@ -738,6 +741,9 @@
#define AR_SREV_REVISION_9285_10 0 #define AR_SREV_REVISION_9285_10 0
#define AR_SREV_REVISION_9285_11 1 #define AR_SREV_REVISION_9285_11 1
#define AR_SREV_REVISION_9285_12 2 #define AR_SREV_REVISION_9285_12 2
#define AR_SREV_VERSION_9287 0x180
#define AR_SREV_REVISION_9287_10 0
#define AR_SREV_REVISION_9287_11 1
#define AR_SREV_5416(_ah) \ #define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@ -794,6 +800,21 @@
(AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \ (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
AR_SREV_REVISION_9285_12))) AR_SREV_REVISION_9285_12)))
#define AR_SREV_9287(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287))
#define AR_SREV_9287_10_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287))
#define AR_SREV_9287_10(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_10))
#define AR_SREV_9287_11(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_11))
#define AR_SREV_9287_11_OR_LATER(_ah) \
(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11)))
#define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RADIO_SREV_MAJOR 0xf0
#define AR_RAD5133_SREV_MAJOR 0xc0 #define AR_RAD5133_SREV_MAJOR 0xc0
#define AR_RAD2133_SREV_MAJOR 0xd0 #define AR_RAD2133_SREV_MAJOR 0xd0
@ -809,6 +830,9 @@
#define AR_AHB_PAGE_SIZE_1K 0x00000000 #define AR_AHB_PAGE_SIZE_1K 0x00000000
#define AR_AHB_PAGE_SIZE_2K 0x00000008 #define AR_AHB_PAGE_SIZE_2K 0x00000008
#define AR_AHB_PAGE_SIZE_4K 0x00000010 #define AR_AHB_PAGE_SIZE_4K 0x00000010
#define AR_AHB_CUSTOM_BURST_EN 0x000000C0
#define AR_AHB_CUSTOM_BURST_EN_S 6
#define AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL 3
#define AR_INTR_RTC_IRQ 0x00000001 #define AR_INTR_RTC_IRQ 0x00000001
#define AR_INTR_MAC_IRQ 0x00000002 #define AR_INTR_MAC_IRQ 0x00000002
@ -885,6 +909,7 @@ enum {
#define AR_NUM_GPIO 14 #define AR_NUM_GPIO 14
#define AR928X_NUM_GPIO 10 #define AR928X_NUM_GPIO 10
#define AR9285_NUM_GPIO 12 #define AR9285_NUM_GPIO 12
#define AR9287_NUM_GPIO 11
#define AR_GPIO_IN_OUT 0x4048 #define AR_GPIO_IN_OUT 0x4048
#define AR_GPIO_IN_VAL 0x0FFFC000 #define AR_GPIO_IN_VAL 0x0FFFC000
@ -893,6 +918,8 @@ enum {
#define AR928X_GPIO_IN_VAL_S 10 #define AR928X_GPIO_IN_VAL_S 10
#define AR9285_GPIO_IN_VAL 0x00FFF000 #define AR9285_GPIO_IN_VAL 0x00FFF000
#define AR9285_GPIO_IN_VAL_S 12 #define AR9285_GPIO_IN_VAL_S 12
#define AR9287_GPIO_IN_VAL 0x003FF800
#define AR9287_GPIO_IN_VAL_S 11
#define AR_GPIO_OE_OUT 0x404c #define AR_GPIO_OE_OUT 0x404c
#define AR_GPIO_OE_OUT_DRV 0x3 #define AR_GPIO_OE_OUT_DRV 0x3
@ -1154,6 +1181,33 @@ enum {
#define AR9285_AN_TOP4 0x7870 #define AR9285_AN_TOP4 0x7870
#define AR9285_AN_TOP4_DEFAULT 0x10142c00 #define AR9285_AN_TOP4_DEFAULT 0x10142c00
#define AR9287_AN_RF2G3_CH0 0x7808
#define AR9287_AN_RF2G3_CH1 0x785c
#define AR9287_AN_RF2G3_DB1 0xE0000000
#define AR9287_AN_RF2G3_DB1_S 29
#define AR9287_AN_RF2G3_DB2 0x1C000000
#define AR9287_AN_RF2G3_DB2_S 26
#define AR9287_AN_RF2G3_OB_CCK 0x03800000
#define AR9287_AN_RF2G3_OB_CCK_S 23
#define AR9287_AN_RF2G3_OB_PSK 0x00700000
#define AR9287_AN_RF2G3_OB_PSK_S 20
#define AR9287_AN_RF2G3_OB_QAM 0x000E0000
#define AR9287_AN_RF2G3_OB_QAM_S 17
#define AR9287_AN_RF2G3_OB_PAL_OFF 0x0001C000
#define AR9287_AN_RF2G3_OB_PAL_OFF_S 14
#define AR9287_AN_TXPC0 0x7898
#define AR9287_AN_TXPC0_TXPCMODE 0x0000C000
#define AR9287_AN_TXPC0_TXPCMODE_S 14
#define AR9287_AN_TXPC0_TXPCMODE_NORMAL 0
#define AR9287_AN_TXPC0_TXPCMODE_TEST 1
#define AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE 2
#define AR9287_AN_TXPC0_TXPCMODE_ATBTEST 3
#define AR9287_AN_TOP2 0x78b4
#define AR9287_AN_TOP2_XPABIAS_LVL 0xC0000000
#define AR9287_AN_TOP2_XPABIAS_LVL_S 30
#define AR_STA_ID0 0x8000 #define AR_STA_ID0 0x8000
#define AR_STA_ID1 0x8004 #define AR_STA_ID1 0x8004
#define AR_STA_ID1_SADH_MASK 0x0000FFFF #define AR_STA_ID1_SADH_MASK 0x0000FFFF
@ -1188,6 +1242,7 @@ enum {
#define AR_TIME_OUT_ACK_S 0 #define AR_TIME_OUT_ACK_S 0
#define AR_TIME_OUT_CTS 0x3FFF0000 #define AR_TIME_OUT_CTS 0x3FFF0000
#define AR_TIME_OUT_CTS_S 16 #define AR_TIME_OUT_CTS_S 16
#define AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR 0x16001D56
#define AR_RSSI_THR 0x8018 #define AR_RSSI_THR 0x8018
#define AR_RSSI_THR_MASK 0x000000FF #define AR_RSSI_THR_MASK 0x000000FF
@ -1203,6 +1258,7 @@ enum {
#define AR_USEC_TX_LAT_S 14 #define AR_USEC_TX_LAT_S 14
#define AR_USEC_RX_LAT 0x1F800000 #define AR_USEC_RX_LAT 0x1F800000
#define AR_USEC_RX_LAT_S 23 #define AR_USEC_RX_LAT_S 23
#define AR_USEC_ASYNC_FIFO_DUR 0x12e00074
#define AR_RESET_TSF 0x8020 #define AR_RESET_TSF 0x8020
#define AR_RESET_TSF_ONCE 0x01000000 #define AR_RESET_TSF_ONCE 0x01000000
@ -1468,6 +1524,10 @@ enum {
#define AR_SLP_MIB_CLEAR 0x00000001 #define AR_SLP_MIB_CLEAR 0x00000001
#define AR_SLP_MIB_PENDING 0x00000002 #define AR_SLP_MIB_PENDING 0x00000002
#define AR_MAC_PCU_LOGIC_ANALYZER 0x8264
#define AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768 0x20000000
#define AR_2040_MODE 0x8318 #define AR_2040_MODE 0x8318
#define AR_2040_JOINED_RX_CLEAR 0x00000001 #define AR_2040_JOINED_RX_CLEAR 0x00000001
@ -1485,6 +1545,39 @@ enum {
#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002 #define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002
#define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004 #define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004
#define AR_PCU_MISC_MODE2_RESERVED 0x00000038
#define AR_PCU_MISC_MODE2_ADHOC_MCAST_KEYID_ENABLE 0x00000040
#define AR_PCU_MISC_MODE2_CFP_IGNORE 0x00000080
#define AR_PCU_MISC_MODE2_MGMT_QOS 0x0000FF00
#define AR_PCU_MISC_MODE2_MGMT_QOS_S 8
#define AR_PCU_MISC_MODE2_ENABLE_LOAD_NAV_BEACON_DURATION 0x00010000
#define AR_PCU_MISC_MODE2_ENABLE_AGGWEP 0x00020000
#define AR_PCU_MISC_MODE2_HWWAR1 0x00100000
#define AR_PCU_MISC_MODE2_HWWAR2 0x02000000
#define AR_PCU_MISC_MODE2_RESERVED2 0xFFFE0000
#define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358
#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400
#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000
#define AR_AES_MUTE_MASK0 0x805c
#define AR_AES_MUTE_MASK0_FC 0x0000FFFF
#define AR_AES_MUTE_MASK0_QOS 0xFFFF0000
#define AR_AES_MUTE_MASK0_QOS_S 16
#define AR_AES_MUTE_MASK1 0x8060
#define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF
#define AR_AES_MUTE_MASK1_SEQ_S 0
#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000
#define AR_AES_MUTE_MASK1_FC_MGMT_S 16
#define AR_RATE_DURATION_0 0x8700
#define AR_RATE_DURATION_31 0x87CC
#define AR_RATE_DURATION_32 0x8780
#define AR_RATE_DURATION(_n) (AR_RATE_DURATION_0 + ((_n)<<2))
#define AR_KEYTABLE_0 0x8800 #define AR_KEYTABLE_0 0x8800
#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32)) #define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32))
#define AR_KEY_CACHE_SIZE 128 #define AR_KEY_CACHE_SIZE 128

View File

@ -660,3 +660,20 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work, queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
sc->wiphy_scheduler_int); sc->wiphy_scheduler_int);
} }
/* caller must hold wiphy_lock */
bool ath9k_all_wiphys_idle(struct ath_softc *sc)
{
unsigned int i;
if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
return false;
}
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
if (!aphy)
continue;
if (aphy->state != ATH_WIPHY_INACTIVE)
return false;
}
return true;
}

View File

@ -242,7 +242,6 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
spin_unlock_bh(&sc->tx.txbuflock); spin_unlock_bh(&sc->tx.txbuflock);
return NULL; return NULL;
} }
ASSERT(!list_empty((&sc->tx.txbuf)));
tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
list_del(&tbf->list); list_del(&tbf->list);
spin_unlock_bh(&sc->tx.txbuflock); spin_unlock_bh(&sc->tx.txbuflock);
@ -383,8 +382,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *tbf; struct ath_buf *tbf;
tbf = ath_clone_txbuf(sc, bf_last); tbf = ath_clone_txbuf(sc, bf_last);
if (!tbf) /*
* Update tx baw and complete the frame with
* failed status if we run out of tx buf
*/
if (!tbf) {
spin_lock_bh(&txq->axq_lock);
ath_tx_update_baw(sc, tid,
bf->bf_seqno);
spin_unlock_bh(&txq->axq_lock);
bf->bf_state.bf_type |= BUF_XRETRY;
ath_tx_rc_status(bf, ds, nbad,
0, false);
ath_tx_complete_buf(sc, bf, &bf_head,
0, 0);
break; break;
}
ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc); ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc);
list_add_tail(&tbf->list, &bf_head); list_add_tail(&tbf->list, &bf_head);
} else { } else {
@ -857,6 +872,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
txq->axq_aggr_depth = 0; txq->axq_aggr_depth = 0;
txq->axq_totalqueued = 0; txq->axq_totalqueued = 0;
txq->axq_linkbuf = NULL; txq->axq_linkbuf = NULL;
txq->axq_tx_inprogress = false;
sc->tx.txqsetup |= 1<<qnum; sc->tx.txqsetup |= 1<<qnum;
} }
return &sc->tx.txq[qnum]; return &sc->tx.txq[qnum];
@ -1023,6 +1039,10 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
} }
spin_lock_bh(&txq->axq_lock);
txq->axq_tx_inprogress = false;
spin_unlock_bh(&txq->axq_lock);
/* flush any pending frames if aggregation is enabled */ /* flush any pending frames if aggregation is enabled */
if (sc->sc_flags & SC_OP_TXAGGR) { if (sc->sc_flags & SC_OP_TXAGGR) {
if (!retry_tx) { if (!retry_tx) {
@ -1103,8 +1123,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
if (tid->paused) if (tid->paused)
continue; continue;
if ((txq->axq_depth % 2) == 0) ath_tx_sched_aggr(sc, txq, tid);
ath_tx_sched_aggr(sc, txq, tid);
/* /*
* add tid to round-robin queue if more frames * add tid to round-robin queue if more frames
@ -1947,19 +1966,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (bf->bf_stale) { if (bf->bf_stale) {
bf_held = bf; bf_held = bf;
if (list_is_last(&bf_held->list, &txq->axq_q)) { if (list_is_last(&bf_held->list, &txq->axq_q)) {
txq->axq_link = NULL;
txq->axq_linkbuf = NULL;
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
/*
* The holding descriptor is the last
* descriptor in queue. It's safe to remove
* the last holding descriptor in BH context.
*/
spin_lock_bh(&sc->tx.txbuflock);
list_move_tail(&bf_held->list, &sc->tx.txbuf);
spin_unlock_bh(&sc->tx.txbuflock);
break; break;
} else { } else {
bf = list_entry(bf_held->list.next, bf = list_entry(bf_held->list.next,
@ -1996,6 +2003,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
txq->axq_aggr_depth--; txq->axq_aggr_depth--;
txok = (ds->ds_txstat.ts_status == 0); txok = (ds->ds_txstat.ts_status == 0);
txq->axq_tx_inprogress = false;
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
if (bf_held) { if (bf_held) {
@ -2029,6 +2037,40 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
} }
} }
void ath_tx_complete_poll_work(struct work_struct *work)
{
struct ath_softc *sc = container_of(work, struct ath_softc,
tx_complete_work.work);
struct ath_txq *txq;
int i;
bool needreset = false;
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i)) {
txq = &sc->tx.txq[i];
spin_lock_bh(&txq->axq_lock);
if (txq->axq_depth) {
if (txq->axq_tx_inprogress) {
needreset = true;
spin_unlock_bh(&txq->axq_lock);
break;
} else {
txq->axq_tx_inprogress = true;
}
}
spin_unlock_bh(&txq->axq_lock);
}
if (needreset) {
DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n");
ath_reset(sc, false);
}
queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work,
msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
}
void ath_tx_tasklet(struct ath_softc *sc) void ath_tx_tasklet(struct ath_softc *sc)
{ {
@ -2069,6 +2111,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
goto err; goto err;
} }
INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
err: err:
if (error != 0) if (error != 0)
ath_tx_cleanup(sc); ath_tx_cleanup(sc);

View File

@ -938,7 +938,6 @@ static void b43_clear_keys(struct b43_wldev *dev)
static void b43_dump_keymemory(struct b43_wldev *dev) static void b43_dump_keymemory(struct b43_wldev *dev)
{ {
unsigned int i, index, offset; unsigned int i, index, offset;
DECLARE_MAC_BUF(macbuf);
u8 mac[ETH_ALEN]; u8 mac[ETH_ALEN];
u16 algo; u16 algo;
u32 rcmta0; u32 rcmta0;
@ -973,8 +972,7 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
((index - 4) * 2) + 1); ((index - 4) * 2) + 1);
*((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0); *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
*((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1); *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
printk(" MAC: %s", printk(" MAC: %pM", mac);
print_mac(macbuf, mac));
} else } else
printk(" DEFAULT KEY"); printk(" DEFAULT KEY");
printk("\n"); printk("\n");

View File

@ -666,7 +666,8 @@ static int prism2_config(struct pcmcia_device *link)
* irq structure is initialized. * irq structure is initialized.
*/ */
if (link->conf.Attributes & CONF_ENABLE_IRQ) { if (link->conf.Attributes & CONF_ENABLE_IRQ) {
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING |
IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = prism2_interrupt; link->irq.Handler = prism2_interrupt;
link->irq.Instance = dev; link->irq.Instance = dev;

View File

@ -7250,9 +7250,6 @@ static void ipw_bg_qos_activate(struct work_struct *work)
struct ipw_priv *priv = struct ipw_priv *priv =
container_of(work, struct ipw_priv, qos_activate); container_of(work, struct ipw_priv, qos_activate);
if (priv == NULL)
return;
mutex_lock(&priv->mutex); mutex_lock(&priv->mutex);
if (priv->status & STATUS_ASSOCIATED) if (priv->status & STATUS_ASSOCIATED)

View File

@ -46,7 +46,7 @@
#include "iwl-5000-hw.h" #include "iwl-5000-hw.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
#define IWL1000_UCODE_API_MAX 2 #define IWL1000_UCODE_API_MAX 3
/* Lowest firmware API version supported */ /* Lowest firmware API version supported */
#define IWL1000_UCODE_API_MIN 1 #define IWL1000_UCODE_API_MIN 1

View File

@ -232,9 +232,8 @@ struct iwl3945_eeprom {
#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */ #define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */
#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */ #define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */
#define TFD_QUEUE_MIN 0 /* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */
#define TFD_QUEUE_MAX 5 /* 4 DATA + 1 CMD */ #define IWL39_NUM_QUEUES 5
#define IWL_NUM_SCAN_RATES (2) #define IWL_NUM_SCAN_RATES (2)
#define IWL_DEFAULT_TX_RETRY 15 #define IWL_DEFAULT_TX_RETRY 15
@ -280,8 +279,6 @@ struct iwl3945_eeprom {
/* Size of uCode instruction memory in bootstrap state machine */ /* Size of uCode instruction memory in bootstrap state machine */
#define IWL39_MAX_BSM_SIZE IWL39_RTC_INST_SIZE #define IWL39_MAX_BSM_SIZE IWL39_RTC_INST_SIZE
#define IWL39_MAX_NUM_QUEUES 8
static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr) static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
{ {
return (addr >= IWL39_RTC_DATA_LOWER_BOUND) && return (addr >= IWL39_RTC_DATA_LOWER_BOUND) &&

View File

@ -673,33 +673,17 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
s8 scale_action = 0; s8 scale_action = 0;
unsigned long flags; unsigned long flags;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
u16 fc; u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0;
u16 rate_mask = 0;
s8 max_rate_idx = -1; s8 max_rate_idx = -1;
struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
IWL_DEBUG_RATE(priv, "enter\n"); IWL_DEBUG_RATE(priv, "enter\n");
if (sta) if (rate_control_send_low(sta, priv_sta, txrc))
rate_mask = sta->supp_rates[sband->band];
/* Send management frames and NO_ACK data using lowest rate. */
fc = le16_to_cpu(hdr->frame_control);
if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
info->flags & IEEE80211_TX_CTL_NO_ACK ||
!sta || !priv_sta) {
IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n");
if (!rate_mask)
info->control.rates[0].idx =
rate_lowest_index(sband, NULL);
else
info->control.rates[0].idx =
rate_lowest_index(sband, sta);
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
info->control.rates[0].count = 1;
return; return;
}
rate_mask = sta->supp_rates[sband->band];
/* get user max rate if set */ /* get user max rate if set */
max_rate_idx = txrc->max_rate_idx; max_rate_idx = txrc->max_rate_idx;

View File

@ -502,14 +502,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
} }
} }
if (print_dump) if (print_dump)
iwl_print_hex_dump(priv, IWL_DL_RX, data, length); iwl_print_hex_dump(IWL_DL_RX, data, length);
} }
static void iwl3945_dbg_report_frame(struct iwl_priv *priv, static void iwl3945_dbg_report_frame(struct iwl_priv *priv,
struct iwl_rx_packet *pkt, struct iwl_rx_packet *pkt,
struct ieee80211_hdr *header, int group100) struct ieee80211_hdr *header, int group100)
{ {
if (priv->debug_level & IWL_DL_RX) if (iwl_debug_level & IWL_DL_RX)
_iwl3945_dbg_report_frame(priv, pkt, header, group100); _iwl3945_dbg_report_frame(priv, pkt, header, group100);
} }
@ -963,7 +963,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
goto error; goto error;
/* Tx queue(s) */ /* Tx queue(s) */
for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) { for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
@ -1140,7 +1140,7 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
int txq_id; int txq_id;
/* Tx queues */ /* Tx queues */
for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
if (txq_id == IWL_CMD_QUEUE_NUM) if (txq_id == IWL_CMD_QUEUE_NUM)
iwl_cmd_queue_free(priv); iwl_cmd_queue_free(priv);
else else
@ -1156,7 +1156,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
/* reset TFD queues */ /* reset TFD queues */
for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) { for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0); iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0);
iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS, iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS,
FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id), FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
@ -2552,7 +2552,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
} }
/* Assign number of Usable TX queues */ /* Assign number of Usable TX queues */
priv->hw_params.max_txq_num = TFD_QUEUE_MAX; priv->hw_params.max_txq_num = IWL39_NUM_QUEUES;
priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K;
@ -2786,11 +2786,50 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
return 0; return 0;
} }
#define IWL3945_UCODE_GET(item) \
static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
u32 api_ver) \
{ \
return le32_to_cpu(ucode->u.v1.item); \
}
static u32 iwl3945_ucode_get_header_size(u32 api_ver)
{
return UCODE_HEADER_SIZE(1);
}
static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
return 0;
}
static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
return (u8 *) ucode->u.v1.data;
}
IWL3945_UCODE_GET(inst_size);
IWL3945_UCODE_GET(data_size);
IWL3945_UCODE_GET(init_size);
IWL3945_UCODE_GET(init_data_size);
IWL3945_UCODE_GET(boot_size);
static struct iwl_hcmd_ops iwl3945_hcmd = { static struct iwl_hcmd_ops iwl3945_hcmd = {
.rxon_assoc = iwl3945_send_rxon_assoc, .rxon_assoc = iwl3945_send_rxon_assoc,
.commit_rxon = iwl3945_commit_rxon, .commit_rxon = iwl3945_commit_rxon,
}; };
static struct iwl_ucode_ops iwl3945_ucode = {
.get_header_size = iwl3945_ucode_get_header_size,
.get_build = iwl3945_ucode_get_build,
.get_inst_size = iwl3945_ucode_get_inst_size,
.get_data_size = iwl3945_ucode_get_data_size,
.get_init_size = iwl3945_ucode_get_init_size,
.get_init_data_size = iwl3945_ucode_get_init_data_size,
.get_boot_size = iwl3945_ucode_get_boot_size,
.get_data = iwl3945_ucode_get_data,
};
static struct iwl_lib_ops iwl3945_lib = { static struct iwl_lib_ops iwl3945_lib = {
.txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd, .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl3945_hw_txq_free_tfd, .txq_free_tfd = iwl3945_hw_txq_free_tfd,
@ -2831,6 +2870,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
}; };
static struct iwl_ops iwl3945_ops = { static struct iwl_ops iwl3945_ops = {
.ucode = &iwl3945_ucode,
.lib = &iwl3945_lib, .lib = &iwl3945_lib,
.hcmd = &iwl3945_hcmd, .hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils, .utils = &iwl3945_hcmd_utils,

View File

@ -111,9 +111,6 @@ enum iwl3945_antenna {
#define IWL_TX_FIFO_HCCA_2 6 #define IWL_TX_FIFO_HCCA_2 6
#define IWL_TX_FIFO_NONE 7 #define IWL_TX_FIFO_NONE 7
/* Minimum number of queues. MAX_NUM is defined in hw specific files */
#define IWL_MIN_NUM_QUEUES 4
#define IEEE80211_DATA_LEN 2304 #define IEEE80211_DATA_LEN 2304
#define IEEE80211_4ADDR_LEN 30 #define IEEE80211_4ADDR_LEN 30
#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)

View File

@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "Begin load bsm\n"); IWL_DEBUG_INFO(priv, "Begin load bsm\n");
priv->ucode_type = UCODE_RT; priv->ucode_type = UCODE_INIT;
/* make sure bootstrap program is no larger than BSM's SRAM size */ /* make sure bootstrap program is no larger than BSM's SRAM size */
if (len > IWL49_MAX_BSM_SIZE) if (len > IWL49_MAX_BSM_SIZE)
@ -256,6 +256,8 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
*/ */
static void iwl4965_init_alive_start(struct iwl_priv *priv) static void iwl4965_init_alive_start(struct iwl_priv *priv)
{ {
int ret;
/* Check alive response for "valid" sign from uCode */ /* Check alive response for "valid" sign from uCode */
if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
/* We had an error bringing up the hardware, so take it /* We had an error bringing up the hardware, so take it
@ -287,6 +289,28 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n"); IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n");
goto restart; goto restart;
} }
priv->ucode_type = UCODE_RT;
if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
IWL_WARN(priv, "Runtime uCode already alive? "
"Waiting for alive anyway\n");
clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
}
ret = wait_event_interruptible_timeout(
priv->wait_command_queue,
test_bit(STATUS_RT_UCODE_ALIVE, &priv->status),
UCODE_ALIVE_TIMEOUT);
if (!ret) {
/* FIXME: if STATUS_RT_UCODE_ALIVE timeout
* go back to restart the download Init uCode again
* this might cause to trap in the restart loop
*/
priv->ucode_type = UCODE_NONE;
if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
IWL_ERR(priv, "Runtime timeout after %dms\n",
jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
goto restart;
}
}
return; return;
restart: restart:
@ -2221,12 +2245,50 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
cancel_work_sync(&priv->txpower_work); cancel_work_sync(&priv->txpower_work);
} }
#define IWL4965_UCODE_GET(item) \
static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
u32 api_ver) \
{ \
return le32_to_cpu(ucode->u.v1.item); \
}
static u32 iwl4965_ucode_get_header_size(u32 api_ver)
{
return UCODE_HEADER_SIZE(1);
}
static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
return 0;
}
static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
return (u8 *) ucode->u.v1.data;
}
IWL4965_UCODE_GET(inst_size);
IWL4965_UCODE_GET(data_size);
IWL4965_UCODE_GET(init_size);
IWL4965_UCODE_GET(init_data_size);
IWL4965_UCODE_GET(boot_size);
static struct iwl_hcmd_ops iwl4965_hcmd = { static struct iwl_hcmd_ops iwl4965_hcmd = {
.rxon_assoc = iwl4965_send_rxon_assoc, .rxon_assoc = iwl4965_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon, .commit_rxon = iwl_commit_rxon,
.set_rxon_chain = iwl_set_rxon_chain, .set_rxon_chain = iwl_set_rxon_chain,
}; };
static struct iwl_ucode_ops iwl4965_ucode = {
.get_header_size = iwl4965_ucode_get_header_size,
.get_build = iwl4965_ucode_get_build,
.get_inst_size = iwl4965_ucode_get_inst_size,
.get_data_size = iwl4965_ucode_get_data_size,
.get_init_size = iwl4965_ucode_get_init_size,
.get_init_data_size = iwl4965_ucode_get_init_data_size,
.get_boot_size = iwl4965_ucode_get_boot_size,
.get_data = iwl4965_ucode_get_data,
};
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.get_hcmd_size = iwl4965_get_hcmd_size, .get_hcmd_size = iwl4965_get_hcmd_size,
.build_addsta_hcmd = iwl4965_build_addsta_hcmd, .build_addsta_hcmd = iwl4965_build_addsta_hcmd,
@ -2287,6 +2349,7 @@ static struct iwl_lib_ops iwl4965_lib = {
}; };
static struct iwl_ops iwl4965_ops = { static struct iwl_ops iwl4965_ops = {
.ucode = &iwl4965_ucode,
.lib = &iwl4965_lib, .lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd, .hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils, .utils = &iwl4965_hcmd_utils,
@ -2313,8 +2376,6 @@ module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
module_param_named( module_param_named(
disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444); disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");

View File

@ -239,6 +239,13 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) {
/* Setting digital SVR for 1000 card to 1.32V */
iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
APMG_SVR_DIGITAL_VOLTAGE_1_32,
~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
}
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
} }
@ -1449,6 +1456,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
return max_rssi - agc - IWL49_RSSI_OFFSET; return max_rssi - agc - IWL49_RSSI_OFFSET;
} }
#define IWL5000_UCODE_GET(item) \
static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
u32 api_ver) \
{ \
if (api_ver <= 2) \
return le32_to_cpu(ucode->u.v1.item); \
return le32_to_cpu(ucode->u.v2.item); \
}
static u32 iwl5000_ucode_get_header_size(u32 api_ver)
{
if (api_ver <= 2)
return UCODE_HEADER_SIZE(1);
return UCODE_HEADER_SIZE(2);
}
static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
if (api_ver <= 2)
return 0;
return le32_to_cpu(ucode->u.v2.build);
}
static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
u32 api_ver)
{
if (api_ver <= 2)
return (u8 *) ucode->u.v1.data;
return (u8 *) ucode->u.v2.data;
}
IWL5000_UCODE_GET(inst_size);
IWL5000_UCODE_GET(data_size);
IWL5000_UCODE_GET(init_size);
IWL5000_UCODE_GET(init_data_size);
IWL5000_UCODE_GET(boot_size);
struct iwl_hcmd_ops iwl5000_hcmd = { struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc, .rxon_assoc = iwl5000_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon, .commit_rxon = iwl_commit_rxon,
@ -1464,6 +1509,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
.calc_rssi = iwl5000_calc_rssi, .calc_rssi = iwl5000_calc_rssi,
}; };
struct iwl_ucode_ops iwl5000_ucode = {
.get_header_size = iwl5000_ucode_get_header_size,
.get_build = iwl5000_ucode_get_build,
.get_inst_size = iwl5000_ucode_get_inst_size,
.get_data_size = iwl5000_ucode_get_data_size,
.get_init_size = iwl5000_ucode_get_init_size,
.get_init_data_size = iwl5000_ucode_get_init_data_size,
.get_boot_size = iwl5000_ucode_get_boot_size,
.get_data = iwl5000_ucode_get_data,
};
struct iwl_lib_ops iwl5000_lib = { struct iwl_lib_ops iwl5000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params, .set_hw_params = iwl5000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@ -1565,12 +1621,14 @@ static struct iwl_lib_ops iwl5150_lib = {
}; };
struct iwl_ops iwl5000_ops = { struct iwl_ops iwl5000_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl5000_lib, .lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd, .hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils, .utils = &iwl5000_hcmd_utils,
}; };
static struct iwl_ops iwl5150_ops = { static struct iwl_ops iwl5150_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl5150_lib, .lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd, .hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils, .utils = &iwl5000_hcmd_utils,
@ -1687,8 +1745,6 @@ MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
MODULE_PARM_DESC(swcrypto50, MODULE_PARM_DESC(swcrypto50,
"using software crypto engine (default 0 [hardware])\n"); "using software crypto engine (default 0 [hardware])\n");
module_param_named(debug50, iwl50_mod_params.debug, uint, 0444);
MODULE_PARM_DESC(debug50, "50XX debug output mask");
module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444); module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);

View File

@ -46,8 +46,8 @@
#include "iwl-5000-hw.h" #include "iwl-5000-hw.h"
/* Highest firmware API version supported */ /* Highest firmware API version supported */
#define IWL6000_UCODE_API_MAX 2 #define IWL6000_UCODE_API_MAX 3
#define IWL6050_UCODE_API_MAX 2 #define IWL6050_UCODE_API_MAX 3
/* Lowest firmware API version supported */ /* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 1 #define IWL6000_UCODE_API_MIN 1
@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
}; };
static struct iwl_ops iwl6000_ops = { static struct iwl_ops iwl6000_ops = {
.ucode = &iwl5000_ucode,
.lib = &iwl5000_lib, .lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd, .hcmd = &iwl5000_hcmd,
.utils = &iwl6000_hcmd_utils, .utils = &iwl6000_hcmd_utils,

View File

@ -2466,7 +2466,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_lq_sta *lq_sta = priv_sta;
int rate_idx; int rate_idx;
u64 mask_bit = 0;
IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n"); IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n");
@ -2481,22 +2480,9 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
lq_sta->max_rate_idx = -1; lq_sta->max_rate_idx = -1;
} }
if (sta)
mask_bit = sta->supp_rates[sband->band];
/* Send management frames and NO_ACK data using lowest rate. */ /* Send management frames and NO_ACK data using lowest rate. */
if (!ieee80211_is_data(hdr->frame_control) || if (rate_control_send_low(sta, priv_sta, txrc))
info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) {
if (!mask_bit)
info->control.rates[0].idx =
rate_lowest_index(sband, NULL);
else
info->control.rates[0].idx =
rate_lowest_index(sband, sta);
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
info->control.rates[0].count = 1;
return; return;
}
rate_idx = lq_sta->last_txrate_idx; rate_idx = lq_sta->last_txrate_idx;

View File

@ -533,12 +533,16 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
if (palive->ver_subtype == INITIALIZE_SUBTYPE) { if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
memcpy(&priv->card_alive_init, memcpy(&priv->card_alive_init,
&pkt->u.alive_frame, &pkt->u.alive_frame,
sizeof(struct iwl_init_alive_resp)); sizeof(struct iwl_init_alive_resp));
pwork = &priv->init_alive_start; pwork = &priv->init_alive_start;
} else { } else {
IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
set_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
memcpy(&priv->card_alive, &pkt->u.alive_frame, memcpy(&priv->card_alive, &pkt->u.alive_frame,
sizeof(struct iwl_alive_resp)); sizeof(struct iwl_alive_resp));
pwork = &priv->alive_start; pwork = &priv->alive_start;
@ -900,7 +904,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & IWL_DL_ISR) { if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */ /* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@ -919,7 +923,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */ /* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) { if (inta & CSR_INT_BIT_HW_ERR) {
IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */ /* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv); iwl_disable_interrupts(priv);
@ -935,7 +939,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
} }
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & (IWL_DL_ISR)) { if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */ /* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) { if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@ -960,7 +964,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1; hw_rf_kill = 1;
IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio"); hw_rf_kill ? "disable radio" : "enable radio");
priv->isr_stats.rfkill++; priv->isr_stats.rfkill++;
@ -1049,7 +1053,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
iwl_enable_interrupts(priv); iwl_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & (IWL_DL_ISR)) { if (iwl_debug_level & (IWL_DL_ISR)) {
inta = iwl_read32(priv, CSR_INT); inta = iwl_read32(priv, CSR_INT);
inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_mask = iwl_read32(priv, CSR_INT_MASK);
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@ -1080,7 +1084,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
inta = priv->inta; inta = priv->inta;
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & IWL_DL_ISR) { if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */ /* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ",
@ -1092,7 +1096,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */ /* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) { if (inta & CSR_INT_BIT_HW_ERR) {
IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */ /* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv); iwl_disable_interrupts(priv);
@ -1108,7 +1112,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
} }
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & (IWL_DL_ISR)) { if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */ /* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) { if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@ -1133,7 +1137,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1; hw_rf_kill = 1;
IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio"); hw_rf_kill ? "disable radio" : "enable radio");
priv->isr_stats.rfkill++; priv->isr_stats.rfkill++;
@ -1284,7 +1288,7 @@ static void iwl_nic_start(struct iwl_priv *priv)
*/ */
static int iwl_read_ucode(struct iwl_priv *priv) static int iwl_read_ucode(struct iwl_priv *priv)
{ {
struct iwl_ucode *ucode; struct iwl_ucode_header *ucode;
int ret = -EINVAL, index; int ret = -EINVAL, index;
const struct firmware *ucode_raw; const struct firmware *ucode_raw;
const char *name_pre = priv->cfg->fw_name_pre; const char *name_pre = priv->cfg->fw_name_pre;
@ -1293,7 +1297,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
char buf[25]; char buf[25];
u8 *src; u8 *src;
size_t len; size_t len;
u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; u32 api_ver, build;
u32 inst_size, data_size, init_size, init_data_size, boot_size;
/* Ask kernel firmware_class module to get the boot firmware off disk. /* Ask kernel firmware_class module to get the boot firmware off disk.
* request_firmware() is synchronous, file is in memory on return. */ * request_firmware() is synchronous, file is in memory on return. */
@ -1323,23 +1328,26 @@ static int iwl_read_ucode(struct iwl_priv *priv)
if (ret < 0) if (ret < 0)
goto error; goto error;
/* Make sure that we got at least our header! */ /* Make sure that we got at least the v1 header! */
if (ucode_raw->size < sizeof(*ucode)) { if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n"); IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL; ret = -EINVAL;
goto err_release; goto err_release;
} }
/* Data from ucode file: header followed by uCode images */ /* Data from ucode file: header followed by uCode images */
ucode = (void *)ucode_raw->data; ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver); priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver); api_ver = IWL_UCODE_API(priv->ucode_ver);
inst_size = le32_to_cpu(ucode->inst_size); build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
data_size = le32_to_cpu(ucode->data_size); inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
init_size = le32_to_cpu(ucode->init_size); data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
init_data_size = le32_to_cpu(ucode->init_data_size); init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
boot_size = le32_to_cpu(ucode->boot_size); init_data_size =
priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
/* api_ver should match the api version forming part of the /* api_ver should match the api version forming part of the
* firmware filename ... but we don't check for that and only rely * firmware filename ... but we don't check for that and only rely
@ -1365,6 +1373,9 @@ static int iwl_read_ucode(struct iwl_priv *priv)
IWL_UCODE_API(priv->ucode_ver), IWL_UCODE_API(priv->ucode_ver),
IWL_UCODE_SERIAL(priv->ucode_ver)); IWL_UCODE_SERIAL(priv->ucode_ver));
if (build)
IWL_DEBUG_INFO(priv, "Build %u\n", build);
IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
priv->ucode_ver); priv->ucode_ver);
IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n", IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
@ -1379,12 +1390,14 @@ static int iwl_read_ucode(struct iwl_priv *priv)
boot_size); boot_size);
/* Verify size of file vs. image size info in file's header */ /* Verify size of file vs. image size info in file's header */
if (ucode_raw->size < sizeof(*ucode) + if (ucode_raw->size !=
priv->cfg->ops->ucode->get_header_size(api_ver) +
inst_size + data_size + init_size + inst_size + data_size + init_size +
init_data_size + boot_size) { init_data_size + boot_size) {
IWL_DEBUG_INFO(priv, "uCode file size %d too small\n", IWL_DEBUG_INFO(priv,
(int)ucode_raw->size); "uCode file size %d does not match expected size\n",
(int)ucode_raw->size);
ret = -EINVAL; ret = -EINVAL;
goto err_release; goto err_release;
} }
@ -1464,42 +1477,42 @@ static int iwl_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */ /* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */ /* Runtime instructions (first block of data in file) */
src = &ucode->data[0]; len = inst_size;
len = priv->ucode_code.len;
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len); IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
memcpy(priv->ucode_code.v_addr, src, len); memcpy(priv->ucode_code.v_addr, src, len);
src += len;
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
/* Runtime data (2nd block) /* Runtime data (2nd block)
* NOTE: Copy into backup buffer will be done in iwl_up() */ * NOTE: Copy into backup buffer will be done in iwl_up() */
src = &ucode->data[inst_size]; len = data_size;
len = priv->ucode_data.len;
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len); IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
memcpy(priv->ucode_data.v_addr, src, len); memcpy(priv->ucode_data.v_addr, src, len);
memcpy(priv->ucode_data_backup.v_addr, src, len); memcpy(priv->ucode_data_backup.v_addr, src, len);
src += len;
/* Initialization instructions (3rd block) */ /* Initialization instructions (3rd block) */
if (init_size) { if (init_size) {
src = &ucode->data[inst_size + data_size]; len = init_size;
len = priv->ucode_init.len;
IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n", IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
len); len);
memcpy(priv->ucode_init.v_addr, src, len); memcpy(priv->ucode_init.v_addr, src, len);
src += len;
} }
/* Initialization data (4th block) */ /* Initialization data (4th block) */
if (init_data_size) { if (init_data_size) {
src = &ucode->data[inst_size + data_size + init_size]; len = init_data_size;
len = priv->ucode_init_data.len;
IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n", IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
len); len);
memcpy(priv->ucode_init_data.v_addr, src, len); memcpy(priv->ucode_init_data.v_addr, src, len);
src += len;
} }
/* Bootstrap instructions (5th block) */ /* Bootstrap instructions (5th block) */
src = &ucode->data[inst_size + data_size + init_size + init_data_size]; len = boot_size;
len = priv->ucode_boot.len;
IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len); IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len); memcpy(priv->ucode_boot.v_addr, src, len);
@ -1773,6 +1786,7 @@ static int __iwl_up(struct iwl_priv *priv)
{ {
int i; int i;
int ret; int ret;
unsigned long status;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
@ -1850,6 +1864,51 @@ static int __iwl_up(struct iwl_priv *priv)
/* start card; "initialize" will load runtime ucode */ /* start card; "initialize" will load runtime ucode */
iwl_nic_start(priv); iwl_nic_start(priv);
/* Just finish download Init or Runtime uCode image to device
* now we wait here for uCode send REPLY_ALIVE notification
* to indicate uCode is ready.
* 1) For Init uCode image, all iwlagn devices should wait here
* on STATUS_INIT_UCODE_ALIVE status bit; if timeout before
* receive the REPLY_ALIVE notification, go back and try to
* download the Init uCode image again.
* 2) For Runtime uCode image, all iwlagn devices except 4965
* wait here on STATUS_RT_UCODE_ALIVE status bit; if
* timeout before receive the REPLY_ALIVE notification, go back
* and download the Runtime uCode image again.
* 3) For 4965 Runtime uCode, it will not go through this path,
* need to wait for STATUS_RT_UCODE_ALIVE status bit in
* iwl4965_init_alive_start() function; if timeout, need to
* restart and download Init uCode image.
*/
if (priv->ucode_type == UCODE_INIT)
status = STATUS_INIT_UCODE_ALIVE;
else
status = STATUS_RT_UCODE_ALIVE;
if (test_bit(status, &priv->status)) {
IWL_WARN(priv,
"%s uCode already alive? "
"Waiting for alive anyway\n",
(status == STATUS_INIT_UCODE_ALIVE)
? "INIT" : "Runtime");
clear_bit(status, &priv->status);
}
ret = wait_event_interruptible_timeout(
priv->wait_command_queue,
test_bit(status, &priv->status),
UCODE_ALIVE_TIMEOUT);
if (!ret) {
if (!test_bit(status, &priv->status)) {
priv->ucode_type =
(status == STATUS_INIT_UCODE_ALIVE)
? UCODE_NONE : UCODE_INIT;
IWL_ERR(priv,
"%s timeout after %dms\n",
(status == STATUS_INIT_UCODE_ALIVE)
? "INIT" : "Runtime",
jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
continue;
}
}
IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n");
return 0; return 0;
@ -2397,14 +2456,16 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
* used for controlling the debug level. * used for controlling the debug level.
* *
* See the level definitions in iwl for details. * See the level definitions in iwl for details.
*
* FIXME This file can be deprecated as the module parameter is
* writable and users can thus also change the debug level
* using the /sys/module/iwl3945/parameters/debug file.
*/ */
static ssize_t show_debug_level(struct device *d, static ssize_t show_debug_level(struct device *d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%08X\n", iwl_debug_level);
return sprintf(buf, "0x%08X\n", priv->debug_level);
} }
static ssize_t store_debug_level(struct device *d, static ssize_t store_debug_level(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
@ -2418,7 +2479,7 @@ static ssize_t store_debug_level(struct device *d,
if (ret) if (ret)
IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
else else
priv->debug_level = val; iwl_debug_level = val;
return strnlen(buf, count); return strnlen(buf, count);
} }
@ -2627,26 +2688,6 @@ static ssize_t show_power_level(struct device *d,
static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
store_power_level); store_power_level);
static ssize_t show_qos(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwl_priv *priv = dev_get_drvdata(d);
char *p = buf;
int q;
for (q = 0; q < AC_NUM; q++) {
p += sprintf(p, "\tcw_min\tcw_max\taifsn\ttxop\n");
p += sprintf(p, "AC[%d]\t%u\t%u\t%u\t%u\n", q,
priv->qos_data.def_qos_parm.ac[q].cw_min,
priv->qos_data.def_qos_parm.ac[q].cw_max,
priv->qos_data.def_qos_parm.ac[q].aifsn,
priv->qos_data.def_qos_parm.ac[q].edca_txop);
}
return p - buf + 1;
}
static DEVICE_ATTR(qos, S_IRUGO, show_qos, NULL);
static ssize_t show_statistics(struct device *d, static ssize_t show_statistics(struct device *d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
@ -2747,7 +2788,6 @@ static struct attribute *iwl_sysfs_entries[] = {
&dev_attr_debug_level.attr, &dev_attr_debug_level.attr,
#endif #endif
&dev_attr_version.attr, &dev_attr_version.attr,
&dev_attr_qos.attr,
NULL NULL
}; };
@ -2791,7 +2831,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Disabling hardware scan means that mac80211 will perform scans /* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. */ * "the hard way", rather than using device's scan. */
if (cfg->mod_params->disable_hw_scan) { if (cfg->mod_params->disable_hw_scan) {
if (cfg->mod_params->debug & IWL_DL_INFO) if (iwl_debug_level & IWL_DL_INFO)
dev_printk(KERN_DEBUG, &(pdev->dev), dev_printk(KERN_DEBUG, &(pdev->dev),
"Disabling hw_scan\n"); "Disabling hw_scan\n");
iwl_hw_ops.hw_scan = NULL; iwl_hw_ops.hw_scan = NULL;
@ -2813,7 +2853,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv->inta_mask = CSR_INI_SET_MASK; priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
priv->debug_level = priv->cfg->mod_params->debug;
atomic_set(&priv->restrict_refcnt, 0); atomic_set(&priv->restrict_refcnt, 0);
#endif #endif
@ -3173,3 +3212,11 @@ static void __exit iwl_exit(void)
module_exit(iwl_exit); module_exit(iwl_exit);
module_init(iwl_init); module_init(iwl_init);
#ifdef CONFIG_IWLWIFI_DEBUG
module_param_named(debug50, iwl_debug_level, uint, 0444);
MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)");
module_param_named(debug, iwl_debug_level, uint, 0644);
MODULE_PARM_DESC(debug, "debug output mask");
#endif

View File

@ -59,6 +59,9 @@ MODULE_LICENSE("GPL");
IWL_RATE_##pp##M_INDEX, \ IWL_RATE_##pp##M_INDEX, \
IWL_RATE_##np##M_INDEX } IWL_RATE_##np##M_INDEX }
u32 iwl_debug_level;
EXPORT_SYMBOL(iwl_debug_level);
static irqreturn_t iwl_isr(int irq, void *data); static irqreturn_t iwl_isr(int irq, void *data);
/* /*
@ -1275,7 +1278,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
struct iwl_rxon_cmd *rxon = &priv->staging_rxon; struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n", IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
@ -1290,6 +1293,209 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
} }
#endif #endif
static const char *desc_lookup_text[] = {
"OK",
"FAIL",
"BAD_PARAM",
"BAD_CHECKSUM",
"NMI_INTERRUPT_WDG",
"SYSASSERT",
"FATAL_ERROR",
"BAD_COMMAND",
"HW_ERROR_TUNE_LOCK",
"HW_ERROR_TEMPERATURE",
"ILLEGAL_CHAN_FREQ",
"VCC_NOT_STABLE",
"FH_ERROR",
"NMI_INTERRUPT_HOST",
"NMI_INTERRUPT_ACTION_PT",
"NMI_INTERRUPT_UNKNOWN",
"UCODE_VERSION_MISMATCH",
"HW_ERROR_ABS_LOCK",
"HW_ERROR_CAL_LOCK_FAIL",
"NMI_INTERRUPT_INST_ACTION_PT",
"NMI_INTERRUPT_DATA_ACTION_PT",
"NMI_TRM_HW_ER",
"NMI_INTERRUPT_TRM",
"NMI_INTERRUPT_BREAK_POINT"
"DEBUG_0",
"DEBUG_1",
"DEBUG_2",
"DEBUG_3",
"UNKNOWN"
};
static const char *desc_lookup(int i)
{
int max = ARRAY_SIZE(desc_lookup_text) - 1;
if (i < 0 || i > max)
i = max;
return desc_lookup_text[i];
}
#define ERROR_START_OFFSET (1 * sizeof(u32))
#define ERROR_ELEM_SIZE (7 * sizeof(u32))
static void iwl_dump_nic_error_log(struct iwl_priv *priv)
{
u32 data2, line;
u32 desc, time, count, base, data1;
u32 blink1, blink2, ilink1, ilink2;
switch (priv->ucode_type) {
case UCODE_RT:
base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
break;
case UCODE_INIT:
base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
break;
default:
IWL_ERR(priv, "uCode image not available\n");
return;
}
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
return;
}
count = iwl_read_targ_mem(priv, base);
if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
IWL_ERR(priv, "Start IWL Error Log Dump:\n");
IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
priv->status, count);
}
desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
IWL_ERR(priv, "Desc Time "
"data1 data2 line\n");
IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
desc_lookup(desc), desc, time, data1, data2, line);
IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n");
IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
ilink1, ilink2);
}
#define EVENT_START_OFFSET (4 * sizeof(u32))
/**
* iwl_print_event_log - Dump error event log to syslog
*
*/
static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
u32 num_events, u32 mode)
{
u32 i;
u32 base; /* SRAM byte address of event log header */
u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
u32 ptr; /* SRAM byte address of log data */
u32 ev, time, data; /* event log data */
if (num_events == 0)
return;
switch (priv->ucode_type) {
case UCODE_RT:
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
break;
case UCODE_INIT:
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
break;
default:
IWL_ERR(priv, "uCode image not available\n");
return;
}
if (mode == 0)
event_size = 2 * sizeof(u32);
else
event_size = 3 * sizeof(u32);
ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
/* "time" is actually "data" for mode 0 (no timestamp).
* place event id # at far right for easier visual parsing. */
for (i = 0; i < num_events; i++) {
ev = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
time = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
if (mode == 0) {
/* data, ev */
IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
} else {
data = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
time, data, ev);
}
}
}
void iwl_dump_nic_event_log(struct iwl_priv *priv)
{
u32 base; /* SRAM byte address of event log header */
u32 capacity; /* event log capacity in # entries */
u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
u32 num_wraps; /* # times uCode wrapped to top of log */
u32 next_entry; /* index of next entry to be written by uCode */
u32 size; /* # entries that we'll print */
switch (priv->ucode_type) {
case UCODE_RT:
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
break;
case UCODE_INIT:
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
break;
default:
IWL_ERR(priv, "uCode image not available\n");
return;
}
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
return;
}
/* event log header */
capacity = iwl_read_targ_mem(priv, base);
mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
size = num_wraps ? capacity : next_entry;
/* bail out if nothing in log */
if (size == 0) {
IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
return;
}
IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
size, num_wraps);
/* if uCode has wrapped back to top of log, start at the oldest entry,
* i.e the next one that uCode would fill. */
if (num_wraps)
iwl_print_event_log(priv, next_entry,
capacity - next_entry, mode);
/* (then/else) start at top of log */
iwl_print_event_log(priv, 0, next_entry, mode);
}
/** /**
* iwl_irq_handle_error - called for HW or SW error interrupt from card * iwl_irq_handle_error - called for HW or SW error interrupt from card
*/ */
@ -1302,7 +1508,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
clear_bit(STATUS_HCMD_ACTIVE, &priv->status); clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & IWL_DL_FW_ERRORS) { if (iwl_debug_level & IWL_DL_FW_ERRORS) {
iwl_dump_nic_error_log(priv); iwl_dump_nic_error_log(priv);
iwl_dump_nic_event_log(priv); iwl_dump_nic_event_log(priv);
iwl_print_rx_config_cmd(priv); iwl_print_rx_config_cmd(priv);
@ -1543,31 +1749,6 @@ void iwl_uninit_drv(struct iwl_priv *priv)
} }
EXPORT_SYMBOL(iwl_uninit_drv); EXPORT_SYMBOL(iwl_uninit_drv);
void iwl_disable_interrupts(struct iwl_priv *priv)
{
clear_bit(STATUS_INT_ENABLED, &priv->status);
/* disable interrupts from uCode/NIC to host */
iwl_write32(priv, CSR_INT_MASK, 0x00000000);
/* acknowledge/clear/reset any interrupts still pending
* from uCode or flow handler (Rx/Tx DMA) */
iwl_write32(priv, CSR_INT, 0xffffffff);
iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
}
EXPORT_SYMBOL(iwl_disable_interrupts);
void iwl_enable_interrupts(struct iwl_priv *priv)
{
IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
set_bit(STATUS_INT_ENABLED, &priv->status);
iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
}
EXPORT_SYMBOL(iwl_enable_interrupts);
#define ICT_COUNT (PAGE_SIZE/sizeof(u32)) #define ICT_COUNT (PAGE_SIZE/sizeof(u32))
/* Free dram table */ /* Free dram table */
@ -1801,7 +1982,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
} }
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & (IWL_DL_ISR)) { if (iwl_debug_level & (IWL_DL_ISR)) {
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
"fh 0x%08x\n", inta, inta_mask, inta_fh); "fh 0x%08x\n", inta, inta_mask, inta_fh);
@ -2040,191 +2221,6 @@ int iwl_verify_ucode(struct iwl_priv *priv)
EXPORT_SYMBOL(iwl_verify_ucode); EXPORT_SYMBOL(iwl_verify_ucode);
static const char *desc_lookup_text[] = {
"OK",
"FAIL",
"BAD_PARAM",
"BAD_CHECKSUM",
"NMI_INTERRUPT_WDG",
"SYSASSERT",
"FATAL_ERROR",
"BAD_COMMAND",
"HW_ERROR_TUNE_LOCK",
"HW_ERROR_TEMPERATURE",
"ILLEGAL_CHAN_FREQ",
"VCC_NOT_STABLE",
"FH_ERROR",
"NMI_INTERRUPT_HOST",
"NMI_INTERRUPT_ACTION_PT",
"NMI_INTERRUPT_UNKNOWN",
"UCODE_VERSION_MISMATCH",
"HW_ERROR_ABS_LOCK",
"HW_ERROR_CAL_LOCK_FAIL",
"NMI_INTERRUPT_INST_ACTION_PT",
"NMI_INTERRUPT_DATA_ACTION_PT",
"NMI_TRM_HW_ER",
"NMI_INTERRUPT_TRM",
"NMI_INTERRUPT_BREAK_POINT"
"DEBUG_0",
"DEBUG_1",
"DEBUG_2",
"DEBUG_3",
"UNKNOWN"
};
static const char *desc_lookup(int i)
{
int max = ARRAY_SIZE(desc_lookup_text) - 1;
if (i < 0 || i > max)
i = max;
return desc_lookup_text[i];
}
#define ERROR_START_OFFSET (1 * sizeof(u32))
#define ERROR_ELEM_SIZE (7 * sizeof(u32))
void iwl_dump_nic_error_log(struct iwl_priv *priv)
{
u32 data2, line;
u32 desc, time, count, base, data1;
u32 blink1, blink2, ilink1, ilink2;
if (priv->ucode_type == UCODE_INIT)
base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
else
base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
return;
}
count = iwl_read_targ_mem(priv, base);
if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
IWL_ERR(priv, "Start IWL Error Log Dump:\n");
IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
priv->status, count);
}
desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
IWL_ERR(priv, "Desc Time "
"data1 data2 line\n");
IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
desc_lookup(desc), desc, time, data1, data2, line);
IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n");
IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
ilink1, ilink2);
}
EXPORT_SYMBOL(iwl_dump_nic_error_log);
#define EVENT_START_OFFSET (4 * sizeof(u32))
/**
* iwl_print_event_log - Dump error event log to syslog
*
*/
static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
u32 num_events, u32 mode)
{
u32 i;
u32 base; /* SRAM byte address of event log header */
u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
u32 ptr; /* SRAM byte address of log data */
u32 ev, time, data; /* event log data */
if (num_events == 0)
return;
if (priv->ucode_type == UCODE_INIT)
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
else
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
if (mode == 0)
event_size = 2 * sizeof(u32);
else
event_size = 3 * sizeof(u32);
ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
/* "time" is actually "data" for mode 0 (no timestamp).
* place event id # at far right for easier visual parsing. */
for (i = 0; i < num_events; i++) {
ev = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
time = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
if (mode == 0) {
/* data, ev */
IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
} else {
data = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
time, data, ev);
}
}
}
void iwl_dump_nic_event_log(struct iwl_priv *priv)
{
u32 base; /* SRAM byte address of event log header */
u32 capacity; /* event log capacity in # entries */
u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
u32 num_wraps; /* # times uCode wrapped to top of log */
u32 next_entry; /* index of next entry to be written by uCode */
u32 size; /* # entries that we'll print */
if (priv->ucode_type == UCODE_INIT)
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
else
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
return;
}
/* event log header */
capacity = iwl_read_targ_mem(priv, base);
mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
size = num_wraps ? capacity : next_entry;
/* bail out if nothing in log */
if (size == 0) {
IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
return;
}
IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
size, num_wraps);
/* if uCode has wrapped back to top of log, start at the oldest entry,
* i.e the next one that uCode would fill. */
if (num_wraps)
iwl_print_event_log(priv, next_entry,
capacity - next_entry, mode);
/* (then/else) start at top of log */
iwl_print_event_log(priv, 0, next_entry, mode);
}
EXPORT_SYMBOL(iwl_dump_nic_event_log);
void iwl_rf_kill_ct_config(struct iwl_priv *priv) void iwl_rf_kill_ct_config(struct iwl_priv *priv)
{ {
struct iwl_ct_kill_config cmd; struct iwl_ct_kill_config cmd;
@ -2293,7 +2289,7 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
"notification for %s:\n", "notification for %s:\n",
le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
} }
EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);

View File

@ -116,6 +116,17 @@ struct iwl_temp_ops {
void (*set_ct_kill)(struct iwl_priv *priv); void (*set_ct_kill)(struct iwl_priv *priv);
}; };
struct iwl_ucode_ops {
u32 (*get_header_size)(u32);
u32 (*get_build)(const struct iwl_ucode_header *, u32);
u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
u8 * (*get_data)(const struct iwl_ucode_header *, u32);
};
struct iwl_lib_ops { struct iwl_lib_ops {
/* set hw dependent parameters */ /* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv); int (*set_hw_params)(struct iwl_priv *priv);
@ -171,6 +182,7 @@ struct iwl_lib_ops {
}; };
struct iwl_ops { struct iwl_ops {
const struct iwl_ucode_ops *ucode;
const struct iwl_lib_ops *lib; const struct iwl_lib_ops *lib;
const struct iwl_hcmd_ops *hcmd; const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils; const struct iwl_hcmd_utils_ops *utils;
@ -178,7 +190,6 @@ struct iwl_ops {
struct iwl_mod_params { struct iwl_mod_params {
int sw_crypto; /* def: 0 = using hardware encryption */ int sw_crypto; /* def: 0 = using hardware encryption */
u32 debug; /* def: 0 = minimal debug log messages */
int disable_hw_scan; /* def: 0 = use h/w scan */ int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */ int num_of_queues; /* def: HW dependent */
int num_of_ampdu_queues;/* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */
@ -447,8 +458,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
/***************************************************** /*****************************************************
* PCI * * PCI *
*****************************************************/ *****************************************************/
void iwl_disable_interrupts(struct iwl_priv *priv);
void iwl_enable_interrupts(struct iwl_priv *priv);
irqreturn_t iwl_isr_legacy(int irq, void *data); irqreturn_t iwl_isr_legacy(int irq, void *data);
int iwl_reset_ict(struct iwl_priv *priv); int iwl_reset_ict(struct iwl_priv *priv);
void iwl_disable_ict(struct iwl_priv *priv); void iwl_disable_ict(struct iwl_priv *priv);
@ -472,7 +481,6 @@ int iwl_pci_resume(struct pci_dev *pdev);
/***************************************************** /*****************************************************
* Error Handling Debugging * Error Handling Debugging
******************************************************/ ******************************************************/
void iwl_dump_nic_error_log(struct iwl_priv *priv);
void iwl_dump_nic_event_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv);
void iwl_clear_isr_stats(struct iwl_priv *priv); void iwl_clear_isr_stats(struct iwl_priv *priv);
@ -501,6 +509,8 @@ void iwlcore_free_geos(struct iwl_priv *priv);
#define STATUS_POWER_PMI 16 #define STATUS_POWER_PMI 16
#define STATUS_FW_ERROR 17 #define STATUS_FW_ERROR 17
#define STATUS_MODE_PENDING 18 #define STATUS_MODE_PENDING 18
#define STATUS_INIT_UCODE_ALIVE 19
#define STATUS_RT_UCODE_ALIVE 20
static inline int iwl_is_ready(struct iwl_priv *priv) static inline int iwl_is_ready(struct iwl_priv *priv)

View File

@ -30,6 +30,7 @@
#define __iwl_debug_h__ #define __iwl_debug_h__
struct iwl_priv; struct iwl_priv;
extern u32 iwl_debug_level;
#define IWL_ERR(p, f, a...) dev_err(&((p)->pci_dev->dev), f, ## a) #define IWL_ERR(p, f, a...) dev_err(&((p)->pci_dev->dev), f, ## a)
#define IWL_WARN(p, f, a...) dev_warn(&((p)->pci_dev->dev), f, ## a) #define IWL_WARN(p, f, a...) dev_warn(&((p)->pci_dev->dev), f, ## a)
@ -45,7 +46,7 @@ do { \
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
#define IWL_DEBUG(__priv, level, fmt, args...) \ #define IWL_DEBUG(__priv, level, fmt, args...) \
do { \ do { \
if (__priv->debug_level & (level)) \ if (iwl_debug_level & (level)) \
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \ __func__ , ## args); \
@ -53,15 +54,15 @@ do { \
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \ #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \
do { \ do { \
if ((__priv->debug_level & (level)) && net_ratelimit()) \ if ((iwl_debug_level & (level)) && net_ratelimit()) \
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \ __func__ , ## args); \
} while (0) } while (0)
#define iwl_print_hex_dump(priv, level, p, len) \ #define iwl_print_hex_dump(level, p, len) \
do { \ do { \
if (priv->debug_level & level) \ if (iwl_debug_level & level) \
print_hex_dump(KERN_DEBUG, "iwl data: ", \ print_hex_dump(KERN_DEBUG, "iwl data: ", \
DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
} while (0) } while (0)
@ -82,6 +83,10 @@ struct iwl_debugfs {
struct dentry *file_channels; struct dentry *file_channels;
struct dentry *file_status; struct dentry *file_status;
struct dentry *file_interrupt; struct dentry *file_interrupt;
struct dentry *file_qos;
#ifdef CONFIG_IWLWIFI_LEDS
struct dentry *file_led;
#endif
} dbgfs_data_files; } dbgfs_data_files;
struct dir_rf_files { struct dir_rf_files {
struct dentry *file_disable_sensitivity; struct dentry *file_disable_sensitivity;
@ -99,8 +104,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv);
#else #else
#define IWL_DEBUG(__priv, level, fmt, args...) #define IWL_DEBUG(__priv, level, fmt, args...)
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) #define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)
static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, static inline void iwl_print_hex_dump(int level, void *p, u32 len)
void *p, u32 len)
{} {}
#endif /* CONFIG_IWLWIFI_DEBUG */ #endif /* CONFIG_IWLWIFI_DEBUG */

View File

@ -49,7 +49,8 @@
#define DEBUGFS_ADD_FILE(name, parent) do { \ #define DEBUGFS_ADD_FILE(name, parent) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \ dbgfs->dbgfs_##parent##_files.file_##name = \
debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \ debugfs_create_file(#name, S_IWUSR | S_IRUSR, \
dbgfs->dir_##parent, priv, \
&iwl_dbgfs_##name##_ops); \ &iwl_dbgfs_##name##_ops); \
if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \ if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
goto err; \ goto err; \
@ -57,7 +58,8 @@
#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \ dbgfs->dbgfs_##parent##_files.file_##name = \
debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \ debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
dbgfs->dir_##parent, ptr); \
if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
|| !dbgfs->dbgfs_##parent##_files.file_##name) \ || !dbgfs->dbgfs_##parent##_files.file_##name) \
goto err; \ goto err; \
@ -65,7 +67,7 @@
#define DEBUGFS_ADD_X32(name, parent, ptr) do { \ #define DEBUGFS_ADD_X32(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \ dbgfs->dbgfs_##parent##_files.file_##name = \
debugfs_create_x32(#name, 0444, dbgfs->dir_##parent, ptr); \ debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr); \
if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
|| !dbgfs->dbgfs_##parent##_files.file_##name) \ || !dbgfs->dbgfs_##parent##_files.file_##name) \
goto err; \ goto err; \
@ -566,6 +568,55 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
return count; return count;
} }
static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
int pos = 0, i;
char buf[256];
const size_t bufsz = sizeof(buf);
ssize_t ret;
for (i = 0; i < AC_NUM; i++) {
pos += scnprintf(buf + pos, bufsz - pos,
"\tcw_min\tcw_max\taifsn\ttxop\n");
pos += scnprintf(buf + pos, bufsz - pos,
"AC[%d]\t%u\t%u\t%u\t%u\n", i,
priv->qos_data.def_qos_parm.ac[i].cw_min,
priv->qos_data.def_qos_parm.ac[i].cw_max,
priv->qos_data.def_qos_parm.ac[i].aifsn,
priv->qos_data.def_qos_parm.ac[i].edca_txop);
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
return ret;
}
#ifdef CONFIG_IWLWIFI_LEDS
static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
int pos = 0;
char buf[256];
const size_t bufsz = sizeof(buf);
ssize_t ret;
pos += scnprintf(buf + pos, bufsz - pos,
"allow blinking: %s\n",
(priv->allow_blinking) ? "True" : "False");
if (priv->allow_blinking) {
pos += scnprintf(buf + pos, bufsz - pos,
"Led blinking rate: %u\n",
priv->last_blink_rate);
pos += scnprintf(buf + pos, bufsz - pos,
"Last blink time: %lu\n",
priv->last_blink_time);
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
return ret;
}
#endif
DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_WRITE_FILE_OPS(log_event);
@ -576,6 +627,10 @@ DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(channels);
DEBUGFS_READ_FILE_OPS(status); DEBUGFS_READ_FILE_OPS(status);
DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
DEBUGFS_READ_FILE_OPS(qos);
#ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_READ_FILE_OPS(led);
#endif
/* /*
* Create the debugfs files and directories * Create the debugfs files and directories
@ -612,6 +667,10 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_FILE(channels, data);
DEBUGFS_ADD_FILE(status, data); DEBUGFS_ADD_FILE(status, data);
DEBUGFS_ADD_FILE(interrupt, data); DEBUGFS_ADD_FILE(interrupt, data);
DEBUGFS_ADD_FILE(qos, data);
#ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_ADD_FILE(led, data);
#endif
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
DEBUGFS_ADD_BOOL(disable_chain_noise, rf, DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
&priv->disable_chain_noise_cal); &priv->disable_chain_noise_cal);
@ -646,6 +705,10 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos);
#ifdef CONFIG_IWLWIFI_LEDS
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
#endif
DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dir_data);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);

View File

@ -66,6 +66,7 @@ extern struct iwl_cfg iwl1000_bgn_cfg;
/* shared structures from iwl-5000.c */ /* shared structures from iwl-5000.c */
extern struct iwl_mod_params iwl50_mod_params; extern struct iwl_mod_params iwl50_mod_params;
extern struct iwl_ops iwl5000_ops; extern struct iwl_ops iwl5000_ops;
extern struct iwl_ucode_ops iwl5000_ucode;
extern struct iwl_lib_ops iwl5000_lib; extern struct iwl_lib_ops iwl5000_lib;
extern struct iwl_hcmd_ops iwl5000_hcmd; extern struct iwl_hcmd_ops iwl5000_hcmd;
extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils; extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
@ -258,8 +259,10 @@ struct iwl_channel_info {
#define IWL_TX_FIFO_HCCA_2 6 #define IWL_TX_FIFO_HCCA_2 6
#define IWL_TX_FIFO_NONE 7 #define IWL_TX_FIFO_NONE 7
/* Minimum number of queues. MAX_NUM is defined in hw specific files */ /* Minimum number of queues. MAX_NUM is defined in hw specific files.
#define IWL_MIN_NUM_QUEUES 4 * Set the minimum to accommodate the 4 standard TX queues, 1 command
* queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */
#define IWL_MIN_NUM_QUEUES 10
/* Power management (not Tx power) structures */ /* Power management (not Tx power) structures */
@ -523,15 +526,29 @@ struct fw_desc {
}; };
/* uCode file layout */ /* uCode file layout */
struct iwl_ucode { struct iwl_ucode_header {
__le32 ver; /* major/minor/API/serial */ __le32 ver; /* major/minor/API/serial */
__le32 inst_size; /* bytes of runtime instructions */ union {
__le32 data_size; /* bytes of runtime data */ struct {
__le32 init_size; /* bytes of initialization instructions */ __le32 inst_size; /* bytes of runtime code */
__le32 init_data_size; /* bytes of initialization data */ __le32 data_size; /* bytes of runtime data */
__le32 boot_size; /* bytes of bootstrap instructions */ __le32 init_size; /* bytes of init code */
u8 data[0]; /* data in same order as "size" elements */ __le32 init_data_size; /* bytes of init data */
__le32 boot_size; /* bytes of bootstrap code */
u8 data[0]; /* in same order as sizes */
} v1;
struct {
__le32 build; /* build number */
__le32 inst_size; /* bytes of runtime code */
__le32 data_size; /* bytes of runtime data */
__le32 init_size; /* bytes of init code */
__le32 init_data_size; /* bytes of init data */
__le32 boot_size; /* bytes of bootstrap code */
u8 data[0]; /* in same order as sizes */
} v2;
} u;
}; };
#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
struct iwl4965_ibss_seq { struct iwl4965_ibss_seq {
u8 mac[ETH_ALEN]; u8 mac[ETH_ALEN];
@ -755,6 +772,8 @@ struct iwl_calib_result {
size_t buf_len; size_t buf_len;
}; };
#define UCODE_ALIVE_TIMEOUT (5 * HZ)
enum ucode_type { enum ucode_type {
UCODE_NONE = 0, UCODE_NONE = 0,
UCODE_INIT, UCODE_INIT,
@ -1092,7 +1111,6 @@ struct iwl_priv {
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
/* debugging info */ /* debugging info */
u32 debug_level;
u32 framecnt_to_us; u32 framecnt_to_us;
atomic_t restrict_refcnt; atomic_t restrict_refcnt;
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS

View File

@ -159,6 +159,9 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv)
/* OTP only valid for CP/PP and after */ /* OTP only valid for CP/PP and after */
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
case CSR_HW_REV_TYPE_NONE:
IWL_ERR(priv, "Unknown hardware type\n");
return -ENOENT;
case CSR_HW_REV_TYPE_3945: case CSR_HW_REV_TYPE_3945:
case CSR_HW_REV_TYPE_4965: case CSR_HW_REV_TYPE_4965:
case CSR_HW_REV_TYPE_5300: case CSR_HW_REV_TYPE_5300:
@ -266,7 +269,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
u32 otpgp; u32 otpgp;
priv->nvm_device_type = iwlcore_get_nvm_type(priv); priv->nvm_device_type = iwlcore_get_nvm_type(priv);
if (priv->nvm_device_type == -ENOENT)
return -ENOENT;
/* allocate eeprom */ /* allocate eeprom */
if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
priv->cfg->eeprom_size = priv->cfg->eeprom_size =

View File

@ -145,4 +145,25 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue)
#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
static inline void iwl_disable_interrupts(struct iwl_priv *priv)
{
clear_bit(STATUS_INT_ENABLED, &priv->status);
/* disable interrupts from uCode/NIC to host */
iwl_write32(priv, CSR_INT_MASK, 0x00000000);
/* acknowledge/clear/reset any interrupts still pending
* from uCode or flow handler (Rx/Tx DMA) */
iwl_write32(priv, CSR_INT, 0xffffffff);
iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
}
static inline void iwl_enable_interrupts(struct iwl_priv *priv)
{
IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
set_bit(STATUS_INT_ENABLED, &priv->status);
iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
}
#endif /* __iwl_helpers_h__ */ #endif /* __iwl_helpers_h__ */

View File

@ -54,7 +54,7 @@ static const char *led_type_str[] = {
static const struct { static const struct {
u16 tpt; u16 tpt; /* Mb/s */
u8 on_time; u8 on_time;
u8 off_time; u8 off_time;
} blink_tbl[] = } blink_tbl[] =
@ -104,7 +104,7 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
} }
/* Set led pattern command */ /* Set led pattern command */
static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id, static int iwl_led_pattern(struct iwl_priv *priv, int led_id,
unsigned int idx) unsigned int idx)
{ {
struct iwl_led_cmd led_cmd = { struct iwl_led_cmd led_cmd = {
@ -121,7 +121,7 @@ static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
} }
/* Set led register off */ /* Set led register off */
static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id) static int iwl_led_on_reg(struct iwl_priv *priv, int led_id)
{ {
IWL_DEBUG_LED(priv, "led on %d\n", led_id); IWL_DEBUG_LED(priv, "led on %d\n", led_id);
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
@ -130,7 +130,7 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
#if 0 #if 0
/* Set led on command */ /* Set led on command */
static int iwl4965_led_on(struct iwl_priv *priv, int led_id) static int iwl_led_on(struct iwl_priv *priv, int led_id)
{ {
struct iwl_led_cmd led_cmd = { struct iwl_led_cmd led_cmd = {
.id = led_id, .id = led_id,
@ -142,7 +142,7 @@ static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
} }
/* Set led off command */ /* Set led off command */
int iwl4965_led_off(struct iwl_priv *priv, int led_id) int iwl_led_off(struct iwl_priv *priv, int led_id)
{ {
struct iwl_led_cmd led_cmd = { struct iwl_led_cmd led_cmd = {
.id = led_id, .id = led_id,
@ -157,7 +157,7 @@ int iwl4965_led_off(struct iwl_priv *priv, int led_id)
/* Set led register off */ /* Set led register off */
static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id) static int iwl_led_off_reg(struct iwl_priv *priv, int led_id)
{ {
IWL_DEBUG_LED(priv, "LED Reg off\n"); IWL_DEBUG_LED(priv, "LED Reg off\n");
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
@ -171,7 +171,7 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id)
{ {
IWL_DEBUG_LED(priv, "Associated\n"); IWL_DEBUG_LED(priv, "Associated\n");
priv->allow_blinking = 1; priv->allow_blinking = 1;
return iwl4965_led_on_reg(priv, led_id); return iwl_led_on_reg(priv, led_id);
} }
static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
{ {
@ -264,13 +264,15 @@ static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
/* /*
* calculate blink rate according to last 2 sec Tx/Rx activities * calculate blink rate according to last second Tx/Rx activities
*/ */
static int iwl_get_blink_rate(struct iwl_priv *priv) static int iwl_get_blink_rate(struct iwl_priv *priv)
{ {
int i; int i;
u64 current_tpt = priv->tx_stats[2].bytes; /* count both tx and rx traffic to be able to
/* FIXME: + priv->rx_stats[2].bytes; */ * handle traffic in either direction
*/
u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes;
s64 tpt = current_tpt - priv->led_tpt; s64 tpt = current_tpt - priv->led_tpt;
if (tpt < 0) /* wraparound */ if (tpt < 0) /* wraparound */
@ -314,7 +316,7 @@ void iwl_leds_background(struct iwl_priv *priv)
priv->last_blink_time = 0; priv->last_blink_time = 0;
if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
priv->last_blink_rate = IWL_SOLID_BLINK_IDX; priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
iwl4965_led_pattern(priv, IWL_LED_LINK, iwl_led_pattern(priv, IWL_LED_LINK,
IWL_SOLID_BLINK_IDX); IWL_SOLID_BLINK_IDX);
} }
return; return;
@ -328,7 +330,7 @@ void iwl_leds_background(struct iwl_priv *priv)
/* call only if blink rate change */ /* call only if blink rate change */
if (blink_idx != priv->last_blink_rate) if (blink_idx != priv->last_blink_rate)
iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx); iwl_led_pattern(priv, IWL_LED_LINK, blink_idx);
priv->last_blink_time = jiffies; priv->last_blink_time = jiffies;
priv->last_blink_rate = blink_idx; priv->last_blink_rate = blink_idx;
@ -351,8 +353,8 @@ int iwl_leds_register(struct iwl_priv *priv)
sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio", sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
wiphy_name(priv->hw->wiphy)); wiphy_name(priv->hw->wiphy));
priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg; priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg;
priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg; priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg;
priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO], ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
@ -386,7 +388,7 @@ int iwl_leds_register(struct iwl_priv *priv)
priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated; priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated; priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern; priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern;
if (ret) if (ret)
goto exit_fail; goto exit_fail;
@ -401,7 +403,7 @@ int iwl_leds_register(struct iwl_priv *priv)
priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated; priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated; priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern; priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern;
if (ret) if (ret)
goto exit_fail; goto exit_fail;

View File

@ -80,6 +80,8 @@
#define APMG_RFKILL_REG (APMG_BASE + 0x0014) #define APMG_RFKILL_REG (APMG_BASE + 0x0014)
#define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c) #define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c)
#define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020) #define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020)
#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058)
#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C)
#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200) #define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800) #define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
@ -91,7 +93,8 @@
#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) #define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */ #define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */
#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) #define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000)
#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */
#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060)
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)

View File

@ -646,7 +646,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
u32 tsf_low; u32 tsf_low;
int rssi; int rssi;
if (likely(!(priv->debug_level & IWL_DL_RX))) if (likely(!(iwl_debug_level & IWL_DL_RX)))
return; return;
/* MAC header */ /* MAC header */
@ -742,7 +742,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
} }
} }
if (print_dump) if (print_dump)
iwl_print_hex_dump(priv, IWL_DL_RX, header, length); iwl_print_hex_dump(IWL_DL_RX, header, length);
} }
#endif #endif
@ -1061,11 +1061,11 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
/* Set "1" to report good data frames in groups of 100 */ /* Set "1" to report good data frames in groups of 100 */
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (unlikely(priv->debug_level & IWL_DL_RX)) if (unlikely(iwl_debug_level & IWL_DL_RX))
iwl_dbg_report_frame(priv, rx_start, len, header, 1); iwl_dbg_report_frame(priv, rx_start, len, header, 1);
#endif #endif
IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n",
rx_status.signal, rx_status.noise, rx_status.signal, rx_status.signal, rx_status.noise, rx_status.qual,
(unsigned long long)rx_status.mactime); (unsigned long long)rx_status.mactime);
/* /*

View File

@ -566,6 +566,8 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&priv->sta_lock, flags); spin_lock_irqsave(&priv->sta_lock, flags);
IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
keyconf->keyidx);
if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table)) if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
IWL_ERR(priv, "index %d not used in uCode key table.\n", IWL_ERR(priv, "index %d not used in uCode key table.\n",
@ -573,6 +575,11 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
priv->default_wep_key--; priv->default_wep_key--;
memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0])); memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
if (iwl_is_rfkill(priv)) {
IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
spin_unlock_irqrestore(&priv->sta_lock, flags);
return 0;
}
ret = iwl_send_static_wepkey_cmd(priv, 1); ret = iwl_send_static_wepkey_cmd(priv, 1);
IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n", IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
keyconf->keyidx, ret); keyconf->keyidx, ret);
@ -853,6 +860,11 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
if (iwl_is_rfkill(priv)) {
IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled. \n");
spin_unlock_irqrestore(&priv->sta_lock, flags);
return 0;
}
ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags); spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret; return ret;
@ -1044,11 +1056,10 @@ EXPORT_SYMBOL(iwl_rxon_add_station);
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
{ {
int sta_id; int sta_id;
u16 fc = le16_to_cpu(hdr->frame_control); __le16 fc = hdr->frame_control;
/* If this frame is broadcast or management, use broadcast station id */ /* If this frame is broadcast or management, use broadcast station id */
if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
is_multicast_ether_addr(hdr->addr1))
return priv->hw_params.bcast_sta_id; return priv->hw_params.bcast_sta_id;
switch (priv->iw_mode) { switch (priv->iw_mode) {
@ -1082,7 +1093,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
IWL_DEBUG_DROP(priv, "Station %pM not in station map. " IWL_DEBUG_DROP(priv, "Station %pM not in station map. "
"Defaulting to broadcast...\n", "Defaulting to broadcast...\n",
hdr->addr1); hdr->addr1);
iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
return priv->hw_params.bcast_sta_id; return priv->hw_params.bcast_sta_id;
default: default:

View File

@ -869,8 +869,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
le16_to_cpu(out_cmd->hdr.sequence)); le16_to_cpu(out_cmd->hdr.sequence));
IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags));
iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
/* Set up entry for this TFD in Tx byte-count array */ /* Set up entry for this TFD in Tx byte-count array */
if (info->flags & IEEE80211_TX_CTL_AMPDU) if (info->flags & IEEE80211_TX_CTL_AMPDU)
@ -940,7 +940,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
!(cmd->meta.flags & CMD_SIZE_HUGE)); !(cmd->meta.flags & CMD_SIZE_HUGE));
if (iwl_is_rfkill(priv)) { if (iwl_is_rfkill(priv)) {
IWL_DEBUG_INFO(priv, "Not sending command - RF KILL"); IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
return -EIO; return -EIO;
} }

View File

@ -89,7 +89,7 @@ MODULE_LICENSE("GPL");
/* module parameters */ /* module parameters */
struct iwl_mod_params iwl3945_mod_params = { struct iwl_mod_params iwl3945_mod_params = {
.num_of_queues = IWL39_MAX_NUM_QUEUES, .num_of_queues = IWL39_NUM_QUEUES, /* Not used */
.sw_crypto = 1, .sw_crypto = 1,
.restart_fw = 1, .restart_fw = 1,
/* the rest are 0 by default */ /* the rest are 0 by default */
@ -612,8 +612,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n", IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
le16_to_cpu(out_cmd->hdr.sequence)); le16_to_cpu(out_cmd->hdr.sequence));
IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags)); IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags));
iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx)); iwl_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx));
iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr, iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr,
ieee80211_hdrlen(fc)); ieee80211_hdrlen(fc));
/* /*
@ -926,7 +926,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status; unsigned long status = priv->status;
IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", IWL_WARN(priv, "Card state received: HW:%s SW:%s\n",
(flags & HW_CARD_DISABLED) ? "Kill" : "On", (flags & HW_CARD_DISABLED) ? "Kill" : "On",
(flags & SW_CARD_DISABLED) ? "Kill" : "On"); (flags & SW_CARD_DISABLED) ? "Kill" : "On");
@ -1644,7 +1644,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh); iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & IWL_DL_ISR) { if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */ /* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@ -1663,7 +1663,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */ /* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) { if (inta & CSR_INT_BIT_HW_ERR) {
IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */ /* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv); iwl_disable_interrupts(priv);
@ -1679,7 +1679,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
} }
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & (IWL_DL_ISR)) { if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */ /* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) { if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@ -1758,7 +1758,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
iwl_enable_interrupts(priv); iwl_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (priv->debug_level & (IWL_DL_ISR)) { if (iwl_debug_level & (IWL_DL_ISR)) {
inta = iwl_read32(priv, CSR_INT); inta = iwl_read32(priv, CSR_INT);
inta_mask = iwl_read32(priv, CSR_INT_MASK); inta_mask = iwl_read32(priv, CSR_INT_MASK);
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@ -2041,7 +2041,7 @@ static void iwl3945_nic_start(struct iwl_priv *priv)
*/ */
static int iwl3945_read_ucode(struct iwl_priv *priv) static int iwl3945_read_ucode(struct iwl_priv *priv)
{ {
struct iwl_ucode *ucode; const struct iwl_ucode_header *ucode;
int ret = -EINVAL, index; int ret = -EINVAL, index;
const struct firmware *ucode_raw; const struct firmware *ucode_raw;
/* firmware file name contains uCode/driver compatibility version */ /* firmware file name contains uCode/driver compatibility version */
@ -2082,22 +2082,24 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
goto error; goto error;
/* Make sure that we got at least our header! */ /* Make sure that we got at least our header! */
if (ucode_raw->size < sizeof(*ucode)) { if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n"); IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL; ret = -EINVAL;
goto err_release; goto err_release;
} }
/* Data from ucode file: header followed by uCode images */ /* Data from ucode file: header followed by uCode images */
ucode = (void *)ucode_raw->data; ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver); priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver); api_ver = IWL_UCODE_API(priv->ucode_ver);
inst_size = le32_to_cpu(ucode->inst_size); inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
data_size = le32_to_cpu(ucode->data_size); data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
init_size = le32_to_cpu(ucode->init_size); init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
init_data_size = le32_to_cpu(ucode->init_data_size); init_data_size =
boot_size = le32_to_cpu(ucode->boot_size); priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
/* api_ver should match the api version forming part of the /* api_ver should match the api version forming part of the
* firmware filename ... but we don't check for that and only rely * firmware filename ... but we don't check for that and only rely
@ -2138,12 +2140,13 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
/* Verify size of file vs. image size info in file's header */ /* Verify size of file vs. image size info in file's header */
if (ucode_raw->size < sizeof(*ucode) + if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) +
inst_size + data_size + init_size + inst_size + data_size + init_size +
init_data_size + boot_size) { init_data_size + boot_size) {
IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n", IWL_DEBUG_INFO(priv,
ucode_raw->size); "uCode file size %zd does not match expected size\n",
ucode_raw->size);
ret = -EINVAL; ret = -EINVAL;
goto err_release; goto err_release;
} }
@ -2226,44 +2229,44 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */ /* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */ /* Runtime instructions (first block of data in file) */
src = &ucode->data[0]; len = inst_size;
len = priv->ucode_code.len;
IWL_DEBUG_INFO(priv, IWL_DEBUG_INFO(priv,
"Copying (but not loading) uCode instr len %zd\n", len); "Copying (but not loading) uCode instr len %zd\n", len);
memcpy(priv->ucode_code.v_addr, src, len); memcpy(priv->ucode_code.v_addr, src, len);
src += len;
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
/* Runtime data (2nd block) /* Runtime data (2nd block)
* NOTE: Copy into backup buffer will be done in iwl3945_up() */ * NOTE: Copy into backup buffer will be done in iwl3945_up() */
src = &ucode->data[inst_size]; len = data_size;
len = priv->ucode_data.len;
IWL_DEBUG_INFO(priv, IWL_DEBUG_INFO(priv,
"Copying (but not loading) uCode data len %zd\n", len); "Copying (but not loading) uCode data len %zd\n", len);
memcpy(priv->ucode_data.v_addr, src, len); memcpy(priv->ucode_data.v_addr, src, len);
memcpy(priv->ucode_data_backup.v_addr, src, len); memcpy(priv->ucode_data_backup.v_addr, src, len);
src += len;
/* Initialization instructions (3rd block) */ /* Initialization instructions (3rd block) */
if (init_size) { if (init_size) {
src = &ucode->data[inst_size + data_size]; len = init_size;
len = priv->ucode_init.len;
IWL_DEBUG_INFO(priv, IWL_DEBUG_INFO(priv,
"Copying (but not loading) init instr len %zd\n", len); "Copying (but not loading) init instr len %zd\n", len);
memcpy(priv->ucode_init.v_addr, src, len); memcpy(priv->ucode_init.v_addr, src, len);
src += len;
} }
/* Initialization data (4th block) */ /* Initialization data (4th block) */
if (init_data_size) { if (init_data_size) {
src = &ucode->data[inst_size + data_size + init_size]; len = init_data_size;
len = priv->ucode_init_data.len;
IWL_DEBUG_INFO(priv, IWL_DEBUG_INFO(priv,
"Copying (but not loading) init data len %zd\n", len); "Copying (but not loading) init data len %zd\n", len);
memcpy(priv->ucode_init_data.v_addr, src, len); memcpy(priv->ucode_init_data.v_addr, src, len);
src += len;
} }
/* Bootstrap instructions (5th block) */ /* Bootstrap instructions (5th block) */
src = &ucode->data[inst_size + data_size + init_size + init_data_size]; len = boot_size;
len = priv->ucode_boot.len;
IWL_DEBUG_INFO(priv, IWL_DEBUG_INFO(priv,
"Copying (but not loading) boot instr len %zd\n", len); "Copying (but not loading) boot instr len %zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len); memcpy(priv->ucode_boot.v_addr, src, len);
@ -3305,13 +3308,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* used for controlling the debug level. * used for controlling the debug level.
* *
* See the level definitions in iwl for details. * See the level definitions in iwl for details.
*
* FIXME This file can be deprecated as the module parameter is
* writable and users can thus also change the debug level
* using the /sys/module/iwl3945/parameters/debug file.
*/ */
static ssize_t show_debug_level(struct device *d, static ssize_t show_debug_level(struct device *d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct iwl_priv *priv = dev_get_drvdata(d); return sprintf(buf, "0x%08X\n", iwl_debug_level);
return sprintf(buf, "0x%08X\n", priv->debug_level);
} }
static ssize_t store_debug_level(struct device *d, static ssize_t store_debug_level(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
@ -3325,7 +3330,7 @@ static ssize_t store_debug_level(struct device *d,
if (ret) if (ret)
IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf); IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf);
else else
priv->debug_level = val; iwl_debug_level = val;
return strnlen(buf, count); return strnlen(buf, count);
} }
@ -3947,15 +3952,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv = hw->priv; priv = hw->priv;
SET_IEEE80211_DEV(hw, &pdev->dev); SET_IEEE80211_DEV(hw, &pdev->dev);
if ((iwl3945_mod_params.num_of_queues > IWL39_MAX_NUM_QUEUES) ||
(iwl3945_mod_params.num_of_queues < IWL_MIN_NUM_QUEUES)) {
IWL_ERR(priv,
"invalid queues_num, should be between %d and %d\n",
IWL_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
err = -EINVAL;
goto out_ieee80211_free_hw;
}
/* /*
* Disabling hardware scan means that mac80211 will perform scans * Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. * "the hard way", rather than using device's scan.
@ -3972,7 +3968,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->inta_mask = CSR_INI_SET_MASK; priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
priv->debug_level = iwl3945_mod_params.debug;
atomic_set(&priv->restrict_refcnt, 0); atomic_set(&priv->restrict_refcnt, 0);
#endif #endif
@ -4268,14 +4263,12 @@ MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444); module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto, MODULE_PARM_DESC(swcrypto,
"using software crypto (default 1 [software])\n"); "using software crypto (default 1 [software])\n");
module_param_named(debug, iwl3945_mod_params.debug, uint, 0444); #ifdef CONFIG_IWLWIFI_DEBUG
module_param_named(debug, iwl_debug_level, uint, 0644);
MODULE_PARM_DESC(debug, "debug output mask"); MODULE_PARM_DESC(debug, "debug output mask");
#endif
module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444); module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
module_param_named(queues_num, iwl3945_mod_params.num_of_queues, int, 0444);
MODULE_PARM_DESC(queues_num, "number of hw queues.");
module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444); module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444);
MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error"); MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");

View File

@ -158,34 +158,6 @@ static int iwm_key_init(struct iwm_key *key, u8 key_index,
return 0; return 0;
} }
static int iwm_reset_profile(struct iwm_priv *iwm)
{
int ret;
if (!iwm->umac_profile_active)
return 0;
/*
* If there is a current active profile, but no
* default key, it's not worth trying to associate again.
*/
if (iwm->default_key < 0)
return 0;
/*
* Here we have an active profile, but a key setting changed.
* We thus have to invalidate the current profile, and push the
* new one. Keys will be pushed when association takes place.
*/
ret = iwm_invalidate_mlme_profile(iwm);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't invalidate profile\n");
return ret;
}
return iwm_send_mlme_profile(iwm);
}
static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_index, const u8 *mac_addr, u8 key_index, const u8 *mac_addr,
struct key_params *params) struct key_params *params)
@ -203,32 +175,6 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
return ret; return ret;
} }
/*
* The WEP keys can be set before or after setting the essid.
* We need to handle both cases by simply pushing the keys after
* we send the profile.
* If the profile is not set yet (i.e. we're pushing keys before
* the essid), we set the cipher appropriately.
* If the profile is set, we havent associated yet because our
* cipher was incorrectly set. So we invalidate and send the
* profile again.
*/
if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
key->cipher == WLAN_CIPHER_SUITE_WEP104) {
u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher;
u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher;
IWM_DBG_WEXT(iwm, DBG, "WEP key\n");
if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
*ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
if (key->cipher == WLAN_CIPHER_SUITE_WEP104)
*ucast_cipher = *mcast_cipher =
UMAC_CIPHER_TYPE_WEP_104;
return iwm_reset_profile(iwm);
}
return iwm_set_key(iwm, 0, key); return iwm_set_key(iwm, 0, key);
} }
@ -271,10 +217,6 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
if (key_index == iwm->default_key) if (key_index == iwm->default_key)
iwm->default_key = -1; iwm->default_key = -1;
/* If the interface is down, we just cache this */
if (!test_bit(IWM_STATUS_READY, &iwm->status))
return 0;
return iwm_set_key(iwm, 1, key); return iwm_set_key(iwm, 1, key);
} }
@ -283,7 +225,6 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
u8 key_index) u8 key_index)
{ {
struct iwm_priv *iwm = ndev_to_iwm(ndev); struct iwm_priv *iwm = ndev_to_iwm(ndev);
int ret;
IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index); IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
@ -294,15 +235,26 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
iwm->default_key = key_index; iwm->default_key = key_index;
/* If the interface is down, we just cache this */ return iwm_set_tx_key(iwm, key_index);
if (!test_bit(IWM_STATUS_READY, &iwm->status)) }
return 0;
ret = iwm_set_tx_key(iwm, key_index); int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
if (ret < 0) u8 *mac, struct station_info *sinfo)
return ret; {
struct iwm_priv *iwm = ndev_to_iwm(ndev);
return iwm_reset_profile(iwm); if (memcmp(mac, iwm->bssid, ETH_ALEN))
return -ENOENT;
sinfo->filled |= STATION_INFO_TX_BITRATE;
sinfo->txrate.legacy = iwm->rate * 10;
if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
sinfo->filled |= STATION_INFO_SIGNAL;
sinfo->signal = iwm->wstats.qual.level;
}
return 0;
} }
@ -500,6 +452,179 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return 0; return 0;
} }
static int iwm_set_auth_type(struct iwm_priv *iwm,
enum nl80211_auth_type sme_auth_type)
{
u8 *auth_type = &iwm->umac_profile->sec.auth_type;
switch (sme_auth_type) {
case NL80211_AUTHTYPE_AUTOMATIC:
case NL80211_AUTHTYPE_OPEN_SYSTEM:
IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
*auth_type = UMAC_AUTH_TYPE_OPEN;
break;
case NL80211_AUTHTYPE_SHARED_KEY:
if (iwm->umac_profile->sec.flags &
(UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
} else {
IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
}
break;
default:
IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
return -ENOTSUPP;
}
return 0;
}
static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
{
if (!wpa_version) {
iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
return 0;
}
if (wpa_version & NL80211_WPA_VERSION_2)
iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
if (wpa_version & NL80211_WPA_VERSION_1)
iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
return 0;
}
static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
{
u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
&iwm->umac_profile->sec.mcast_cipher;
if (!cipher) {
*profile_cipher = UMAC_CIPHER_TYPE_NONE;
return 0;
}
switch (cipher) {
case IW_AUTH_CIPHER_NONE:
*profile_cipher = UMAC_CIPHER_TYPE_NONE;
break;
case WLAN_CIPHER_SUITE_WEP40:
*profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
break;
case WLAN_CIPHER_SUITE_WEP104:
*profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
break;
case WLAN_CIPHER_SUITE_TKIP:
*profile_cipher = UMAC_CIPHER_TYPE_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
*profile_cipher = UMAC_CIPHER_TYPE_CCMP;
break;
default:
IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
return -ENOTSUPP;
}
return 0;
}
static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
{
u8 *auth_type = &iwm->umac_profile->sec.auth_type;
IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
if (key_mgt == WLAN_AKM_SUITE_8021X)
*auth_type = UMAC_AUTH_TYPE_8021X;
else if (key_mgt == WLAN_AKM_SUITE_PSK) {
if (iwm->umac_profile->sec.flags &
(UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
else
*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
} else {
IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
return -EINVAL;
}
return 0;
}
static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme)
{
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
struct ieee80211_channel *chan = sme->channel;
int ret;
if (!test_bit(IWM_STATUS_READY, &iwm->status))
return -EIO;
if (!sme->ssid)
return -EINVAL;
if (chan)
iwm->channel =
ieee80211_frequency_to_channel(chan->center_freq);
iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
if (sme->bssid) {
IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
iwm->umac_profile->bss_num = 1;
} else {
memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
iwm->umac_profile->bss_num = 0;
}
ret = iwm_set_auth_type(iwm, sme->auth_type);
if (ret < 0)
return ret;
ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
if (ret < 0)
return ret;
if (sme->crypto.n_ciphers_pairwise) {
ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
true);
if (ret < 0)
return ret;
}
ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
if (ret < 0)
return ret;
if (sme->crypto.n_akm_suites) {
ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
if (ret < 0)
return ret;
}
return iwm_send_mlme_profile(iwm);
}
static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
u16 reason_code)
{
struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
if (iwm->umac_profile_active)
return iwm_invalidate_mlme_profile(iwm);
return 0;
}
static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
enum tx_power_setting type, int dbm) enum tx_power_setting type, int dbm)
{ {
@ -549,8 +674,11 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
.get_key = iwm_cfg80211_get_key, .get_key = iwm_cfg80211_get_key,
.del_key = iwm_cfg80211_del_key, .del_key = iwm_cfg80211_del_key,
.set_default_key = iwm_cfg80211_set_default_key, .set_default_key = iwm_cfg80211_set_default_key,
.get_station = iwm_cfg80211_get_station,
.scan = iwm_cfg80211_scan, .scan = iwm_cfg80211_scan,
.set_wiphy_params = iwm_cfg80211_set_wiphy_params, .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
.connect = iwm_cfg80211_connect,
.disconnect = iwm_cfg80211_disconnect,
.join_ibss = iwm_cfg80211_join_ibss, .join_ibss = iwm_cfg80211_join_ibss,
.leave_ibss = iwm_cfg80211_leave_ibss, .leave_ibss = iwm_cfg80211_leave_ibss,
.set_tx_power = iwm_cfg80211_set_txpower, .set_tx_power = iwm_cfg80211_set_txpower,
@ -558,6 +686,13 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
.set_power_mgmt = iwm_cfg80211_set_power_mgmt, .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
}; };
static const u32 cipher_suites[] = {
WLAN_CIPHER_SUITE_WEP40,
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
};
struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
{ {
int ret = 0; int ret = 0;
@ -600,6 +735,9 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz; wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wdev->wiphy->cipher_suites = cipher_suites;
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
ret = wiphy_register(wdev->wiphy); ret = wiphy_register(wdev->wiphy);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Couldn't register wiphy device\n"); dev_err(dev, "Couldn't register wiphy device\n");

View File

@ -87,8 +87,7 @@ int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
test_and_clear_bit(oid, &iwm->wifi_ntfy[0]), test_and_clear_bit(oid, &iwm->wifi_ntfy[0]),
3 * HZ); 3 * HZ);
if (!ret) return ret ? 0 : -EBUSY;
ret = -EBUSY;
} }
return ret; return ret;
@ -480,8 +479,10 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
target_cmd.eop = 1; target_cmd.eop = 1;
ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
if (ret < 0) if (ret < 0) {
IWM_ERR(iwm, "Couldn't send READ command\n"); IWM_ERR(iwm, "Couldn't send READ command\n");
return ret;
}
/* When succeding, the send_target routine returns the seq number */ /* When succeding, the send_target routine returns the seq number */
seq_num = ret; seq_num = ret;
@ -501,7 +502,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
kfree(cmd); kfree(cmd);
return ret; return 0;
} }
int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
@ -511,7 +512,7 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR), ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR),
mac_align, sizeof(mac_align)); mac_align, sizeof(mac_align));
if (ret < 0) if (ret)
return ret; return ret;
if (is_valid_ether_addr(mac_align)) if (is_valid_ether_addr(mac_align))
@ -583,12 +584,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
/*
* We check if our current profile is valid.
* If not, we dont push the key, we just cache them,
* so that with the next siwsessid call, the keys
* will be actually pushed.
*/
if (!remove) { if (!remove) {
ret = iwm_check_profile(iwm); ret = iwm_check_profile(iwm);
if (ret < 0) if (ret < 0)
@ -714,7 +709,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
ret = iwm_send_wifi_if_cmd(iwm, &key_remove, ret = iwm_send_wifi_if_cmd(iwm, &key_remove,
sizeof(struct iwm_umac_key_remove), sizeof(struct iwm_umac_key_remove),
1); 1);
if (ret < 0) if (ret)
return ret; return ret;
iwm->keys[key_idx].key_len = 0; iwm->keys[key_idx].key_len = 0;
@ -726,7 +721,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
int iwm_send_mlme_profile(struct iwm_priv *iwm) int iwm_send_mlme_profile(struct iwm_priv *iwm)
{ {
int ret, i; int ret;
struct iwm_umac_profile profile; struct iwm_umac_profile profile;
memcpy(&profile, iwm->umac_profile, sizeof(profile)); memcpy(&profile, iwm->umac_profile, sizeof(profile));
@ -736,32 +731,11 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
sizeof(struct iwm_umac_wifi_if)); sizeof(struct iwm_umac_wifi_if));
ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1); ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1);
if (ret < 0) { if (ret) {
IWM_ERR(iwm, "Send profile command failed\n"); IWM_ERR(iwm, "Send profile command failed\n");
return ret; return ret;
} }
for (i = 0; i < IWM_NUM_KEYS; i++)
if (iwm->keys[i].key_len) {
struct iwm_key *key = &iwm->keys[i];
/* Wait for the profile before sending the keys */
wait_event_interruptible_timeout(iwm->mlme_queue,
(test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
3 * HZ);
ret = iwm_set_key(iwm, 0, key);
if (ret < 0)
return ret;
if (iwm->default_key == i) {
ret = iwm_set_tx_key(iwm, i);
if (ret < 0)
return ret;
}
}
return 0; return 0;
} }
@ -778,15 +752,13 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
invalid.reason = WLAN_REASON_UNSPECIFIED; invalid.reason = WLAN_REASON_UNSPECIFIED;
ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1); ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
if (ret < 0) if (ret)
return ret; return ret;
ret = wait_event_interruptible_timeout(iwm->mlme_queue, ret = wait_event_interruptible_timeout(iwm->mlme_queue,
(iwm->umac_profile_active == 0), 2 * HZ); (iwm->umac_profile_active == 0), 2 * HZ);
if (!ret)
return -EBUSY;
return 0; return ret ? 0 : -EBUSY;
} }
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
@ -869,7 +841,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
} }
ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0); ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0);
if (ret < 0) { if (ret) {
IWM_ERR(iwm, "Couldn't send scan request\n"); IWM_ERR(iwm, "Couldn't send scan request\n");
return ret; return ret;
} }

View File

@ -105,9 +105,9 @@
#include "umac.h" #include "umac.h"
#include "debug.h" #include "debug.h"
static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
struct iwm_nonwifi_cmd *cmd, struct iwm_nonwifi_cmd *cmd,
struct iwm_udma_nonwifi_cmd *udma_cmd) struct iwm_udma_nonwifi_cmd *udma_cmd)
{ {
INIT_LIST_HEAD(&cmd->pending); INIT_LIST_HEAD(&cmd->pending);
@ -118,7 +118,7 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
cmd->seq_num = iwm->nonwifi_seq_num; cmd->seq_num = iwm->nonwifi_seq_num;
udma_cmd->seq_num = cpu_to_le16(cmd->seq_num); udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
cmd->seq_num = iwm->nonwifi_seq_num++; iwm->nonwifi_seq_num++;
iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX; iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
if (udma_cmd->resp) if (udma_cmd->resp)
@ -130,6 +130,8 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
cmd->buf.len = 0; cmd->buf.len = 0;
memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
return cmd->seq_num;
} }
u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm) u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
@ -369,7 +371,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
const void *payload) const void *payload)
{ {
struct iwm_nonwifi_cmd *cmd; struct iwm_nonwifi_cmd *cmd;
int ret; int ret, seq_num;
cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL); cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
if (!cmd) { if (!cmd) {
@ -377,7 +379,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
return -ENOMEM; return -ENOMEM;
} }
iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE || if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) { cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
@ -393,7 +395,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
if (ret < 0) if (ret < 0)
return ret; return ret;
return cmd->seq_num; return seq_num;
} }
static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr, static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,

View File

@ -281,6 +281,11 @@ struct iwm_priv {
struct work_struct reset_worker; struct work_struct reset_worker;
struct mutex mutex; struct mutex mutex;
u8 *req_ie;
int req_ie_len;
u8 *resp_ie;
int resp_ie_len;
char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
}; };

View File

@ -497,6 +497,13 @@ void iwm_link_off(struct iwm_priv *iwm)
memset(wstats, 0, sizeof(struct iw_statistics)); memset(wstats, 0, sizeof(struct iw_statistics));
wstats->qual.updated = IW_QUAL_ALL_INVALID; wstats->qual.updated = IW_QUAL_ALL_INVALID;
kfree(iwm->req_ie);
iwm->req_ie = NULL;
iwm->req_ie_len = 0;
kfree(iwm->resp_ie);
iwm->resp_ie = NULL;
iwm->resp_ie_len = 0;
del_timer_sync(&iwm->watchdog); del_timer_sync(&iwm->watchdog);
} }

View File

@ -102,7 +102,6 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
error = (struct iwm_umac_notif_error *)buf; error = (struct iwm_umac_notif_error *)buf;
fw_err = &error->err; fw_err = &error->err;
IWM_ERR(iwm, "%cMAC FW ERROR:\n", IWM_ERR(iwm, "%cMAC FW ERROR:\n",
(le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category));
@ -219,17 +218,17 @@ static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf,
(buf + sizeof(struct iwm_umac_wifi_in_hdr)); (buf + sizeof(struct iwm_umac_wifi_in_hdr));
hdr = (struct iwm_umac_wifi_in_hdr *)buf; hdr = (struct iwm_umac_wifi_in_hdr *)buf;
IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n", IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n",
le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n", IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n",
le16_to_cpu(tx_resp->retry_cnt)); le16_to_cpu(tx_resp->retry_cnt));
IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n", IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n",
le16_to_cpu(tx_resp->byte_cnt)); le16_to_cpu(tx_resp->byte_cnt));
IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
return 0; return 0;
} }
@ -419,8 +418,8 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
if (IS_ERR(ticket_node)) if (IS_ERR(ticket_node))
return PTR_ERR(ticket_node); return PTR_ERR(ticket_node);
IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n", IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n",
ticket->id); ticket->id);
list_add_tail(&ticket_node->node, &iwm->rx_tickets); list_add_tail(&ticket_node->node, &iwm->rx_tickets);
/* /*
@ -455,15 +454,15 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
u16 id, buf_offset; u16 id, buf_offset;
u32 packet_size; u32 packet_size;
IWM_DBG_NTF(iwm, DBG, "\n"); IWM_DBG_RX(iwm, DBG, "\n");
wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
buf_offset = sizeof(struct iwm_umac_wifi_in_hdr); buf_offset = sizeof(struct iwm_umac_wifi_in_hdr);
packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr); packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr);
IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id); IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id);
IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size); IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size);
@ -504,13 +503,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
{ {
struct iwm_umac_notif_assoc_complete *complete = struct iwm_umac_notif_assoc_complete *complete =
(struct iwm_umac_notif_assoc_complete *)buf; (struct iwm_umac_notif_assoc_complete *)buf;
union iwreq_data wrqu;
IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n",
complete->bssid, complete->status); complete->bssid, complete->status);
memset(&wrqu, 0, sizeof(wrqu));
clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
switch (le32_to_cpu(complete->status)) { switch (le32_to_cpu(complete->status)) {
@ -521,7 +517,14 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
iwm_link_on(iwm); iwm_link_on(iwm);
memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN); if (iwm->conf.mode == UMAC_MODE_IBSS)
goto ibss;
cfg80211_connect_result(iwm_to_ndev(iwm),
complete->bssid,
iwm->req_ie, iwm->req_ie_len,
iwm->resp_ie, iwm->resp_ie_len,
WLAN_STATUS_SUCCESS, GFP_KERNEL);
break; break;
case UMAC_ASSOC_COMPLETE_FAILURE: case UMAC_ASSOC_COMPLETE_FAILURE:
clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@ -529,18 +532,22 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
iwm->channel = 0; iwm->channel = 0;
iwm_link_off(iwm); iwm_link_off(iwm);
if (iwm->conf.mode == UMAC_MODE_IBSS)
goto ibss;
cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
default: default:
break; break;
} }
if (iwm->conf.mode == UMAC_MODE_IBSS) { return 0;
cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
return 0;
}
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
ibss:
cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
return 0; return 0;
} }
@ -770,37 +777,46 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd) unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{ {
struct iwm_umac_notif_mgt_frame *mgt_frame = struct iwm_umac_notif_mgt_frame *mgt_frame =
(struct iwm_umac_notif_mgt_frame *)buf; (struct iwm_umac_notif_mgt_frame *)buf;
struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
u8 *ie; u8 *ie;
unsigned int event;
union iwreq_data wrqu;
IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
le16_to_cpu(mgt_frame->len)); le16_to_cpu(mgt_frame->len));
if (ieee80211_is_assoc_req(mgt->frame_control)) { if (ieee80211_is_assoc_req(mgt->frame_control)) {
ie = mgt->u.assoc_req.variable;; ie = mgt->u.assoc_req.variable;;
event = IWEVASSOCREQIE; iwm->req_ie_len =
le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
kfree(iwm->req_ie);
iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_req(mgt->frame_control)) { } else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
ie = mgt->u.reassoc_req.variable;; ie = mgt->u.reassoc_req.variable;;
event = IWEVASSOCREQIE; iwm->req_ie_len =
le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
kfree(iwm->req_ie);
iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_assoc_resp(mgt->frame_control)) { } else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
ie = mgt->u.assoc_resp.variable;; ie = mgt->u.assoc_resp.variable;;
event = IWEVASSOCRESPIE; iwm->resp_ie_len =
le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
kfree(iwm->resp_ie);
iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
iwm->resp_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
ie = mgt->u.reassoc_resp.variable;; ie = mgt->u.reassoc_resp.variable;;
event = IWEVASSOCRESPIE; iwm->resp_ie_len =
le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
kfree(iwm->resp_ie);
iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
iwm->resp_ie_len, GFP_KERNEL);
} else { } else {
IWM_ERR(iwm, "Unsupported management frame"); IWM_ERR(iwm, "Unsupported management frame");
return 0; return 0;
} }
wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length);
wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie);
return 0; return 0;
} }
@ -1360,7 +1376,7 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
skb->dev = iwm_to_ndev(iwm); skb->dev = iwm_to_ndev(iwm);
skb->protocol = eth_type_trans(skb, ndev); skb->protocol = eth_type_trans(skb, ndev);
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_NONE;
memset(skb->cb, 0, sizeof(skb->cb)); memset(skb->cb, 0, sizeof(skb->cb));
ndev->stats.rx_packets++; ndev->stats.rx_packets++;

View File

@ -615,6 +615,7 @@ struct iwm_umac_notif_alive {
} __attribute__ ((packed)); } __attribute__ ((packed));
struct iwm_umac_notif_init_complete { struct iwm_umac_notif_init_complete {
struct iwm_umac_wifi_in_hdr hdr;
__le16 status; __le16 status;
__le16 reserved; __le16 reserved;
} __attribute__ ((packed)); } __attribute__ ((packed));
@ -643,6 +644,11 @@ struct iwm_fw_error_hdr {
__le32 umac_status; __le32 umac_status;
__le32 lmac_status; __le32 lmac_status;
__le32 sdio_status; __le32 sdio_status;
__le32 dbm_sample_ctrl;
__le32 dbm_buf_base;
__le32 dbm_buf_end;
__le32 dbm_buf_write_ptr;
__le32 dbm_buf_cycle_cnt;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct iwm_umac_notif_error { struct iwm_umac_notif_error {

View File

@ -21,31 +21,11 @@
* *
*/ */
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/wireless.h> #include <linux/wireless.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include <net/iw_handler.h>
#include "iwm.h" #include "iwm.h"
#include "umac.h"
#include "commands.h" #include "commands.h"
#include "debug.h"
static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
struct iw_statistics *wstats = &iwm->wstats;
if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
memset(wstats, 0, sizeof(struct iw_statistics));
wstats->qual.updated = IW_QUAL_ALL_INVALID;
}
return wstats;
}
static int iwm_wext_siwfreq(struct net_device *dev, static int iwm_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info, struct iw_request_info *info,
@ -53,14 +33,12 @@ static int iwm_wext_siwfreq(struct net_device *dev,
{ {
struct iwm_priv *iwm = ndev_to_iwm(dev); struct iwm_priv *iwm = ndev_to_iwm(dev);
if (freq->flags == IW_FREQ_AUTO) switch (iwm->conf.mode) {
return 0; case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
/* frequency/channel can only be set in IBSS mode */ default:
if (iwm->conf.mode != UMAC_MODE_IBSS)
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
} }
static int iwm_wext_giwfreq(struct net_device *dev, static int iwm_wext_giwfreq(struct net_device *dev,
@ -69,69 +47,29 @@ static int iwm_wext_giwfreq(struct net_device *dev,
{ {
struct iwm_priv *iwm = ndev_to_iwm(dev); struct iwm_priv *iwm = ndev_to_iwm(dev);
if (iwm->conf.mode == UMAC_MODE_IBSS) switch (iwm->conf.mode) {
case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
case UMAC_MODE_BSS:
freq->e = 0; return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
freq->m = iwm->channel; default:
return -EOPNOTSUPP;
return 0; }
} }
static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
struct sockaddr *ap_addr, char *extra) struct sockaddr *ap_addr, char *extra)
{ {
struct iwm_priv *iwm = ndev_to_iwm(dev); struct iwm_priv *iwm = ndev_to_iwm(dev);
int ret;
IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data); switch (iwm->conf.mode) {
case UMAC_MODE_IBSS:
if (iwm->conf.mode == UMAC_MODE_IBSS)
return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
case UMAC_MODE_BSS:
if (!test_bit(IWM_STATUS_READY, &iwm->status)) return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
return -EIO; default:
return -EOPNOTSUPP;
if (is_zero_ether_addr(ap_addr->sa_data) ||
is_broadcast_ether_addr(ap_addr->sa_data)) {
IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
iwm->umac_profile->bssid[0]);
memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
iwm->umac_profile->bss_num = 0;
} else {
IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
ap_addr->sa_data);
memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
ETH_ALEN);
iwm->umac_profile->bss_num = 1;
} }
if (iwm->umac_profile_active) {
int i;
if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
return 0;
/*
* If we're clearing the BSSID, and we're associated,
* we have to clear the keys as they're no longer valid.
*/
if (is_zero_ether_addr(ap_addr->sa_data)) {
for (i = 0; i < IWM_NUM_KEYS; i++)
iwm->keys[i].key_len = 0;
}
ret = iwm_invalidate_mlme_profile(iwm);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't invalidate profile\n");
return ret;
}
}
if (iwm->umac_profile->ssid.ssid_len)
return iwm_send_mlme_profile(iwm);
return 0;
} }
static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
@ -143,17 +81,10 @@ static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
case UMAC_MODE_IBSS: case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
case UMAC_MODE_BSS: case UMAC_MODE_BSS:
if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
ap_addr->sa_family = ARPHRD_ETHER;
memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
} else
memset(&ap_addr->sa_data, 0, ETH_ALEN);
break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
return 0;
} }
static int iwm_wext_siwessid(struct net_device *dev, static int iwm_wext_siwessid(struct net_device *dev,
@ -161,36 +92,15 @@ static int iwm_wext_siwessid(struct net_device *dev,
struct iw_point *data, char *ssid) struct iw_point *data, char *ssid)
{ {
struct iwm_priv *iwm = ndev_to_iwm(dev); struct iwm_priv *iwm = ndev_to_iwm(dev);
size_t len = data->length;
int ret;
IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid); switch (iwm->conf.mode) {
case UMAC_MODE_IBSS:
if (iwm->conf.mode == UMAC_MODE_IBSS)
return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
case UMAC_MODE_BSS:
if (!test_bit(IWM_STATUS_READY, &iwm->status)) return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
return -EIO; default:
return -EOPNOTSUPP;
if (len > 0 && ssid[len - 1] == '\0')
len--;
if (iwm->umac_profile_active) {
if (iwm->umac_profile->ssid.ssid_len == len &&
!memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
return 0;
ret = iwm_invalidate_mlme_profile(iwm);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't invalidate profile\n");
return ret;
}
} }
iwm->umac_profile->ssid.ssid_len = len;
memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
return iwm_send_mlme_profile(iwm);
} }
static int iwm_wext_giwessid(struct net_device *dev, static int iwm_wext_giwessid(struct net_device *dev,
@ -199,174 +109,14 @@ static int iwm_wext_giwessid(struct net_device *dev,
{ {
struct iwm_priv *iwm = ndev_to_iwm(dev); struct iwm_priv *iwm = ndev_to_iwm(dev);
if (iwm->conf.mode == UMAC_MODE_IBSS) switch (iwm->conf.mode) {
case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
case UMAC_MODE_BSS:
if (!test_bit(IWM_STATUS_READY, &iwm->status)) return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
return -EIO;
data->length = iwm->umac_profile->ssid.ssid_len;
if (data->length) {
memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
data->flags = 1;
} else
data->flags = 0;
return 0;
}
static int iwm_wext_giwrate(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rate, char *extra)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
rate->value = iwm->rate * 1000000;
return 0;
}
static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
{
if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
else
iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
return 0;
}
static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
{
u8 *auth_type = &iwm->umac_profile->sec.auth_type;
IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
*auth_type = UMAC_AUTH_TYPE_8021X;
else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
if (iwm->umac_profile->sec.flags &
(UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
else
*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
} else {
IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
return -EINVAL;
}
return 0;
}
static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
{
u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
&iwm->umac_profile->sec.mcast_cipher;
switch (cipher) {
case IW_AUTH_CIPHER_NONE:
*profile_cipher = UMAC_CIPHER_TYPE_NONE;
break;
case IW_AUTH_CIPHER_WEP40:
*profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
break;
case IW_AUTH_CIPHER_TKIP:
*profile_cipher = UMAC_CIPHER_TYPE_TKIP;
break;
case IW_AUTH_CIPHER_CCMP:
*profile_cipher = UMAC_CIPHER_TYPE_CCMP;
break;
case IW_AUTH_CIPHER_WEP104:
*profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
break;
default: default:
IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); return -EOPNOTSUPP;
return -ENOTSUPP;
} }
return 0;
}
static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
{
u8 *auth_type = &iwm->umac_profile->sec.auth_type;
IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg);
switch (auth_alg) {
case IW_AUTH_ALG_OPEN_SYSTEM:
*auth_type = UMAC_AUTH_TYPE_OPEN;
break;
case IW_AUTH_ALG_SHARED_KEY:
if (iwm->umac_profile->sec.flags &
(UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
if (*auth_type == UMAC_AUTH_TYPE_8021X)
return -EINVAL;
*auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
} else {
IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n");
*auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
}
break;
case IW_AUTH_ALG_LEAP:
default:
IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
return -ENOTSUPP;
}
return 0;
}
static int iwm_wext_siwauth(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *data, char *extra)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
int ret;
if ((data->flags) &
(IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
/* We need to invalidate the current profile */
if (iwm->umac_profile_active) {
ret = iwm_invalidate_mlme_profile(iwm);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't invalidate profile\n");
return ret;
}
}
}
switch (data->flags & IW_AUTH_INDEX) {
case IW_AUTH_WPA_VERSION:
return iwm_set_wpa_version(iwm, data->value);
break;
case IW_AUTH_CIPHER_PAIRWISE:
return iwm_set_cipher(iwm, data->value, 1);
break;
case IW_AUTH_CIPHER_GROUP:
return iwm_set_cipher(iwm, data->value, 0);
break;
case IW_AUTH_KEY_MGMT:
return iwm_set_key_mgt(iwm, data->value);
break;
case IW_AUTH_80211_AUTH_ALG:
return iwm_set_auth_alg(iwm, data->value);
break;
default:
return -ENOTSUPP;
}
return 0;
}
static int iwm_wext_giwauth(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *data, char *extra)
{
return 0;
} }
static const iw_handler iwm_handlers[] = static const iw_handler iwm_handlers[] =
@ -404,7 +154,7 @@ static const iw_handler iwm_handlers[] =
(iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* SIOCSIWRATE */ (iw_handler) NULL, /* SIOCSIWRATE */
(iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */ (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */
(iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
(iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
(iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
@ -419,10 +169,10 @@ static const iw_handler iwm_handlers[] =
(iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */
(iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* SIOCSIWGENIE */ (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */
(iw_handler) NULL, /* SIOCGIWGENIE */ (iw_handler) NULL, /* SIOCGIWGENIE */
(iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */ (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */
(iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */ (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */
(iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
(iw_handler) NULL, /* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCGIWENCODEEXT */
(iw_handler) NULL, /* SIOCSIWPMKSA */ (iw_handler) NULL, /* SIOCSIWPMKSA */
@ -432,6 +182,6 @@ static const iw_handler iwm_handlers[] =
const struct iw_handler_def iwm_iw_handler_def = { const struct iw_handler_def iwm_iw_handler_def = {
.num_standard = ARRAY_SIZE(iwm_handlers), .num_standard = ARRAY_SIZE(iwm_handlers),
.standard = (iw_handler *) iwm_handlers, .standard = (iw_handler *) iwm_handlers,
.get_wireless_stats = iwm_get_wireless_stats, .get_wireless_stats = cfg80211_wireless_stats,
}; };

View File

@ -129,7 +129,6 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
{ {
struct cmd_ds_802_11_authenticate cmd; struct cmd_ds_802_11_authenticate cmd;
int ret = -1; int ret = -1;
DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN); lbs_deb_enter(LBS_DEB_JOIN);
@ -138,8 +137,7 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
cmd.authtype = iw_auth_to_ieee_auth(auth); cmd.authtype = iw_auth_to_ieee_auth(auth);
lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
print_mac(mac, bssid), cmd.authtype);
ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
@ -342,8 +340,6 @@ static int lbs_associate(struct lbs_private *priv,
/* Firmware v9+ indicate authentication suites as a TLV */ /* Firmware v9+ indicate authentication suites as a TLV */
if (priv->fwrelease >= 0x09000000) { if (priv->fwrelease >= 0x09000000) {
DECLARE_MAC_BUF(mac);
auth = (struct mrvl_ie_auth_type *) pos; auth = (struct mrvl_ie_auth_type *) pos;
auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
auth->header.len = cpu_to_le16(2); auth->header.len = cpu_to_le16(2);
@ -351,8 +347,8 @@ static int lbs_associate(struct lbs_private *priv,
auth->auth = cpu_to_le16(tmpauth); auth->auth = cpu_to_le16(tmpauth);
pos += sizeof(auth->header) + 2; pos += sizeof(auth->header) + 2;
lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
print_mac(mac, bss->bssid), priv->secinfo.auth_mode); bss->bssid, priv->secinfo.auth_mode);
} }
/* WPA/WPA2 IEs */ /* WPA/WPA2 IEs */

View File

@ -406,7 +406,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
rx_status.freq = data->channel->center_freq; rx_status.freq = data->channel->center_freq;
rx_status.band = data->channel->band; rx_status.band = data->channel->band;
rx_status.rate_idx = info->control.rates[0].idx; rx_status.rate_idx = info->control.rates[0].idx;
/* TODO: simulate signal strength (and optional packet drop) */ /* TODO: simulate real signal strength (and optional packet loss) */
rx_status.signal = -50;
if (data->ps != PS_DISABLED) if (data->ps != PS_DISABLED)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
@ -836,7 +837,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
{ {
struct mac80211_hwsim_data *data = dat; struct mac80211_hwsim_data *data = dat;
struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
DECLARE_MAC_BUF(buf);
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_pspoll *pspoll; struct ieee80211_pspoll *pspoll;
@ -866,7 +866,6 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
struct ieee80211_vif *vif, int ps) struct ieee80211_vif *vif, int ps)
{ {
struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
DECLARE_MAC_BUF(buf);
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
@ -1024,7 +1023,8 @@ static int __init init_mac80211_hwsim(void)
BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT); BIT(NL80211_IFTYPE_MESH_POINT);
hw->flags = IEEE80211_HW_MFP_CAPABLE; hw->flags = IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_SIGNAL_DBM;
/* ask mac80211 to reserve space for magic */ /* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv); hw->vif_data_size = sizeof(struct hwsim_vif_priv);

View File

@ -2271,7 +2271,6 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
struct mwl8k_cmd_update_sta_db *cmd; struct mwl8k_cmd_update_sta_db *cmd;
struct peer_capability_info *peer_info; struct peer_capability_info *peer_info;
struct ieee80211_rate *bitrates = mv_vif->legacy_rates; struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
DECLARE_MAC_BUF(mac);
int rc; int rc;
__u8 count, *rates; __u8 count, *rates;
@ -3480,7 +3479,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
{ {
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
struct mwl8k_priv *priv; struct mwl8k_priv *priv;
DECLARE_MAC_BUF(mac);
int rc; int rc;
int i; int i;
u8 *fw; u8 *fw;
@ -3669,8 +3667,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
MWL8K_DESC); MWL8K_DESC);
printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n", printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n",
priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]); priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]);
printk(KERN_INFO "%s: MAC Address: %s\n", priv->name, printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name,
print_mac(mac, hw->wiphy->perm_addr)); hw->wiphy->perm_addr);
return 0; return 0;

View File

@ -19,6 +19,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/sort.h>
#include <net/mac80211.h> #include <net/mac80211.h>
@ -41,30 +42,6 @@ static struct ieee80211_rate p54_bgrates[] = {
{ .bitrate = 540, .hw_value = 11, }, { .bitrate = 540, .hw_value = 11, },
}; };
static struct ieee80211_channel p54_bgchannels[] = {
{ .center_freq = 2412, .hw_value = 1, },
{ .center_freq = 2417, .hw_value = 2, },
{ .center_freq = 2422, .hw_value = 3, },
{ .center_freq = 2427, .hw_value = 4, },
{ .center_freq = 2432, .hw_value = 5, },
{ .center_freq = 2437, .hw_value = 6, },
{ .center_freq = 2442, .hw_value = 7, },
{ .center_freq = 2447, .hw_value = 8, },
{ .center_freq = 2452, .hw_value = 9, },
{ .center_freq = 2457, .hw_value = 10, },
{ .center_freq = 2462, .hw_value = 11, },
{ .center_freq = 2467, .hw_value = 12, },
{ .center_freq = 2472, .hw_value = 13, },
{ .center_freq = 2484, .hw_value = 14, },
};
static struct ieee80211_supported_band band_2GHz = {
.channels = p54_bgchannels,
.n_channels = ARRAY_SIZE(p54_bgchannels),
.bitrates = p54_bgrates,
.n_bitrates = ARRAY_SIZE(p54_bgrates),
};
static struct ieee80211_rate p54_arates[] = { static struct ieee80211_rate p54_arates[] = {
{ .bitrate = 60, .hw_value = 4, }, { .bitrate = 60, .hw_value = 4, },
{ .bitrate = 90, .hw_value = 5, }, { .bitrate = 90, .hw_value = 5, },
@ -76,51 +53,257 @@ static struct ieee80211_rate p54_arates[] = {
{ .bitrate = 540, .hw_value = 11, }, { .bitrate = 540, .hw_value = 11, },
}; };
static struct ieee80211_channel p54_achannels[] = { #define CHAN_HAS_CAL BIT(0)
{ .center_freq = 4920 }, #define CHAN_HAS_LIMIT BIT(1)
{ .center_freq = 4940 }, #define CHAN_HAS_CURVE BIT(2)
{ .center_freq = 4960 }, #define CHAN_HAS_ALL (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
{ .center_freq = 4980 },
{ .center_freq = 5040 }, struct p54_channel_entry {
{ .center_freq = 5060 }, u16 freq;
{ .center_freq = 5080 }, u16 data;
{ .center_freq = 5170 }, int index;
{ .center_freq = 5180 }, enum ieee80211_band band;
{ .center_freq = 5190 },
{ .center_freq = 5200 },
{ .center_freq = 5210 },
{ .center_freq = 5220 },
{ .center_freq = 5230 },
{ .center_freq = 5240 },
{ .center_freq = 5260 },
{ .center_freq = 5280 },
{ .center_freq = 5300 },
{ .center_freq = 5320 },
{ .center_freq = 5500 },
{ .center_freq = 5520 },
{ .center_freq = 5540 },
{ .center_freq = 5560 },
{ .center_freq = 5580 },
{ .center_freq = 5600 },
{ .center_freq = 5620 },
{ .center_freq = 5640 },
{ .center_freq = 5660 },
{ .center_freq = 5680 },
{ .center_freq = 5700 },
{ .center_freq = 5745 },
{ .center_freq = 5765 },
{ .center_freq = 5785 },
{ .center_freq = 5805 },
{ .center_freq = 5825 },
}; };
static struct ieee80211_supported_band band_5GHz = { struct p54_channel_list {
.channels = p54_achannels, struct p54_channel_entry *channels;
.n_channels = ARRAY_SIZE(p54_achannels), size_t entries;
.bitrates = p54_arates, size_t max_entries;
.n_bitrates = ARRAY_SIZE(p54_arates), size_t band_channel_num[IEEE80211_NUM_BANDS];
}; };
static int p54_get_band_from_freq(u16 freq)
{
/* FIXME: sync these values with the 802.11 spec */
if ((freq >= 2412) && (freq <= 2484))
return IEEE80211_BAND_2GHZ;
if ((freq >= 4920) && (freq <= 5825))
return IEEE80211_BAND_5GHZ;
return -1;
}
static int p54_compare_channels(const void *_a,
const void *_b)
{
const struct p54_channel_entry *a = _a;
const struct p54_channel_entry *b = _b;
return a->index - b->index;
}
static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
struct ieee80211_supported_band *band_entry,
enum ieee80211_band band)
{
/* TODO: generate rate array dynamically */
switch (band) {
case IEEE80211_BAND_2GHZ:
band_entry->bitrates = p54_bgrates;
band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
break;
case IEEE80211_BAND_5GHZ:
band_entry->bitrates = p54_arates;
band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
break;
default:
return -EINVAL;
}
return 0;
}
static int p54_generate_band(struct ieee80211_hw *dev,
struct p54_channel_list *list,
enum ieee80211_band band)
{
struct p54_common *priv = dev->priv;
struct ieee80211_supported_band *tmp, *old;
unsigned int i, j;
int ret = -ENOMEM;
if ((!list->entries) || (!list->band_channel_num[band]))
return 0;
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp)
goto err_out;
tmp->channels = kzalloc(sizeof(struct ieee80211_channel) *
list->band_channel_num[band], GFP_KERNEL);
if (!tmp->channels)
goto err_out;
ret = p54_fill_band_bitrates(dev, tmp, band);
if (ret)
goto err_out;
for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
(i < list->entries); i++) {
if (list->channels[i].band != band)
continue;
if (list->channels[i].data != CHAN_HAS_ALL) {
printk(KERN_ERR "%s:%s%s%s is/are missing for "
"channel:%d [%d MHz].\n",
wiphy_name(dev->wiphy),
(list->channels[i].data & CHAN_HAS_CAL ? "" :
" [iqauto calibration data]"),
(list->channels[i].data & CHAN_HAS_LIMIT ? "" :
" [output power limits]"),
(list->channels[i].data & CHAN_HAS_CURVE ? "" :
" [curve data]"),
list->channels[i].index, list->channels[i].freq);
}
tmp->channels[j].band = list->channels[i].band;
tmp->channels[j].center_freq = list->channels[i].freq;
j++;
}
tmp->n_channels = list->band_channel_num[band];
old = priv->band_table[band];
priv->band_table[band] = tmp;
if (old) {
kfree(old->channels);
kfree(old);
}
return 0;
err_out:
if (tmp) {
kfree(tmp->channels);
kfree(tmp);
}
return ret;
}
static void p54_update_channel_param(struct p54_channel_list *list,
u16 freq, u16 data)
{
int band, i;
/*
* usually all lists in the eeprom are mostly sorted.
* so it's very likely that the entry we are looking for
* is right at the end of the list
*/
for (i = list->entries; i >= 0; i--) {
if (freq == list->channels[i].freq) {
list->channels[i].data |= data;
break;
}
}
if ((i < 0) && (list->entries < list->max_entries)) {
/* entry does not exist yet. Initialize a new one. */
band = p54_get_band_from_freq(freq);
/*
* filter out frequencies which don't belong into
* any supported band.
*/
if (band < 0)
return ;
i = list->entries++;
list->band_channel_num[band]++;
list->channels[i].freq = freq;
list->channels[i].data = data;
list->channels[i].band = band;
list->channels[i].index = ieee80211_frequency_to_channel(freq);
/* TODO: parse output_limit and fill max_power */
}
}
static int p54_generate_channel_lists(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
struct p54_channel_list *list;
unsigned int i, j, max_channel_num;
int ret = -ENOMEM;
u16 freq;
if ((priv->iq_autocal_len != priv->curve_data->entries) ||
(priv->iq_autocal_len != priv->output_limit->entries))
printk(KERN_ERR "%s: EEPROM is damaged... you may not be able"
"to use all channels with this device.\n",
wiphy_name(dev->wiphy));
max_channel_num = max_t(unsigned int, priv->output_limit->entries,
priv->iq_autocal_len);
max_channel_num = max_t(unsigned int, max_channel_num,
priv->curve_data->entries);
list = kzalloc(sizeof(*list), GFP_KERNEL);
if (!list)
goto free;
list->max_entries = max_channel_num;
list->channels = kzalloc(sizeof(struct p54_channel_entry) *
max_channel_num, GFP_KERNEL);
if (!list->channels)
goto free;
for (i = 0; i < max_channel_num; i++) {
if (i < priv->iq_autocal_len) {
freq = le16_to_cpu(priv->iq_autocal[i].freq);
p54_update_channel_param(list, freq, CHAN_HAS_CAL);
}
if (i < priv->output_limit->entries) {
freq = le16_to_cpup((__le16 *) (i *
priv->output_limit->entry_size +
priv->output_limit->offset +
priv->output_limit->data));
p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
}
if (i < priv->curve_data->entries) {
freq = le16_to_cpup((__le16 *) (i *
priv->curve_data->entry_size +
priv->curve_data->offset +
priv->curve_data->data));
p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
}
}
/* sort the list by the channel index */
sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
p54_compare_channels, NULL);
for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
if (list->band_channel_num[i]) {
ret = p54_generate_band(dev, list, i);
if (ret)
goto free;
j++;
}
}
if (j == 0) {
/* no useable band available. */
ret = -EINVAL;
}
free:
if (list) {
kfree(list->channels);
kfree(list);
}
return ret;
}
static int p54_convert_rev0(struct ieee80211_hw *dev, static int p54_convert_rev0(struct ieee80211_hw *dev,
struct pda_pa_curve_data *curve_data) struct pda_pa_curve_data *curve_data)
{ {
@ -346,7 +529,7 @@ static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
{ {
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
struct eeprom_pda_wrap *wrap = NULL; struct eeprom_pda_wrap *wrap;
struct pda_entry *entry; struct pda_entry *entry;
unsigned int data_len, entry_len; unsigned int data_len, entry_len;
void *tmp; void *tmp;
@ -487,13 +670,19 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
goto err; goto err;
} }
err = p54_generate_channel_lists(dev);
if (err)
goto err;
priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
p54_init_xbow_synth(priv); p54_init_xbow_synth(priv);
if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; dev->wiphy->bands[IEEE80211_BAND_2GHZ] =
priv->band_table[IEEE80211_BAND_2GHZ];
if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; dev->wiphy->bands[IEEE80211_BAND_5GHZ] =
priv->band_table[IEEE80211_BAND_5GHZ];
if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED) if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
priv->rx_diversity_mask = 3; priv->rx_diversity_mask = 3;
if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED) if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
@ -533,7 +722,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev)
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
int ret = -ENOMEM; int ret = -ENOMEM;
void *eeprom = NULL; void *eeprom;
maxblocksize = EEPROM_READBACK_LEN; maxblocksize = EEPROM_READBACK_LEN;
if (priv->fw_var >= 0x509) if (priv->fw_var >= 0x509)

View File

@ -585,7 +585,8 @@ int p54_set_ps(struct p54_common *priv)
unsigned int i; unsigned int i;
u16 mode; u16 mode;
if (priv->hw->conf.flags & IEEE80211_CONF_PS) if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
!priv->powersave_override)
mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM | mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
P54_PSM_CHECKSUM | P54_PSM_MCBC; P54_PSM_CHECKSUM | P54_PSM_MCBC;
else else
@ -607,8 +608,8 @@ int p54_set_ps(struct p54_common *priv)
psm->beacon_rssi_skip_max = 200; psm->beacon_rssi_skip_max = 200;
psm->rssi_delta_threshold = 0; psm->rssi_delta_threshold = 0;
psm->nr = 10; psm->nr = 1;
psm->exclude[0] = 0; psm->exclude[0] = WLAN_EID_TIM;
p54_tx(priv, skb); p54_tx(priv, skb);
return 0; return 0;
@ -685,6 +686,8 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len,
int p54_fetch_statistics(struct p54_common *priv) int p54_fetch_statistics(struct p54_common *priv)
{ {
struct ieee80211_tx_info *txinfo;
struct p54_tx_info *p54info;
struct sk_buff *skb; struct sk_buff *skb;
skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL,
@ -693,6 +696,20 @@ int p54_fetch_statistics(struct p54_common *priv)
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
/*
* The statistic feedback causes some extra headaches here, if it
* is not to crash/corrupt the firmware data structures.
*
* Unlike all other Control Get OIDs we can not use helpers like
* skb_put to reserve the space for the data we're requesting.
* Instead the extra frame length -which will hold the results later-
* will only be told to the p54_assign_address, so that following
* frames won't be placed into the allegedly empty area.
*/
txinfo = IEEE80211_SKB_CB(skb);
p54info = (void *) txinfo->rate_driver_data;
p54info->extra_len = sizeof(struct p54_statistics);
p54_tx(priv, skb); p54_tx(priv, skb);
return 0; return 0;
} }

View File

@ -98,6 +98,10 @@ struct p54_hdr {
(!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL))) flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL)))
#define GET_HW_QUEUE(skb) \
(((struct p54_tx_data *)((struct p54_hdr *) \
skb->data)->data)->hw_queue)
/* /*
* shared interface ID definitions * shared interface ID definitions
* The interface ID is a unique identification of a specific interface. * The interface ID is a unique identification of a specific interface.
@ -548,4 +552,7 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot,
int p54_download_eeprom(struct p54_common *priv, void *buf, int p54_download_eeprom(struct p54_common *priv, void *buf,
u16 offset, u16 len); u16 offset, u16 len);
/* utility */
u8 *p54_find_ie(struct sk_buff *skb, u8 ie);
#endif /* LMAC_H */ #endif /* LMAC_H */

View File

@ -65,6 +65,28 @@ static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
return p54_update_beacon_tim(priv, sta->aid, set); return p54_update_beacon_tim(priv, sta->aid, set);
} }
u8 *p54_find_ie(struct sk_buff *skb, u8 ie)
{
struct ieee80211_mgmt *mgmt = (void *)skb->data;
u8 *pos, *end;
if (skb->len <= sizeof(mgmt))
return NULL;
pos = (u8 *)mgmt->u.beacon.variable;
end = skb->data + skb->len;
while (pos < end) {
if (pos + 2 + pos[1] > end)
return NULL;
if (pos[0] == ie)
return pos;
pos += 2 + pos[1];
}
return NULL;
}
static int p54_beacon_format_ie_tim(struct sk_buff *skb) static int p54_beacon_format_ie_tim(struct sk_buff *skb)
{ {
/* /*
@ -72,44 +94,35 @@ static int p54_beacon_format_ie_tim(struct sk_buff *skb)
* The dummy TIM MUST be at the end of the beacon frame, * The dummy TIM MUST be at the end of the beacon frame,
* because it'll be overwritten! * because it'll be overwritten!
*/ */
u8 *tim;
u8 dtim_len;
u8 dtim_period;
u8 *next;
struct ieee80211_mgmt *mgmt = (void *)skb->data; tim = p54_find_ie(skb, WLAN_EID_TIM);
u8 *pos, *end; if (!tim)
return 0;
if (skb->len <= sizeof(mgmt)) dtim_len = tim[1];
dtim_period = tim[3];
next = tim + 2 + dtim_len;
if (dtim_len < 3)
return -EINVAL; return -EINVAL;
pos = (u8 *)mgmt->u.beacon.variable; memmove(tim, next, skb_tail_pointer(skb) - next);
end = skb->data + skb->len; tim = skb_tail_pointer(skb) - (dtim_len + 2);
while (pos < end) {
if (pos + 2 + pos[1] > end)
return -EINVAL;
if (pos[0] == WLAN_EID_TIM) { /* add the dummy at the end */
u8 dtim_len = pos[1]; tim[0] = WLAN_EID_TIM;
u8 dtim_period = pos[3]; tim[1] = 3;
u8 *next = pos + 2 + dtim_len; tim[2] = 0;
tim[3] = dtim_period;
tim[4] = 0;
if (dtim_len < 3) if (dtim_len > 3)
return -EINVAL; skb_trim(skb, skb->len - (dtim_len - 3));
memmove(pos, next, end - next);
if (dtim_len > 3)
skb_trim(skb, skb->len - (dtim_len - 3));
pos = end - (dtim_len + 2);
/* add the dummy at the end */
pos[0] = WLAN_EID_TIM;
pos[1] = 3;
pos[2] = 0;
pos[3] = dtim_period;
pos[4] = 0;
return 0;
}
pos += 2 + pos[1];
}
return 0; return 0;
} }
@ -117,7 +130,6 @@ static int p54_beacon_update(struct p54_common *priv,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct sk_buff *beacon; struct sk_buff *beacon;
__le32 old_beacon_req_id;
int ret; int ret;
beacon = ieee80211_beacon_get(priv->hw, vif); beacon = ieee80211_beacon_get(priv->hw, vif);
@ -127,15 +139,16 @@ static int p54_beacon_update(struct p54_common *priv,
if (ret) if (ret)
return ret; return ret;
old_beacon_req_id = priv->beacon_req_id; /*
priv->beacon_req_id = GET_REQ_ID(beacon); * During operation, the firmware takes care of beaconing.
* The driver only needs to upload a new beacon template, once
ret = p54_tx_80211(priv->hw, beacon); * the template was changed by the stack or userspace.
if (ret) { *
priv->beacon_req_id = old_beacon_req_id; * LMAC API 3.2.2 also specifies that the driver does not need
return -ENOSPC; * to cancel the old beacon template by hand, instead the firmware
} * will release the previous one through the feedback mechanism.
*/
WARN_ON(p54_tx_80211(priv->hw, beacon));
priv->tsf_high32 = 0; priv->tsf_high32 = 0;
priv->tsf_low32 = 0; priv->tsf_low32 = 0;
@ -240,9 +253,14 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
mutex_lock(&priv->conf_mutex); mutex_lock(&priv->conf_mutex);
priv->vif = NULL; priv->vif = NULL;
if (priv->beacon_req_id) {
/*
* LMAC API 3.2.2 states that any active beacon template must be
* canceled by the driver before attempting a mode transition.
*/
if (le32_to_cpu(priv->beacon_req_id) != 0) {
p54_tx_cancel(priv, priv->beacon_req_id); p54_tx_cancel(priv, priv->beacon_req_id);
priv->beacon_req_id = cpu_to_le32(0); wait_for_completion_interruptible_timeout(&priv->beacon_comp, HZ);
} }
priv->mode = NL80211_IFTYPE_MONITOR; priv->mode = NL80211_IFTYPE_MONITOR;
memset(priv->mac_addr, 0, ETH_ALEN); memset(priv->mac_addr, 0, ETH_ALEN);
@ -384,6 +402,9 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
priv->wakeup_timer = info->beacon_int * priv->wakeup_timer = info->beacon_int *
info->dtim_period * 5; info->dtim_period * 5;
p54_setup_mac(priv); p54_setup_mac(priv);
} else {
priv->wakeup_timer = 500;
priv->aid = 0;
} }
} }
@ -517,6 +538,9 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
skb_queue_head_init(&priv->tx_pending); skb_queue_head_init(&priv->tx_pending);
dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_BEACON_FILTER |
IEEE80211_HW_NOISE_DBM; IEEE80211_HW_NOISE_DBM;
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
@ -525,6 +549,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
BIT(NL80211_IFTYPE_MESH_POINT); BIT(NL80211_IFTYPE_MESH_POINT);
dev->channel_change_time = 1000; /* TODO: find actual value */ dev->channel_change_time = 1000; /* TODO: find actual value */
priv->beacon_req_id = cpu_to_le32(0);
priv->tx_stats[P54_QUEUE_BEACON].limit = 1; priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1; priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
priv->tx_stats[P54_QUEUE_MGMT].limit = 3; priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
@ -548,6 +573,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
mutex_init(&priv->conf_mutex); mutex_init(&priv->conf_mutex);
mutex_init(&priv->eeprom_mutex); mutex_init(&priv->eeprom_mutex);
init_completion(&priv->eeprom_comp); init_completion(&priv->eeprom_comp);
init_completion(&priv->beacon_comp);
INIT_DELAYED_WORK(&priv->work, p54_work); INIT_DELAYED_WORK(&priv->work, p54_work);
return dev; return dev;
@ -579,6 +605,10 @@ EXPORT_SYMBOL_GPL(p54_register_common);
void p54_free_common(struct ieee80211_hw *dev) void p54_free_common(struct ieee80211_hw *dev)
{ {
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
unsigned int i;
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
kfree(priv->band_table[i]);
kfree(priv->iq_autocal); kfree(priv->iq_autocal);
kfree(priv->output_limit); kfree(priv->output_limit);

View File

@ -198,6 +198,7 @@ struct p54_common {
struct p54_cal_database *curve_data; struct p54_cal_database *curve_data;
struct p54_cal_database *output_limit; struct p54_cal_database *output_limit;
struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS];
/* BBP/MAC state */ /* BBP/MAC state */
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
@ -208,7 +209,9 @@ struct p54_common {
u32 tsf_low32, tsf_high32; u32 tsf_low32, tsf_high32;
u32 basic_rate_mask; u32 basic_rate_mask;
u16 aid; u16 aid;
bool powersave_override;
__le32 beacon_req_id; __le32 beacon_req_id;
struct completion beacon_comp;
/* cryptographic engine information */ /* cryptographic engine information */
u8 privacy_caps; u8 privacy_caps;

View File

@ -87,9 +87,6 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
u32 target_addr = priv->rx_start; u32 target_addr = priv->rx_start;
u16 len = priv->headroom + skb->len + priv->tailroom + 3; u16 len = priv->headroom + skb->len + priv->tailroom + 3;
if (unlikely(WARN_ON(!skb || !priv)))
return -EINVAL;
info = IEEE80211_SKB_CB(skb); info = IEEE80211_SKB_CB(skb);
range = (void *) info->rate_driver_data; range = (void *) info->rate_driver_data;
len = (range->extra_len + len) & ~0x3; len = (range->extra_len + len) & ~0x3;
@ -111,11 +108,6 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
range = (void *) info->rate_driver_data; range = (void *) info->rate_driver_data;
hole_size = range->start_addr - last_addr; hole_size = range->start_addr - last_addr;
if (!entry->next) {
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
return -ENOSPC;
}
if (!target_skb && hole_size >= len) { if (!target_skb && hole_size >= len) {
target_skb = entry->prev; target_skb = entry->prev;
hole_size -= len; hole_size -= len;
@ -142,9 +134,13 @@ static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
range = (void *) info->rate_driver_data; range = (void *) info->rate_driver_data;
range->start_addr = target_addr; range->start_addr = target_addr;
range->end_addr = target_addr + len; range->end_addr = target_addr + len;
data->req_id = cpu_to_le32(target_addr + priv->headroom);
if (IS_DATA_FRAME(skb) &&
unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
priv->beacon_req_id = data->req_id;
__skb_queue_after(&priv->tx_queue, target_skb, skb); __skb_queue_after(&priv->tx_queue, target_skb, skb);
spin_unlock_irqrestore(&priv->tx_queue.lock, flags); spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
data->req_id = cpu_to_le32(target_addr + priv->headroom);
return 0; return 0;
} }
@ -153,9 +149,6 @@ static void p54_tx_pending(struct p54_common *priv)
struct sk_buff *skb; struct sk_buff *skb;
int ret; int ret;
if (unlikely(WARN_ON(!priv)))
return ;
skb = skb_dequeue(&priv->tx_pending); skb = skb_dequeue(&priv->tx_pending);
if (unlikely(!skb)) if (unlikely(!skb))
return ; return ;
@ -219,14 +212,20 @@ static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
static void p54_tx_qos_accounting_free(struct p54_common *priv, static void p54_tx_qos_accounting_free(struct p54_common *priv,
struct sk_buff *skb) struct sk_buff *skb)
{ {
if (skb && IS_DATA_FRAME(skb)) { if (IS_DATA_FRAME(skb)) {
struct p54_hdr *hdr = (void *) skb->data;
struct p54_tx_data *data = (void *) hdr->data;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&priv->tx_stats_lock, flags); spin_lock_irqsave(&priv->tx_stats_lock, flags);
priv->tx_stats[data->hw_queue].len--; priv->tx_stats[GET_HW_QUEUE(skb)].len--;
spin_unlock_irqrestore(&priv->tx_stats_lock, flags); spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) {
if (priv->beacon_req_id == GET_REQ_ID(skb)) {
/* this is the active beacon set anymore */
priv->beacon_req_id = 0;
}
complete(&priv->beacon_comp);
}
} }
p54_wake_queues(priv); p54_wake_queues(priv);
} }
@ -266,9 +265,6 @@ static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv,
void p54_tx(struct p54_common *priv, struct sk_buff *skb) void p54_tx(struct p54_common *priv, struct sk_buff *skb)
{ {
if (unlikely(WARN_ON(!priv)))
return ;
skb_queue_tail(&priv->tx_pending, skb); skb_queue_tail(&priv->tx_pending, skb);
p54_tx_pending(priv); p54_tx_pending(priv);
} }
@ -288,6 +284,45 @@ static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
priv->rssical_db[band].add) / 4; priv->rssical_db[band].add) / 4;
} }
/*
* Even if the firmware is capable of dealing with incoming traffic,
* while dozing, we have to prepared in case mac80211 uses PS-POLL
* to retrieve outstanding frames from our AP.
* (see comment in net/mac80211/mlme.c @ line 1993)
*/
static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (void *) skb->data;
struct ieee80211_tim_ie *tim_ie;
u8 *tim;
u8 tim_len;
bool new_psm;
/* only beacons have a TIM IE */
if (!ieee80211_is_beacon(hdr->frame_control))
return;
if (!priv->aid)
return;
/* only consider beacons from the associated BSSID */
if (compare_ether_addr(hdr->addr3, priv->bssid))
return;
tim = p54_find_ie(skb, WLAN_EID_TIM);
if (!tim)
return;
tim_len = tim[1];
tim_ie = (struct ieee80211_tim_ie *) &tim[2];
new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid);
if (new_psm != priv->powersave_override) {
priv->powersave_override = new_psm;
p54_set_ps(priv);
}
}
static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb) static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
{ {
struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
@ -340,6 +375,9 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
skb_pull(skb, header_len); skb_pull(skb, header_len);
skb_trim(skb, le16_to_cpu(hdr->len)); skb_trim(skb, le16_to_cpu(hdr->len));
if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
p54_pspoll_workaround(priv, skb);
ieee80211_rx_irqsafe(priv->hw, skb); ieee80211_rx_irqsafe(priv->hw, skb);
queue_delayed_work(priv->hw->workqueue, &priv->work, queue_delayed_work(priv->hw->workqueue, &priv->work,
@ -375,10 +413,6 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
* and we don't want to confuse the mac80211 stack. * and we don't want to confuse the mac80211 stack.
*/ */
if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) { if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
if (entry_data->hw_queue == P54_QUEUE_BEACON &&
hdr->req_id == priv->beacon_req_id)
priv->beacon_req_id = cpu_to_le32(0);
dev_kfree_skb_any(entry); dev_kfree_skb_any(entry);
return ; return ;
} }

View File

@ -1561,6 +1561,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface, .remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config, .config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter, .configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.get_stats = rt2x00mac_get_stats, .get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed, .bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2400pci_conf_tx, .conf_tx = rt2400pci_conf_tx,

View File

@ -928,7 +928,7 @@
#define RXD_W7_RESERVED FIELD32(0xffffffff) #define RXD_W7_RESERVED FIELD32(0xffffffff)
/* /*
* Macro's for converting txpower from EEPROM to mac80211 value * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value. * and from mac80211 value to register value.
* NOTE: Logics in rt2400pci for txpower are reversed * NOTE: Logics in rt2400pci for txpower are reversed
* compared to the other rt2x00 drivers. A higher txpower * compared to the other rt2x00 drivers. A higher txpower

View File

@ -1860,6 +1860,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface, .remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config, .config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter, .configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.get_stats = rt2x00mac_get_stats, .get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed, .bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx, .conf_tx = rt2x00mac_conf_tx,

View File

@ -1218,7 +1218,7 @@
#define RXD_W10_DROP FIELD32(0x00000001) #define RXD_W10_DROP FIELD32(0x00000001)
/* /*
* Macro's for converting txpower from EEPROM to mac80211 value * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value. * and from mac80211 value to register value.
*/ */
#define MIN_TXPOWER 0 #define MIN_TXPOWER 0

View File

@ -1896,6 +1896,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface, .remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config, .config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter, .configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key, .set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats, .get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed, .bss_info_changed = rt2x00mac_bss_info_changed,

View File

@ -831,7 +831,7 @@
#define RXD_W3_EIV FIELD32(0xffffffff) #define RXD_W3_EIV FIELD32(0xffffffff)
/* /*
* Macro's for converting txpower from EEPROM to mac80211 value * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value. * and from mac80211 value to register value.
*/ */
#define MIN_TXPOWER 0 #define MIN_TXPOWER 0

View File

@ -1910,7 +1910,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
/* /*
* Before the radio can be enabled, the device first has * Before the radio can be enabled, the device first has
* to be woken up. After that it needs a bit of time * to be woken up. After that it needs a bit of time
* to be fully awake and the radio can be enabled. * to be fully awake and then the radio can be enabled.
*/ */
rt2800usb_set_state(rt2x00dev, STATE_AWAKE); rt2800usb_set_state(rt2x00dev, STATE_AWAKE);
msleep(1); msleep(1);
@ -1918,7 +1918,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
break; break;
case STATE_RADIO_OFF: case STATE_RADIO_OFF:
/* /*
* After the radio has been disablee, the device should * After the radio has been disabled, the device should
* be put to sleep for powersaving. * be put to sleep for powersaving.
*/ */
rt2800usb_disable_radio(rt2x00dev); rt2800usb_disable_radio(rt2x00dev);
@ -2220,10 +2220,8 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
*/ */
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) { if (!is_valid_ether_addr(mac)) {
DECLARE_MAC_BUF(macbuf);
random_ether_addr(mac); random_ether_addr(mac);
EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); EEPROM(rt2x00dev, "MAC: %pM\n", mac);
} }
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@ -2786,6 +2784,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface, .remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config, .config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter, .configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key, .set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats, .get_stats = rt2x00mac_get_stats,
.get_tkip_seq = rt2800usb_get_tkip_seq, .get_tkip_seq = rt2800usb_get_tkip_seq,

View File

@ -1921,7 +1921,7 @@ struct mac_iveiv_entry {
#define RXWI_W3_SNR1 FIELD32(0x0000ff00) #define RXWI_W3_SNR1 FIELD32(0x0000ff00)
/* /*
* Macro's for converting txpower from EEPROM to mac80211 value * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value. * and from mac80211 value to register value.
*/ */
#define MIN_G_TXPOWER 0 #define MIN_G_TXPOWER 0

View File

@ -245,7 +245,7 @@ struct link_ant {
struct antenna_setup active; struct antenna_setup active;
/* /*
* RSSI information for the different antenna's. * RSSI information for the different antennas.
* These statistics are used to determine when * These statistics are used to determine when
* to switch antenna when using software diversity. * to switch antenna when using software diversity.
* *
@ -594,7 +594,6 @@ enum rt2x00_flags {
DEVICE_STATE_INITIALIZED, DEVICE_STATE_INITIALIZED,
DEVICE_STATE_STARTED, DEVICE_STATE_STARTED,
DEVICE_STATE_ENABLED_RADIO, DEVICE_STATE_ENABLED_RADIO,
DEVICE_STATE_DISABLED_RADIO_HW,
/* /*
* Driver requirements * Driver requirements
@ -634,7 +633,7 @@ struct rt2x00_dev {
* The structure stored in here depends on the * The structure stored in here depends on the
* system bus (PCI or USB). * system bus (PCI or USB).
* When accessing this variable, the rt2x00dev_{pci,usb} * When accessing this variable, the rt2x00dev_{pci,usb}
* macro's should be used for correct typecasting. * macros should be used for correct typecasting.
*/ */
struct device *dev; struct device *dev;
@ -963,6 +962,8 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags, unsigned int changed_flags,
unsigned int *total_flags, unsigned int *total_flags,
int mc_count, struct dev_addr_list *mc_list); int mc_count, struct dev_addr_list *mc_list);
int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set);
#ifdef CONFIG_RT2X00_LIB_CRYPTO #ifdef CONFIG_RT2X00_LIB_CRYPTO
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_vif *vif, struct ieee80211_sta *sta,

View File

@ -132,7 +132,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
/* /*
* Failsafe: Make sure we are not sending the * Failsafe: Make sure we are not sending the
* ANTENNA_SW_DIVERSITY state to the driver. * ANTENNA_SW_DIVERSITY state to the driver.
* If that happes fallback to hardware default, * If that happens, fallback to hardware defaults,
* or our own default. * or our own default.
* The calls to rt2x00lib_config_antenna_check() * The calls to rt2x00lib_config_antenna_check()
* might have caused that we restore back to the already * might have caused that we restore back to the already

View File

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

View File

@ -40,8 +40,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
* Don't enable the radio twice. * Don't enable the radio twice.
* And check if the hardware button has been disabled. * And check if the hardware button has been disabled.
*/ */
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags))
return 0; return 0;
/* /*

View File

@ -158,7 +158,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
/* /*
* During the last period we have sampled the RSSI * During the last period we have sampled the RSSI
* from both antenna's. It now is time to determine * from both antennas. It now is time to determine
* which antenna demonstrated the best performance. * which antenna demonstrated the best performance.
* When we are already on the antenna with the best * When we are already on the antenna with the best
* performance, then there really is nothing for us * performance, then there really is nothing for us

View File

@ -341,7 +341,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
int status; int status;
/* /*
* Mac80211 might be calling this function while we are trying * mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it. * to remove the device or perhaps suspending it.
*/ */
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
@ -454,6 +454,16 @@ static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
sizeof(crypto->rx_mic)); sizeof(crypto->rx_mic));
} }
int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
rt2x00lib_beacondone(rt2x00dev);
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key) struct ieee80211_key_conf *key)
@ -577,7 +587,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
int update_bssid = 0; int update_bssid = 0;
/* /*
* Mac80211 might be calling this function while we are trying * mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it. * to remove the device or perhaps suspending it.
*/ */
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))

View File

@ -29,7 +29,7 @@
#include <linux/prefetch.h> #include <linux/prefetch.h>
/** /**
* DOC: Entrie frame size * DOC: Entry frame size
* *
* Ralink PCI devices demand the Frame size to be a multiple of 128 bytes, * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes,
* for USB devices this restriction does not apply, but the value of * for USB devices this restriction does not apply, but the value of
@ -45,13 +45,13 @@
/** /**
* DOC: Number of entries per queue * DOC: Number of entries per queue
* *
* Under normal load without fragmentation 12 entries are sufficient * Under normal load without fragmentation, 12 entries are sufficient
* without the queue being filled up to the maximum. When using fragmentation * without the queue being filled up to the maximum. When using fragmentation
* and the queue threshold code we need to add some additional margins to * and the queue threshold code, we need to add some additional margins to
* make sure the queue will never (or only under extreme load) fill up * make sure the queue will never (or only under extreme load) fill up
* completely. * completely.
* Since we don't use preallocated DMA having a large number of queue entries * Since we don't use preallocated DMA, having a large number of queue entries
* will have only minimal impact on the memory requirements for the queue. * will have minimal impact on the memory requirements for the queue.
*/ */
#define RX_ENTRIES 24 #define RX_ENTRIES 24
#define TX_ENTRIES 24 #define TX_ENTRIES 24

View File

@ -176,8 +176,8 @@ struct rt2x00_field32 {
#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x)) #define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x))
/* /*
* Macro's to find first set bit in a variable. * Macros to find first set bit in a variable.
* These macro's behaves the same as the __ffs() function with * These macros behave the same as the __ffs() functions but
* the most important difference that this is done during * the most important difference that this is done during
* compile-time rather then run-time. * compile-time rather then run-time.
*/ */

View File

@ -2312,7 +2312,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
} }
/* /*
* Determine number of antenna's. * Determine number of antennas.
*/ */
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
__set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
@ -2716,6 +2716,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface, .remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config, .config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter, .configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key, .set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats, .get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed, .bss_info_changed = rt2x00mac_bss_info_changed,

View File

@ -1476,7 +1476,7 @@ struct hw_pairwise_ta_entry {
#define RXD_W15_RESERVED FIELD32(0xffffffff) #define RXD_W15_RESERVED FIELD32(0xffffffff)
/* /*
* Macro's for converting txpower from EEPROM to mac80211 value * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value. * and from mac80211 value to register value.
*/ */
#define MIN_TXPOWER 0 #define MIN_TXPOWER 0

View File

@ -2241,6 +2241,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface, .remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config, .config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter, .configure_filter = rt2x00mac_configure_filter,
.set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key, .set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats, .get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed, .bss_info_changed = rt2x00mac_bss_info_changed,

View File

@ -809,7 +809,7 @@ struct hw_pairwise_ta_entry {
/* /*
* EEPROM antenna. * EEPROM antenna.
* ANTENNA_NUM: Number of antenna's. * ANTENNA_NUM: Number of antennas.
* TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B. * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only. * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
@ -1058,7 +1058,7 @@ struct hw_pairwise_ta_entry {
#define RXD_W5_RESERVED FIELD32(0xffffffff) #define RXD_W5_RESERVED FIELD32(0xffffffff)
/* /*
* Macro's for converting txpower from EEPROM to mac80211 value * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value. * and from mac80211 value to register value.
*/ */
#define MIN_TXPOWER 0 #define MIN_TXPOWER 0

View File

@ -84,7 +84,7 @@ int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id)
ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY, ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY,
default_key, sizeof(*default_key)); default_key, sizeof(*default_key));
if (ret < 0) { if (ret < 0) {
wl1251_error("Couldnt set default key"); wl1251_error("Couldn't set default key");
goto out; goto out;
} }
@ -231,7 +231,7 @@ int wl1251_acx_feature_cfg(struct wl1251 *wl)
ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG,
feature, sizeof(*feature)); feature, sizeof(*feature));
if (ret < 0) { if (ret < 0) {
wl1251_error("Couldnt set HW encryption"); wl1251_error("Couldn't set HW encryption");
goto out; goto out;
} }

View File

@ -246,60 +246,6 @@ out:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
} }
int wl1251_plt_start(struct wl1251 *wl)
{
int ret;
mutex_lock(&wl->mutex);
wl1251_notice("power up");
if (wl->state != WL1251_STATE_OFF) {
wl1251_error("cannot go into PLT state because not "
"in off state: %d", wl->state);
return -EBUSY;
}
wl->state = WL1251_STATE_PLT;
ret = wl1251_chip_wakeup(wl);
if (ret < 0)
return ret;
ret = wl->chip.op_boot(wl);
if (ret < 0)
return ret;
wl1251_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
ret = wl->chip.op_plt_init(wl);
if (ret < 0)
return ret;
return 0;
}
int wl1251_plt_stop(struct wl1251 *wl)
{
mutex_lock(&wl->mutex);
wl1251_notice("power down");
if (wl->state != WL1251_STATE_PLT) {
wl1251_error("cannot power down because not in PLT "
"state: %d", wl->state);
return -EBUSY;
}
wl1251_disable_interrupts(wl);
wl1251_power_off(wl);
wl->state = WL1251_STATE_OFF;
return 0;
}
static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{ {
struct wl1251 *wl = hw->priv; struct wl1251 *wl = hw->priv;
@ -349,7 +295,7 @@ static int wl1251_op_start(struct ieee80211_hw *hw)
ret = wl1251_chip_wakeup(wl); ret = wl1251_chip_wakeup(wl);
if (ret < 0) if (ret < 0)
return ret; goto out;
ret = wl->chip.op_boot(wl); ret = wl->chip.op_boot(wl);
if (ret < 0) if (ret < 0)
@ -435,11 +381,10 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf) struct ieee80211_if_init_conf *conf)
{ {
struct wl1251 *wl = hw->priv; struct wl1251 *wl = hw->priv;
DECLARE_MAC_BUF(mac);
int ret = 0; int ret = 0;
wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s", wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
conf->type, print_mac(mac, conf->mac_addr)); conf->type, conf->mac_addr);
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);

View File

@ -1,679 +0,0 @@
/*
* This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
* Contact: Kalle Valo <kalle.valo@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include "wl1251_netlink.h"
#include <linux/mutex.h>
#include <linux/socket.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/genetlink.h>
#include <net/wireless.h>
#include <net/mac80211.h>
#include "wl1251.h"
#include "wl1251_spi.h"
#include "wl1251_acx.h"
/* FIXME: this should be changed as soon as user space catches up */
#define WL1251_NL_NAME "wl1251"
#define WL1251_NL_VERSION 1
#define WL1251_MAX_TEST_LENGTH 1024
#define WL1251_MAX_NVS_LENGTH 1024
enum wl1251_nl_commands {
WL1251_NL_CMD_UNSPEC,
WL1251_NL_CMD_TEST,
WL1251_NL_CMD_INTERROGATE,
WL1251_NL_CMD_CONFIGURE,
WL1251_NL_CMD_PHY_REG_READ,
WL1251_NL_CMD_NVS_PUSH,
WL1251_NL_CMD_REG_WRITE,
WL1251_NL_CMD_REG_READ,
WL1251_NL_CMD_SET_PLT_MODE,
__WL1251_NL_CMD_AFTER_LAST
};
#define WL1251_NL_CMD_MAX (__WL1251_NL_CMD_AFTER_LAST - 1)
enum wl1251_nl_attrs {
WL1251_NL_ATTR_UNSPEC,
WL1251_NL_ATTR_IFNAME,
WL1251_NL_ATTR_CMD_TEST_PARAM,
WL1251_NL_ATTR_CMD_TEST_ANSWER,
WL1251_NL_ATTR_CMD_IE,
WL1251_NL_ATTR_CMD_IE_LEN,
WL1251_NL_ATTR_CMD_IE_BUFFER,
WL1251_NL_ATTR_CMD_IE_ANSWER,
WL1251_NL_ATTR_REG_ADDR,
WL1251_NL_ATTR_REG_VAL,
WL1251_NL_ATTR_NVS_BUFFER,
WL1251_NL_ATTR_NVS_LEN,
WL1251_NL_ATTR_PLT_MODE,
__WL1251_NL_ATTR_AFTER_LAST
};
#define WL1251_NL_ATTR_MAX (__WL1251_NL_ATTR_AFTER_LAST - 1)
static struct genl_family wl1251_nl_family = {
.id = GENL_ID_GENERATE,
.name = WL1251_NL_NAME,
.hdrsize = 0,
.version = WL1251_NL_VERSION,
.maxattr = WL1251_NL_ATTR_MAX,
};
static struct net_device *ifname_to_netdev(struct net *net,
struct genl_info *info)
{
char *ifname;
if (!info->attrs[WL1251_NL_ATTR_IFNAME])
return NULL;
ifname = nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]);
wl1251_debug(DEBUG_NETLINK, "Looking for %s", ifname);
return dev_get_by_name(net, ifname);
}
static struct wl1251 *ifname_to_wl1251(struct net *net, struct genl_info *info)
{
struct net_device *netdev;
struct wireless_dev *wdev;
struct wiphy *wiphy;
struct ieee80211_hw *hw;
netdev = ifname_to_netdev(net, info);
if (netdev == NULL) {
wl1251_error("Wrong interface");
return NULL;
}
wdev = netdev->ieee80211_ptr;
if (wdev == NULL) {
wl1251_error("ieee80211_ptr is NULL");
return NULL;
}
wiphy = wdev->wiphy;
if (wiphy == NULL) {
wl1251_error("wiphy is NULL");
return NULL;
}
hw = wiphy_priv(wiphy);
if (hw == NULL) {
wl1251_error("hw is NULL");
return NULL;
}
dev_put(netdev);
return hw->priv;
}
static int wl1251_nl_test_cmd(struct sk_buff *skb, struct genl_info *info)
{
struct wl1251 *wl;
struct wl1251_command *cmd;
char *buf;
int buf_len, ret, cmd_len;
u8 answer;
if (!info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM])
return -EINVAL;
wl = ifname_to_wl1251(&init_net, info);
if (wl == NULL) {
wl1251_error("wl1251 not found");
return -EINVAL;
}
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
buf = nla_data(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]);
buf_len = nla_len(info->attrs[WL1251_NL_ATTR_CMD_TEST_PARAM]);
answer = nla_get_u8(info->attrs[WL1251_NL_ATTR_CMD_TEST_ANSWER]);
cmd->header.id = CMD_TEST;
memcpy(cmd->parameters, buf, buf_len);
cmd_len = sizeof(struct wl1251_cmd_header) + buf_len;
mutex_lock(&wl->mutex);
ret = wl1251_cmd_test(wl, cmd, cmd_len, answer);
mutex_unlock(&wl->mutex);
if (ret < 0) {
wl1251_error("%s() failed", __func__);
goto out;
}
if (answer) {
struct sk_buff *msg;
void *hdr;
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg) {
ret = -ENOMEM;
goto out;
}
hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
&wl1251_nl_family, 0, WL1251_NL_CMD_TEST);
if (IS_ERR(hdr)) {
ret = PTR_ERR(hdr);
goto nla_put_failure;
}
NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
NLA_PUT(msg, WL1251_NL_ATTR_CMD_TEST_ANSWER,
sizeof(*cmd), cmd);
ret = genlmsg_end(msg, hdr);
if (ret < 0) {
wl1251_error("%s() failed", __func__);
goto nla_put_failure;
}
wl1251_debug(DEBUG_NETLINK, "TEST cmd sent, answer");
ret = genlmsg_reply(msg, info);
goto out;
nla_put_failure:
nlmsg_free(msg);
} else
wl1251_debug(DEBUG_NETLINK, "TEST cmd sent");
out:
kfree(cmd);
return ret;
}
static int wl1251_nl_interrogate(struct sk_buff *skb, struct genl_info *info)
{
struct wl1251 *wl;
struct sk_buff *msg;
int ret = -ENOBUFS, cmd_ie, cmd_ie_len;
struct wl1251_command *cmd;
void *hdr;
if (!info->attrs[WL1251_NL_ATTR_CMD_IE])
return -EINVAL;
if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN])
return -EINVAL;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
wl = ifname_to_wl1251(&init_net, info);
if (wl == NULL) {
wl1251_error("wl1251 not found");
ret = -EINVAL;
goto nla_put_failure;
}
/* acx id */
cmd_ie = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE]);
/* maximum length of acx, including all headers */
cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]);
wl1251_debug(DEBUG_NETLINK, "Getting IE 0x%x (len %d)",
cmd_ie, cmd_ie_len);
mutex_lock(&wl->mutex);
ret = wl1251_cmd_interrogate(wl, cmd_ie, cmd, cmd_ie_len);
mutex_unlock(&wl->mutex);
if (ret < 0) {
wl1251_error("%s() failed", __func__);
goto nla_put_failure;
}
hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
&wl1251_nl_family, 0, WL1251_NL_CMD_INTERROGATE);
if (IS_ERR(hdr)) {
ret = PTR_ERR(hdr);
goto nla_put_failure;
}
NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
NLA_PUT(msg, WL1251_NL_ATTR_CMD_IE_ANSWER, cmd_ie_len, cmd);
ret = genlmsg_end(msg, hdr);
if (ret < 0) {
wl1251_error("%s() failed", __func__);
goto nla_put_failure;
}
kfree(cmd);
return genlmsg_reply(msg, info);
nla_put_failure:
kfree(cmd);
nlmsg_free(msg);
return ret;
}
static int wl1251_nl_configure(struct sk_buff *skb, struct genl_info *info)
{
int ret = 0, cmd_ie_len, acx_len;
struct acx_header *acx = NULL;
struct sk_buff *msg;
struct wl1251 *wl;
void *cmd_ie;
u16 *id;
if (!info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER])
return -EINVAL;
if (!info->attrs[WL1251_NL_ATTR_CMD_IE_LEN])
return -EINVAL;
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
wl = ifname_to_wl1251(&init_net, info);
if (wl == NULL) {
wl1251_error("wl1251 not found");
ret = -EINVAL;
goto nla_put_failure;
}
/* contains the acx header but not the cmd header */
cmd_ie = nla_data(info->attrs[WL1251_NL_ATTR_CMD_IE_BUFFER]);
cmd_ie_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_CMD_IE_LEN]);
/* acx id is in the first two bytes */
id = cmd_ie;
/* need to add acx_header before cmd_ie, so create a new command */
acx_len = sizeof(struct acx_header) + cmd_ie_len;
acx = kzalloc(acx_len, GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto nla_put_failure;
}
/* copy the acx header and the payload */
memcpy(&acx->id, cmd_ie, cmd_ie_len);
mutex_lock(&wl->mutex);
ret = wl1251_cmd_configure(wl, *id, acx, acx_len);
mutex_unlock(&wl->mutex);
if (ret < 0) {
wl1251_error("%s() failed", __func__);
goto nla_put_failure;
}
wl1251_debug(DEBUG_NETLINK, "CONFIGURE cmd sent");
nla_put_failure:
kfree(acx);
nlmsg_free(msg);
return ret;
}
static int wl1251_nl_phy_reg_read(struct sk_buff *skb, struct genl_info *info)
{
struct wl1251 *wl;
struct sk_buff *msg;
u32 reg_addr, *reg_value = NULL;
int ret = 0;
void *hdr;
if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
return -EINVAL;
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
wl = ifname_to_wl1251(&init_net, info);
if (wl == NULL) {
wl1251_error("wl1251 not found");
ret = -EINVAL;
goto nla_put_failure;
}
reg_value = kmalloc(sizeof(*reg_value), GFP_KERNEL);
if (!reg_value) {
ret = -ENOMEM;
goto nla_put_failure;
}
reg_addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
wl1251_debug(DEBUG_NETLINK, "Reading PHY reg 0x%x", reg_addr);
mutex_lock(&wl->mutex);
ret = wl1251_cmd_read_memory(wl, reg_addr, reg_value,
sizeof(*reg_value));
mutex_unlock(&wl->mutex);
if (ret < 0) {
wl1251_error("%s() failed", __func__);
goto nla_put_failure;
}
hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
&wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ);
if (IS_ERR(hdr)) {
ret = PTR_ERR(hdr);
goto nla_put_failure;
}
NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, *reg_value);
ret = genlmsg_end(msg, hdr);
if (ret < 0) {
wl1251_error("%s() failed", __func__);
goto nla_put_failure;
}
kfree(reg_value);
return genlmsg_reply(msg, info);
nla_put_failure:
nlmsg_free(msg);
kfree(reg_value);
return ret;
}
static int wl1251_nl_nvs_push(struct sk_buff *skb, struct genl_info *info)
{
struct wl1251 *wl;
int ret = 0;
if (!info->attrs[WL1251_NL_ATTR_NVS_BUFFER])
return -EINVAL;
if (!info->attrs[WL1251_NL_ATTR_NVS_LEN])
return -EINVAL;
wl = ifname_to_wl1251(&init_net, info);
if (wl == NULL) {
wl1251_error("wl1251 not found");
return -EINVAL;
}
mutex_lock(&wl->mutex);
wl->nvs_len = nla_get_u32(info->attrs[WL1251_NL_ATTR_NVS_LEN]);
if (wl->nvs_len % 4) {
wl1251_error("NVS size is not multiple of 32: %d", wl->nvs_len);
ret = -EILSEQ;
goto out;
}
/* If we already have an NVS, we should free it */
kfree(wl->nvs);
wl->nvs = kzalloc(wl->nvs_len, GFP_KERNEL);
if (wl->nvs == NULL) {
wl1251_error("Can't allocate NVS");
ret = -ENOMEM;
goto out;
}
memcpy(wl->nvs,
nla_data(info->attrs[WL1251_NL_ATTR_NVS_BUFFER]),
wl->nvs_len);
wl1251_debug(DEBUG_NETLINK, "got NVS from userspace, %d bytes",
wl->nvs_len);
out:
mutex_unlock(&wl->mutex);
return ret;
}
static int wl1251_nl_reg_read(struct sk_buff *skb, struct genl_info *info)
{
struct wl1251 *wl;
u32 addr, val;
int ret = 0;
struct sk_buff *msg;
void *hdr;
if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
return -EINVAL;
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
wl = ifname_to_wl1251(&init_net, info);
if (wl == NULL) {
wl1251_error("wl1251 not found");
return -EINVAL;
}
addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
mutex_lock(&wl->mutex);
val = wl1251_reg_read32(wl, addr);
mutex_unlock(&wl->mutex);
hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
&wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ);
if (IS_ERR(hdr)) {
ret = PTR_ERR(hdr);
goto nla_put_failure;
}
NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));
NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, val);
ret = genlmsg_end(msg, hdr);
if (ret < 0) {
wl1251_error("%s() failed", __func__);
goto nla_put_failure;
}
return genlmsg_reply(msg, info);
nla_put_failure:
nlmsg_free(msg);
return ret;
}
static int wl1251_nl_reg_write(struct sk_buff *skb, struct genl_info *info)
{
struct wl1251 *wl;
u32 addr, val;
if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
return -EINVAL;
if (!info->attrs[WL1251_NL_ATTR_REG_VAL])
return -EINVAL;
wl = ifname_to_wl1251(&init_net, info);
if (wl == NULL) {
wl1251_error("wl1251 not found");
return -EINVAL;
}
addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);
val = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_VAL]);
mutex_lock(&wl->mutex);
wl1251_reg_write32(wl, addr, val);
mutex_unlock(&wl->mutex);
return 0;
}
static int wl1251_nl_set_plt_mode(struct sk_buff *skb, struct genl_info *info)
{
struct wl1251 *wl;
u32 val;
int ret;
if (!info->attrs[WL1251_NL_ATTR_PLT_MODE])
return -EINVAL;
wl = ifname_to_wl1251(&init_net, info);
if (wl == NULL) {
wl1251_error("wl1251 not found");
return -EINVAL;
}
val = nla_get_u32(info->attrs[WL1251_NL_ATTR_PLT_MODE]);
switch (val) {
case 0:
ret = wl1251_plt_stop(wl);
break;
case 1:
ret = wl1251_plt_start(wl);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static struct nla_policy wl1251_nl_policy[WL1251_NL_ATTR_MAX + 1] = {
[WL1251_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING,
.len = IFNAMSIZ-1 },
[WL1251_NL_ATTR_CMD_TEST_PARAM] = { .type = NLA_BINARY,
.len = WL1251_MAX_TEST_LENGTH },
[WL1251_NL_ATTR_CMD_TEST_ANSWER] = { .type = NLA_U8 },
[WL1251_NL_ATTR_CMD_IE] = { .type = NLA_U32 },
[WL1251_NL_ATTR_CMD_IE_LEN] = { .type = NLA_U32 },
[WL1251_NL_ATTR_CMD_IE_BUFFER] = { .type = NLA_BINARY,
.len = WL1251_MAX_TEST_LENGTH },
[WL1251_NL_ATTR_CMD_IE_ANSWER] = { .type = NLA_BINARY,
.len = WL1251_MAX_TEST_LENGTH },
[WL1251_NL_ATTR_REG_ADDR] = { .type = NLA_U32 },
[WL1251_NL_ATTR_REG_VAL] = { .type = NLA_U32 },
[WL1251_NL_ATTR_NVS_BUFFER] = { .type = NLA_BINARY,
.len = WL1251_MAX_NVS_LENGTH },
[WL1251_NL_ATTR_NVS_LEN] = { .type = NLA_U32 },
[WL1251_NL_ATTR_PLT_MODE] = { .type = NLA_U32 },
};
static struct genl_ops wl1251_nl_ops[] = {
{
.cmd = WL1251_NL_CMD_TEST,
.doit = wl1251_nl_test_cmd,
.policy = wl1251_nl_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = WL1251_NL_CMD_INTERROGATE,
.doit = wl1251_nl_interrogate,
.policy = wl1251_nl_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = WL1251_NL_CMD_CONFIGURE,
.doit = wl1251_nl_configure,
.policy = wl1251_nl_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = WL1251_NL_CMD_PHY_REG_READ,
.doit = wl1251_nl_phy_reg_read,
.policy = wl1251_nl_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = WL1251_NL_CMD_NVS_PUSH,
.doit = wl1251_nl_nvs_push,
.policy = wl1251_nl_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = WL1251_NL_CMD_REG_WRITE,
.doit = wl1251_nl_reg_write,
.policy = wl1251_nl_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = WL1251_NL_CMD_REG_READ,
.doit = wl1251_nl_reg_read,
.policy = wl1251_nl_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = WL1251_NL_CMD_SET_PLT_MODE,
.doit = wl1251_nl_set_plt_mode,
.policy = wl1251_nl_policy,
.flags = GENL_ADMIN_PERM,
},
};
int wl1251_nl_register(void)
{
int err, i;
err = genl_register_family(&wl1251_nl_family);
if (err)
return err;
for (i = 0; i < ARRAY_SIZE(wl1251_nl_ops); i++) {
err = genl_register_ops(&wl1251_nl_family, &wl1251_nl_ops[i]);
if (err)
goto err_out;
}
return 0;
err_out:
genl_unregister_family(&wl1251_nl_family);
return err;
}
void wl1251_nl_unregister(void)
{
genl_unregister_family(&wl1251_nl_family);
}

View File

@ -423,7 +423,7 @@ static void wl1251_irq_work(struct work_struct *work)
wl->rx_counter = wl->rx_counter =
wl1251_mem_read32(wl, wl->data_path->rx_control_addr); wl1251_mem_read32(wl, wl->data_path->rx_control_addr);
/* We handle a frmware bug here */ /* We handle a firmware bug here */
switch ((wl->rx_counter - wl->rx_handled) & 0xf) { switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
case 0: case 0:
wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync");
@ -575,7 +575,7 @@ static int wl1251_hw_init_data_path_config(struct wl1251 *wl)
wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp), wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
GFP_KERNEL); GFP_KERNEL);
if (!wl->data_path) { if (!wl->data_path) {
wl1251_error("Couldnt allocate data path parameters"); wl1251_error("Couldn't allocate data path parameters");
return -ENOMEM; return -ENOMEM;
} }

View File

@ -88,7 +88,7 @@ struct wl1251_rx_descriptor {
u8 type; u8 type;
/* /*
* Recevied Rate: * Received Rate:
* 0x0A - 1MBPS * 0x0A - 1MBPS
* 0x14 - 2MBPS * 0x14 - 2MBPS
* 0x37 - 5_5MBPS * 0x37 - 5_5MBPS

View File

@ -76,6 +76,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0xe501), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },

View File

@ -567,6 +567,12 @@ enum nl80211_commands {
* @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
* commands to specify using a reassociate frame * commands to specify using a reassociate frame
* *
* @NL80211_ATTR_KEY: key information in a nested attribute with
* %NL80211_KEY_* sub-attributes
* @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
* and join_ibss(), key information is in a nested attribute each
* with %NL80211_KEY_* sub-attributes
*
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
*/ */
@ -692,6 +698,9 @@ enum nl80211_attrs {
NL80211_ATTR_PREV_BSSID, NL80211_ATTR_PREV_BSSID,
NL80211_ATTR_KEY,
NL80211_ATTR_KEYS,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
@ -720,6 +729,8 @@ enum nl80211_attrs {
#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP #define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS #define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
#define NL80211_ATTR_KEY NL80211_ATTR_KEY
#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
#define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_REG_RULES 32 #define NL80211_MAX_SUPP_REG_RULES 32
@ -1249,6 +1260,7 @@ enum nl80211_channel_type {
* in mBm (100 * dBm) (s32) * in mBm (100 * dBm) (s32)
* @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
* in unspecified units, scaled to 0..100 (u8) * in unspecified units, scaled to 0..100 (u8)
* @NL80211_BSS_STATUS: status, if this BSS is "used"
* @__NL80211_BSS_AFTER_LAST: internal * @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute * @NL80211_BSS_MAX: highest BSS attribute
*/ */
@ -1262,12 +1274,22 @@ enum nl80211_bss {
NL80211_BSS_INFORMATION_ELEMENTS, NL80211_BSS_INFORMATION_ELEMENTS,
NL80211_BSS_SIGNAL_MBM, NL80211_BSS_SIGNAL_MBM,
NL80211_BSS_SIGNAL_UNSPEC, NL80211_BSS_SIGNAL_UNSPEC,
NL80211_BSS_STATUS,
/* keep last */ /* keep last */
__NL80211_BSS_AFTER_LAST, __NL80211_BSS_AFTER_LAST,
NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1 NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
}; };
/**
* enum nl80211_bss_status - BSS "status"
*/
enum nl80211_bss_status {
NL80211_BSS_STATUS_AUTHENTICATED,
NL80211_BSS_STATUS_ASSOCIATED,
NL80211_BSS_STATUS_IBSS_JOINED,
};
/** /**
* enum nl80211_auth_type - AuthenticationType * enum nl80211_auth_type - AuthenticationType
* *
@ -1320,4 +1342,34 @@ enum nl80211_wpa_versions {
NL80211_WPA_VERSION_2 = 1 << 1, NL80211_WPA_VERSION_2 = 1 << 1,
}; };
/**
* enum nl80211_key_attributes - key attributes
* @__NL80211_KEY_INVALID: invalid
* @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
* 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
* keys
* @NL80211_KEY_IDX: key ID (u8, 0-3)
* @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
* section 7.3.2.25.1, e.g. 0x000FAC04)
* @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
* CCMP keys, each six bytes in little endian
* @NL80211_KEY_DEFAULT: flag indicating default key
* @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
* @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute
*/
enum nl80211_key_attributes {
__NL80211_KEY_INVALID,
NL80211_KEY_DATA,
NL80211_KEY_IDX,
NL80211_KEY_CIPHER,
NL80211_KEY_SEQ,
NL80211_KEY_DEFAULT,
NL80211_KEY_DEFAULT_MGMT,
/* keep last */
__NL80211_KEY_AFTER_LAST,
NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
};
#endif /* __LINUX_NL80211_H */ #endif /* __LINUX_NL80211_H */

View File

@ -304,7 +304,6 @@ typedef unsigned char *sk_buff_data_t;
* @tc_index: Traffic control index * @tc_index: Traffic control index
* @tc_verd: traffic control verdict * @tc_verd: traffic control verdict
* @ndisc_nodetype: router type (from link layer) * @ndisc_nodetype: router type (from link layer)
* @do_not_encrypt: set to prevent encryption of this frame
* @dma_cookie: a cookie to one of several possible DMA operations * @dma_cookie: a cookie to one of several possible DMA operations
* done by skb DMA functions * done by skb DMA functions
* @secmark: security marking * @secmark: security marking
@ -379,13 +378,10 @@ struct sk_buff {
kmemcheck_bitfield_begin(flags2); kmemcheck_bitfield_begin(flags2);
#ifdef CONFIG_IPV6_NDISC_NODETYPE #ifdef CONFIG_IPV6_NDISC_NODETYPE
__u8 ndisc_nodetype:2; __u8 ndisc_nodetype:2;
#endif
#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
__u8 do_not_encrypt:1;
#endif #endif
kmemcheck_bitfield_end(flags2); kmemcheck_bitfield_end(flags2);
/* 0/13/14 bit hole */ /* 0/14 bit hole */
#ifdef CONFIG_NET_DMA #ifdef CONFIG_NET_DMA
dma_cookie_t dma_cookie; dma_cookie_t dma_cookie;

View File

@ -538,7 +538,7 @@ struct cfg80211_ssid {
* @ssids: SSIDs to scan for (active scan only) * @ssids: SSIDs to scan for (active scan only)
* @n_ssids: number of SSIDs * @n_ssids: number of SSIDs
* @channels: channels to scan on. * @channels: channels to scan on.
* @n_channels: number of channels for each band * @n_channels: total number of channels to scan
* @ie: optional information element(s) to add into Probe Request or %NULL * @ie: optional information element(s) to add into Probe Request or %NULL
* @ie_len: length of ie in octets * @ie_len: length of ie in octets
* @wiphy: the wiphy this was for * @wiphy: the wiphy this was for
@ -647,12 +647,17 @@ struct cfg80211_crypto_settings {
* @auth_type: Authentication type (algorithm) * @auth_type: Authentication type (algorithm)
* @ie: Extra IEs to add to Authentication frame or %NULL * @ie: Extra IEs to add to Authentication frame or %NULL
* @ie_len: Length of ie buffer in octets * @ie_len: Length of ie buffer in octets
* @key_len: length of WEP key for shared key authentication
* @key_idx: index of WEP key for shared key authentication
* @key: WEP key for shared key authentication
*/ */
struct cfg80211_auth_request { struct cfg80211_auth_request {
struct cfg80211_bss *bss; struct cfg80211_bss *bss;
const u8 *ie; const u8 *ie;
size_t ie_len; size_t ie_len;
enum nl80211_auth_type auth_type; enum nl80211_auth_type auth_type;
const u8 *key;
u8 key_len, key_idx;
}; };
/** /**
@ -727,6 +732,8 @@ struct cfg80211_disassoc_request {
* @ie: information element(s) to include in the beacon * @ie: information element(s) to include in the beacon
* @ie_len: length of that * @ie_len: length of that
* @beacon_interval: beacon interval to use * @beacon_interval: beacon interval to use
* @privacy: this is a protected network, keys will be configured
* after joining
*/ */
struct cfg80211_ibss_params { struct cfg80211_ibss_params {
u8 *ssid; u8 *ssid;
@ -736,6 +743,7 @@ struct cfg80211_ibss_params {
u8 ssid_len, ie_len; u8 ssid_len, ie_len;
u16 beacon_interval; u16 beacon_interval;
bool channel_fixed; bool channel_fixed;
bool privacy;
}; };
/** /**
@ -755,6 +763,9 @@ struct cfg80211_ibss_params {
* @assoc_ie_len: Length of assoc_ie in octets * @assoc_ie_len: Length of assoc_ie in octets
* @privacy: indicates whether privacy-enabled APs should be used * @privacy: indicates whether privacy-enabled APs should be used
* @crypto: crypto settings * @crypto: crypto settings
* @key_len: length of WEP key for shared key authentication
* @key_idx: index of WEP key for shared key authentication
* @key: WEP key for shared key authentication
*/ */
struct cfg80211_connect_params { struct cfg80211_connect_params {
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
@ -766,6 +777,8 @@ struct cfg80211_connect_params {
size_t ie_len; size_t ie_len;
bool privacy; bool privacy;
struct cfg80211_crypto_settings crypto; struct cfg80211_crypto_settings crypto;
const u8 *key;
u8 key_len, key_idx;
}; };
/** /**
@ -1223,9 +1236,10 @@ extern void wiphy_unregister(struct wiphy *wiphy);
*/ */
extern void wiphy_free(struct wiphy *wiphy); extern void wiphy_free(struct wiphy *wiphy);
/* internal struct */ /* internal structs */
struct cfg80211_conn; struct cfg80211_conn;
struct cfg80211_internal_bss; struct cfg80211_internal_bss;
struct cfg80211_cached_keys;
#define MAX_AUTH_BSSES 4 #define MAX_AUTH_BSSES 4
@ -1267,6 +1281,7 @@ struct wireless_dev {
CFG80211_SME_CONNECTED, CFG80211_SME_CONNECTED,
} sme_state; } sme_state;
struct cfg80211_conn *conn; struct cfg80211_conn *conn;
struct cfg80211_cached_keys *connect_keys;
struct list_head event_list; struct list_head event_list;
spinlock_t event_lock; spinlock_t event_lock;
@ -1280,6 +1295,7 @@ struct wireless_dev {
struct { struct {
struct cfg80211_ibss_params ibss; struct cfg80211_ibss_params ibss;
struct cfg80211_connect_params connect; struct cfg80211_connect_params connect;
struct cfg80211_cached_keys *keys;
u8 *ie; u8 *ie;
size_t ie_len; size_t ie_len;
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];

View File

@ -241,6 +241,8 @@ struct ieee80211_bss_conf {
* it can be sent out. * it can be sent out.
* @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211, * @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211,
* used to indicate that a frame was already retried due to PS * used to indicate that a frame was already retried due to PS
* @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
* used to indicate frame should not be encrypted
*/ */
enum mac80211_tx_control_flags { enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
@ -259,6 +261,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_INTFL_RCALGO = BIT(13), IEEE80211_TX_INTFL_RCALGO = BIT(13),
IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
IEEE80211_TX_INTFL_RETRIED = BIT(15), IEEE80211_TX_INTFL_RETRIED = BIT(15),
IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
}; };
/** /**
@ -2094,6 +2097,29 @@ static inline int rate_supported(struct ieee80211_sta *sta,
return (sta == NULL || sta->supp_rates[band] & BIT(index)); return (sta == NULL || sta->supp_rates[band] & BIT(index));
} }
/**
* rate_control_send_low - helper for drivers for management/no-ack frames
*
* Rate control algorithms that agree to use the lowest rate to
* send management frames and NO_ACK data with the respective hw
* retries should use this in the beginning of their mac80211 get_rate
* callback. If true is returned the rate control can simply return.
* If false is returned we guarantee that sta and sta and priv_sta is
* not null.
*
* Rate control algorithms wishing to do more intelligent selection of
* rate for multicast/broadcast frames may choose to not use this.
*
* @sta: &struct ieee80211_sta pointer to the target destination. Note
* that this may be null.
* @priv_sta: private rate control structure. This may be null.
* @txrc: rate control information we sholud populate for mac80211.
*/
bool rate_control_send_low(struct ieee80211_sta *sta,
void *priv_sta,
struct ieee80211_tx_rate_control *txrc);
static inline s8 static inline s8
rate_lowest_index(struct ieee80211_supported_band *sband, rate_lowest_index(struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
@ -2110,6 +2136,17 @@ rate_lowest_index(struct ieee80211_supported_band *sband,
return 0; return 0;
} }
static inline
bool rate_usable_index_exists(struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta)
{
unsigned int i;
for (i = 0; i < sband->n_bitrates; i++)
if (rate_supported(sta, sband->band, i))
return true;
return false;
}
int ieee80211_rate_control_register(struct rate_control_ops *ops); int ieee80211_rate_control_register(struct rate_control_ops *ops);
void ieee80211_rate_control_unregister(struct rate_control_ops *ops); void ieee80211_rate_control_unregister(struct rate_control_ops *ops);

View File

@ -3923,6 +3923,7 @@ int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
} }
return err; return err;
} }
EXPORT_SYMBOL_GPL(__dev_addr_sync);
void __dev_addr_unsync(struct dev_addr_list **to, int *to_count, void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
struct dev_addr_list **from, int *from_count) struct dev_addr_list **from, int *from_count)
@ -3942,6 +3943,7 @@ void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
da = next; da = next;
} }
} }
EXPORT_SYMBOL_GPL(__dev_addr_unsync);
/** /**
* dev_unicast_sync - Synchronize device's unicast list to another device * dev_unicast_sync - Synchronize device's unicast list to another device

View File

@ -559,9 +559,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
#endif #endif
#endif #endif
new->vlan_tci = old->vlan_tci; new->vlan_tci = old->vlan_tci;
#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
new->do_not_encrypt = old->do_not_encrypt;
#endif
skb_copy_secmark(new, old); skb_copy_secmark(new, old);
} }

View File

@ -206,3 +206,15 @@ config MAC80211_DEBUG_COUNTERS
and show them in debugfs. and show them in debugfs.
If unsure, say N. If unsure, say N.
config MAC80211_DRIVER_API_TRACER
bool "Driver API tracer"
depends on MAC80211_DEBUG_MENU
depends on EVENT_TRACING
help
Say Y here to make mac80211 register with the ftrace
framework for the driver API -- you can see which
driver methods it is calling then by looking at the
trace.
If unsure, say N.

View File

@ -41,6 +41,9 @@ mac80211-$(CONFIG_MAC80211_MESH) += \
mac80211-$(CONFIG_PM) += pm.o mac80211-$(CONFIG_PM) += pm.o
mac80211-$(CONFIG_MAC80211_DRIVER_API_TRACER) += driver-trace.o
CFLAGS_driver-trace.o := -I$(src)
# objects for PID algorithm # objects for PID algorithm
rc80211_pid-y := rc80211_pid_algo.o rc80211_pid-y := rc80211_pid_algo.o
rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o

View File

@ -383,9 +383,6 @@ static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) { if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
spin_lock_irqsave(&local->queue_stop_reason_lock, flags); spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
/* mark queue as pending, it is stopped already */
__set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING,
&local->queue_stop_reasons[queue]);
/* copy over remaining packets */ /* copy over remaining packets */
skb_queue_splice_tail_init( skb_queue_splice_tail_init(
&sta->ampdu_mlme.tid_tx[tid]->pending, &sta->ampdu_mlme.tid_tx[tid]->pending,

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