1 // SPDX-License-Identifier: ISC
2 /* Copyright (C) 2020 MediaTek Inc. */
3 
4 #include "mt7921.h"
5 #include "eeprom.h"
6 
7 static int
8 mt7921_fw_debug_set(void *data, u64 val)
9 {
10 	struct mt7921_dev *dev = data;
11 
12 	dev->fw_debug = (u8)val;
13 
14 	mt7921_mcu_fw_log_2_host(dev, dev->fw_debug);
15 
16 	return 0;
17 }
18 
19 static int
20 mt7921_fw_debug_get(void *data, u64 *val)
21 {
22 	struct mt7921_dev *dev = data;
23 
24 	*val = dev->fw_debug;
25 
26 	return 0;
27 }
28 
29 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7921_fw_debug_get,
30 			 mt7921_fw_debug_set, "%lld\n");
31 
32 static void
33 mt7921_ampdu_stat_read_phy(struct mt7921_phy *phy,
34 			   struct seq_file *file)
35 {
36 	struct mt7921_dev *dev = file->private;
37 	int bound[15], range[4], i;
38 
39 	if (!phy)
40 		return;
41 
42 	/* Tx ampdu stat */
43 	for (i = 0; i < ARRAY_SIZE(range); i++)
44 		range[i] = mt76_rr(dev, MT_MIB_ARNG(0, i));
45 
46 	for (i = 0; i < ARRAY_SIZE(bound); i++)
47 		bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i) + 1;
48 
49 	seq_printf(file, "\nPhy0\n");
50 
51 	seq_printf(file, "Length: %8d | ", bound[0]);
52 	for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
53 		seq_printf(file, "%3d -%3d | ",
54 			   bound[i] + 1, bound[i + 1]);
55 
56 	seq_puts(file, "\nCount:  ");
57 	for (i = 0; i < ARRAY_SIZE(bound); i++)
58 		seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]);
59 	seq_puts(file, "\n");
60 
61 	seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
62 }
63 
64 static int
65 mt7921_tx_stats_read(struct seq_file *file, void *data)
66 {
67 	struct mt7921_dev *dev = file->private;
68 	int stat[8], i, n;
69 
70 	mt7921_ampdu_stat_read_phy(&dev->phy, file);
71 
72 	/* Tx amsdu info */
73 	seq_puts(file, "Tx MSDU stat:\n");
74 	for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) {
75 		stat[i] = mt76_rr(dev,  MT_PLE_AMSDU_PACK_MSDU_CNT(i));
76 		n += stat[i];
77 	}
78 
79 	for (i = 0; i < ARRAY_SIZE(stat); i++) {
80 		seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ",
81 			   i + 1, stat[i]);
82 		if (n != 0)
83 			seq_printf(file, "(%d%%)\n", stat[i] * 100 / n);
84 		else
85 			seq_puts(file, "\n");
86 	}
87 
88 	return 0;
89 }
90 
91 static int
92 mt7921_tx_stats_open(struct inode *inode, struct file *f)
93 {
94 	return single_open(f, mt7921_tx_stats_read, inode->i_private);
95 }
96 
97 static const struct file_operations fops_tx_stats = {
98 	.open = mt7921_tx_stats_open,
99 	.read = seq_read,
100 	.llseek = seq_lseek,
101 	.release = single_release,
102 	.owner = THIS_MODULE,
103 };
104 
105 static int
106 mt7921_queues_acq(struct seq_file *s, void *data)
107 {
108 	struct mt7921_dev *dev = dev_get_drvdata(s->private);
109 	int i;
110 
111 	for (i = 0; i < 16; i++) {
112 		int j, acs = i / 4, index = i % 4;
113 		u32 ctrl, val, qlen = 0;
114 
115 		val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index));
116 		ctrl = BIT(31) | BIT(15) | (acs << 8);
117 
118 		for (j = 0; j < 32; j++) {
119 			if (val & BIT(j))
120 				continue;
121 
122 			mt76_wr(dev, MT_PLE_FL_Q0_CTRL,
123 				ctrl | (j + (index << 5)));
124 			qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL,
125 					       GENMASK(11, 0));
126 		}
127 		seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen);
128 	}
129 
130 	return 0;
131 }
132 
133 static int
134 mt7921_queues_read(struct seq_file *s, void *data)
135 {
136 	struct mt7921_dev *dev = dev_get_drvdata(s->private);
137 	struct {
138 		struct mt76_queue *q;
139 		char *queue;
140 	} queue_map[] = {
141 		{ dev->mphy.q_tx[MT_TXQ_BE],	 "WFDMA0" },
142 		{ dev->mt76.q_mcu[MT_MCUQ_WM],	 "MCUWM"  },
143 		{ dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" },
144 	};
145 	int i;
146 
147 	for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
148 		struct mt76_queue *q = queue_map[i].q;
149 
150 		if (!q)
151 			continue;
152 
153 		seq_printf(s,
154 			   "%s:	queued=%d head=%d tail=%d\n",
155 			   queue_map[i].queue, q->queued, q->head,
156 			   q->tail);
157 	}
158 
159 	return 0;
160 }
161 
162 static int
163 mt7921_pm_set(void *data, u64 val)
164 {
165 	struct mt7921_dev *dev = data;
166 	struct mt76_phy *mphy = dev->phy.mt76;
167 	int ret = 0;
168 
169 	mt7921_mutex_acquire(dev);
170 
171 	dev->pm.enable = val;
172 
173 	ieee80211_iterate_active_interfaces(mphy->hw,
174 					    IEEE80211_IFACE_ITER_RESUME_ALL,
175 					    mt7921_pm_interface_iter, mphy->priv);
176 	mt7921_mutex_release(dev);
177 
178 	return ret;
179 }
180 
181 static int
182 mt7921_pm_get(void *data, u64 *val)
183 {
184 	struct mt7921_dev *dev = data;
185 
186 	*val = dev->pm.enable;
187 
188 	return 0;
189 }
190 
191 DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n");
192 
193 static int
194 mt7921_pm_idle_timeout_set(void *data, u64 val)
195 {
196 	struct mt7921_dev *dev = data;
197 
198 	dev->pm.idle_timeout = msecs_to_jiffies(val);
199 
200 	return 0;
201 }
202 
203 static int
204 mt7921_pm_idle_timeout_get(void *data, u64 *val)
205 {
206 	struct mt7921_dev *dev = data;
207 
208 	*val = jiffies_to_msecs(dev->pm.idle_timeout);
209 
210 	return 0;
211 }
212 
213 DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7921_pm_idle_timeout_get,
214 			 mt7921_pm_idle_timeout_set, "%lld\n");
215 
216 static int mt7921_config(void *data, u64 val)
217 {
218 	struct mt7921_dev *dev = data;
219 	int ret;
220 
221 	mt7921_mutex_acquire(dev);
222 	ret = mt76_connac_mcu_chip_config(&dev->mt76);
223 	mt7921_mutex_release(dev);
224 
225 	return ret;
226 }
227 
228 DEFINE_DEBUGFS_ATTRIBUTE(fops_config, NULL, mt7921_config, "%lld\n");
229 
230 int mt7921_init_debugfs(struct mt7921_dev *dev)
231 {
232 	struct dentry *dir;
233 
234 	dir = mt76_register_debugfs(&dev->mt76);
235 	if (!dir)
236 		return -ENOMEM;
237 
238 	debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
239 				    mt7921_queues_read);
240 	debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
241 				    mt7921_queues_acq);
242 	debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats);
243 	debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
244 	debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm);
245 	debugfs_create_file("idle-timeout", 0600, dir, dev,
246 			    &fops_pm_idle_timeout);
247 	debugfs_create_file("chip_config", 0600, dir, dev, &fops_config);
248 
249 	return 0;
250 }
251