Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7dff37c6 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "wil6210: add ability to help debug tx latency"

parents 59eee282 0fcdf063
Loading
Loading
Loading
Loading
+55 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: ISC
/*
 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/module.h>
@@ -864,6 +864,57 @@ static const struct file_operations fops_rbufcap = {
	.open  = simple_open,
};

static int wil_tx_latency_threshold_low_show(struct seq_file *s, void *data)
{
	struct wil6210_priv *wil = s->private;

	seq_printf(s, "%d\n", wil->tx_latency_threshold_low);
	return 0;
}

static int wil_tx_latency_threshold_low_seq_open(struct inode *inode,
						 struct file *file)
{
	return single_open(file, wil_tx_latency_threshold_low_show,
			   inode->i_private);
}

static ssize_t wil_tx_latency_threshold_low_write(struct file *file,
						  const char __user *buf,
						  size_t len, loff_t *ppos)
{
	struct seq_file *s = file->private_data;
	struct wil6210_priv *wil = s->private;
	int rc;
	u32 val;

	rc = kstrtouint_from_user(buf, len, 0, &val);
	if (rc) {
		wil_err(wil, "Invalid argument\n");
		return rc;
	}

	if (!wil->tx_latency_threshold_base) {
		/* tx latency debug - failure can be safely ignored */
		rc = wmi_ut_update_txlatency_base(wil);
		wil_dbg_misc(wil, "ut_update_txlatency base returned %d\n", rc);
	}

	wil->tx_latency_threshold_low = val;

	wil_info(wil, "Setting tx_latency_threshold_low to %d\n",
		 wil->tx_latency_threshold_low);
	return len;
}

static const struct file_operations fops_tx_latency_threshold_low = {
	.open		= wil_tx_latency_threshold_low_seq_open,
	.release	= single_release,
	.read		= seq_read,
	.write		= wil_tx_latency_threshold_low_write,
	.llseek		= seq_lseek,
};

/* block ack control, write:
 * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
 * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
@@ -2616,6 +2667,7 @@ static const struct {
	{"link_stats",	0644,		&fops_link_stats},
	{"link_stats_global",	0644,	&fops_link_stats_global},
	{"rbufcap",	0244,		&fops_rbufcap},
	{"tx_latency_threshold_low", 0644, &fops_tx_latency_threshold_low},
};

static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
@@ -2670,6 +2722,8 @@ static const struct dbg_off dbg_wil_off[] = {
	WIL_FIELD(force_edmg_channel, 0644,	doff_u8),
	WIL_FIELD(ap_ps, 0644, doff_u8),
	WIL_FIELD(tx_reserved_entries, 0644, doff_u32),
	WIL_FIELD(tx_latency_threshold_high,	0644,	doff_u32),
	WIL_FIELD(tx_latency_threshold_info.threshold_detected, 0644, doff_u8),
	{},
};

+37 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: ISC
/*
 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/interrupt.h>
@@ -286,6 +286,36 @@ void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
	      BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL);
}

static inline void write_rx_intr_cnt(struct wil6210_priv *wil)
{
	if (wil_tx_latency_threshold_enabled(wil))
		wil_w(wil,
		      wil->tx_latency_threshold_base +
			      offsetof(struct wil_tx_latency_threshold_info,
				       rx_intr_cnt),
		      ++wil->tx_latency_threshold_info.rx_intr_cnt);
}

static inline void write_tx_intr_cnt(struct wil6210_priv *wil)
{
	if (wil_tx_latency_threshold_enabled(wil))
		wil_w(wil,
		      wil->tx_latency_threshold_base +
			      offsetof(struct wil_tx_latency_threshold_info,
				       tx_intr_cnt),
		      ++wil->tx_latency_threshold_info.tx_intr_cnt);
}

static inline void write_hard_irq_cnt(struct wil6210_priv *wil)
{
	if (wil_tx_latency_threshold_enabled(wil))
		wil_w(wil,
		      wil->tx_latency_threshold_base +
			      offsetof(struct wil_tx_latency_threshold_info,
				       hard_irq_cnt),
		      ++wil->tx_latency_threshold_info.hard_irq_cnt);
}

static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
{
	struct wil6210_priv *wil = cookie;
@@ -300,6 +330,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)

	trace_wil6210_irq_rx(isr);
	wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
	write_rx_intr_cnt(wil);

	if (unlikely(!isr)) {
		wil_err_ratelimited(wil, "spurious IRQ: RX\n");
@@ -362,6 +393,7 @@ static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie)

	trace_wil6210_irq_rx(isr);
	wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
	write_rx_intr_cnt(wil);

	if (unlikely(!isr)) {
		wil_err(wil, "spurious IRQ: RX\n");
@@ -413,6 +445,7 @@ static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie)

	trace_wil6210_irq_tx(isr);
	wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
	write_tx_intr_cnt(wil);

	if (unlikely(!isr)) {
		wil_err(wil, "spurious IRQ: TX\n");
@@ -459,6 +492,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)

	trace_wil6210_irq_tx(isr);
	wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
	write_tx_intr_cnt(wil);

	if (unlikely(!isr)) {
		wil_err_ratelimited(wil, "spurious IRQ: TX\n");
@@ -756,6 +790,8 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie)
	struct wil6210_priv *wil = cookie;
	u32 pseudo_cause = wil_r(wil, RGF_DMA_PSEUDO_CAUSE);

	write_hard_irq_cnt(wil);

	/**
	 * pseudo_cause is Clear-On-Read, no need to ACK
	 */
