aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorBruno Randolf <br1@einfach.org>2010-03-09 02:56:00 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-03-10 17:44:39 -0500
commit7644395f8df9aa5b42af268a485b83e44bba2784 (patch)
treedca8b3d98c45cf8e6fceb2545b34daa96cb26a2c /drivers/net/wireless/ath
parent919154540aa26e8c333c420b5b930e94ef7a6839 (diff)
ath5k: add debugfs file frameerrors
add a debugfs file to see different RX and TX errors as reported in our status descriptors. this can help to diagnose driver problems. statistics can be cleared by writing 'clear' into the frameerrors file. example: # cat /sys/kernel/debug/ath5k/phy0/frameerrors RX --------------------- CRC 27 (11%) PHY 3 (1%) FIFO 0 (0%) decrypt 0 (0%) MIC 0 (0%) process 0 (0%) jumbo 0 (0%) [RX all 245] TX --------------------- retry 2 (9%) FIFO 0 (0%) filter 0 (0%) [TX all 21] Signed-off-by: Bruno Randolf <br1@einfach.org> Acked-by: Nick Kossifidis <mickflemm@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c23
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h12
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c106
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.h1
4 files changed, 140 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 79922cfd96b8..b142a78ed1e5 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1902,18 +1902,28 @@ ath5k_tasklet_rx(unsigned long data)
1902 break; 1902 break;
1903 else if (unlikely(ret)) { 1903 else if (unlikely(ret)) {
1904 ATH5K_ERR(sc, "error in processing rx descriptor\n"); 1904 ATH5K_ERR(sc, "error in processing rx descriptor\n");
1905 sc->stats.rxerr_proc++;
1905 spin_unlock(&sc->rxbuflock); 1906 spin_unlock(&sc->rxbuflock);
1906 return; 1907 return;
1907 } 1908 }
1908 1909
1910 sc->stats.rx_all_count++;
1911
1909 if (unlikely(rs.rs_more)) { 1912 if (unlikely(rs.rs_more)) {
1910 ATH5K_WARN(sc, "unsupported jumbo\n"); 1913 ATH5K_WARN(sc, "unsupported jumbo\n");
1914 sc->stats.rxerr_jumbo++;
1911 goto next; 1915 goto next;
1912 } 1916 }
1913 1917
1914 if (unlikely(rs.rs_status)) { 1918 if (unlikely(rs.rs_status)) {
1915 if (rs.rs_status & AR5K_RXERR_PHY) 1919 if (rs.rs_status & AR5K_RXERR_CRC)
1920 sc->stats.rxerr_crc++;
1921 if (rs.rs_status & AR5K_RXERR_FIFO)
1922 sc->stats.rxerr_fifo++;
1923 if (rs.rs_status & AR5K_RXERR_PHY) {
1924 sc->stats.rxerr_phy++;
1916 goto next; 1925 goto next;
1926 }
1917 if (rs.rs_status & AR5K_RXERR_DECRYPT) { 1927 if (rs.rs_status & AR5K_RXERR_DECRYPT) {
1918 /* 1928 /*
1919 * Decrypt error. If the error occurred 1929 * Decrypt error. If the error occurred
@@ -1925,12 +1935,14 @@ ath5k_tasklet_rx(unsigned long data)
1925 * 1935 *
1926 * XXX do key cache faulting 1936 * XXX do key cache faulting
1927 */ 1937 */
1938 sc->stats.rxerr_decrypt++;
1928 if (rs.rs_keyix == AR5K_RXKEYIX_INVALID && 1939 if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&
1929 !(rs.rs_status & AR5K_RXERR_CRC)) 1940 !(rs.rs_status & AR5K_RXERR_CRC))
1930 goto accept; 1941 goto accept;
1931 } 1942 }
1932 if (rs.rs_status & AR5K_RXERR_MIC) { 1943 if (rs.rs_status & AR5K_RXERR_MIC) {
1933 rx_flag |= RX_FLAG_MMIC_ERROR; 1944 rx_flag |= RX_FLAG_MMIC_ERROR;
1945 sc->stats.rxerr_mic++;
1934 goto accept; 1946 goto accept;
1935 } 1947 }
1936 1948
@@ -2056,6 +2068,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
2056 break; 2068 break;
2057 } 2069 }
2058 2070
2071 sc->stats.tx_all_count++;
2059 skb = bf->skb; 2072 skb = bf->skb;
2060 info = IEEE80211_SKB_CB(skb); 2073 info = IEEE80211_SKB_CB(skb);
2061 bf->skb = NULL; 2074 bf->skb = NULL;
@@ -2082,8 +2095,14 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
2082 2095
2083 if (unlikely(ts.ts_status)) { 2096 if (unlikely(ts.ts_status)) {
2084 sc->ll_stats.dot11ACKFailureCount++; 2097 sc->ll_stats.dot11ACKFailureCount++;
2085 if (ts.ts_status & AR5K_TXERR_FILT) 2098 if (ts.ts_status & AR5K_TXERR_FILT) {
2086 info->flags |= IEEE80211_TX_STAT_TX_FILTERED; 2099 info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
2100 sc->stats.txerr_filt++;
2101 }
2102 if (ts.ts_status & AR5K_TXERR_XRETRY)
2103 sc->stats.txerr_retry++;
2104 if (ts.ts_status & AR5K_TXERR_FIFO)
2105 sc->stats.txerr_fifo++;
2087 } else { 2106 } else {
2088 info->flags |= IEEE80211_TX_STAT_ACK; 2107 info->flags |= IEEE80211_TX_STAT_ACK;
2089 info->status.ack_signal = ts.ts_rssi; 2108 info->status.ack_signal = ts.ts_rssi;
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index ca525842d827..33f1d8b87ee1 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -109,6 +109,18 @@ struct ath5k_rfkill {
109struct ath5k_statistics { 109struct ath5k_statistics {
110 unsigned int antenna_rx[5]; /* frames count per antenna RX */ 110 unsigned int antenna_rx[5]; /* frames count per antenna RX */
111 unsigned int antenna_tx[5]; /* frames count per antenna TX */ 111 unsigned int antenna_tx[5]; /* frames count per antenna TX */
112 unsigned int rx_all_count; /* all RX frames, including errors */
113 unsigned int tx_all_count; /* all TX frames, including errors */
114 unsigned int rxerr_crc;
115 unsigned int rxerr_phy;
116 unsigned int rxerr_fifo;
117 unsigned int rxerr_decrypt;
118 unsigned int rxerr_mic;
119 unsigned int rxerr_proc;
120 unsigned int rxerr_jumbo;
121 unsigned int txerr_retry;
122 unsigned int txerr_fifo;
123 unsigned int txerr_filt;
112}; 124};
113 125
114#if CHAN_DEBUG 126#if CHAN_DEBUG
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 236f20f9cd40..bccd4a78027e 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -465,6 +465,106 @@ static const struct file_operations fops_antenna = {
465}; 465};
466 466
467 467
468/* debugfs: frameerrors */
469
470static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
471 size_t count, loff_t *ppos)
472{
473 struct ath5k_softc *sc = file->private_data;
474 struct ath5k_statistics *st = &sc->stats;
475 char buf[700];
476 unsigned int len = 0;
477
478 len += snprintf(buf+len, sizeof(buf)-len,
479 "RX\n---------------------\n");
480 len += snprintf(buf+len, sizeof(buf)-len, "CRC\t%d\t(%d%%)\n",
481 st->rxerr_crc,
482 st->rx_all_count > 0 ?
483 st->rxerr_crc*100/st->rx_all_count : 0);
484 len += snprintf(buf+len, sizeof(buf)-len, "PHY\t%d\t(%d%%)\n",
485 st->rxerr_phy,
486 st->rx_all_count > 0 ?
487 st->rxerr_phy*100/st->rx_all_count : 0);
488 len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n",
489 st->rxerr_fifo,
490 st->rx_all_count > 0 ?
491 st->rxerr_fifo*100/st->rx_all_count : 0);
492 len += snprintf(buf+len, sizeof(buf)-len, "decrypt\t%d\t(%d%%)\n",
493 st->rxerr_decrypt,
494 st->rx_all_count > 0 ?
495 st->rxerr_decrypt*100/st->rx_all_count : 0);
496 len += snprintf(buf+len, sizeof(buf)-len, "MIC\t%d\t(%d%%)\n",
497 st->rxerr_mic,
498 st->rx_all_count > 0 ?
499 st->rxerr_mic*100/st->rx_all_count : 0);
500 len += snprintf(buf+len, sizeof(buf)-len, "process\t%d\t(%d%%)\n",
501 st->rxerr_proc,
502 st->rx_all_count > 0 ?
503 st->rxerr_proc*100/st->rx_all_count : 0);
504 len += snprintf(buf+len, sizeof(buf)-len, "jumbo\t%d\t(%d%%)\n",
505 st->rxerr_jumbo,
506 st->rx_all_count > 0 ?
507 st->rxerr_jumbo*100/st->rx_all_count : 0);
508 len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%d]\n",
509 st->rx_all_count);
510
511 len += snprintf(buf+len, sizeof(buf)-len,
512 "\nTX\n---------------------\n");
513 len += snprintf(buf+len, sizeof(buf)-len, "retry\t%d\t(%d%%)\n",
514 st->txerr_retry,
515 st->tx_all_count > 0 ?
516 st->txerr_retry*100/st->tx_all_count : 0);
517 len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n",
518 st->txerr_fifo,
519 st->tx_all_count > 0 ?
520 st->txerr_fifo*100/st->tx_all_count : 0);
521 len += snprintf(buf+len, sizeof(buf)-len, "filter\t%d\t(%d%%)\n",
522 st->txerr_filt,
523 st->tx_all_count > 0 ?
524 st->txerr_filt*100/st->tx_all_count : 0);
525 len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n",
526 st->tx_all_count);
527
528 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
529}
530
531static ssize_t write_file_frameerrors(struct file *file,
532 const char __user *userbuf,
533 size_t count, loff_t *ppos)
534{
535 struct ath5k_softc *sc = file->private_data;
536 struct ath5k_statistics *st = &sc->stats;
537 char buf[20];
538
539 if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
540 return -EFAULT;
541
542 if (strncmp(buf, "clear", 5) == 0) {
543 st->rxerr_crc = 0;
544 st->rxerr_phy = 0;
545 st->rxerr_fifo = 0;
546 st->rxerr_decrypt = 0;
547 st->rxerr_mic = 0;
548 st->rxerr_proc = 0;
549 st->rxerr_jumbo = 0;
550 st->rx_all_count = 0;
551 st->txerr_retry = 0;
552 st->txerr_fifo = 0;
553 st->txerr_filt = 0;
554 st->tx_all_count = 0;
555 printk(KERN_INFO "ath5k debug: cleared frameerrors stats\n");
556 }
557 return count;
558}
559
560static const struct file_operations fops_frameerrors = {
561 .read = read_file_frameerrors,
562 .write = write_file_frameerrors,
563 .open = ath5k_debugfs_open,
564 .owner = THIS_MODULE,
565};
566
567
468/* init */ 568/* init */
469 569
470void 570void
@@ -498,6 +598,11 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
498 sc->debug.debugfs_antenna = debugfs_create_file("antenna", 598 sc->debug.debugfs_antenna = debugfs_create_file("antenna",
499 S_IWUSR | S_IRUSR, 599 S_IWUSR | S_IRUSR,
500 sc->debug.debugfs_phydir, sc, &fops_antenna); 600 sc->debug.debugfs_phydir, sc, &fops_antenna);
601
602 sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors",
603 S_IWUSR | S_IRUSR,
604 sc->debug.debugfs_phydir, sc,
605 &fops_frameerrors);
501} 606}
502 607
503void 608void
@@ -514,6 +619,7 @@ ath5k_debug_finish_device(struct ath5k_softc *sc)
514 debugfs_remove(sc->debug.debugfs_beacon); 619 debugfs_remove(sc->debug.debugfs_beacon);
515 debugfs_remove(sc->debug.debugfs_reset); 620 debugfs_remove(sc->debug.debugfs_reset);
516 debugfs_remove(sc->debug.debugfs_antenna); 621 debugfs_remove(sc->debug.debugfs_antenna);
622 debugfs_remove(sc->debug.debugfs_frameerrors);
517 debugfs_remove(sc->debug.debugfs_phydir); 623 debugfs_remove(sc->debug.debugfs_phydir);
518} 624}
519 625
diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h
index 018612711045..da24ff52e274 100644
--- a/drivers/net/wireless/ath/ath5k/debug.h
+++ b/drivers/net/wireless/ath/ath5k/debug.h
@@ -75,6 +75,7 @@ struct ath5k_dbg_info {
75 struct dentry *debugfs_beacon; 75 struct dentry *debugfs_beacon;
76 struct dentry *debugfs_reset; 76 struct dentry *debugfs_reset;
77 struct dentry *debugfs_antenna; 77 struct dentry *debugfs_antenna;
78 struct dentry *debugfs_frameerrors;
78}; 79};
79 80
80/** 81/**