blob: 9da122465100d653a863ce0851f44c51cf91334f [file] [log] [blame]
developer381cffa2023-08-03 17:08:00 +08001From f65c0f12471c39c5833b045a429d25ad504dc320 Mon Sep 17 00:00:00 2001
2From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
3Date: Thu, 3 Aug 2023 17:05:20 +0800
4Subject: [PATCH] 999-2728-net-phy-aquantia-add-mib-read.patch
5
6---
7 drivers/net/phy/Kconfig | 6 ++
8 drivers/net/phy/Makefile | 3 +
9 drivers/net/phy/aquantia.h | 22 +++++
10 drivers/net/phy/aquantia_main.c | 4 +
11 drivers/net/phy/aquantia_mib.c | 167 ++++++++++++++++++++++++++++++++
12 5 files changed, 202 insertions(+)
13 create mode 100644 drivers/net/phy/aquantia_mib.c
14
15diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
16index d467834..d6e2f37 100644
17--- a/drivers/net/phy/Kconfig
18+++ b/drivers/net/phy/Kconfig
19@@ -405,6 +405,12 @@ config AQUANTIA_PHY_FW_FILE
20 ---help---
21 Currently supports the Aquantia AQR113c
22
23+config AQUANTIA_PHY_MIB
24+ tristate "MIB Read Enable"
25+ depends on AQUANTIA_PHY
26+ ---help---
27+ Currently supports the Aquantia AQR113C
28+
29 config AX88796B_PHY
30 tristate "Asix PHYs"
31 help
32diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
33index e9653de..7aff0be 100644
34--- a/drivers/net/phy/Makefile
35+++ b/drivers/net/phy/Makefile
36@@ -71,6 +71,9 @@ endif
37 ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
38 aquantia-objs += aquantia_firmware.o
39 endif
40+ifdef CONFIG_AQUANTIA_PHY_MIB
41+aquantia-objs += aquantia_mib.o
42+endif
43 obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o
44 obj-$(CONFIG_AIROHA_EN8811H_PHY) += air_en8811h.o
45 obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
46diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h
47index ab1c241..68845b5 100644
48--- a/drivers/net/phy/aquantia.h
49+++ b/drivers/net/phy/aquantia.h
50@@ -47,6 +47,21 @@ static const struct aqr107_hw_stat aqr107_hw_stats[] = {
51 };
52 #define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats)
53
54+#ifdef CONFIG_AQUANTIA_PHY_MIB
55+struct aqr107_mib_stat {
56+ u64 crc8_error_packets;
57+ u64 ldpc_error_packets;
58+ u64 ls_tx_good_packets;
59+ u64 ls_tx_bad_packets;
60+ u64 ls_rx_good_packets;
61+ u64 ls_rx_bad_packets;
62+ u64 ss_tx_good_packets;
63+ u64 ss_tx_bad_packets;
64+ u64 ss_rx_good_packets;
65+ u64 ss_rx_bad_packets;
66+};
67+#endif
68+
69 struct aqr107_priv {
70 u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
71 #ifdef CONFIG_AQUANTIA_PHY_FW_DOWNLOAD
72@@ -57,6 +72,10 @@ struct aqr107_priv {
73 int fw_dl_mode;
74 u16 heartbeat;
75 #endif
76+#ifdef CONFIG_AQUANTIA_PHY_MIB
77+ struct aqr107_mib_stat mib;
78+ struct task_struct *mib_thread;
79+#endif
80 };
81
82 int aqr107_set_downshift(struct phy_device *phydev, u8 cnt);
83@@ -78,3 +97,6 @@ enum {
84 int aqr_firmware_heartbeat_thread(void *data);
85 int aqr_firmware_download(struct phy_device *phydev);
86 #endif
87+#ifdef CONFIG_AQUANTIA_PHY_MIB
88+int aqr107_config_mib(struct phy_device *phydev);
89+#endif
90\ No newline at end of file
91diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c
92index 874cd26..5c05ea8 100644
93--- a/drivers/net/phy/aquantia_main.c
94+++ b/drivers/net/phy/aquantia_main.c
95@@ -605,6 +605,10 @@ static int aqr107_probe(struct phy_device *phydev)
96 if (!phydev->priv)
97 return -ENOMEM;
98
99+#ifdef CONFIG_AQUANTIA_PHY_MIB
100+ aqr107_config_mib(phydev);
101+#endif
102+
103 return aqr_hwmon_probe(phydev);
104 }
105
106diff --git a/drivers/net/phy/aquantia_mib.c b/drivers/net/phy/aquantia_mib.c
107new file mode 100644
108index 0000000..07223fa
109--- /dev/null
110+++ b/drivers/net/phy/aquantia_mib.c
111@@ -0,0 +1,167 @@
112+// SPDX-License-Identifier: GPL-2.0
113+/* Packet counter driver for Aquantia PHY
114+ */
115+
116+#include <linux/phy.h>
117+#include <linux/kernel.h>
118+#include <linux/debugfs.h>
119+#include <linux/kthread.h>
120+
121+#include "aquantia.h"
122+
123+#define MDIO_PCS_LS_TX_GOOD_COUNTER 0xc820
124+#define MDIO_PCS_LS_TX_BAD_COUNTER 0xc822
125+#define MDIO_PCS_SS_TX_GOOD_COUNTER 0xc860
126+#define MDIO_PCS_SS_TX_BAD_COUNTER 0xc862
127+#define MDIO_PCS_CRC8_ERROR_COUNTER 0xe810
128+#define MDIO_PCS_LS_RX_GOOD_COUNTER 0xe812
129+#define MDIO_PCS_LS_RX_BAD_COUNTER 0xe814
130+#define MDIO_PCS_LDPC_ERROR_COUNTER 0xe820
131+#define MDIO_PCS_SS_RX_GOOD_COUNTER 0xe860
132+#define MDIO_PCS_SS_RX_BAD_COUNTER 0xe862
133+
134+static int aqr107_mib_read_word(struct phy_device *phydev, u32 reg, u16 *lsw, u16 *msw)
135+{
136+ int val;
137+
138+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, reg + 1);
139+ if (val < 0)
140+ return val;
141+
142+ *msw = val;
143+
144+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, reg);
145+ if (val < 0)
146+ return val;
147+
148+ *lsw = val;
149+
150+ return 0;
151+}
152+
153+static void aqr107_mib_read(struct phy_device *phydev)
154+{
155+ struct aqr107_priv *priv = phydev->priv;
156+ u16 lsw, msw;
157+
158+ if (!aqr107_mib_read_word(phydev, MDIO_PCS_CRC8_ERROR_COUNTER, &lsw, &msw))
159+ priv->mib.crc8_error_packets += ((msw << 16) | lsw);
160+
161+ if (!aqr107_mib_read_word(phydev, MDIO_PCS_LDPC_ERROR_COUNTER, &lsw, &msw))
162+ priv->mib.ldpc_error_packets += ((msw << 16) | lsw);
163+
164+ if (!aqr107_mib_read_word(phydev, MDIO_PCS_LS_TX_GOOD_COUNTER, &lsw, &msw))
165+ priv->mib.ls_tx_good_packets += ((msw << 16) | lsw);
166+
167+ if (!aqr107_mib_read_word(phydev, MDIO_PCS_LS_TX_BAD_COUNTER, &lsw, &msw))
168+ priv->mib.ls_tx_bad_packets += ((msw << 16) | lsw);
169+
170+ if (!aqr107_mib_read_word(phydev, MDIO_PCS_LS_RX_GOOD_COUNTER, &lsw, &msw))
171+ priv->mib.ls_rx_good_packets += ((msw << 16) | lsw);
172+
173+ if (!aqr107_mib_read_word(phydev, MDIO_PCS_LS_RX_BAD_COUNTER, &lsw, &msw))
174+ priv->mib.ls_rx_bad_packets += ((msw << 16) | lsw);
175+
176+ if (!aqr107_mib_read_word(phydev, MDIO_PCS_SS_TX_GOOD_COUNTER, &lsw, &msw))
177+ priv->mib.ss_tx_good_packets += ((msw << 16) | lsw);
178+
179+ if (!aqr107_mib_read_word(phydev, MDIO_PCS_SS_TX_BAD_COUNTER, &lsw, &msw))
180+ priv->mib.ss_tx_bad_packets += ((msw << 16) | lsw);
181+
182+ if (!aqr107_mib_read_word(phydev, MDIO_PCS_SS_RX_GOOD_COUNTER, &lsw, &msw))
183+ priv->mib.ss_rx_good_packets += ((msw << 16) | lsw);
184+
185+ if (!aqr107_mib_read_word(phydev, MDIO_PCS_SS_RX_BAD_COUNTER, &lsw, &msw))
186+ priv->mib.ss_rx_bad_packets += ((msw << 16) | lsw);
187+}
188+
189+static int aqr107_mib_thread(void *data)
190+{
191+ struct phy_device *phydev = data;
192+
193+ for (;;) {
194+ if (kthread_should_stop())
195+ break;
196+
197+ aqr107_mib_read(phydev);
198+
199+ set_current_state(TASK_INTERRUPTIBLE);
200+ schedule_timeout(HZ);
201+ }
202+
203+ return 0;
204+}
205+
206+static int aqr107_mib_show(struct seq_file *m, void *private)
207+{
208+ struct phy_device *phydev = m->private;
209+ struct aqr107_priv *priv = phydev->priv;
210+
211+ aqr107_mib_read(phydev);
212+
213+ seq_printf(m, "+---------------------------------+\n");
214+ seq_printf(m, "| <<AQUANTIA MIB>> |\n");
215+ seq_printf(m, "| CRC8 Error Packets=%012lld |\n", priv->mib.crc8_error_packets);
216+ seq_printf(m, "| LDPC Error Packets=%012lld |\n", priv->mib.ldpc_error_packets);
217+ seq_printf(m, "| [Line Side]\n");
218+ seq_printf(m, "| TX Good Packets=%012lld |\n", priv->mib.ls_tx_good_packets);
219+ seq_printf(m, "| TX Bad Packets=%012lld |\n", priv->mib.ls_tx_bad_packets);
220+ seq_printf(m, "| RX Good Packets=%012lld |\n", priv->mib.ls_rx_good_packets);
221+ seq_printf(m, "| RX Bad Packets=%012lld |\n", priv->mib.ls_rx_bad_packets);
222+ seq_printf(m, "| [System Side]\n");
223+ seq_printf(m, "| TX Good Packets=%012lld |\n", priv->mib.ss_tx_good_packets);
224+ seq_printf(m, "| TX Bad Packets=%012lld |\n", priv->mib.ss_tx_bad_packets);
225+ seq_printf(m, "| RX Good Packets=%012lld |\n", priv->mib.ss_rx_good_packets);
226+ seq_printf(m, "| RX Bad Packets=%012lld |\n", priv->mib.ss_rx_bad_packets);
227+ seq_printf(m, "+---------------------------------+\n");
228+
229+ memset(&priv->mib, 0, sizeof(priv->mib));
230+
231+ return 0;
232+}
233+
234+static int aqr107_mib_open(struct inode *inode, struct file *file)
235+{
236+ return single_open(file, aqr107_mib_show, inode->i_private);
237+}
238+
239+int aqr107_config_mib(struct phy_device *phydev)
240+{
241+ static const struct file_operations fops_mib = {
242+ .open = aqr107_mib_open,
243+ .read = seq_read,
244+ .llseek = seq_lseek,
245+ .release = single_release
246+ };
247+
248+ struct aqr107_priv *priv = phydev->priv;
249+ struct dentry *root;
250+ char dirname[5];
251+
252+ snprintf(dirname, sizeof(dirname), "phy%d", phydev->mdio.addr);
253+
254+ root = debugfs_lookup("aquantia", NULL);
255+ if (!root) {
256+ root = debugfs_create_dir("aquantia", NULL);
257+ if (!root)
258+ return -ENOMEM;
259+ }
260+
261+ debugfs_create_file(dirname, S_IRUGO, root, phydev, &fops_mib);
262+
263+ if (!priv->mib_thread) {
264+ /* create a thread for recording packet counts */
265+ priv->mib_thread = kthread_create(aqr107_mib_thread,
266+ phydev,
267+ "aqr107_mib_thread");
268+ if (IS_ERR(priv->mib_thread)) {
269+ phydev_err(phydev,
270+ "failed to create aqr107_mib_thread(%ld)\n",
271+ PTR_ERR(priv->mib_thread));
272+ return PTR_ERR(priv->mib_thread);
273+ }
274+ wake_up_process(priv->mib_thread);
275+ }
276+
277+ return 0;
278+}
279--
2802.18.0
281