+69 −6
Original line number Diff line number Diff line
@@ -2454,19 +2454,51 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
	return NET_XMIT_DROP;
}

void wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb,
static void wil_process_tx_latency(struct wil6210_priv *wil, u32 *tsf_low,
				   u32 *tsf_high, ktime_t *before_tsf_read)
{
	/* Stop PMC recording */
	wil_s(wil, RGF_MAC_PMC_GENERAL_0, BIT_STOP_PMC_RECORDING);

	*before_tsf_read = ktime_get();
	*tsf_low = wil_r(wil, RGF_MSRB_CAPTURE_TS_LOW);
	*tsf_high = wil_r(wil, RGF_MSRB_CAPTURE_TS_HIGH);

	wil_w(wil,
	      wil->tx_latency_threshold_base +
		      offsetof(struct wil_tx_latency_threshold_info,
			       threshold_detected),
	      0xffffffff);
}

static inline void
wil_dump_vring_tx_desc(struct wil6210_priv *wil, struct vring_tx_desc *dd)
{
	wil_err(wil,
		"Desc.MAC: d[0]: 0x%x, d[1]: 0x%x, d[2]: 0x%x, ucode_cmd: 0x%x\n",
		dd->mac.d[0], dd->mac.d[1], dd->mac.d[2], dd->mac.ucode_cmd);
	wil_err(wil,
		"Desc.DMA: d0: 0x%x, addr.high: 0x%x, addr.low: 0x%x, ip_length: 0x%x, b11: 0x%x, error: 0x%x, status: 0x%x, length: 0x%x\n",
		dd->dma.d0, dd->dma.addr.addr_high, dd->dma.addr.addr_low,
		dd->dma.ip_length, dd->dma.b11, dd->dma.error,
		dd->dma.status, dd->dma.length);
}

int wil_tx_latency_calc_common(struct wil6210_priv *wil, struct sk_buff *skb,
			       struct wil_sta_info *sta)
{
	int skb_time_us;
	int bin;
	ktime_t end;

	if (!wil->tx_latency)
		return;
		return 0;

	if (ktime_to_ms(*(ktime_t *)&skb->cb) == 0)
		return;
		return 0;

