diff -urw compat-wireless-2014-05-22.orig/drivers/net/wireless/ath/ath9k/ath9k.h compat-wireless-2014-05-22/drivers/net/wireless/ath/ath9k/ath9k.h --- compat-wireless-2014-05-22.orig/drivers/net/wireless/ath/ath9k/ath9k.h 2014-07-21 15:29:29.032197395 +0200 +++ compat-wireless-2014-05-22/drivers/net/wireless/ath/ath9k/ath9k.h 2014-07-21 15:49:42.032167390 +0200 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "common.h" @@ -281,6 +282,7 @@ u8 key_idx[4]; atomic_t decrypt_errors; + struct hlist_node list; }; struct ath_tx_control { @@ -862,4 +864,9 @@ static inline void ath_ahb_exit(void) {}; #endif + +extern struct hlist_head an_list; +extern spinlock_t an_list_lock; +struct ath_frame_info *get_frame_info(struct sk_buff *skb); + #endif /* ATH9K_H */ diff -urw compat-wireless-2014-05-22.orig/drivers/net/wireless/ath/ath9k/debug.c compat-wireless-2014-05-22/drivers/net/wireless/ath/ath9k/debug.c --- compat-wireless-2014-05-22.orig/drivers/net/wireless/ath/ath9k/debug.c 2014-07-21 15:29:29.034197395 +0200 +++ compat-wireless-2014-05-22/drivers/net/wireless/ath/ath9k/debug.c 2014-07-21 15:50:22.406166391 +0200 @@ -18,6 +18,7 @@ #include #include #include +#include #include "ath9k.h" @@ -26,6 +27,9 @@ #define REG_READ_D(_ah, _reg) \ ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) +static unsigned int nodes_len, nodes_size = 1024 * 1024; +static char *nodes_buf; + void ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause) { if (sync_cause) @@ -709,6 +713,134 @@ return len; } +static void ath9k_debug_print_skb(struct sk_buff_head *skb_head) +{ + struct ath_frame_info *fi; + struct ath_buf *bf; + struct sk_buff *skb; + + skb_queue_walk(skb_head, skb) { + fi = get_frame_info(skb); + bf = fi->bf; + + if (!bf) { + nodes_len += snprintf(nodes_buf + nodes_len, nodes_size - nodes_len, "no bf\n"); + continue; + } + + nodes_len += snprintf(nodes_buf + nodes_len, + nodes_size - nodes_len, + "bf->bf_state.seqno:%d fi->baw_tracked:%d fi->retries:%hhu fi->framelen:%d\n", + bf->bf_state.seqno, fi->baw_tracked, + fi->retries, fi->framelen); + } +} + +static void ath9k_debug_print_tid(struct ath_atx_tid *tid, int idx) +{ + int i; + + nodes_len += snprintf(nodes_buf + nodes_len, nodes_size - nodes_len, + "TID: %d AC: %p\n", idx, tid->ac); + + nodes_len += snprintf(nodes_buf + nodes_len, nodes_size - nodes_len, + "buf_q list begin.\n"); + ath9k_debug_print_skb(&tid->buf_q); + nodes_len += snprintf(nodes_buf + nodes_len, nodes_size - nodes_len, + "buf_q list end.\n"); + + nodes_len += snprintf(nodes_buf + nodes_len, nodes_size - nodes_len, + "retry_q list begin.\n"); + ath9k_debug_print_skb(&tid->retry_q); + nodes_len += snprintf(nodes_buf + nodes_len, nodes_size - nodes_len, + "retry_q list end.\n"); + + for (i = 0; i < BITS_TO_LONGS(ATH_TID_MAX_BUFS); i++) { + nodes_len += snprintf(nodes_buf + nodes_len, + nodes_size - nodes_len, "tx_buf %d: %lu\n", + i, tid->tx_buf[i]); + } + + nodes_len += snprintf(nodes_buf + nodes_len, nodes_size - nodes_len, + "seq_start:%hu seq_next:%hu baw_size:%hu tidno:%hhu baw_head:%d baw_tail:%d bar_index:%hhd sched:%hhu active:%hhu\n", + tid->seq_start, tid->seq_next, + tid->baw_size, tid->tidno, tid->baw_head, tid->baw_tail, + tid->bar_index, tid->sched, tid->active); +} + +static void ath9k_debug_print_ac(struct ath_atx_ac *ac, int idx) +{ + nodes_len += snprintf(nodes_buf + nodes_len, nodes_size - nodes_len, + "AC: %i (%p) sched:%hhu clear_ps_filter:%hhu is_empty(tid_q):%hhu\n", + idx, ac, ac->sched, ac->clear_ps_filter, + list_empty(&ac->tid_q)); +} + +static void ath9k_debug_print_node(struct ath_node *an) +{ + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + int i; + + if (an->sta) { + nodes_len += snprintf(nodes_buf + nodes_len, + nodes_size - nodes_len, + "STA MAC: %pM ", an->sta->addr); + } + + nodes_len += snprintf(nodes_buf + nodes_len, nodes_size - nodes_len, + "an->sleeping: %d\n", an->sleeping); + + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { + tid = &an->tid[i]; + ath9k_debug_print_tid(tid, i); + } + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + ac = &an->ac[i]; + ath9k_debug_print_ac(ac, i); + } +} + +static void ath9k_debug_print_mcast_node(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct ath_vif *avif = (struct ath_vif *)vif->drv_priv; + + nodes_len += snprintf(nodes_buf + nodes_len, nodes_size - nodes_len, + "VIF %pM\n", vif->addr); + + ath9k_debug_print_node(&avif->mcast_node); +} + +static ssize_t read_file_nodes(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_node *an; + int retval = 0; + + nodes_len = 0; + nodes_buf = kzalloc(nodes_size, GFP_KERNEL); + if (!nodes_buf) + return -ENOMEM; + + rcu_read_lock(); + hlist_for_each_entry_rcu(an, &an_list, list) { + ath9k_debug_print_node(an); + } + rcu_read_unlock(); + + ieee80211_iterate_active_interfaces(sc->hw, 0, + ath9k_debug_print_mcast_node, NULL); + + retval = simple_read_from_buffer(user_buf, count, ppos, nodes_buf, + nodes_len); + kfree(nodes_buf); + + return retval; +} + static ssize_t read_file_queues(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -931,6 +1063,13 @@ .llseek = default_llseek, }; +static const struct file_operations fops_nodes = { + .read = read_file_nodes, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static const struct file_operations fops_queues = { .read = read_file_queues, .open = simple_open, @@ -1522,6 +1661,8 @@ &fops_xmit); debugfs_create_file("queues", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_queues); + debugfs_create_file("nodes", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_nodes); debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->tx.txq_max_pending[IEEE80211_AC_BK]); debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, diff -urw compat-wireless-2014-05-22.orig/drivers/net/wireless/ath/ath9k/main.c compat-wireless-2014-05-22/drivers/net/wireless/ath/ath9k/main.c --- compat-wireless-2014-05-22.orig/drivers/net/wireless/ath/ath9k/main.c 2014-07-21 15:29:29.031197395 +0200 +++ compat-wireless-2014-05-22/drivers/net/wireless/ath/ath9k/main.c 2014-07-21 15:49:42.033167390 +0200 @@ -16,10 +16,14 @@ #include #include +#include #include #include "ath9k.h" #include "btcoex.h" +struct hlist_head an_list; +spinlock_t an_list_lock; + static void ath9k_set_assoc_state(struct ath_softc *sc, struct ieee80211_vif *vif); @@ -429,12 +433,20 @@ memset(&an->key_idx, 0, sizeof(an->key_idx)); ath_tx_node_init(sc, an); + + spin_lock_bh(&an_list_lock); + hlist_add_head_rcu(&an->list, &an_list); + spin_unlock_bh(&an_list_lock); } static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an = (struct ath_node *)sta->drv_priv; ath_tx_node_cleanup(sc, an); + + spin_lock_bh(&an_list_lock); + hlist_del_rcu(&an->list); + spin_unlock_bh(&an_list_lock); } void ath9k_tasklet(unsigned long data) @@ -726,6 +738,9 @@ struct ath9k_channel *init_channel; int r; + INIT_HLIST_HEAD(&an_list); + spin_lock_init(&an_list_lock); + ath_dbg(common, CONFIG, "Starting driver with initial channel: %d MHz\n", curchan->center_freq); diff -urw compat-wireless-2014-05-22.orig/drivers/net/wireless/ath/ath9k/xmit.c compat-wireless-2014-05-22/drivers/net/wireless/ath/ath9k/xmit.c --- compat-wireless-2014-05-22.orig/drivers/net/wireless/ath/ath9k/xmit.c 2014-07-21 15:29:29.034197395 +0200 +++ compat-wireless-2014-05-22/drivers/net/wireless/ath/ath9k/xmit.c 2014-07-21 15:49:42.033167390 +0200 @@ -120,7 +120,7 @@ list_add_tail(&ac->list, &txq->axq_acq); } -static struct ath_frame_info *get_frame_info(struct sk_buff *skb) +struct ath_frame_info *get_frame_info(struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); BUILD_BUG_ON(sizeof(struct ath_frame_info) >