DEFINE_DEBUGFS_ATTRIBUTE(fops_edcca, mt7603_edcca_get,
                         mt7603_edcca_set, "%lld\n");
 
+static int
+mt7603_ampdu_stat_read(struct seq_file *file, void *data)
+{
+       struct mt7603_dev *dev = file->private;
+       int bound[3], i, range;
+
+       range = mt76_rr(dev, MT_AGG_ASRCR);
+       for (i = 0; i < ARRAY_SIZE(bound); i++)
+               bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1;
+
+       seq_printf(file, "Length: %8d | ", bound[0]);
+       for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
+               seq_printf(file, "%3d -%3d | ",
+                          bound[i], bound[i + 1]);
+       seq_puts(file, "\nCount:  ");
+       for (i = 0; i < ARRAY_SIZE(bound); i++)
+               seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]);
+       seq_puts(file, "\n");
+
+       return 0;
+}
+
+static int
+mt7603_ampdu_stat_open(struct inode *inode, struct file *f)
+{
+       return single_open(f, mt7603_ampdu_stat_read, inode->i_private);
+}
+
+static const struct file_operations fops_ampdu_stat = {
+       .open = mt7603_ampdu_stat_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
 void mt7603_init_debugfs(struct mt7603_dev *dev)
 {
        struct dentry *dir;
        if (!dir)
                return;
 
+       debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
        debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
                                    mt76_queues_read);
        debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca);
 
        mt76_set(dev, MT_WF_ARB_TX_START_0, mt7603_ac_queue_mask0(mask));
 }
 
+void mt7603_mac_reset_counters(struct mt7603_dev *dev)
+{
+       int i;
+
+       for (i = 0; i < 2; i++)
+               mt76_rr(dev, MT_TX_AGG_CNT(i));
+
+       memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats));
+}
+
 void mt7603_mac_set_timing(struct mt7603_dev *dev)
 {
        u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
        struct mt7603_dev *dev = container_of(work, struct mt7603_dev,
                                              mt76.mac_work.work);
        bool reset = false;
+       int i, idx;
 
        mt76_tx_status_check(&dev->mt76, NULL, false);
 
        mt7603_update_channel(&dev->mt76);
        mt7603_edcca_check(dev);
 
+       for (i = 0, idx = 0; i < 2; i++) {
+               u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
+
+               dev->mt76.aggr_stats[idx++] += val & 0xffff;
+               dev->mt76.aggr_stats[idx++] += val >> 16;
+       }
+
        if (dev->mac_work_count == 10)
                mt7603_false_cca_check(dev);
 
 
 {
        struct mt7603_dev *dev = hw->priv;
 
+       mt7603_mac_reset_counters(dev);
        mt7603_mac_start(dev);
        dev->mt76.survey_time = ktime_get_boottime();
        set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
 
        mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
 }
 
+void mt7603_mac_reset_counters(struct mt7603_dev *dev);
 void mt7603_mac_dma_start(struct mt7603_dev *dev);
 void mt7603_mac_start(struct mt7603_dev *dev);
 void mt7603_mac_stop(struct mt7603_dev *dev);
 
 #define MT_AGG_PCR_RTS_THR             GENMASK(19, 0)
 #define MT_AGG_PCR_RTS_PKT_THR         GENMASK(31, 25)
 
+#define MT_AGG_ASRCR                   MT_WF_AGG(0x060)
+#define MT_AGG_ASRCR_RANGE(val, n)     (((val) >> ((n) << 3)) & GENMASK(5, 0))
+
 #define MT_AGG_CONTROL                 MT_WF_AGG(0x070)
 #define MT_AGG_CONTROL_NO_BA_RULE      BIT(0)
 #define MT_AGG_CONTROL_NO_BA_AR_RULE   BIT(1)
 #define MT_MIB_STAT_PSCCA              MT_MIB_STAT(16)
 #define MT_MIB_STAT_PSCCA_MASK         GENMASK(23, 0)
 
+#define MT_TX_AGG_CNT(n)               MT_MIB(0xa8 + ((n) << 2))
+
 #define MT_MIB_STAT_ED                 MT_MIB_STAT(18)
 #define MT_MIB_STAT_ED_MASK            GENMASK(23, 0)