	skb_time_us = ktime_us_delta(ktime_get(), *(ktime_t *)&skb->cb);
	end = ktime_get();
	skb_time_us = ktime_us_delta(end, *(ktime_t *)&skb->cb);
	bin = skb_time_us / wil->tx_latency_res;
	bin = min_t(int, bin, WIL_NUM_LATENCY_BINS - 1);

@@ -2477,6 +2509,37 @@ void wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb,
		sta->stats.tx_latency_min_us = skb_time_us;
	if (skb_time_us > sta->stats.tx_latency_max_us)
		sta->stats.tx_latency_max_us = skb_time_us;
	if (!wil_tx_latency_threshold_enabled(wil))
		return 0;
	if (wil->tx_latency_threshold_info.threshold_detected == 0 &&
	    skb_time_us >= wil->tx_latency_threshold_low &&
	    skb_time_us <= wil->tx_latency_threshold_high) {
		ktime_t start, before_tsf_read;
		u32 tsf_low, tsf_high;

		start = *(ktime_t *)&skb->cb;
		wil->tx_latency_threshold_info.threshold_detected = 1;
		wil_process_tx_latency(wil, &tsf_low, &tsf_high,
				       &before_tsf_read);
		wil_err(wil,
			"Latency Start: %lld, end: %lld, diff: %lld (us)\n",
			ktime_to_us(start), ktime_to_us(end),
			ktime_to_us(end) - ktime_to_us(start));
		wil_err(wil,
			"TSF Low: 0x%x, high: 0x%x, before: %lld\n",
			tsf_low, tsf_high, ktime_to_us(before_tsf_read));
		return 1;
	}
	return 0;
}

static inline void
wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb,
		    struct wil_sta_info *sta,
		    struct vring_tx_desc *dd)
{
	if (wil_tx_latency_calc_common(wil, skb, sta))
		wil_dump_vring_tx_desc(wil, dd);
}

/**
@@ -2567,7 +2630,7 @@ int wil_tx_complete(struct wil6210_vif *vif, int ringid)
						stats->tx_bytes += skb->len;

						wil_tx_latency_calc(wil, skb,
							&wil->sta[cid]);
							&wil->sta[cid], &dd);
					}
				} else {
					ndev->stats.tx_errors++;
+2 −2
Original line number Diff line number Diff line
@@ -708,7 +708,7 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
void wil_tx_data_init(const struct wil6210_priv *wil,
		      struct wil_ring_tx_data *txdata);
void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil);
void wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb,
int wil_tx_latency_calc_common(struct wil6210_priv *wil, struct sk_buff *skb,
			       struct wil_sta_info *sta);
int wil_get_cid_by_ring(struct wil6210_priv *wil, struct wil_ring *ring);
bool wil_is_special_packet(const struct sk_buff *skb);
+27 −2
Original line number Diff line number Diff line
@@ -1268,6 +1268,26 @@ wil_get_next_tx_status_msg(struct wil_status_ring *sring, u8 *dr_bit,
	*msg = *_msg;
}

static inline void wil_dump_tx_status(struct wil6210_priv *wil,
				      struct wil_ring_tx_status *msg)
{
	wil_err(wil,
		"Status Msg: num_desc: %d, ring_id: %d, status: %d, desc_ready: %d, timestamp: 0x%x, d2: 0x%x, seq_num: 0x%x, w7: 0x%x\n",
		msg->num_descriptors, msg->ring_id, msg->status,
		msg->desc_ready, msg->timestamp, msg->d2, msg->seq_number,
		msg->w7);
}

static inline void
wil_tx_latency_calc_edma(struct wil6210_priv *wil,
			 struct sk_buff *skb,
			 struct wil_sta_info *sta,
			 struct wil_ring_tx_status *msg)
{
	if (wil_tx_latency_calc_common(wil, skb, sta))
		wil_dump_tx_status(wil, msg);
}

/**
 * Clean up transmitted skb's from the Tx descriptor RING.
 * Return number of descriptors cleared.
@@ -1371,11 +1391,16 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
					ndev->stats.tx_packets++;
					ndev->stats.tx_bytes += skb->len;
					if (stats) {
						struct wil_sta_info *sta;

						stats->tx_packets++;
						stats->tx_bytes += skb->len;
						sta = &wil->sta[cid];

						wil_tx_latency_calc(wil, skb,
							&wil->sta[cid]);
						wil_tx_latency_calc_edma(wil,
									 skb,
									 sta,
									 &msg);
					}
				} else {
					ndev->stats.tx_errors++;
Loading