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
                                 *
                                 * 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;
                        }
 
                        break;
                }
 
+               sc->stats.tx_all_count++;
                skb = bf->skb;
                info = IEEE80211_SKB_CB(skb);
                bf->skb = NULL;
 
                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;
 
 };
 
 
+/* 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
        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
        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);
 }