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>
This commit is contained in:
parent
919154540a
commit
7644395f8d
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue