blob: 164578a3fb0b88cbbe2ded6dba7d8f2dd04d8b89 [file] [log] [blame]
developer38afb1a2023-04-17 09:57:27 +08001diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
2index 799ff9c..54ad7e8 100644
3--- a/drivers/net/phy/Makefile
4+++ b/drivers/net/phy/Makefile
5@@ -1,7 +1,8 @@
6 # SPDX-License-Identifier: GPL-2.0
7 # Makefile for Linux PHY drivers and MDIO bus drivers
8
9-libphy-y := phy.o phy-c45.o phy-core.o phy_device.o
10+libphy-y := phy.o phy-c45.o phy-core.o phy_device.o \
11+ linkmode.o
12 mdio-bus-y += mdio_bus.o mdio_device.o
13
14 ifdef CONFIG_MDIO_DEVICE
15diff --git a/drivers/net/phy/linkmode.c b/drivers/net/phy/linkmode.c
16new file mode 100644
17index 0000000..a5a347b
18--- /dev/null
19+++ b/drivers/net/phy/linkmode.c
20@@ -0,0 +1,95 @@
21+// SPDX-License-Identifier: GPL-2.0+
22+#include <linux/linkmode.h>
23+
24+/**
25+ * linkmode_resolve_pause - resolve the allowable pause modes
26+ * @local_adv: local advertisement in ethtool format
27+ * @partner_adv: partner advertisement in ethtool format
28+ * @tx_pause: pointer to bool to indicate whether transmit pause should be
29+ * enabled.
30+ * @rx_pause: pointer to bool to indicate whether receive pause should be
31+ * enabled.
32+ *
33+ * Flow control is resolved according to our and the link partners
34+ * advertisements using the following drawn from the 802.3 specs:
35+ * Local device Link partner
36+ * Pause AsymDir Pause AsymDir Result
37+ * 0 X 0 X Disabled
38+ * 0 1 1 0 Disabled
39+ * 0 1 1 1 TX
40+ * 1 0 0 X Disabled
41+ * 1 X 1 X TX+RX
42+ * 1 1 0 1 RX
43+ */
44+void linkmode_resolve_pause(unsigned long *local_adv,
45+ unsigned long *partner_adv,
46+ bool *tx_pause, bool *rx_pause)
47+{
48+ __ETHTOOL_DECLARE_LINK_MODE_MASK(m);
49+
50+ linkmode_and(m, local_adv, partner_adv);
51+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, m)) {
52+ *tx_pause = true;
53+ *rx_pause = true;
54+ } else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, m)) {
55+ *tx_pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
56+ partner_adv);
57+ *rx_pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
58+ local_adv);
59+ } else {
60+ *tx_pause = false;
61+ *rx_pause = false;
62+ }
63+}
64+EXPORT_SYMBOL_GPL(linkmode_resolve_pause);
65+
66+/**
67+ * linkmode_set_pause - set the pause mode advertisement
68+ * @advertisement: advertisement in ethtool format
69+ * @tx: boolean from ethtool struct ethtool_pauseparam tx_pause member
70+ * @rx: boolean from ethtool struct ethtool_pauseparam rx_pause member
71+ *
72+ * Configure the advertised Pause and Asym_Pause bits according to the
73+ * capabilities of provided in @tx and @rx.
74+ *
75+ * We convert as follows:
76+ * tx rx Pause AsymDir
77+ * 0 0 0 0
78+ * 0 1 1 1
79+ * 1 0 0 1
80+ * 1 1 1 0
81+ *
82+ * Note: this translation from ethtool tx/rx notation to the advertisement
83+ * is actually very problematical. Here are some examples:
84+ *
85+ * For tx=0 rx=1, meaning transmit is unsupported, receive is supported:
86+ *
87+ * Local device Link partner
88+ * Pause AsymDir Pause AsymDir Result
89+ * 1 1 1 0 TX + RX - but we have no TX support.
90+ * 1 1 0 1 Only this gives RX only
91+ *
92+ * For tx=1 rx=1, meaning we have the capability to transmit and receive
93+ * pause frames:
94+ *
95+ * Local device Link partner
96+ * Pause AsymDir Pause AsymDir Result
97+ * 1 0 0 1 Disabled - but since we do support tx and rx,
98+ * this should resolve to RX only.
99+ *
100+ * Hence, asking for:
101+ * rx=1 tx=0 gives Pause+AsymDir advertisement, but we may end up
102+ * resolving to tx+rx pause or only rx pause depending on
103+ * the partners advertisement.
104+ * rx=0 tx=1 gives AsymDir only, which will only give tx pause if
105+ * the partners advertisement allows it.
106+ * rx=1 tx=1 gives Pause only, which will only allow tx+rx pause
107+ * if the other end also advertises Pause.
108+ */
109+void linkmode_set_pause(unsigned long *advertisement, bool tx, bool rx)
110+{
111+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertisement, rx);
112+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertisement,
113+ rx ^ tx);
114+}
115+EXPORT_SYMBOL_GPL(linkmode_set_pause);
116diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
117index ead9b37..fec6d0e 100644
118--- a/drivers/net/phy/phylink.c
119+++ b/drivers/net/phy/phylink.c
120@@ -2184,4 +2184,192 @@ void phylink_helper_basex_speed(struct phylink_link_state *state)
121 }
122 EXPORT_SYMBOL_GPL(phylink_helper_basex_speed);
123
124+static void phylink_decode_c37_word(struct phylink_link_state *state,
125+ uint16_t config_reg, int speed)
126+{
127+ bool tx_pause, rx_pause;
128+ int fd_bit;
129+
130+ if (speed == SPEED_2500)
131+ fd_bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT;
132+ else
133+ fd_bit = ETHTOOL_LINK_MODE_1000baseX_Full_BIT;
134+
135+ mii_lpa_mod_linkmode_x(state->lp_advertising, config_reg, fd_bit);
136+
137+ if (linkmode_test_bit(fd_bit, state->advertising) &&
138+ linkmode_test_bit(fd_bit, state->lp_advertising)) {
139+ state->speed = speed;
140+ state->duplex = DUPLEX_FULL;
141+ } else {
142+ /* negotiation failure */
143+ state->link = false;
144+ }
145+
146+ linkmode_resolve_pause(state->advertising, state->lp_advertising,
147+ &tx_pause, &rx_pause);
148+
149+ if (tx_pause)
150+ state->pause |= MLO_PAUSE_TX;
151+ if (rx_pause)
152+ state->pause |= MLO_PAUSE_RX;
153+}
154+
155+static void phylink_decode_sgmii_word(struct phylink_link_state *state,
156+ uint16_t config_reg)
157+{
158+ if (!(config_reg & LPA_SGMII_LINK)) {
159+ state->link = false;
160+ return;
161+ }
162+
163+ switch (config_reg & LPA_SGMII_SPD_MASK) {
164+ case LPA_SGMII_10:
165+ state->speed = SPEED_10;
166+ break;
167+ case LPA_SGMII_100:
168+ state->speed = SPEED_100;
169+ break;
170+ case LPA_SGMII_1000:
171+ state->speed = SPEED_1000;
172+ break;
173+ default:
174+ state->link = false;
175+ return;
176+ }
177+ if (config_reg & LPA_SGMII_FULL_DUPLEX)
178+ state->duplex = DUPLEX_FULL;
179+ else
180+ state->duplex = DUPLEX_HALF;
181+}
182+
183+/**
184+ * phylink_decode_usxgmii_word() - decode the USXGMII word from a MAC PCS
185+ * @state: a pointer to a struct phylink_link_state.
186+ * @lpa: a 16 bit value which stores the USXGMII auto-negotiation word
187+ *
188+ * Helper for MAC PCS supporting the USXGMII protocol and the auto-negotiation
189+ * code word. Decode the USXGMII code word and populate the corresponding fields
190+ * (speed, duplex) into the phylink_link_state structure.
191+ */
192+void phylink_decode_usxgmii_word(struct phylink_link_state *state,
193+ uint16_t lpa)
194+{
195+ switch (lpa & MDIO_USXGMII_SPD_MASK) {
196+ case MDIO_USXGMII_10:
197+ state->speed = SPEED_10;
198+ break;
199+ case MDIO_USXGMII_100:
200+ state->speed = SPEED_100;
201+ break;
202+ case MDIO_USXGMII_1000:
203+ state->speed = SPEED_1000;
204+ break;
205+ case MDIO_USXGMII_2500:
206+ state->speed = SPEED_2500;
207+ break;
208+ case MDIO_USXGMII_5000:
209+ state->speed = SPEED_5000;
210+ break;
211+ case MDIO_USXGMII_10G:
212+ state->speed = SPEED_10000;
213+ break;
214+ default:
215+ state->link = false;
216+ return;
217+ }
218+
219+ if (lpa & MDIO_USXGMII_FULL_DUPLEX)
220+ state->duplex = DUPLEX_FULL;
221+ else
222+ state->duplex = DUPLEX_HALF;
223+}
224+EXPORT_SYMBOL_GPL(phylink_decode_usxgmii_word);
225+
226+/**
227+ * phylink_mii_c22_pcs_decode_state() - Decode MAC PCS state from MII registers
228+ * @state: a pointer to a &struct phylink_link_state.
229+ * @bmsr: The value of the %MII_BMSR register
230+ * @lpa: The value of the %MII_LPA register
231+ *
232+ * Helper for MAC PCS supporting the 802.3 clause 22 register set for
233+ * clause 37 negotiation and/or SGMII control.
234+ *
235+ * Parse the Clause 37 or Cisco SGMII link partner negotiation word into
236+ * the phylink @state structure. This is suitable to be used for implementing
237+ * the mac_pcs_get_state() member of the struct phylink_mac_ops structure if
238+ * accessing @bmsr and @lpa cannot be done with MDIO directly.
239+ */
240+void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state,
241+ u16 bmsr, u16 lpa)
242+{
243+ state->link = !!(bmsr & BMSR_LSTATUS);
244+ state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
245+ /* If there is no link or autonegotiation is disabled, the LP advertisement
246+ * data is not meaningful, so don't go any further.
247+ */
248+ if (!state->link || !state->an_enabled)
249+ return;
250+
251+ switch (state->interface) {
252+ case PHY_INTERFACE_MODE_1000BASEX:
253+ phylink_decode_c37_word(state, lpa, SPEED_1000);
254+ break;
255+
256+ case PHY_INTERFACE_MODE_2500BASEX:
257+ phylink_decode_c37_word(state, lpa, SPEED_2500);
258+ break;
259+
260+ case PHY_INTERFACE_MODE_SGMII:
261+ case PHY_INTERFACE_MODE_QSGMII:
262+ phylink_decode_sgmii_word(state, lpa);
263+ break;
264+
265+ default:
266+ state->link = false;
267+ break;
268+ }
269+}
270+EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_decode_state);
271+
272+/**
273+ * phylink_mii_c22_pcs_encode_advertisement() - configure the clause 37 PCS
274+ * advertisement
275+ * @interface: the PHY interface mode being configured
276+ * @advertising: the ethtool advertisement mask
277+ *
278+ * Helper for MAC PCS supporting the 802.3 clause 22 register set for
279+ * clause 37 negotiation and/or SGMII control.
280+ *
281+ * Encode the clause 37 PCS advertisement as specified by @interface and
282+ * @advertising.
283+ *
284+ * Return: The new value for @adv, or ``-EINVAL`` if it should not be changed.
285+ */
286+int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface,
287+ const unsigned long *advertising)
288+{
289+ u16 adv;
290+
291+ switch (interface) {
292+ case PHY_INTERFACE_MODE_1000BASEX:
293+ case PHY_INTERFACE_MODE_2500BASEX:
294+ adv = ADVERTISE_1000XFULL;
295+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
296+ advertising))
297+ adv |= ADVERTISE_1000XPAUSE;
298+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
299+ advertising))
300+ adv |= ADVERTISE_1000XPSE_ASYM;
301+ return adv;
302+ case PHY_INTERFACE_MODE_SGMII:
303+ case PHY_INTERFACE_MODE_QSGMII:
304+ return 0x0001;
305+ default:
306+ /* Nothing to do for other modes */
307+ return -EINVAL;
308+ }
309+}
310+EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_encode_advertisement);
311+
312 MODULE_LICENSE("GPL v2");
313diff --git a/include/linux/linkmode.h b/include/linux/linkmode.h
314index a99c588..d38da4e 100644
315--- a/include/linux/linkmode.h
316+++ b/include/linux/linkmode.h
317@@ -82,4 +82,10 @@ static inline int linkmode_equal(const unsigned long *src1,
318 return bitmap_equal(src1, src2, __ETHTOOL_LINK_MODE_MASK_NBITS);
319 }
320
321+void linkmode_resolve_pause(unsigned long *local_adv,
322+ unsigned long *partner_adv,
323+ bool *tx_pause, bool *rx_pause);
324+
325+void linkmode_set_pause(unsigned long *advertisement, bool tx, bool rx);
326+
327 #endif /* __LINKMODE_H */
328diff --git a/include/linux/mii.h b/include/linux/mii.h
329index 4ce8901..54b7f64 100644
330--- a/include/linux/mii.h
331+++ b/include/linux/mii.h
332@@ -485,6 +485,45 @@ static inline u32 linkmode_adv_to_lcl_adv_t(unsigned long *advertising)
333 return lcl_adv;
334 }
335
336+/**
337+ * mii_lpa_mod_linkmode_x - decode the link partner's config_reg to linkmodes
338+ * @linkmodes: link modes array
339+ * @lpa: config_reg word from link partner
340+ * @fd_bit: link mode for 1000XFULL bit
341+ */
342+static inline void mii_lpa_mod_linkmode_x(unsigned long *linkmodes, u16 lpa,
343+ int fd_bit)
344+{
345+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, linkmodes,
346+ lpa & LPA_LPACK);
347+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes,
348+ lpa & LPA_1000XPAUSE);
349+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes,
350+ lpa & LPA_1000XPAUSE_ASYM);
351+ linkmode_mod_bit(fd_bit, linkmodes,
352+ lpa & LPA_1000XFULL);
353+}
354+
355+/**
356+ * linkmode_adv_to_mii_adv_x - encode a linkmode to config_reg
357+ * @linkmodes: linkmodes
358+ * @fd_bit: full duplex bit
359+ */
360+static inline u16 linkmode_adv_to_mii_adv_x(unsigned long *linkmodes,
361+ int fd_bit)
362+{
363+ u16 adv = 0;
364+
365+ if (linkmode_test_bit(fd_bit, linkmodes))
366+ adv |= ADVERTISE_1000XFULL;
367+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes))
368+ adv |= ADVERTISE_1000XPAUSE;
369+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes))
370+ adv |= ADVERTISE_1000XPSE_ASYM;
371+
372+ return adv;
373+}
374+
375 /**
376 * mii_advertise_flowctrl - get flow control advertisement flags
377 * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both)
378diff --git a/include/linux/phylink.h b/include/linux/phylink.h
379index ba0f09d..48ff9fe 100644
380--- a/include/linux/phylink.h
381+++ b/include/linux/phylink.h
382@@ -490,4 +490,34 @@ int phylink_mii_ioctl(struct phylink *, struct ifreq *, int);
383 void phylink_set_port_modes(unsigned long *bits);
384 void phylink_helper_basex_speed(struct phylink_link_state *state);
385
386+/**
387+ * phylink_get_link_timer_ns - return the PCS link timer value
388+ * @interface: link &typedef phy_interface_t mode
389+ *
390+ * Return the PCS link timer setting in nanoseconds for the PHY @interface
391+ * mode, or -EINVAL if not appropriate.
392+ */
393+static inline int phylink_get_link_timer_ns(phy_interface_t interface)
394+{
395+ switch (interface) {
396+ case PHY_INTERFACE_MODE_SGMII:
397+ case PHY_INTERFACE_MODE_QSGMII:
398+ case PHY_INTERFACE_MODE_USXGMII:
399+ return 1600000;
400+
401+ case PHY_INTERFACE_MODE_1000BASEX:
402+ case PHY_INTERFACE_MODE_2500BASEX:
403+ return 10000000;
404+
405+ default:
406+ return -EINVAL;
407+ }
408+}
409+
410+void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state,
411+ u16 bmsr, u16 lpa);
412+int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface,
413+ const unsigned long *advertising);
414+void phylink_decode_usxgmii_word(struct phylink_link_state *state,
415+ uint16_t lpa);
416 #endif
417diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
418index 4bcb41c..3f302e2 100644
419--- a/include/uapi/linux/mdio.h
420+++ b/include/uapi/linux/mdio.h
421@@ -324,4 +324,30 @@ static inline __u16 mdio_phy_id_c45(int prtad, int devad)
422 return MDIO_PHY_ID_C45 | (prtad << 5) | devad;
423 }
424
425+/* UsxgmiiChannelInfo[15:0] for USXGMII in-band auto-negotiation.*/
426+#define MDIO_USXGMII_EEE_CLK_STP 0x0080 /* EEE clock stop supported */
427+#define MDIO_USXGMII_EEE 0x0100 /* EEE supported */
428+#define MDIO_USXGMII_SPD_MASK 0x0e00 /* USXGMII speed mask */
429+#define MDIO_USXGMII_FULL_DUPLEX 0x1000 /* USXGMII full duplex */
430+#define MDIO_USXGMII_DPX_SPD_MASK 0x1e00 /* USXGMII duplex and speed bits */
431+#define MDIO_USXGMII_10 0x0000 /* 10Mbps */
432+#define MDIO_USXGMII_10HALF 0x0000 /* 10Mbps half-duplex */
433+#define MDIO_USXGMII_10FULL 0x1000 /* 10Mbps full-duplex */
434+#define MDIO_USXGMII_100 0x0200 /* 100Mbps */
435+#define MDIO_USXGMII_100HALF 0x0200 /* 100Mbps half-duplex */
436+#define MDIO_USXGMII_100FULL 0x1200 /* 100Mbps full-duplex */
437+#define MDIO_USXGMII_1000 0x0400 /* 1000Mbps */
438+#define MDIO_USXGMII_1000HALF 0x0400 /* 1000Mbps half-duplex */
439+#define MDIO_USXGMII_1000FULL 0x1400 /* 1000Mbps full-duplex */
440+#define MDIO_USXGMII_10G 0x0600 /* 10Gbps */
441+#define MDIO_USXGMII_10GHALF 0x0600 /* 10Gbps half-duplex */
442+#define MDIO_USXGMII_10GFULL 0x1600 /* 10Gbps full-duplex */
443+#define MDIO_USXGMII_2500 0x0800 /* 2500Mbps */
444+#define MDIO_USXGMII_2500HALF 0x0800 /* 2500Mbps half-duplex */
445+#define MDIO_USXGMII_2500FULL 0x1800 /* 2500Mbps full-duplex */
446+#define MDIO_USXGMII_5000 0x0a00 /* 5000Mbps */
447+#define MDIO_USXGMII_5000HALF 0x0a00 /* 5000Mbps half-duplex */
448+#define MDIO_USXGMII_5000FULL 0x1a00 /* 5000Mbps full-duplex */
449+#define MDIO_USXGMII_LINK 0x8000 /* PHY link with copper-side partner */
450+
451 #endif /* _UAPI__LINUX_MDIO_H__ */
452diff --git a/include/uapi/linux/mii.h b/include/uapi/linux/mii.h
453index 51b48e4..90f9b4e 100644
454--- a/include/uapi/linux/mii.h
455+++ b/include/uapi/linux/mii.h
456@@ -131,6 +131,23 @@
457 #define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */
458 #define NWAYTEST_RESV2 0xfe00 /* Unused... */
459
460+/* MAC and PHY tx_config_Reg[15:0] for SGMII in-band auto-negotiation.*/
461+#define ADVERTISE_SGMII 0x0001 /* MAC can do SGMII */
462+#define LPA_SGMII 0x0001 /* PHY can do SGMII */
463+#define LPA_SGMII_SPD_MASK 0x0c00 /* SGMII speed mask */
464+#define LPA_SGMII_FULL_DUPLEX 0x1000 /* SGMII full duplex */
465+#define LPA_SGMII_DPX_SPD_MASK 0x1C00 /* SGMII duplex and speed bits */
466+#define LPA_SGMII_10 0x0000 /* 10Mbps */
467+#define LPA_SGMII_10HALF 0x0000 /* Can do 10mbps half-duplex */
468+#define LPA_SGMII_10FULL 0x1000 /* Can do 10mbps full-duplex */
469+#define LPA_SGMII_100 0x0400 /* 100Mbps */
470+#define LPA_SGMII_100HALF 0x0400 /* Can do 100mbps half-duplex */
471+#define LPA_SGMII_100FULL 0x1400 /* Can do 100mbps full-duplex */
472+#define LPA_SGMII_1000 0x0800 /* 1000Mbps */
473+#define LPA_SGMII_1000HALF 0x0800 /* Can do 1000mbps half-duplex */
474+#define LPA_SGMII_1000FULL 0x1800 /* Can do 1000mbps full-duplex */
475+#define LPA_SGMII_LINK 0x8000 /* PHY link with copper-side partner */
476+
477 /* 1000BASE-T Control register */
478 #define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
479 #define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */