diff options
author | Ben Greear <greearb@candelatech.com> | 2011-01-10 02:11:49 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-01-21 15:32:22 -0500 |
commit | 7f010c93d73847ffc6b74b572fef9a63e305d65e (patch) | |
tree | 9ed4a9cb46b55995b415f255fc83da7f4e4a95f8 /drivers/net/wireless | |
parent | bda8addaed08834956d5695212717893a2e0cb13 (diff) |
ath9k: Keep track of stations for debugfs.
The stations hold the ath_node, which holds the tid
and other xmit logic structures. In order to debug
stuck xmit logic, we need a way to print out the tid
state for the stations.
Signed-off-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/debug.c | 94 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/init.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 13 |
4 files changed, 115 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index aadb5de9ac76..d4640117fa8c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -254,7 +254,10 @@ struct ath_atx_tid { | |||
254 | }; | 254 | }; |
255 | 255 | ||
256 | struct ath_node { | 256 | struct ath_node { |
257 | struct ath_common *common; | 257 | #ifdef CONFIG_ATH9K_DEBUGFS |
258 | struct list_head list; /* for sc->nodes */ | ||
259 | struct ieee80211_sta *sta; /* station struct we're part of */ | ||
260 | #endif | ||
258 | struct ath_atx_tid tid[WME_NUM_TID]; | 261 | struct ath_atx_tid tid[WME_NUM_TID]; |
259 | struct ath_atx_ac ac[WME_NUM_AC]; | 262 | struct ath_atx_ac ac[WME_NUM_AC]; |
260 | u16 maxampdu; | 263 | u16 maxampdu; |
@@ -638,6 +641,8 @@ struct ath_softc { | |||
638 | 641 | ||
639 | #ifdef CONFIG_ATH9K_DEBUGFS | 642 | #ifdef CONFIG_ATH9K_DEBUGFS |
640 | struct ath9k_debug debug; | 643 | struct ath9k_debug debug; |
644 | spinlock_t nodes_lock; | ||
645 | struct list_head nodes; /* basically, stations */ | ||
641 | #endif | 646 | #endif |
642 | struct ath_beacon_config cur_beacon_conf; | 647 | struct ath_beacon_config cur_beacon_conf; |
643 | struct delayed_work tx_complete_work; | 648 | struct delayed_work tx_complete_work; |
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index faf84e499c8f..650f00f59d79 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c | |||
@@ -587,6 +587,8 @@ static const struct file_operations fops_wiphy = { | |||
587 | sc->debug.stats.txstats[WME_AC_BK].elem, \ | 587 | sc->debug.stats.txstats[WME_AC_BK].elem, \ |
588 | sc->debug.stats.txstats[WME_AC_VI].elem, \ | 588 | sc->debug.stats.txstats[WME_AC_VI].elem, \ |
589 | sc->debug.stats.txstats[WME_AC_VO].elem); \ | 589 | sc->debug.stats.txstats[WME_AC_VO].elem); \ |
590 | if (len >= size) \ | ||
591 | goto done; \ | ||
590 | } while(0) | 592 | } while(0) |
591 | 593 | ||
592 | #define PRX(str, elem) \ | 594 | #define PRX(str, elem) \ |
@@ -597,6 +599,8 @@ do { \ | |||
597 | (unsigned int)(sc->tx.txq[WME_AC_BK].elem), \ | 599 | (unsigned int)(sc->tx.txq[WME_AC_BK].elem), \ |
598 | (unsigned int)(sc->tx.txq[WME_AC_VI].elem), \ | 600 | (unsigned int)(sc->tx.txq[WME_AC_VI].elem), \ |
599 | (unsigned int)(sc->tx.txq[WME_AC_VO].elem)); \ | 601 | (unsigned int)(sc->tx.txq[WME_AC_VO].elem)); \ |
602 | if (len >= size) \ | ||
603 | goto done; \ | ||
600 | } while(0) | 604 | } while(0) |
601 | 605 | ||
602 | #define PRQLE(str, elem) \ | 606 | #define PRQLE(str, elem) \ |
@@ -607,6 +611,8 @@ do { \ | |||
607 | list_empty(&sc->tx.txq[WME_AC_BK].elem), \ | 611 | list_empty(&sc->tx.txq[WME_AC_BK].elem), \ |
608 | list_empty(&sc->tx.txq[WME_AC_VI].elem), \ | 612 | list_empty(&sc->tx.txq[WME_AC_VI].elem), \ |
609 | list_empty(&sc->tx.txq[WME_AC_VO].elem)); \ | 613 | list_empty(&sc->tx.txq[WME_AC_VO].elem)); \ |
614 | if (len >= size) \ | ||
615 | goto done; \ | ||
610 | } while (0) | 616 | } while (0) |
611 | 617 | ||
612 | static ssize_t read_file_xmit(struct file *file, char __user *user_buf, | 618 | static ssize_t read_file_xmit(struct file *file, char __user *user_buf, |
@@ -614,7 +620,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, | |||
614 | { | 620 | { |
615 | struct ath_softc *sc = file->private_data; | 621 | struct ath_softc *sc = file->private_data; |
616 | char *buf; | 622 | char *buf; |
617 | unsigned int len = 0, size = 4000; | 623 | unsigned int len = 0, size = 8000; |
618 | int i; | 624 | int i; |
619 | ssize_t retval = 0; | 625 | ssize_t retval = 0; |
620 | char tmp[32]; | 626 | char tmp[32]; |
@@ -623,7 +629,10 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, | |||
623 | if (buf == NULL) | 629 | if (buf == NULL) |
624 | return -ENOMEM; | 630 | return -ENOMEM; |
625 | 631 | ||
626 | len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO"); | 632 | len += sprintf(buf, "Num-Tx-Queues: %i tx-queues-setup: 0x%x\n" |
633 | "%30s %10s%10s%10s\n\n", | ||
634 | ATH9K_NUM_TX_QUEUES, sc->tx.txqsetup, | ||
635 | "BE", "BK", "VI", "VO"); | ||
627 | 636 | ||
628 | PR("MPDUs Queued: ", queued); | 637 | PR("MPDUs Queued: ", queued); |
629 | PR("MPDUs Completed: ", completed); | 638 | PR("MPDUs Completed: ", completed); |
@@ -644,6 +653,14 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, | |||
644 | PR("hw-put-tx-buf: ", puttxbuf); | 653 | PR("hw-put-tx-buf: ", puttxbuf); |
645 | PR("hw-tx-start: ", txstart); | 654 | PR("hw-tx-start: ", txstart); |
646 | PR("hw-tx-proc-desc: ", txprocdesc); | 655 | PR("hw-tx-proc-desc: ", txprocdesc); |
656 | len += snprintf(buf + len, size - len, | ||
657 | "%s%11p%11p%10p%10p\n", "txq-memory-address:", | ||
658 | &(sc->tx.txq[WME_AC_BE]), | ||
659 | &(sc->tx.txq[WME_AC_BK]), | ||
660 | &(sc->tx.txq[WME_AC_VI]), | ||
661 | &(sc->tx.txq[WME_AC_VO])); | ||
662 | if (len >= size) | ||
663 | goto done; | ||
647 | 664 | ||
648 | PRX("axq-qnum: ", axq_qnum); | 665 | PRX("axq-qnum: ", axq_qnum); |
649 | PRX("axq-depth: ", axq_depth); | 666 | PRX("axq-depth: ", axq_depth); |
@@ -661,6 +678,68 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, | |||
661 | snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i); | 678 | snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i); |
662 | PRQLE(tmp, txq_fifo[i]); | 679 | PRQLE(tmp, txq_fifo[i]); |
663 | } | 680 | } |
681 | |||
682 | done: | ||
683 | if (len > size) | ||
684 | len = size; | ||
685 | |||
686 | retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
687 | kfree(buf); | ||
688 | |||
689 | return retval; | ||
690 | } | ||
691 | |||
692 | static ssize_t read_file_stations(struct file *file, char __user *user_buf, | ||
693 | size_t count, loff_t *ppos) | ||
694 | { | ||
695 | struct ath_softc *sc = file->private_data; | ||
696 | char *buf; | ||
697 | unsigned int len = 0, size = 64000; | ||
698 | struct ath_node *an = NULL; | ||
699 | ssize_t retval = 0; | ||
700 | int q; | ||
701 | |||
702 | buf = kzalloc(size, GFP_KERNEL); | ||
703 | if (buf == NULL) | ||
704 | return -ENOMEM; | ||
705 | |||
706 | len += snprintf(buf + len, size - len, | ||
707 | "Stations:\n" | ||
708 | " tid: addr sched paused buf_q-empty an ac\n" | ||
709 | " ac: addr sched tid_q-empty txq\n"); | ||
710 | |||
711 | spin_lock(&sc->nodes_lock); | ||
712 | list_for_each_entry(an, &sc->nodes, list) { | ||
713 | len += snprintf(buf + len, size - len, | ||
714 | "%pM\n", an->sta->addr); | ||
715 | if (len >= size) | ||
716 | goto done; | ||
717 | |||
718 | for (q = 0; q < WME_NUM_TID; q++) { | ||
719 | struct ath_atx_tid *tid = &(an->tid[q]); | ||
720 | len += snprintf(buf + len, size - len, | ||
721 | " tid: %p %s %s %i %p %p\n", | ||
722 | tid, tid->sched ? "sched" : "idle", | ||
723 | tid->paused ? "paused" : "running", | ||
724 | list_empty(&tid->buf_q), | ||
725 | tid->an, tid->ac); | ||
726 | if (len >= size) | ||
727 | goto done; | ||
728 | } | ||
729 | |||
730 | for (q = 0; q < WME_NUM_AC; q++) { | ||
731 | struct ath_atx_ac *ac = &(an->ac[q]); | ||
732 | len += snprintf(buf + len, size - len, | ||
733 | " ac: %p %s %i %p\n", | ||
734 | ac, ac->sched ? "sched" : "idle", | ||
735 | list_empty(&ac->tid_q), ac->txq); | ||
736 | if (len >= size) | ||
737 | goto done; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | done: | ||
742 | spin_unlock(&sc->nodes_lock); | ||
664 | if (len > size) | 743 | if (len > size) |
665 | len = size; | 744 | len = size; |
666 | 745 | ||
@@ -708,6 +787,13 @@ static const struct file_operations fops_xmit = { | |||
708 | .llseek = default_llseek, | 787 | .llseek = default_llseek, |
709 | }; | 788 | }; |
710 | 789 | ||
790 | static const struct file_operations fops_stations = { | ||
791 | .read = read_file_stations, | ||
792 | .open = ath9k_debugfs_open, | ||
793 | .owner = THIS_MODULE, | ||
794 | .llseek = default_llseek, | ||
795 | }; | ||
796 | |||
711 | static ssize_t read_file_recv(struct file *file, char __user *user_buf, | 797 | static ssize_t read_file_recv(struct file *file, char __user *user_buf, |
712 | size_t count, loff_t *ppos) | 798 | size_t count, loff_t *ppos) |
713 | { | 799 | { |
@@ -945,6 +1031,10 @@ int ath9k_init_debug(struct ath_hw *ah) | |||
945 | sc, &fops_xmit)) | 1031 | sc, &fops_xmit)) |
946 | goto err; | 1032 | goto err; |
947 | 1033 | ||
1034 | if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, | ||
1035 | sc, &fops_stations)) | ||
1036 | goto err; | ||
1037 | |||
948 | if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, | 1038 | if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, |
949 | sc, &fops_recv)) | 1039 | sc, &fops_recv)) |
950 | goto err; | 1040 | goto err; |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 23b299818b18..59c01ca4379e 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -559,6 +559,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | |||
559 | spin_lock_init(&sc->sc_serial_rw); | 559 | spin_lock_init(&sc->sc_serial_rw); |
560 | spin_lock_init(&sc->sc_pm_lock); | 560 | spin_lock_init(&sc->sc_pm_lock); |
561 | mutex_init(&sc->mutex); | 561 | mutex_init(&sc->mutex); |
562 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
563 | spin_lock_init(&sc->nodes_lock); | ||
564 | INIT_LIST_HEAD(&sc->nodes); | ||
565 | #endif | ||
562 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); | 566 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); |
563 | tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, | 567 | tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, |
564 | (unsigned long)sc); | 568 | (unsigned long)sc); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c03184e7bffe..bed6eb97fac9 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -548,6 +548,12 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) | |||
548 | struct ath_hw *ah = sc->sc_ah; | 548 | struct ath_hw *ah = sc->sc_ah; |
549 | an = (struct ath_node *)sta->drv_priv; | 549 | an = (struct ath_node *)sta->drv_priv; |
550 | 550 | ||
551 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
552 | spin_lock(&sc->nodes_lock); | ||
553 | list_add(&an->list, &sc->nodes); | ||
554 | spin_unlock(&sc->nodes_lock); | ||
555 | an->sta = sta; | ||
556 | #endif | ||
551 | if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM) | 557 | if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM) |
552 | sc->sc_flags |= SC_OP_ENABLE_APM; | 558 | sc->sc_flags |= SC_OP_ENABLE_APM; |
553 | 559 | ||
@@ -563,6 +569,13 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) | |||
563 | { | 569 | { |
564 | struct ath_node *an = (struct ath_node *)sta->drv_priv; | 570 | struct ath_node *an = (struct ath_node *)sta->drv_priv; |
565 | 571 | ||
572 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
573 | spin_lock(&sc->nodes_lock); | ||
574 | list_del(&an->list); | ||
575 | spin_unlock(&sc->nodes_lock); | ||
576 | an->sta = NULL; | ||
577 | #endif | ||
578 | |||
566 | if (sc->sc_flags & SC_OP_TXAGGR) | 579 | if (sc->sc_flags & SC_OP_TXAGGR) |
567 | ath_tx_node_cleanup(sc, an); | 580 | ath_tx_node_cleanup(sc, an); |
568 | } | 581 | } |