提交 7644395f 编写于 作者: B Bruno Randolf 提交者: John W. Linville

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: NBruno Randolf <br1@einfach.org>
Acked-by: NNick Kossifidis <mickflemm@gmail.com>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 91915454
......@@ -1902,18 +1902,28 @@ ath5k_tasklet_rx(unsigned long data)
break;
else if (unlikely(ret)) {
ATH5K_ERR(sc, "error in processing rx descriptor\n");
sc->stats.rxerr_proc++;
spin_unlock(&sc->rxbuflock);
return;
}
sc->stats.rx_all_count++;
if (unlikely(rs.rs_more)) {
ATH5K_WARN(sc, "unsupported jumbo\n");
sc->stats.rxerr_jumbo++;
goto next;
}
if (unlikely(rs.rs_status)) {
if (rs.rs_status & AR5K_RXERR_PHY)
if (rs.rs_status & AR5K_RXERR_CRC)
sc->stats.rxerr_crc++;
if (rs.rs_status & AR5K_RXERR_FIFO)
sc->stats.rxerr_fifo++;
if (rs.rs_status & AR5K_RXERR_PHY) {
sc->stats.rxerr_phy++;
goto next;
}
if (rs.rs_status & AR5K_RXERR_DECRYPT) {
/*
* Decrypt error. If the error occurred
......@@ -1925,12 +1935,14 @@ ath5k_tasklet_rx(unsigned long data)
*
* XXX do key cache faulting
*/
sc->stats.rxerr_decrypt++;
if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&
!(rs.rs_status & AR5K_RXERR_CRC))
goto accept;
}
if (rs.rs_status & AR5K_RXERR_MIC) {
rx_flag |= RX_FLAG_MMIC_ERROR;
sc->stats.rxerr_mic++;
goto accept;
}
......@@ -2056,6 +2068,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
break;
}
sc->stats.tx_all_count++;
skb = bf->skb;
info = IEEE80211_SKB_CB(skb);
bf->skb = NULL;
......@@ -2082,8 +2095,14 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
if (unlikely(ts.ts_status)) {
sc->ll_stats.dot11ACKFailureCount++;
if (ts.ts_status & AR5K_TXERR_FILT)
if (ts.ts_status & AR5K_TXERR_FILT) {
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
sc->stats.txerr_filt++;
}
if (ts.ts_status & AR5K_TXERR_XRETRY)
sc->stats.txerr_retry++;
if (ts.ts_status & AR5K_TXERR_FIFO)
sc->stats.txerr_fifo++;
} else {
info->flags |= IEEE80211_TX_STAT_ACK;
info->status.ack_signal = ts.ts_rssi;
......
......@@ -109,6 +109,18 @@ struct ath5k_rfkill {
struct ath5k_statistics {
unsigned int antenna_rx[5]; /* frames count per antenna RX */
unsigned int antenna_tx[5]; /* frames count per antenna TX */
unsigned int rx_all_count; /* all RX frames, including errors */
unsigned int tx_all_count; /* all TX frames, including errors */
unsigned int rxerr_crc;
unsigned int rxerr_phy;
unsigned int rxerr_fifo;
unsigned int rxerr_decrypt;
unsigned int rxerr_mic;
unsigned int rxerr_proc;
unsigned int rxerr_jumbo;
unsigned int txerr_retry;
unsigned int txerr_fifo;
unsigned int txerr_filt;
};
#if CHAN_DEBUG
......
......@@ -465,6 +465,106 @@ static const struct file_operations fops_antenna = {
};
/* debugfs: frameerrors */
static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath5k_softc *sc = file->private_data;
struct ath5k_statistics *st = &sc->stats;
char buf[700];
unsigned int len = 0;
len += snprintf(buf+len, sizeof(buf)-len,
"RX\n---------------------\n");
len += snprintf(buf+len, sizeof(buf)-len, "CRC\t%d\t(%d%%)\n",
st->rxerr_crc,
st->rx_all_count > 0 ?
st->rxerr_crc*100/st->rx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "PHY\t%d\t(%d%%)\n",
st->rxerr_phy,
st->rx_all_count > 0 ?
st->rxerr_phy*100/st->rx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n",
st->rxerr_fifo,
st->rx_all_count > 0 ?
st->rxerr_fifo*100/st->rx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "decrypt\t%d\t(%d%%)\n",
st->rxerr_decrypt,
st->rx_all_count > 0 ?
st->rxerr_decrypt*100/st->rx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "MIC\t%d\t(%d%%)\n",
st->rxerr_mic,
st->rx_all_count > 0 ?
st->rxerr_mic*100/st->rx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "process\t%d\t(%d%%)\n",
st->rxerr_proc,
st->rx_all_count > 0 ?
st->rxerr_proc*100/st->rx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "jumbo\t%d\t(%d%%)\n",
st->rxerr_jumbo,
st->rx_all_count > 0 ?
st->rxerr_jumbo*100/st->rx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%d]\n",
st->rx_all_count);
len += snprintf(buf+len, sizeof(buf)-len,
"\nTX\n---------------------\n");
len += snprintf(buf+len, sizeof(buf)-len, "retry\t%d\t(%d%%)\n",
st->txerr_retry,
st->tx_all_count > 0 ?
st->txerr_retry*100/st->tx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n",
st->txerr_fifo,
st->tx_all_count > 0 ?
st->txerr_fifo*100/st->tx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "filter\t%d\t(%d%%)\n",
st->txerr_filt,
st->tx_all_count > 0 ?
st->txerr_filt*100/st->tx_all_count : 0);
len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n",
st->tx_all_count);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t write_file_frameerrors(struct file *file,
const char __user *userbuf,
size_t count, loff_t *ppos)
{
struct ath5k_softc *sc = file->private_data;
struct ath5k_statistics *st = &sc->stats;
char buf[20];
if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
return -EFAULT;
if (strncmp(buf, "clear", 5) == 0) {
st->rxerr_crc = 0;
st->rxerr_phy = 0;
st->rxerr_fifo = 0;
st->rxerr_decrypt = 0;
st->rxerr_mic = 0;
st->rxerr_proc = 0;
st->rxerr_jumbo = 0;
st->rx_all_count = 0;
st->txerr_retry = 0;
st->txerr_fifo = 0;
st->txerr_filt = 0;
st->tx_all_count = 0;
printk(KERN_INFO "ath5k debug: cleared frameerrors stats\n");
}
return count;
}
static const struct file_operations fops_frameerrors = {
.read = read_file_frameerrors,
.write = write_file_frameerrors,
.open = ath5k_debugfs_open,
.owner = THIS_MODULE,
};
/* init */
void
......@@ -498,6 +598,11 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
sc->debug.debugfs_antenna = debugfs_create_file("antenna",
S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_antenna);
sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors",
S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc,
&fops_frameerrors);
}
void
......@@ -514,6 +619,7 @@ ath5k_debug_finish_device(struct ath5k_softc *sc)
debugfs_remove(sc->debug.debugfs_beacon);
debugfs_remove(sc->debug.debugfs_reset);
debugfs_remove(sc->debug.debugfs_antenna);
debugfs_remove(sc->debug.debugfs_frameerrors);
debugfs_remove(sc->debug.debugfs_phydir);
}
......
......@@ -75,6 +75,7 @@ struct ath5k_dbg_info {
struct dentry *debugfs_beacon;
struct dentry *debugfs_reset;
struct dentry *debugfs_antenna;
struct dentry *debugfs_frameerrors;
};
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册