From: Sean Wang Add USB debugfs counters for RX/TX URBs, packets, bytes and recent RX aggregation frame counts. These stats make it easier to verify whether USB RX aggregation are working as expected, and to debug throughput issues without adding temporary driver logs. Signed-off-by: Sean Wang --- drivers/net/wireless/mediatek/mt76/debugfs.c | 35 ++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 12 ++++++ drivers/net/wireless/mediatek/mt76/usb.c | 39 ++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index a5ac6ca86735..b3f1bc3cd69b 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -88,6 +88,38 @@ static int mt76_rx_queues_read(struct seq_file *s, void *data) return 0; } +static int mt76_usb_stats_read(struct seq_file *s, void *data) +{ + struct mt76_dev *dev = dev_get_drvdata(s->private); + struct mt76_usb *usb = &dev->usb; + u64 seq; + int i, n; + + seq_printf(s, "rx_aggr\t%d\n", usb->rx_aggr.enable); + seq_printf(s, "sg_en\t%d\n", usb->sg_en); + seq_printf(s, "tx_urbs\t%lld\n", atomic64_read(&usb->stats.tx_urbs)); + seq_printf(s, "tx_packets\t%lld\n", + atomic64_read(&usb->stats.tx_packets)); + seq_printf(s, "tx_bytes\t%lld\n", atomic64_read(&usb->stats.tx_bytes)); + seq_printf(s, "rx_urbs\t%lld\n", atomic64_read(&usb->stats.rx_urbs)); + seq_printf(s, "rx_packets\t%lld\n", + atomic64_read(&usb->stats.rx_packets)); + seq_printf(s, "rx_bytes\t%lld\n", atomic64_read(&usb->stats.rx_bytes)); + + seq = atomic64_read(&usb->stats.rx_aggr_seq); + seq_puts(s, "rx_aggr_nframes"); + n = min_t(u64, seq, MT_USB_AGGR_STATS_LEN); + for (i = 0; i < n; i++) { + u64 idx = seq - n + i; + u64 slot = idx % MT_USB_AGGR_STATS_LEN; + + seq_printf(s, " %u", READ_ONCE(usb->stats.rx_aggr_nframes[slot])); + } + seq_puts(s, "\n"); + + return 0; +} + void mt76_seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len) { @@ -120,6 +152,9 @@ mt76_register_debugfs_fops(struct mt76_phy *phy, debugfs_create_blob("otp", 0400, dir, &dev->otp); debugfs_create_devm_seqfile(dev->dev, "rx-queues", dir, mt76_rx_queues_read); + if (mt76_is_usb(dev)) + debugfs_create_devm_seqfile(dev->dev, "usb-stats", dir, + mt76_usb_stats_read); return dir; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 125c97dc1f28..c11a463ae092 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -664,6 +664,7 @@ struct mt76u_rx_entry { #define MT_RX_SG_MAX_SIZE 4 #define MT_NUM_TX_ENTRIES 256 #define MT_NUM_RX_ENTRIES 128 +#define MT_USB_AGGR_STATS_LEN 128 #define MCU_RESP_URB_SIZE 1024 struct mt76_usb { struct mutex usb_ctrl_mtx; @@ -687,6 +688,17 @@ struct mt76_usb { int buf_size; } rx_aggr; + struct { + atomic64_t tx_urbs; + atomic64_t tx_packets; + atomic64_t tx_bytes; + atomic64_t rx_urbs; + atomic64_t rx_packets; + atomic64_t rx_bytes; + atomic64_t rx_aggr_seq; + u8 rx_aggr_nframes[MT_USB_AGGR_STATS_LEN]; + } stats; + struct mt76u_mcu { u8 *data; /* multiple reads */ diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index cbdd663fbb25..10ad2b024985 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -15,6 +15,36 @@ static bool disable_usb_sg; module_param_named(disable_usb_sg, disable_usb_sg, bool, 0644); MODULE_PARM_DESC(disable_usb_sg, "Disable usb scatter-gather support"); +static void mt76u_tx_stats_add(struct mt76_dev *dev, struct urb *urb, + unsigned int packets) +{ + atomic64_inc(&dev->usb.stats.tx_urbs); + atomic64_add(packets, &dev->usb.stats.tx_packets); + atomic64_add(urb->transfer_buffer_length, &dev->usb.stats.tx_bytes); +} + +static void mt76u_rx_urb_stats_add(struct mt76_dev *dev, struct urb *urb) +{ + atomic64_inc(&dev->usb.stats.rx_urbs); + atomic64_add(urb->actual_length, &dev->usb.stats.rx_bytes); +} + +static void mt76u_rx_packet_stats_add(struct mt76_dev *dev, + unsigned int packets) +{ + atomic64_add(packets, &dev->usb.stats.rx_packets); +} + +static void mt76u_rx_aggr_stats_add(struct mt76_dev *dev, unsigned int packets) +{ + u64 idx, slot; + + idx = atomic64_inc_return(&dev->usb.stats.rx_aggr_seq) - 1; + slot = idx % MT_USB_AGGR_STATS_LEN; + WRITE_ONCE(dev->usb.stats.rx_aggr_nframes[slot], + min_t(unsigned int, packets, U8_MAX)); +} + int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, void *buf, size_t len) { @@ -634,6 +664,10 @@ static int mt76u_process_rx_agg_entry(struct mt76_dev *dev, struct urb *urb) mt76_put_page_pool_buf(urb->transfer_buffer, false); urb->transfer_buffer = NULL; + if (nframes) + mt76u_rx_packet_stats_add(dev, nframes); + mt76u_rx_aggr_stats_add(dev, nframes); + return max(nframes, 1); } @@ -681,6 +715,7 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb, skb_mark_for_recycle(skb); dev->drv->rx_skb(dev, MT_RXQ_MAIN, skb, NULL); + mt76u_rx_packet_stats_add(dev, 1); return nsgs; } @@ -714,6 +749,9 @@ static void mt76u_complete_rx(struct urb *urb) break; } + if (!urb->status) + mt76u_rx_urb_stats_add(dev, urb); + spin_lock_irqsave(&q->lock, flags); idx = e - q->entry; pending = q->ndesc - q->queued; @@ -1083,6 +1121,7 @@ static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) err); break; } + mt76u_tx_stats_add(dev, urb, 1); q->first = (q->first + 1) % q->ndesc; } } -- 2.43.0