blob: 1ecad66f806709a88eeab2091da3387f5716e683 [file] [log] [blame]
developerfd40db22021-04-29 10:08:25 +08001/* Copyright 2016 MediaTek Inc.
2 * Author: Nelson Chang <nelson.chang@mediatek.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13#include "raether.h"
14#include "raether_hwlro.h"
15#include "ra_dbg_proc.h"
16
17/* HW LRO proc */
18#define HW_LRO_RING_NUM 3
19#define MAX_HW_LRO_AGGR 64
20
21typedef int (*HWLRO_DBG_FUNC) (int par1, int par2);
22unsigned int hw_lro_agg_num_cnt[HW_LRO_RING_NUM][MAX_HW_LRO_AGGR + 1];
23unsigned int hw_lro_agg_size_cnt[HW_LRO_RING_NUM][16];
24unsigned int hw_lro_tot_agg_cnt[HW_LRO_RING_NUM];
25unsigned int hw_lro_tot_flush_cnt[HW_LRO_RING_NUM];
26
27/* HW LRO flush reason proc */
28#define HW_LRO_AGG_FLUSH (1)
29#define HW_LRO_AGE_FLUSH (2)
30#define HW_LRO_NOT_IN_SEQ_FLUSH (3)
31#define HW_LRO_TIMESTAMP_FLUSH (4)
32#define HW_LRO_NON_RULE_FLUSH (5)
33
34unsigned int hw_lro_agg_flush_cnt[HW_LRO_RING_NUM];
35unsigned int hw_lro_age_flush_cnt[HW_LRO_RING_NUM];
36unsigned int hw_lro_seq_flush_cnt[HW_LRO_RING_NUM];
37unsigned int hw_lro_timestamp_flush_cnt[HW_LRO_RING_NUM];
38unsigned int hw_lro_norule_flush_cnt[HW_LRO_RING_NUM];
39
40static struct proc_dir_entry *proc_rx_ring1, *proc_rx_ring2, *proc_rx_ring3;
41static struct proc_dir_entry *proc_hw_lro_stats, *proc_hw_lro_auto_tlb;
42
43int rx_lro_ring_read(struct seq_file *seq, void *v,
44 struct PDMA_rxdesc *rx_ring_p)
45{
46 struct PDMA_rxdesc *rx_ring;
47 int i = 0;
48
49 rx_ring =
50 kmalloc(sizeof(struct PDMA_rxdesc) * NUM_LRO_RX_DESC, GFP_KERNEL);
51 if (!rx_ring) {
52 seq_puts(seq, " allocate temp rx_ring fail.\n");
53 return 0;
54 }
55
56 for (i = 0; i < NUM_LRO_RX_DESC; i++)
57 memcpy(&rx_ring[i], &rx_ring_p[i], sizeof(struct PDMA_rxdesc));
58
59 for (i = 0; i < NUM_LRO_RX_DESC; i++) {
60 seq_printf(seq, "%d: %08x %08x %08x %08x\n", i,
61 *(int *)&rx_ring[i].rxd_info1,
62 *(int *)&rx_ring[i].rxd_info2,
63 *(int *)&rx_ring[i].rxd_info3,
64 *(int *)&rx_ring[i].rxd_info4);
65 }
66
67 kfree(rx_ring);
68 return 0;
69}
70
71int rx_ring1_read(struct seq_file *seq, void *v)
72{
73 struct END_DEVICE *ei_local = netdev_priv(dev_raether);
74
75 rx_lro_ring_read(seq, v, ei_local->rx_ring[1]);
76
77 return 0;
78}
79
80int rx_ring2_read(struct seq_file *seq, void *v)
81{
82 struct END_DEVICE *ei_local = netdev_priv(dev_raether);
83
84 rx_lro_ring_read(seq, v, ei_local->rx_ring[2]);
85
86 return 0;
87}
88
89int rx_ring3_read(struct seq_file *seq, void *v)
90{
91 struct END_DEVICE *ei_local = netdev_priv(dev_raether);
92
93 rx_lro_ring_read(seq, v, ei_local->rx_ring[3]);
94
95 return 0;
96}
97
98static int rx_ring1_open(struct inode *inode, struct file *file)
99{
100 return single_open(file, rx_ring1_read, NULL);
101}
102
103static int rx_ring2_open(struct inode *inode, struct file *file)
104{
105 return single_open(file, rx_ring2_read, NULL);
106}
107
108static int rx_ring3_open(struct inode *inode, struct file *file)
109{
110 return single_open(file, rx_ring3_read, NULL);
111}
112
113static const struct file_operations rx_ring1_fops = {
114 .owner = THIS_MODULE,
115 .open = rx_ring1_open,
116 .read = seq_read,
117 .llseek = seq_lseek,
118 .release = single_release
119};
120
121static const struct file_operations rx_ring2_fops = {
122 .owner = THIS_MODULE,
123 .open = rx_ring2_open,
124 .read = seq_read,
125 .llseek = seq_lseek,
126 .release = single_release
127};
128
129static const struct file_operations rx_ring3_fops = {
130 .owner = THIS_MODULE,
131 .open = rx_ring3_open,
132 .read = seq_read,
133 .llseek = seq_lseek,
134 .release = single_release
135};
136
137static int hw_lro_len_update(unsigned int agg_size)
138{
139 int len_idx;
140
141 if (agg_size > 65000)
142 len_idx = 13;
143 else if (agg_size > 60000)
144 len_idx = 12;
145 else if (agg_size > 55000)
146 len_idx = 11;
147 else if (agg_size > 50000)
148 len_idx = 10;
149 else if (agg_size > 45000)
150 len_idx = 9;
151 else if (agg_size > 40000)
152 len_idx = 8;
153 else if (agg_size > 35000)
154 len_idx = 7;
155 else if (agg_size > 30000)
156 len_idx = 6;
157 else if (agg_size > 25000)
158 len_idx = 5;
159 else if (agg_size > 20000)
160 len_idx = 4;
161 else if (agg_size > 15000)
162 len_idx = 3;
163 else if (agg_size > 10000)
164 len_idx = 2;
165 else if (agg_size > 5000)
166 len_idx = 1;
167 else
168 len_idx = 0;
169
170 return len_idx;
171}
172
173void hw_lro_stats_update(unsigned int ring_num, struct PDMA_rxdesc *rx_ring)
174{
175 unsigned int agg_cnt = rx_ring->rxd_info2.LRO_AGG_CNT;
176 unsigned int agg_size = (rx_ring->rxd_info2.PLEN1 << 14) |
177 rx_ring->rxd_info2.PLEN0;
178
179 if ((ring_num > 0) && (ring_num < 4)) {
180 hw_lro_agg_size_cnt[ring_num - 1]
181 [hw_lro_len_update(agg_size)]++;
182 hw_lro_agg_num_cnt[ring_num - 1][agg_cnt]++;
183 hw_lro_tot_flush_cnt[ring_num - 1]++;
184 hw_lro_tot_agg_cnt[ring_num - 1] += agg_cnt;
185 }
186}
187
188void hw_lro_flush_stats_update(unsigned int ring_num,
189 struct PDMA_rxdesc *rx_ring)
190{
191 unsigned int flush_reason = rx_ring->rxd_info2.REV;
192
193 if ((ring_num > 0) && (ring_num < 4)) {
194 if ((flush_reason & 0x7) == HW_LRO_AGG_FLUSH)
195 hw_lro_agg_flush_cnt[ring_num - 1]++;
196 else if ((flush_reason & 0x7) == HW_LRO_AGE_FLUSH)
197 hw_lro_age_flush_cnt[ring_num - 1]++;
198 else if ((flush_reason & 0x7) == HW_LRO_NOT_IN_SEQ_FLUSH)
199 hw_lro_seq_flush_cnt[ring_num - 1]++;
200 else if ((flush_reason & 0x7) == HW_LRO_TIMESTAMP_FLUSH)
201 hw_lro_timestamp_flush_cnt[ring_num - 1]++;
202 else if ((flush_reason & 0x7) == HW_LRO_NON_RULE_FLUSH)
203 hw_lro_norule_flush_cnt[ring_num - 1]++;
204 }
205}
206EXPORT_SYMBOL(hw_lro_flush_stats_update);
207
208ssize_t hw_lro_stats_write(struct file *file, const char __user *buffer,
209 size_t count, loff_t *data)
210{
211 memset(hw_lro_agg_num_cnt, 0, sizeof(hw_lro_agg_num_cnt));
212 memset(hw_lro_agg_size_cnt, 0, sizeof(hw_lro_agg_size_cnt));
213 memset(hw_lro_tot_agg_cnt, 0, sizeof(hw_lro_tot_agg_cnt));
214 memset(hw_lro_tot_flush_cnt, 0, sizeof(hw_lro_tot_flush_cnt));
215 memset(hw_lro_agg_flush_cnt, 0, sizeof(hw_lro_agg_flush_cnt));
216 memset(hw_lro_age_flush_cnt, 0, sizeof(hw_lro_age_flush_cnt));
217 memset(hw_lro_seq_flush_cnt, 0, sizeof(hw_lro_seq_flush_cnt));
218 memset(hw_lro_timestamp_flush_cnt, 0,
219 sizeof(hw_lro_timestamp_flush_cnt));
220 memset(hw_lro_norule_flush_cnt, 0, sizeof(hw_lro_norule_flush_cnt));
221
222 pr_info("clear hw lro cnt table\n");
223
224 return count;
225}
226
227int hw_lro_stats_read(struct seq_file *seq, void *v)
228{
229 int i;
230 struct END_DEVICE *ei_local = netdev_priv(dev_raether);
231
232 seq_puts(seq, "HW LRO statistic dump:\n");
233
234 /* Agg number count */
235 seq_puts(seq, "Cnt: RING1 | RING2 | RING3 | Total\n");
236 for (i = 0; i <= MAX_HW_LRO_AGGR; i++) {
237 seq_printf(seq, " %d : %d %d %d %d\n",
238 i, hw_lro_agg_num_cnt[0][i],
239 hw_lro_agg_num_cnt[1][i], hw_lro_agg_num_cnt[2][i],
240 hw_lro_agg_num_cnt[0][i] + hw_lro_agg_num_cnt[1][i] +
241 hw_lro_agg_num_cnt[2][i]);
242 }
243
244 /* Total agg count */
245 seq_puts(seq, "Total agg: RING1 | RING2 | RING3 | Total\n");
246 seq_printf(seq, " %d %d %d %d\n",
247 hw_lro_tot_agg_cnt[0], hw_lro_tot_agg_cnt[1],
248 hw_lro_tot_agg_cnt[2],
249 hw_lro_tot_agg_cnt[0] + hw_lro_tot_agg_cnt[1] +
250 hw_lro_tot_agg_cnt[2]);
251
252 /* Total flush count */
253 seq_puts(seq, "Total flush: RING1 | RING2 | RING3 | Total\n");
254 seq_printf(seq, " %d %d %d %d\n",
255 hw_lro_tot_flush_cnt[0], hw_lro_tot_flush_cnt[1],
256 hw_lro_tot_flush_cnt[2],
257 hw_lro_tot_flush_cnt[0] + hw_lro_tot_flush_cnt[1] +
258 hw_lro_tot_flush_cnt[2]);
259
260 /* Avg agg count */
261 seq_puts(seq, "Avg agg: RING1 | RING2 | RING3 | Total\n");
262 seq_printf(seq, " %d %d %d %d\n",
263 (hw_lro_tot_flush_cnt[0]) ? hw_lro_tot_agg_cnt[0] /
264 hw_lro_tot_flush_cnt[0] : 0,
265 (hw_lro_tot_flush_cnt[1]) ? hw_lro_tot_agg_cnt[1] /
266 hw_lro_tot_flush_cnt[1] : 0,
267 (hw_lro_tot_flush_cnt[2]) ? hw_lro_tot_agg_cnt[2] /
268 hw_lro_tot_flush_cnt[2] : 0,
269 (hw_lro_tot_flush_cnt[0] + hw_lro_tot_flush_cnt[1] +
270 hw_lro_tot_flush_cnt[2]) ? ((hw_lro_tot_agg_cnt[0] +
271 hw_lro_tot_agg_cnt[1] +
272 hw_lro_tot_agg_cnt[2]) /
273 (hw_lro_tot_flush_cnt[0] +
274 hw_lro_tot_flush_cnt[1] +
275 hw_lro_tot_flush_cnt[2])) : 0);
276
277 /* Statistics of aggregation size counts */
278 seq_puts(seq, "HW LRO flush pkt len:\n");
279 seq_puts(seq, " Length | RING1 | RING2 | RING3 | Total\n");
280 for (i = 0; i < 15; i++) {
281 seq_printf(seq, "%d~%d: %d %d %d %d\n", i * 5000,
282 (i + 1) * 5000, hw_lro_agg_size_cnt[0][i],
283 hw_lro_agg_size_cnt[1][i], hw_lro_agg_size_cnt[2][i],
284 hw_lro_agg_size_cnt[0][i] +
285 hw_lro_agg_size_cnt[1][i] +
286 hw_lro_agg_size_cnt[2][i]);
287 }
288
289 /* CONFIG_RAETH_HW_LRO_REASON_DBG */
290 if (ei_local->features & FE_HW_LRO_DBG) {
291 seq_puts(seq, "Flush reason: RING1 | RING2 | RING3 | Total\n");
292 seq_printf(seq, "AGG timeout: %d %d %d %d\n",
293 hw_lro_agg_flush_cnt[0], hw_lro_agg_flush_cnt[1],
294 hw_lro_agg_flush_cnt[2],
295 (hw_lro_agg_flush_cnt[0] + hw_lro_agg_flush_cnt[1] +
296 hw_lro_agg_flush_cnt[2])
297 );
298 seq_printf(seq, "AGE timeout: %d %d %d %d\n",
299 hw_lro_age_flush_cnt[0], hw_lro_age_flush_cnt[1],
300 hw_lro_age_flush_cnt[2],
301 (hw_lro_age_flush_cnt[0] + hw_lro_age_flush_cnt[1] +
302 hw_lro_age_flush_cnt[2])
303 );
304 seq_printf(seq, "Not in-sequence: %d %d %d %d\n",
305 hw_lro_seq_flush_cnt[0], hw_lro_seq_flush_cnt[1],
306 hw_lro_seq_flush_cnt[2],
307 (hw_lro_seq_flush_cnt[0] + hw_lro_seq_flush_cnt[1] +
308 hw_lro_seq_flush_cnt[2])
309 );
310 seq_printf(seq, "Timestamp: %d %d %d %d\n",
311 hw_lro_timestamp_flush_cnt[0],
312 hw_lro_timestamp_flush_cnt[1],
313 hw_lro_timestamp_flush_cnt[2],
314 (hw_lro_timestamp_flush_cnt[0] +
315 hw_lro_timestamp_flush_cnt[1] +
316 hw_lro_timestamp_flush_cnt[2])
317 );
318 seq_printf(seq, "No LRO rule: %d %d %d %d\n",
319 hw_lro_norule_flush_cnt[0],
320 hw_lro_norule_flush_cnt[1],
321 hw_lro_norule_flush_cnt[2],
322 (hw_lro_norule_flush_cnt[0] +
323 hw_lro_norule_flush_cnt[1] +
324 hw_lro_norule_flush_cnt[2])
325 );
326 }
327
328 return 0;
329}
330
331static int hw_lro_stats_open(struct inode *inode, struct file *file)
332{
333 return single_open(file, hw_lro_stats_read, NULL);
334}
335
336static const struct file_operations hw_lro_stats_fops = {
337 .owner = THIS_MODULE,
338 .open = hw_lro_stats_open,
339 .read = seq_read,
340 .llseek = seq_lseek,
341 .write = hw_lro_stats_write,
342 .release = single_release
343};
344
345int hwlro_agg_cnt_ctrl(int par1, int par2)
346{
347 SET_PDMA_RXRING_MAX_AGG_CNT(ADMA_RX_RING1, par2);
348 SET_PDMA_RXRING_MAX_AGG_CNT(ADMA_RX_RING2, par2);
349 SET_PDMA_RXRING_MAX_AGG_CNT(ADMA_RX_RING3, par2);
350 return 0;
351}
352
353int hwlro_agg_time_ctrl(int par1, int par2)
354{
355 SET_PDMA_RXRING_AGG_TIME(ADMA_RX_RING1, par2);
356 SET_PDMA_RXRING_AGG_TIME(ADMA_RX_RING2, par2);
357 SET_PDMA_RXRING_AGG_TIME(ADMA_RX_RING3, par2);
358 return 0;
359}
360
361int hwlro_age_time_ctrl(int par1, int par2)
362{
363 SET_PDMA_RXRING_AGE_TIME(ADMA_RX_RING1, par2);
364 SET_PDMA_RXRING_AGE_TIME(ADMA_RX_RING2, par2);
365 SET_PDMA_RXRING_AGE_TIME(ADMA_RX_RING3, par2);
366 return 0;
367}
368
369int hwlro_threshold_ctrl(int par1, int par2)
370{
371 /* bandwidth threshold setting */
372 SET_PDMA_LRO_BW_THRESHOLD(par2);
373 return 0;
374}
375
376int hwlro_ring_enable_ctrl(int par1, int par2)
377{
378 if (!par2) {
379 pr_info("[hwlro_ring_enable_ctrl]Disable HW LRO rings\n");
380 SET_PDMA_RXRING_VALID(ADMA_RX_RING0, 0);
381 SET_PDMA_RXRING_VALID(ADMA_RX_RING1, 0);
382 SET_PDMA_RXRING_VALID(ADMA_RX_RING2, 0);
383 SET_PDMA_RXRING_VALID(ADMA_RX_RING3, 0);
384 } else {
385 pr_info("[hwlro_ring_enable_ctrl]Enable HW LRO rings\n");
386 SET_PDMA_RXRING_VALID(ADMA_RX_RING0, 1);
387 SET_PDMA_RXRING_VALID(ADMA_RX_RING1, 1);
388 SET_PDMA_RXRING_VALID(ADMA_RX_RING2, 1);
389 SET_PDMA_RXRING_VALID(ADMA_RX_RING3, 1);
390 }
391
392 return 0;
393}
394
395static const HWLRO_DBG_FUNC hw_lro_dbg_func[] = {
396 [0] = hwlro_agg_cnt_ctrl,
397 [1] = hwlro_agg_time_ctrl,
398 [2] = hwlro_age_time_ctrl,
399 [3] = hwlro_threshold_ctrl,
400 [4] = hwlro_ring_enable_ctrl,
401};
402
403ssize_t hw_lro_auto_tlb_write(struct file *file, const char __user *buffer,
404 size_t count, loff_t *data)
405{
406 char buf[32];
407 char *p_buf;
408 int len = count;
409 long x = 0, y = 0;
410 char *p_token = NULL;
411 char *p_delimiter = " \t";
412 int ret;
413
414 pr_info("[hw_lro_auto_tlb_write]write parameter len = %d\n\r",
415 (int)len);
416 if (len >= sizeof(buf)) {
417 pr_info("input handling fail!\n");
418 len = sizeof(buf) - 1;
419 return -1;
420 }
421
422 if (copy_from_user(buf, buffer, len))
423 return -EFAULT;
424
425 buf[len] = '\0';
426 pr_info("[hw_lro_auto_tlb_write]write parameter data = %s\n\r", buf);
427
428 p_buf = buf;
429 p_token = strsep(&p_buf, p_delimiter);
430 if (!p_token)
431 x = 0;
432 else
433 ret = kstrtol(p_token, 10, &x);
434
435 p_token = strsep(&p_buf, "\t\n ");
436 if (p_token) {
437 ret = kstrtol(p_token, 10, &y);
438 pr_info("y = %ld\n\r", y);
439 }
440
441 if (hw_lro_dbg_func[x] &&
442 (ARRAY_SIZE(hw_lro_dbg_func) > x)) {
443 (*hw_lro_dbg_func[x]) (x, y);
444 }
445
446 return count;
447}
448
449void hw_lro_auto_tlb_dump(struct seq_file *seq, unsigned int index)
450{
451 int i;
452 struct PDMA_LRO_AUTO_TLB_INFO pdma_lro_auto_tlb;
453 unsigned int tlb_info[9];
454 unsigned int dw_len, cnt, priority;
455 unsigned int entry;
456
457 if (index > 4)
458 index = index - 1;
459 entry = (index * 9) + 1;
460
461 /* read valid entries of the auto-learn table */
462 sys_reg_write(PDMA_FE_ALT_CF8, entry);
463
464 /* seq_printf(seq, "\nEntry = %d\n", entry); */
465 for (i = 0; i < 9; i++) {
466 tlb_info[i] = sys_reg_read(PDMA_FE_ALT_SEQ_CFC);
467 /* seq_printf(seq, "tlb_info[%d] = 0x%x\n", i, tlb_info[i]); */
468 }
469 memcpy(&pdma_lro_auto_tlb, tlb_info,
470 sizeof(struct PDMA_LRO_AUTO_TLB_INFO));
471
472 dw_len = pdma_lro_auto_tlb.auto_tlb_info7.DW_LEN;
473 cnt = pdma_lro_auto_tlb.auto_tlb_info6.CNT;
474
475 if (sys_reg_read(ADMA_LRO_CTRL_DW0) & PDMA_LRO_ALT_SCORE_MODE)
476 priority = cnt; /* packet count */
477 else
478 priority = dw_len; /* byte count */
479
480 /* dump valid entries of the auto-learn table */
481 if (index >= 4)
482 seq_printf(seq, "\n===== TABLE Entry: %d (Act) =====\n", index);
483 else
484 seq_printf(seq, "\n===== TABLE Entry: %d (LRU) =====\n", index);
485 if (pdma_lro_auto_tlb.auto_tlb_info8.IPV4) {
486 seq_printf(seq, "SIP = 0x%x:0x%x:0x%x:0x%x (IPv4)\n",
487 pdma_lro_auto_tlb.auto_tlb_info4.SIP3,
488 pdma_lro_auto_tlb.auto_tlb_info3.SIP2,
489 pdma_lro_auto_tlb.auto_tlb_info2.SIP1,
490 pdma_lro_auto_tlb.auto_tlb_info1.SIP0);
491 } else {
492 seq_printf(seq, "SIP = 0x%x:0x%x:0x%x:0x%x (IPv6)\n",
493 pdma_lro_auto_tlb.auto_tlb_info4.SIP3,
494 pdma_lro_auto_tlb.auto_tlb_info3.SIP2,
495 pdma_lro_auto_tlb.auto_tlb_info2.SIP1,
496 pdma_lro_auto_tlb.auto_tlb_info1.SIP0);
497 }
498 seq_printf(seq, "DIP_ID = %d\n",
499 pdma_lro_auto_tlb.auto_tlb_info8.DIP_ID);
500 seq_printf(seq, "TCP SPORT = %d | TCP DPORT = %d\n",
501 pdma_lro_auto_tlb.auto_tlb_info0.STP,
502 pdma_lro_auto_tlb.auto_tlb_info0.DTP);
503 seq_printf(seq, "VLAN_VID_VLD = %d\n",
504 pdma_lro_auto_tlb.auto_tlb_info6.VLAN_VID_VLD);
505 seq_printf(seq, "VLAN1 = %d | VLAN2 = %d | VLAN3 = %d | VLAN4 =%d\n",
506 (pdma_lro_auto_tlb.auto_tlb_info5.VLAN_VID0 & 0xfff),
507 ((pdma_lro_auto_tlb.auto_tlb_info5.VLAN_VID0 >> 12) & 0xfff),
508 ((pdma_lro_auto_tlb.auto_tlb_info6.VLAN_VID1 << 8) |
509 ((pdma_lro_auto_tlb.auto_tlb_info5.VLAN_VID0 >> 24)
510 & 0xfff)),
511 ((pdma_lro_auto_tlb.auto_tlb_info6.VLAN_VID1 >> 4) & 0xfff));
512 seq_printf(seq, "TPUT = %d | FREQ = %d\n", dw_len, cnt);
513 seq_printf(seq, "PRIORITY = %d\n", priority);
514}
515
516int hw_lro_auto_tlb_read(struct seq_file *seq, void *v)
517{
518 int i;
519 unsigned int reg_val;
520 unsigned int reg_op1, reg_op2, reg_op3, reg_op4;
521 unsigned int agg_cnt, agg_time, age_time;
522
523 seq_puts(seq, "Usage of /proc/mt76xx/hw_lro_auto_tlb:\n");
524 seq_puts(seq, "echo [function] [setting] > /proc/mt76xx/hw_lro_auto_tlb\n");
525 seq_puts(seq, "Functions:\n");
526 seq_puts(seq, "[0] = hwlro_agg_cnt_ctrl\n");
527 seq_puts(seq, "[1] = hwlro_agg_time_ctrl\n");
528 seq_puts(seq, "[2] = hwlro_age_time_ctrl\n");
529 seq_puts(seq, "[3] = hwlro_threshold_ctrl\n");
530 seq_puts(seq, "[4] = hwlro_ring_enable_ctrl\n\n");
531
532 /* Read valid entries of the auto-learn table */
533 sys_reg_write(PDMA_FE_ALT_CF8, 0);
534 reg_val = sys_reg_read(PDMA_FE_ALT_SEQ_CFC);
535
536 seq_printf(seq,
537 "HW LRO Auto-learn Table: (PDMA_LRO_ALT_CFC_RSEQ_DBG=0x%x)\n",
538 reg_val);
539
540 for (i = 7; i >= 0; i--) {
541 if (reg_val & (1 << i))
542 hw_lro_auto_tlb_dump(seq, i);
543 }
544
545 /* Read the agg_time/age_time/agg_cnt of LRO rings */
546 seq_puts(seq, "\nHW LRO Ring Settings\n");
547 for (i = 1; i <= 3; i++) {
548 reg_op1 = sys_reg_read(LRO_RX_RING0_CTRL_DW1 + (i * 0x40));
549 reg_op2 = sys_reg_read(LRO_RX_RING0_CTRL_DW2 + (i * 0x40));
550 reg_op3 = sys_reg_read(LRO_RX_RING0_CTRL_DW3 + (i * 0x40));
551 reg_op4 = sys_reg_read(ADMA_LRO_CTRL_DW2);
552 agg_cnt =
553 ((reg_op3 & 0x03) << PDMA_LRO_AGG_CNT_H_OFFSET) |
554 ((reg_op2 >> PDMA_LRO_RING_AGG_CNT1_OFFSET) & 0x3f);
555 agg_time = (reg_op2 >> PDMA_LRO_RING_AGG_OFFSET) & 0xffff;
556 age_time =
557 ((reg_op2 & 0x03f) << PDMA_LRO_AGE_H_OFFSET) |
558 ((reg_op1 >> PDMA_LRO_RING_AGE1_OFFSET) & 0x3ff);
559 seq_printf(seq,
560 "Ring[%d]: MAX_AGG_CNT=%d, AGG_TIME=%d, AGE_TIME=%d, Threshold=%d\n",
561 i, agg_cnt, agg_time, age_time, reg_op4);
562 }
563 seq_puts(seq, "\n");
564
565 return 0;
566}
567
568static int hw_lro_auto_tlb_open(struct inode *inode, struct file *file)
569{
570 return single_open(file, hw_lro_auto_tlb_read, NULL);
571}
572
573static const struct file_operations hw_lro_auto_tlb_fops = {
574 .owner = THIS_MODULE,
575 .open = hw_lro_auto_tlb_open,
576 .read = seq_read,
577 .llseek = seq_lseek,
578 .write = hw_lro_auto_tlb_write,
579 .release = single_release
580};
581
582int hwlro_debug_proc_init(struct proc_dir_entry *proc_reg_dir)
583{
584 proc_rx_ring1 =
585 proc_create(PROCREG_RXRING1, 0, proc_reg_dir, &rx_ring1_fops);
586 if (!proc_rx_ring1)
587 pr_info("!! FAIL to create %s PROC !!\n", PROCREG_RXRING1);
588
589 proc_rx_ring2 =
590 proc_create(PROCREG_RXRING2, 0, proc_reg_dir, &rx_ring2_fops);
591 if (!proc_rx_ring2)
592 pr_info("!! FAIL to create %s PROC !!\n", PROCREG_RXRING2);
593
594 proc_rx_ring3 =
595 proc_create(PROCREG_RXRING3, 0, proc_reg_dir, &rx_ring3_fops);
596 if (!proc_rx_ring3)
597 pr_info("!! FAIL to create %s PROC !!\n", PROCREG_RXRING3);
598
599 proc_hw_lro_stats =
600 proc_create(PROCREG_HW_LRO_STATS, 0, proc_reg_dir,
601 &hw_lro_stats_fops);
602 if (!proc_hw_lro_stats)
603 pr_info("!! FAIL to create %s PROC !!\n", PROCREG_HW_LRO_STATS);
604
605 proc_hw_lro_auto_tlb =
606 proc_create(PROCREG_HW_LRO_AUTO_TLB, 0, proc_reg_dir,
607 &hw_lro_auto_tlb_fops);
608 if (!proc_hw_lro_auto_tlb)
609 pr_info("!! FAIL to create %s PROC !!\n",
610 PROCREG_HW_LRO_AUTO_TLB);
611
612 return 0;
613}
614EXPORT_SYMBOL(hwlro_debug_proc_init);
615
616void hwlro_debug_proc_exit(struct proc_dir_entry *proc_reg_dir)
617{
618 if (proc_rx_ring1)
619 remove_proc_entry(PROCREG_RXRING1, proc_reg_dir);
620 if (proc_rx_ring2)
621 remove_proc_entry(PROCREG_RXRING2, proc_reg_dir);
622 if (proc_rx_ring3)
623 remove_proc_entry(PROCREG_RXRING3, proc_reg_dir);
624 if (proc_hw_lro_stats)
625 remove_proc_entry(PROCREG_HW_LRO_STATS, proc_reg_dir);
626 if (proc_hw_lro_auto_tlb)
627 remove_proc_entry(PROCREG_HW_LRO_AUTO_TLB, proc_reg_dir);
628}
629EXPORT_SYMBOL(hwlro_debug_proc_exit);