1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * linux/mii.h: definitions for MII-compatible transceivers
4*4882a593Smuzhiyun * Originally drivers/net/sunhme.h.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (C) 1996, 1999, 2001 David S. Miller (davem@redhat.com)
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun #ifndef __LINUX_MII_H__
9*4882a593Smuzhiyun #define __LINUX_MII_H__
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/if.h>
13*4882a593Smuzhiyun #include <linux/linkmode.h>
14*4882a593Smuzhiyun #include <uapi/linux/mii.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun struct ethtool_cmd;
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun struct mii_if_info {
19*4882a593Smuzhiyun int phy_id;
20*4882a593Smuzhiyun int advertising;
21*4882a593Smuzhiyun int phy_id_mask;
22*4882a593Smuzhiyun int reg_num_mask;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun unsigned int full_duplex : 1; /* is full duplex? */
25*4882a593Smuzhiyun unsigned int force_media : 1; /* is autoneg. disabled? */
26*4882a593Smuzhiyun unsigned int supports_gmii : 1; /* are GMII registers supported? */
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun struct net_device *dev;
29*4882a593Smuzhiyun int (*mdio_read) (struct net_device *dev, int phy_id, int location);
30*4882a593Smuzhiyun void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun extern int mii_link_ok (struct mii_if_info *mii);
34*4882a593Smuzhiyun extern int mii_nway_restart (struct mii_if_info *mii);
35*4882a593Smuzhiyun extern int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
36*4882a593Smuzhiyun extern void mii_ethtool_get_link_ksettings(
37*4882a593Smuzhiyun struct mii_if_info *mii, struct ethtool_link_ksettings *cmd);
38*4882a593Smuzhiyun extern int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
39*4882a593Smuzhiyun extern int mii_ethtool_set_link_ksettings(
40*4882a593Smuzhiyun struct mii_if_info *mii, const struct ethtool_link_ksettings *cmd);
41*4882a593Smuzhiyun extern int mii_check_gmii_support(struct mii_if_info *mii);
42*4882a593Smuzhiyun extern void mii_check_link (struct mii_if_info *mii);
43*4882a593Smuzhiyun extern unsigned int mii_check_media (struct mii_if_info *mii,
44*4882a593Smuzhiyun unsigned int ok_to_print,
45*4882a593Smuzhiyun unsigned int init_media);
46*4882a593Smuzhiyun extern int generic_mii_ioctl(struct mii_if_info *mii_if,
47*4882a593Smuzhiyun struct mii_ioctl_data *mii_data, int cmd,
48*4882a593Smuzhiyun unsigned int *duplex_changed);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun
if_mii(struct ifreq * rq)51*4882a593Smuzhiyun static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun return (struct mii_ioctl_data *) &rq->ifr_ifru;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /**
57*4882a593Smuzhiyun * mii_nway_result
58*4882a593Smuzhiyun * @negotiated: value of MII ANAR and'd with ANLPAR
59*4882a593Smuzhiyun *
60*4882a593Smuzhiyun * Given a set of MII abilities, check each bit and returns the
61*4882a593Smuzhiyun * currently supported media, in the priority order defined by
62*4882a593Smuzhiyun * IEEE 802.3u. We use LPA_xxx constants but note this is not the
63*4882a593Smuzhiyun * value of LPA solely, as described above.
64*4882a593Smuzhiyun *
65*4882a593Smuzhiyun * The one exception to IEEE 802.3u is that 100baseT4 is placed
66*4882a593Smuzhiyun * between 100T-full and 100T-half. If your phy does not support
67*4882a593Smuzhiyun * 100T4 this is fine. If your phy places 100T4 elsewhere in the
68*4882a593Smuzhiyun * priority order, you will need to roll your own function.
69*4882a593Smuzhiyun */
mii_nway_result(unsigned int negotiated)70*4882a593Smuzhiyun static inline unsigned int mii_nway_result (unsigned int negotiated)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun unsigned int ret;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun if (negotiated & LPA_100FULL)
75*4882a593Smuzhiyun ret = LPA_100FULL;
76*4882a593Smuzhiyun else if (negotiated & LPA_100BASE4)
77*4882a593Smuzhiyun ret = LPA_100BASE4;
78*4882a593Smuzhiyun else if (negotiated & LPA_100HALF)
79*4882a593Smuzhiyun ret = LPA_100HALF;
80*4882a593Smuzhiyun else if (negotiated & LPA_10FULL)
81*4882a593Smuzhiyun ret = LPA_10FULL;
82*4882a593Smuzhiyun else
83*4882a593Smuzhiyun ret = LPA_10HALF;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun return ret;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /**
89*4882a593Smuzhiyun * mii_duplex
90*4882a593Smuzhiyun * @duplex_lock: Non-zero if duplex is locked at full
91*4882a593Smuzhiyun * @negotiated: value of MII ANAR and'd with ANLPAR
92*4882a593Smuzhiyun *
93*4882a593Smuzhiyun * A small helper function for a common case. Returns one
94*4882a593Smuzhiyun * if the media is operating or locked at full duplex, and
95*4882a593Smuzhiyun * returns zero otherwise.
96*4882a593Smuzhiyun */
mii_duplex(unsigned int duplex_lock,unsigned int negotiated)97*4882a593Smuzhiyun static inline unsigned int mii_duplex (unsigned int duplex_lock,
98*4882a593Smuzhiyun unsigned int negotiated)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun if (duplex_lock)
101*4882a593Smuzhiyun return 1;
102*4882a593Smuzhiyun if (mii_nway_result(negotiated) & LPA_DUPLEX)
103*4882a593Smuzhiyun return 1;
104*4882a593Smuzhiyun return 0;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /**
108*4882a593Smuzhiyun * ethtool_adv_to_mii_adv_t
109*4882a593Smuzhiyun * @ethadv: the ethtool advertisement settings
110*4882a593Smuzhiyun *
111*4882a593Smuzhiyun * A small helper function that translates ethtool advertisement
112*4882a593Smuzhiyun * settings to phy autonegotiation advertisements for the
113*4882a593Smuzhiyun * MII_ADVERTISE register.
114*4882a593Smuzhiyun */
ethtool_adv_to_mii_adv_t(u32 ethadv)115*4882a593Smuzhiyun static inline u32 ethtool_adv_to_mii_adv_t(u32 ethadv)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun u32 result = 0;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun if (ethadv & ADVERTISED_10baseT_Half)
120*4882a593Smuzhiyun result |= ADVERTISE_10HALF;
121*4882a593Smuzhiyun if (ethadv & ADVERTISED_10baseT_Full)
122*4882a593Smuzhiyun result |= ADVERTISE_10FULL;
123*4882a593Smuzhiyun if (ethadv & ADVERTISED_100baseT_Half)
124*4882a593Smuzhiyun result |= ADVERTISE_100HALF;
125*4882a593Smuzhiyun if (ethadv & ADVERTISED_100baseT_Full)
126*4882a593Smuzhiyun result |= ADVERTISE_100FULL;
127*4882a593Smuzhiyun if (ethadv & ADVERTISED_Pause)
128*4882a593Smuzhiyun result |= ADVERTISE_PAUSE_CAP;
129*4882a593Smuzhiyun if (ethadv & ADVERTISED_Asym_Pause)
130*4882a593Smuzhiyun result |= ADVERTISE_PAUSE_ASYM;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun return result;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /**
136*4882a593Smuzhiyun * linkmode_adv_to_mii_adv_t
137*4882a593Smuzhiyun * @advertising: the linkmode advertisement settings
138*4882a593Smuzhiyun *
139*4882a593Smuzhiyun * A small helper function that translates linkmode advertisement
140*4882a593Smuzhiyun * settings to phy autonegotiation advertisements for the
141*4882a593Smuzhiyun * MII_ADVERTISE register.
142*4882a593Smuzhiyun */
linkmode_adv_to_mii_adv_t(unsigned long * advertising)143*4882a593Smuzhiyun static inline u32 linkmode_adv_to_mii_adv_t(unsigned long *advertising)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun u32 result = 0;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, advertising))
148*4882a593Smuzhiyun result |= ADVERTISE_10HALF;
149*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, advertising))
150*4882a593Smuzhiyun result |= ADVERTISE_10FULL;
151*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, advertising))
152*4882a593Smuzhiyun result |= ADVERTISE_100HALF;
153*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, advertising))
154*4882a593Smuzhiyun result |= ADVERTISE_100FULL;
155*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising))
156*4882a593Smuzhiyun result |= ADVERTISE_PAUSE_CAP;
157*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising))
158*4882a593Smuzhiyun result |= ADVERTISE_PAUSE_ASYM;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun return result;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun /**
164*4882a593Smuzhiyun * mii_adv_to_ethtool_adv_t
165*4882a593Smuzhiyun * @adv: value of the MII_ADVERTISE register
166*4882a593Smuzhiyun *
167*4882a593Smuzhiyun * A small helper function that translates MII_ADVERTISE bits
168*4882a593Smuzhiyun * to ethtool advertisement settings.
169*4882a593Smuzhiyun */
mii_adv_to_ethtool_adv_t(u32 adv)170*4882a593Smuzhiyun static inline u32 mii_adv_to_ethtool_adv_t(u32 adv)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun u32 result = 0;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun if (adv & ADVERTISE_10HALF)
175*4882a593Smuzhiyun result |= ADVERTISED_10baseT_Half;
176*4882a593Smuzhiyun if (adv & ADVERTISE_10FULL)
177*4882a593Smuzhiyun result |= ADVERTISED_10baseT_Full;
178*4882a593Smuzhiyun if (adv & ADVERTISE_100HALF)
179*4882a593Smuzhiyun result |= ADVERTISED_100baseT_Half;
180*4882a593Smuzhiyun if (adv & ADVERTISE_100FULL)
181*4882a593Smuzhiyun result |= ADVERTISED_100baseT_Full;
182*4882a593Smuzhiyun if (adv & ADVERTISE_PAUSE_CAP)
183*4882a593Smuzhiyun result |= ADVERTISED_Pause;
184*4882a593Smuzhiyun if (adv & ADVERTISE_PAUSE_ASYM)
185*4882a593Smuzhiyun result |= ADVERTISED_Asym_Pause;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun return result;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /**
191*4882a593Smuzhiyun * ethtool_adv_to_mii_ctrl1000_t
192*4882a593Smuzhiyun * @ethadv: the ethtool advertisement settings
193*4882a593Smuzhiyun *
194*4882a593Smuzhiyun * A small helper function that translates ethtool advertisement
195*4882a593Smuzhiyun * settings to phy autonegotiation advertisements for the
196*4882a593Smuzhiyun * MII_CTRL1000 register when in 1000T mode.
197*4882a593Smuzhiyun */
ethtool_adv_to_mii_ctrl1000_t(u32 ethadv)198*4882a593Smuzhiyun static inline u32 ethtool_adv_to_mii_ctrl1000_t(u32 ethadv)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun u32 result = 0;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (ethadv & ADVERTISED_1000baseT_Half)
203*4882a593Smuzhiyun result |= ADVERTISE_1000HALF;
204*4882a593Smuzhiyun if (ethadv & ADVERTISED_1000baseT_Full)
205*4882a593Smuzhiyun result |= ADVERTISE_1000FULL;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun return result;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun /**
211*4882a593Smuzhiyun * linkmode_adv_to_mii_ctrl1000_t
212*4882a593Smuzhiyun * @advertising: the linkmode advertisement settings
213*4882a593Smuzhiyun *
214*4882a593Smuzhiyun * A small helper function that translates linkmode advertisement
215*4882a593Smuzhiyun * settings to phy autonegotiation advertisements for the
216*4882a593Smuzhiyun * MII_CTRL1000 register when in 1000T mode.
217*4882a593Smuzhiyun */
linkmode_adv_to_mii_ctrl1000_t(unsigned long * advertising)218*4882a593Smuzhiyun static inline u32 linkmode_adv_to_mii_ctrl1000_t(unsigned long *advertising)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun u32 result = 0;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
223*4882a593Smuzhiyun advertising))
224*4882a593Smuzhiyun result |= ADVERTISE_1000HALF;
225*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
226*4882a593Smuzhiyun advertising))
227*4882a593Smuzhiyun result |= ADVERTISE_1000FULL;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun return result;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /**
233*4882a593Smuzhiyun * mii_ctrl1000_to_ethtool_adv_t
234*4882a593Smuzhiyun * @adv: value of the MII_CTRL1000 register
235*4882a593Smuzhiyun *
236*4882a593Smuzhiyun * A small helper function that translates MII_CTRL1000
237*4882a593Smuzhiyun * bits, when in 1000Base-T mode, to ethtool
238*4882a593Smuzhiyun * advertisement settings.
239*4882a593Smuzhiyun */
mii_ctrl1000_to_ethtool_adv_t(u32 adv)240*4882a593Smuzhiyun static inline u32 mii_ctrl1000_to_ethtool_adv_t(u32 adv)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun u32 result = 0;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (adv & ADVERTISE_1000HALF)
245*4882a593Smuzhiyun result |= ADVERTISED_1000baseT_Half;
246*4882a593Smuzhiyun if (adv & ADVERTISE_1000FULL)
247*4882a593Smuzhiyun result |= ADVERTISED_1000baseT_Full;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun return result;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun /**
253*4882a593Smuzhiyun * mii_lpa_to_ethtool_lpa_t
254*4882a593Smuzhiyun * @adv: value of the MII_LPA register
255*4882a593Smuzhiyun *
256*4882a593Smuzhiyun * A small helper function that translates MII_LPA
257*4882a593Smuzhiyun * bits, when in 1000Base-T mode, to ethtool
258*4882a593Smuzhiyun * LP advertisement settings.
259*4882a593Smuzhiyun */
mii_lpa_to_ethtool_lpa_t(u32 lpa)260*4882a593Smuzhiyun static inline u32 mii_lpa_to_ethtool_lpa_t(u32 lpa)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun u32 result = 0;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (lpa & LPA_LPACK)
265*4882a593Smuzhiyun result |= ADVERTISED_Autoneg;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun return result | mii_adv_to_ethtool_adv_t(lpa);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun /**
271*4882a593Smuzhiyun * mii_stat1000_to_ethtool_lpa_t
272*4882a593Smuzhiyun * @adv: value of the MII_STAT1000 register
273*4882a593Smuzhiyun *
274*4882a593Smuzhiyun * A small helper function that translates MII_STAT1000
275*4882a593Smuzhiyun * bits, when in 1000Base-T mode, to ethtool
276*4882a593Smuzhiyun * advertisement settings.
277*4882a593Smuzhiyun */
mii_stat1000_to_ethtool_lpa_t(u32 lpa)278*4882a593Smuzhiyun static inline u32 mii_stat1000_to_ethtool_lpa_t(u32 lpa)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun u32 result = 0;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun if (lpa & LPA_1000HALF)
283*4882a593Smuzhiyun result |= ADVERTISED_1000baseT_Half;
284*4882a593Smuzhiyun if (lpa & LPA_1000FULL)
285*4882a593Smuzhiyun result |= ADVERTISED_1000baseT_Full;
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun return result;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun /**
291*4882a593Smuzhiyun * mii_stat1000_mod_linkmode_lpa_t
292*4882a593Smuzhiyun * @advertising: target the linkmode advertisement settings
293*4882a593Smuzhiyun * @adv: value of the MII_STAT1000 register
294*4882a593Smuzhiyun *
295*4882a593Smuzhiyun * A small helper function that translates MII_STAT1000 bits, when in
296*4882a593Smuzhiyun * 1000Base-T mode, to linkmode advertisement settings. Other bits in
297*4882a593Smuzhiyun * advertising are not changes.
298*4882a593Smuzhiyun */
mii_stat1000_mod_linkmode_lpa_t(unsigned long * advertising,u32 lpa)299*4882a593Smuzhiyun static inline void mii_stat1000_mod_linkmode_lpa_t(unsigned long *advertising,
300*4882a593Smuzhiyun u32 lpa)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
303*4882a593Smuzhiyun advertising, lpa & LPA_1000HALF);
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
306*4882a593Smuzhiyun advertising, lpa & LPA_1000FULL);
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun /**
310*4882a593Smuzhiyun * ethtool_adv_to_mii_adv_x
311*4882a593Smuzhiyun * @ethadv: the ethtool advertisement settings
312*4882a593Smuzhiyun *
313*4882a593Smuzhiyun * A small helper function that translates ethtool advertisement
314*4882a593Smuzhiyun * settings to phy autonegotiation advertisements for the
315*4882a593Smuzhiyun * MII_CTRL1000 register when in 1000Base-X mode.
316*4882a593Smuzhiyun */
ethtool_adv_to_mii_adv_x(u32 ethadv)317*4882a593Smuzhiyun static inline u32 ethtool_adv_to_mii_adv_x(u32 ethadv)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun u32 result = 0;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun if (ethadv & ADVERTISED_1000baseT_Half)
322*4882a593Smuzhiyun result |= ADVERTISE_1000XHALF;
323*4882a593Smuzhiyun if (ethadv & ADVERTISED_1000baseT_Full)
324*4882a593Smuzhiyun result |= ADVERTISE_1000XFULL;
325*4882a593Smuzhiyun if (ethadv & ADVERTISED_Pause)
326*4882a593Smuzhiyun result |= ADVERTISE_1000XPAUSE;
327*4882a593Smuzhiyun if (ethadv & ADVERTISED_Asym_Pause)
328*4882a593Smuzhiyun result |= ADVERTISE_1000XPSE_ASYM;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun return result;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun /**
334*4882a593Smuzhiyun * mii_adv_to_ethtool_adv_x
335*4882a593Smuzhiyun * @adv: value of the MII_CTRL1000 register
336*4882a593Smuzhiyun *
337*4882a593Smuzhiyun * A small helper function that translates MII_CTRL1000
338*4882a593Smuzhiyun * bits, when in 1000Base-X mode, to ethtool
339*4882a593Smuzhiyun * advertisement settings.
340*4882a593Smuzhiyun */
mii_adv_to_ethtool_adv_x(u32 adv)341*4882a593Smuzhiyun static inline u32 mii_adv_to_ethtool_adv_x(u32 adv)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun u32 result = 0;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if (adv & ADVERTISE_1000XHALF)
346*4882a593Smuzhiyun result |= ADVERTISED_1000baseT_Half;
347*4882a593Smuzhiyun if (adv & ADVERTISE_1000XFULL)
348*4882a593Smuzhiyun result |= ADVERTISED_1000baseT_Full;
349*4882a593Smuzhiyun if (adv & ADVERTISE_1000XPAUSE)
350*4882a593Smuzhiyun result |= ADVERTISED_Pause;
351*4882a593Smuzhiyun if (adv & ADVERTISE_1000XPSE_ASYM)
352*4882a593Smuzhiyun result |= ADVERTISED_Asym_Pause;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun return result;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun /**
358*4882a593Smuzhiyun * mii_lpa_mod_linkmode_adv_sgmii
359*4882a593Smuzhiyun * @lp_advertising: pointer to destination link mode.
360*4882a593Smuzhiyun * @lpa: value of the MII_LPA register
361*4882a593Smuzhiyun *
362*4882a593Smuzhiyun * A small helper function that translates MII_LPA bits to
363*4882a593Smuzhiyun * linkmode advertisement settings for SGMII.
364*4882a593Smuzhiyun * Leaves other bits unchanged.
365*4882a593Smuzhiyun */
366*4882a593Smuzhiyun static inline void
mii_lpa_mod_linkmode_lpa_sgmii(unsigned long * lp_advertising,u32 lpa)367*4882a593Smuzhiyun mii_lpa_mod_linkmode_lpa_sgmii(unsigned long *lp_advertising, u32 lpa)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun u32 speed_duplex = lpa & LPA_SGMII_DPX_SPD_MASK;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, lp_advertising,
372*4882a593Smuzhiyun speed_duplex == LPA_SGMII_1000HALF);
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, lp_advertising,
375*4882a593Smuzhiyun speed_duplex == LPA_SGMII_1000FULL);
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, lp_advertising,
378*4882a593Smuzhiyun speed_duplex == LPA_SGMII_100HALF);
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, lp_advertising,
381*4882a593Smuzhiyun speed_duplex == LPA_SGMII_100FULL);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, lp_advertising,
384*4882a593Smuzhiyun speed_duplex == LPA_SGMII_10HALF);
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, lp_advertising,
387*4882a593Smuzhiyun speed_duplex == LPA_SGMII_10FULL);
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun /**
391*4882a593Smuzhiyun * mii_lpa_to_linkmode_adv_sgmii
392*4882a593Smuzhiyun * @advertising: pointer to destination link mode.
393*4882a593Smuzhiyun * @lpa: value of the MII_LPA register
394*4882a593Smuzhiyun *
395*4882a593Smuzhiyun * A small helper function that translates MII_ADVERTISE bits
396*4882a593Smuzhiyun * to linkmode advertisement settings when in SGMII mode.
397*4882a593Smuzhiyun * Clears the old value of advertising.
398*4882a593Smuzhiyun */
mii_lpa_to_linkmode_lpa_sgmii(unsigned long * lp_advertising,u32 lpa)399*4882a593Smuzhiyun static inline void mii_lpa_to_linkmode_lpa_sgmii(unsigned long *lp_advertising,
400*4882a593Smuzhiyun u32 lpa)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun linkmode_zero(lp_advertising);
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun mii_lpa_mod_linkmode_lpa_sgmii(lp_advertising, lpa);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun /**
408*4882a593Smuzhiyun * mii_adv_mod_linkmode_adv_t
409*4882a593Smuzhiyun * @advertising:pointer to destination link mode.
410*4882a593Smuzhiyun * @adv: value of the MII_ADVERTISE register
411*4882a593Smuzhiyun *
412*4882a593Smuzhiyun * A small helper function that translates MII_ADVERTISE bits to
413*4882a593Smuzhiyun * linkmode advertisement settings. Leaves other bits unchanged.
414*4882a593Smuzhiyun */
mii_adv_mod_linkmode_adv_t(unsigned long * advertising,u32 adv)415*4882a593Smuzhiyun static inline void mii_adv_mod_linkmode_adv_t(unsigned long *advertising,
416*4882a593Smuzhiyun u32 adv)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
419*4882a593Smuzhiyun advertising, adv & ADVERTISE_10HALF);
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
422*4882a593Smuzhiyun advertising, adv & ADVERTISE_10FULL);
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
425*4882a593Smuzhiyun advertising, adv & ADVERTISE_100HALF);
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
428*4882a593Smuzhiyun advertising, adv & ADVERTISE_100FULL);
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising,
431*4882a593Smuzhiyun adv & ADVERTISE_PAUSE_CAP);
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
434*4882a593Smuzhiyun advertising, adv & ADVERTISE_PAUSE_ASYM);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /**
438*4882a593Smuzhiyun * mii_adv_to_linkmode_adv_t
439*4882a593Smuzhiyun * @advertising:pointer to destination link mode.
440*4882a593Smuzhiyun * @adv: value of the MII_ADVERTISE register
441*4882a593Smuzhiyun *
442*4882a593Smuzhiyun * A small helper function that translates MII_ADVERTISE bits
443*4882a593Smuzhiyun * to linkmode advertisement settings. Clears the old value
444*4882a593Smuzhiyun * of advertising.
445*4882a593Smuzhiyun */
mii_adv_to_linkmode_adv_t(unsigned long * advertising,u32 adv)446*4882a593Smuzhiyun static inline void mii_adv_to_linkmode_adv_t(unsigned long *advertising,
447*4882a593Smuzhiyun u32 adv)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun linkmode_zero(advertising);
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun mii_adv_mod_linkmode_adv_t(advertising, adv);
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /**
455*4882a593Smuzhiyun * mii_lpa_to_linkmode_lpa_t
456*4882a593Smuzhiyun * @adv: value of the MII_LPA register
457*4882a593Smuzhiyun *
458*4882a593Smuzhiyun * A small helper function that translates MII_LPA bits, when in
459*4882a593Smuzhiyun * 1000Base-T mode, to linkmode LP advertisement settings. Clears the
460*4882a593Smuzhiyun * old value of advertising
461*4882a593Smuzhiyun */
mii_lpa_to_linkmode_lpa_t(unsigned long * lp_advertising,u32 lpa)462*4882a593Smuzhiyun static inline void mii_lpa_to_linkmode_lpa_t(unsigned long *lp_advertising,
463*4882a593Smuzhiyun u32 lpa)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun mii_adv_to_linkmode_adv_t(lp_advertising, lpa);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun if (lpa & LPA_LPACK)
468*4882a593Smuzhiyun linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
469*4882a593Smuzhiyun lp_advertising);
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun /**
474*4882a593Smuzhiyun * mii_lpa_mod_linkmode_lpa_t
475*4882a593Smuzhiyun * @adv: value of the MII_LPA register
476*4882a593Smuzhiyun *
477*4882a593Smuzhiyun * A small helper function that translates MII_LPA bits, when in
478*4882a593Smuzhiyun * 1000Base-T mode, to linkmode LP advertisement settings. Leaves
479*4882a593Smuzhiyun * other bits unchanged.
480*4882a593Smuzhiyun */
mii_lpa_mod_linkmode_lpa_t(unsigned long * lp_advertising,u32 lpa)481*4882a593Smuzhiyun static inline void mii_lpa_mod_linkmode_lpa_t(unsigned long *lp_advertising,
482*4882a593Smuzhiyun u32 lpa)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun mii_adv_mod_linkmode_adv_t(lp_advertising, lpa);
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
487*4882a593Smuzhiyun lp_advertising, lpa & LPA_LPACK);
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
mii_ctrl1000_mod_linkmode_adv_t(unsigned long * advertising,u32 ctrl1000)490*4882a593Smuzhiyun static inline void mii_ctrl1000_mod_linkmode_adv_t(unsigned long *advertising,
491*4882a593Smuzhiyun u32 ctrl1000)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertising,
494*4882a593Smuzhiyun ctrl1000 & ADVERTISE_1000HALF);
495*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertising,
496*4882a593Smuzhiyun ctrl1000 & ADVERTISE_1000FULL);
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun /**
500*4882a593Smuzhiyun * linkmode_adv_to_lcl_adv_t
501*4882a593Smuzhiyun * @advertising:pointer to linkmode advertising
502*4882a593Smuzhiyun *
503*4882a593Smuzhiyun * A small helper function that translates linkmode advertising to LVL
504*4882a593Smuzhiyun * pause capabilities.
505*4882a593Smuzhiyun */
linkmode_adv_to_lcl_adv_t(unsigned long * advertising)506*4882a593Smuzhiyun static inline u32 linkmode_adv_to_lcl_adv_t(unsigned long *advertising)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun u32 lcl_adv = 0;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
511*4882a593Smuzhiyun advertising))
512*4882a593Smuzhiyun lcl_adv |= ADVERTISE_PAUSE_CAP;
513*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
514*4882a593Smuzhiyun advertising))
515*4882a593Smuzhiyun lcl_adv |= ADVERTISE_PAUSE_ASYM;
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun return lcl_adv;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun /**
521*4882a593Smuzhiyun * mii_lpa_mod_linkmode_x - decode the link partner's config_reg to linkmodes
522*4882a593Smuzhiyun * @linkmodes: link modes array
523*4882a593Smuzhiyun * @lpa: config_reg word from link partner
524*4882a593Smuzhiyun * @fd_bit: link mode for 1000XFULL bit
525*4882a593Smuzhiyun */
mii_lpa_mod_linkmode_x(unsigned long * linkmodes,u16 lpa,int fd_bit)526*4882a593Smuzhiyun static inline void mii_lpa_mod_linkmode_x(unsigned long *linkmodes, u16 lpa,
527*4882a593Smuzhiyun int fd_bit)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, linkmodes,
530*4882a593Smuzhiyun lpa & LPA_LPACK);
531*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes,
532*4882a593Smuzhiyun lpa & LPA_1000XPAUSE);
533*4882a593Smuzhiyun linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes,
534*4882a593Smuzhiyun lpa & LPA_1000XPAUSE_ASYM);
535*4882a593Smuzhiyun linkmode_mod_bit(fd_bit, linkmodes,
536*4882a593Smuzhiyun lpa & LPA_1000XFULL);
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun /**
540*4882a593Smuzhiyun * linkmode_adv_to_mii_adv_x - encode a linkmode to config_reg
541*4882a593Smuzhiyun * @linkmodes: linkmodes
542*4882a593Smuzhiyun * @fd_bit: full duplex bit
543*4882a593Smuzhiyun */
linkmode_adv_to_mii_adv_x(const unsigned long * linkmodes,int fd_bit)544*4882a593Smuzhiyun static inline u16 linkmode_adv_to_mii_adv_x(const unsigned long *linkmodes,
545*4882a593Smuzhiyun int fd_bit)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun u16 adv = 0;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (linkmode_test_bit(fd_bit, linkmodes))
550*4882a593Smuzhiyun adv |= ADVERTISE_1000XFULL;
551*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes))
552*4882a593Smuzhiyun adv |= ADVERTISE_1000XPAUSE;
553*4882a593Smuzhiyun if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes))
554*4882a593Smuzhiyun adv |= ADVERTISE_1000XPSE_ASYM;
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun return adv;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun /**
560*4882a593Smuzhiyun * mii_advertise_flowctrl - get flow control advertisement flags
561*4882a593Smuzhiyun * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both)
562*4882a593Smuzhiyun */
mii_advertise_flowctrl(int cap)563*4882a593Smuzhiyun static inline u16 mii_advertise_flowctrl(int cap)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun u16 adv = 0;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun if (cap & FLOW_CTRL_RX)
568*4882a593Smuzhiyun adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
569*4882a593Smuzhiyun if (cap & FLOW_CTRL_TX)
570*4882a593Smuzhiyun adv ^= ADVERTISE_PAUSE_ASYM;
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun return adv;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun /**
576*4882a593Smuzhiyun * mii_resolve_flowctrl_fdx
577*4882a593Smuzhiyun * @lcladv: value of MII ADVERTISE register
578*4882a593Smuzhiyun * @rmtadv: value of MII LPA register
579*4882a593Smuzhiyun *
580*4882a593Smuzhiyun * Resolve full duplex flow control as per IEEE 802.3-2005 table 28B-3
581*4882a593Smuzhiyun */
mii_resolve_flowctrl_fdx(u16 lcladv,u16 rmtadv)582*4882a593Smuzhiyun static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun u8 cap = 0;
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun if (lcladv & rmtadv & ADVERTISE_PAUSE_CAP) {
587*4882a593Smuzhiyun cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
588*4882a593Smuzhiyun } else if (lcladv & rmtadv & ADVERTISE_PAUSE_ASYM) {
589*4882a593Smuzhiyun if (lcladv & ADVERTISE_PAUSE_CAP)
590*4882a593Smuzhiyun cap = FLOW_CTRL_RX;
591*4882a593Smuzhiyun else if (rmtadv & ADVERTISE_PAUSE_CAP)
592*4882a593Smuzhiyun cap = FLOW_CTRL_TX;
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun return cap;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun #endif /* __LINUX_MII_H__ */
599