xref: /openbmc/linux/include/linux/mii.h (revision bdb6cfe7)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * linux/mii.h: definitions for MII-compatible transceivers
41da177e4SLinus Torvalds  * Originally drivers/net/sunhme.h.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (C) 1996, 1999, 2001 David S. Miller (davem@redhat.com)
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds #ifndef __LINUX_MII_H__
91da177e4SLinus Torvalds #define __LINUX_MII_H__
101da177e4SLinus Torvalds 
11c3ce7e20SDavid Woodhouse 
12c3ce7e20SDavid Woodhouse #include <linux/if.h>
13b31cdffaSAndrew Lunn #include <linux/linkmode.h>
14607ca46eSDavid Howells #include <uapi/linux/mii.h>
15c3ce7e20SDavid Woodhouse 
16c3ce7e20SDavid Woodhouse struct ethtool_cmd;
17c3ce7e20SDavid Woodhouse 
181da177e4SLinus Torvalds struct mii_if_info {
191da177e4SLinus Torvalds 	int phy_id;
201da177e4SLinus Torvalds 	int advertising;
211da177e4SLinus Torvalds 	int phy_id_mask;
221da177e4SLinus Torvalds 	int reg_num_mask;
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds 	unsigned int full_duplex : 1;	/* is full duplex? */
251da177e4SLinus Torvalds 	unsigned int force_media : 1;	/* is autoneg. disabled? */
261da177e4SLinus Torvalds 	unsigned int supports_gmii : 1; /* are GMII registers supported? */
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds 	struct net_device *dev;
291da177e4SLinus Torvalds 	int (*mdio_read) (struct net_device *dev, int phy_id, int location);
301da177e4SLinus Torvalds 	void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
311da177e4SLinus Torvalds };
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds extern int mii_link_ok (struct mii_if_info *mii);
341da177e4SLinus Torvalds extern int mii_nway_restart (struct mii_if_info *mii);
352274af1dSPavel Skripkin extern void mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
3682c01a84Syuval.shaia@oracle.com extern void mii_ethtool_get_link_ksettings(
37bc8ee596SPhilippe Reynes 	struct mii_if_info *mii, struct ethtool_link_ksettings *cmd);
381da177e4SLinus Torvalds extern int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
39bc8ee596SPhilippe Reynes extern int mii_ethtool_set_link_ksettings(
40bc8ee596SPhilippe Reynes 	struct mii_if_info *mii, const struct ethtool_link_ksettings *cmd);
4143ec6e95SDale Farnsworth extern int mii_check_gmii_support(struct mii_if_info *mii);
421da177e4SLinus Torvalds extern void mii_check_link (struct mii_if_info *mii);
431da177e4SLinus Torvalds extern unsigned int mii_check_media (struct mii_if_info *mii,
441da177e4SLinus Torvalds 				     unsigned int ok_to_print,
451da177e4SLinus Torvalds 				     unsigned int init_media);
461da177e4SLinus Torvalds extern int generic_mii_ioctl(struct mii_if_info *mii_if,
471da177e4SLinus Torvalds 			     struct mii_ioctl_data *mii_data, int cmd,
481da177e4SLinus Torvalds 			     unsigned int *duplex_changed);
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 
if_mii(struct ifreq * rq)511da177e4SLinus Torvalds static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
521da177e4SLinus Torvalds {
531da177e4SLinus Torvalds 	return (struct mii_ioctl_data *) &rq->ifr_ifru;
541da177e4SLinus Torvalds }
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds /**
571da177e4SLinus Torvalds  * mii_nway_result
581da177e4SLinus Torvalds  * @negotiated: value of MII ANAR and'd with ANLPAR
591da177e4SLinus Torvalds  *
601da177e4SLinus Torvalds  * Given a set of MII abilities, check each bit and returns the
611da177e4SLinus Torvalds  * currently supported media, in the priority order defined by
621da177e4SLinus Torvalds  * IEEE 802.3u.  We use LPA_xxx constants but note this is not the
631da177e4SLinus Torvalds  * value of LPA solely, as described above.
641da177e4SLinus Torvalds  *
651da177e4SLinus Torvalds  * The one exception to IEEE 802.3u is that 100baseT4 is placed
661da177e4SLinus Torvalds  * between 100T-full and 100T-half.  If your phy does not support
671da177e4SLinus Torvalds  * 100T4 this is fine.  If your phy places 100T4 elsewhere in the
681da177e4SLinus Torvalds  * priority order, you will need to roll your own function.
691da177e4SLinus Torvalds  */
mii_nway_result(unsigned int negotiated)701da177e4SLinus Torvalds static inline unsigned int mii_nway_result (unsigned int negotiated)
711da177e4SLinus Torvalds {
721da177e4SLinus Torvalds 	unsigned int ret;
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 	if (negotiated & LPA_100FULL)
751da177e4SLinus Torvalds 		ret = LPA_100FULL;
761da177e4SLinus Torvalds 	else if (negotiated & LPA_100BASE4)
771da177e4SLinus Torvalds 		ret = LPA_100BASE4;
781da177e4SLinus Torvalds 	else if (negotiated & LPA_100HALF)
791da177e4SLinus Torvalds 		ret = LPA_100HALF;
801da177e4SLinus Torvalds 	else if (negotiated & LPA_10FULL)
811da177e4SLinus Torvalds 		ret = LPA_10FULL;
821da177e4SLinus Torvalds 	else
831da177e4SLinus Torvalds 		ret = LPA_10HALF;
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds 	return ret;
861da177e4SLinus Torvalds }
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds /**
891da177e4SLinus Torvalds  * mii_duplex
901da177e4SLinus Torvalds  * @duplex_lock: Non-zero if duplex is locked at full
911da177e4SLinus Torvalds  * @negotiated: value of MII ANAR and'd with ANLPAR
921da177e4SLinus Torvalds  *
931da177e4SLinus Torvalds  * A small helper function for a common case.  Returns one
941da177e4SLinus Torvalds  * if the media is operating or locked at full duplex, and
951da177e4SLinus Torvalds  * returns zero otherwise.
961da177e4SLinus Torvalds  */
mii_duplex(unsigned int duplex_lock,unsigned int negotiated)971da177e4SLinus Torvalds static inline unsigned int mii_duplex (unsigned int duplex_lock,
981da177e4SLinus Torvalds 				       unsigned int negotiated)
991da177e4SLinus Torvalds {
1001da177e4SLinus Torvalds 	if (duplex_lock)
1011da177e4SLinus Torvalds 		return 1;
1021da177e4SLinus Torvalds 	if (mii_nway_result(negotiated) & LPA_DUPLEX)
1031da177e4SLinus Torvalds 		return 1;
1041da177e4SLinus Torvalds 	return 0;
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds 
107bc02ff95SSteve Glendinning /**
10837f07023SMatt Carlson  * ethtool_adv_to_mii_adv_t
10928011cf1SMatt Carlson  * @ethadv: the ethtool advertisement settings
11028011cf1SMatt Carlson  *
11128011cf1SMatt Carlson  * A small helper function that translates ethtool advertisement
11228011cf1SMatt Carlson  * settings to phy autonegotiation advertisements for the
11328011cf1SMatt Carlson  * MII_ADVERTISE register.
11428011cf1SMatt Carlson  */
ethtool_adv_to_mii_adv_t(u32 ethadv)11537f07023SMatt Carlson static inline u32 ethtool_adv_to_mii_adv_t(u32 ethadv)
11628011cf1SMatt Carlson {
11728011cf1SMatt Carlson 	u32 result = 0;
11828011cf1SMatt Carlson 
11928011cf1SMatt Carlson 	if (ethadv & ADVERTISED_10baseT_Half)
12028011cf1SMatt Carlson 		result |= ADVERTISE_10HALF;
12128011cf1SMatt Carlson 	if (ethadv & ADVERTISED_10baseT_Full)
12228011cf1SMatt Carlson 		result |= ADVERTISE_10FULL;
12328011cf1SMatt Carlson 	if (ethadv & ADVERTISED_100baseT_Half)
12428011cf1SMatt Carlson 		result |= ADVERTISE_100HALF;
12528011cf1SMatt Carlson 	if (ethadv & ADVERTISED_100baseT_Full)
12628011cf1SMatt Carlson 		result |= ADVERTISE_100FULL;
12728011cf1SMatt Carlson 	if (ethadv & ADVERTISED_Pause)
12828011cf1SMatt Carlson 		result |= ADVERTISE_PAUSE_CAP;
12928011cf1SMatt Carlson 	if (ethadv & ADVERTISED_Asym_Pause)
13028011cf1SMatt Carlson 		result |= ADVERTISE_PAUSE_ASYM;
13128011cf1SMatt Carlson 
13228011cf1SMatt Carlson 	return result;
13328011cf1SMatt Carlson }
13428011cf1SMatt Carlson 
13528011cf1SMatt Carlson /**
136f954a04eSAndrew Lunn  * linkmode_adv_to_mii_adv_t
137f954a04eSAndrew Lunn  * @advertising: the linkmode advertisement settings
138f954a04eSAndrew Lunn  *
139f954a04eSAndrew Lunn  * A small helper function that translates linkmode advertisement
140f954a04eSAndrew Lunn  * settings to phy autonegotiation advertisements for the
141f954a04eSAndrew Lunn  * MII_ADVERTISE register.
142f954a04eSAndrew Lunn  */
linkmode_adv_to_mii_adv_t(unsigned long * advertising)143f954a04eSAndrew Lunn static inline u32 linkmode_adv_to_mii_adv_t(unsigned long *advertising)
144f954a04eSAndrew Lunn {
145f954a04eSAndrew Lunn 	u32 result = 0;
146f954a04eSAndrew Lunn 
147f954a04eSAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, advertising))
148f954a04eSAndrew Lunn 		result |= ADVERTISE_10HALF;
149f954a04eSAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, advertising))
150f954a04eSAndrew Lunn 		result |= ADVERTISE_10FULL;
151f954a04eSAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, advertising))
152f954a04eSAndrew Lunn 		result |= ADVERTISE_100HALF;
153f954a04eSAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, advertising))
154f954a04eSAndrew Lunn 		result |= ADVERTISE_100FULL;
155f954a04eSAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising))
156f954a04eSAndrew Lunn 		result |= ADVERTISE_PAUSE_CAP;
157f954a04eSAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising))
158f954a04eSAndrew Lunn 		result |= ADVERTISE_PAUSE_ASYM;
159f954a04eSAndrew Lunn 
160f954a04eSAndrew Lunn 	return result;
161f954a04eSAndrew Lunn }
162f954a04eSAndrew Lunn 
163f954a04eSAndrew Lunn /**
16437f07023SMatt Carlson  * mii_adv_to_ethtool_adv_t
16528011cf1SMatt Carlson  * @adv: value of the MII_ADVERTISE register
16628011cf1SMatt Carlson  *
16728011cf1SMatt Carlson  * A small helper function that translates MII_ADVERTISE bits
16828011cf1SMatt Carlson  * to ethtool advertisement settings.
16928011cf1SMatt Carlson  */
mii_adv_to_ethtool_adv_t(u32 adv)17037f07023SMatt Carlson static inline u32 mii_adv_to_ethtool_adv_t(u32 adv)
17128011cf1SMatt Carlson {
17228011cf1SMatt Carlson 	u32 result = 0;
17328011cf1SMatt Carlson 
17428011cf1SMatt Carlson 	if (adv & ADVERTISE_10HALF)
17528011cf1SMatt Carlson 		result |= ADVERTISED_10baseT_Half;
17628011cf1SMatt Carlson 	if (adv & ADVERTISE_10FULL)
17728011cf1SMatt Carlson 		result |= ADVERTISED_10baseT_Full;
17828011cf1SMatt Carlson 	if (adv & ADVERTISE_100HALF)
17928011cf1SMatt Carlson 		result |= ADVERTISED_100baseT_Half;
18028011cf1SMatt Carlson 	if (adv & ADVERTISE_100FULL)
18128011cf1SMatt Carlson 		result |= ADVERTISED_100baseT_Full;
18228011cf1SMatt Carlson 	if (adv & ADVERTISE_PAUSE_CAP)
18328011cf1SMatt Carlson 		result |= ADVERTISED_Pause;
18428011cf1SMatt Carlson 	if (adv & ADVERTISE_PAUSE_ASYM)
18528011cf1SMatt Carlson 		result |= ADVERTISED_Asym_Pause;
18628011cf1SMatt Carlson 
18728011cf1SMatt Carlson 	return result;
18828011cf1SMatt Carlson }
18928011cf1SMatt Carlson 
19028011cf1SMatt Carlson /**
19137f07023SMatt Carlson  * ethtool_adv_to_mii_ctrl1000_t
19228011cf1SMatt Carlson  * @ethadv: the ethtool advertisement settings
19328011cf1SMatt Carlson  *
19428011cf1SMatt Carlson  * A small helper function that translates ethtool advertisement
19528011cf1SMatt Carlson  * settings to phy autonegotiation advertisements for the
19628011cf1SMatt Carlson  * MII_CTRL1000 register when in 1000T mode.
19728011cf1SMatt Carlson  */
ethtool_adv_to_mii_ctrl1000_t(u32 ethadv)19837f07023SMatt Carlson static inline u32 ethtool_adv_to_mii_ctrl1000_t(u32 ethadv)
19928011cf1SMatt Carlson {
20028011cf1SMatt Carlson 	u32 result = 0;
20128011cf1SMatt Carlson 
20228011cf1SMatt Carlson 	if (ethadv & ADVERTISED_1000baseT_Half)
20328011cf1SMatt Carlson 		result |= ADVERTISE_1000HALF;
20428011cf1SMatt Carlson 	if (ethadv & ADVERTISED_1000baseT_Full)
20528011cf1SMatt Carlson 		result |= ADVERTISE_1000FULL;
20628011cf1SMatt Carlson 
20728011cf1SMatt Carlson 	return result;
20828011cf1SMatt Carlson }
20928011cf1SMatt Carlson 
21028011cf1SMatt Carlson /**
211f954a04eSAndrew Lunn  * linkmode_adv_to_mii_ctrl1000_t
212fe191914SAndrew Lunn  * @advertising: the linkmode advertisement settings
213f954a04eSAndrew Lunn  *
214f954a04eSAndrew Lunn  * A small helper function that translates linkmode advertisement
215f954a04eSAndrew Lunn  * settings to phy autonegotiation advertisements for the
216f954a04eSAndrew Lunn  * MII_CTRL1000 register when in 1000T mode.
217f954a04eSAndrew Lunn  */
linkmode_adv_to_mii_ctrl1000_t(unsigned long * advertising)218f954a04eSAndrew Lunn static inline u32 linkmode_adv_to_mii_ctrl1000_t(unsigned long *advertising)
219f954a04eSAndrew Lunn {
220f954a04eSAndrew Lunn 	u32 result = 0;
221f954a04eSAndrew Lunn 
222f954a04eSAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
223f954a04eSAndrew Lunn 			      advertising))
224f954a04eSAndrew Lunn 		result |= ADVERTISE_1000HALF;
225f954a04eSAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
226f954a04eSAndrew Lunn 			      advertising))
227f954a04eSAndrew Lunn 		result |= ADVERTISE_1000FULL;
228f954a04eSAndrew Lunn 
229f954a04eSAndrew Lunn 	return result;
230f954a04eSAndrew Lunn }
231f954a04eSAndrew Lunn 
232f954a04eSAndrew Lunn /**
23337f07023SMatt Carlson  * mii_ctrl1000_to_ethtool_adv_t
23428011cf1SMatt Carlson  * @adv: value of the MII_CTRL1000 register
23528011cf1SMatt Carlson  *
23628011cf1SMatt Carlson  * A small helper function that translates MII_CTRL1000
23728011cf1SMatt Carlson  * bits, when in 1000Base-T mode, to ethtool
23828011cf1SMatt Carlson  * advertisement settings.
23928011cf1SMatt Carlson  */
mii_ctrl1000_to_ethtool_adv_t(u32 adv)24037f07023SMatt Carlson static inline u32 mii_ctrl1000_to_ethtool_adv_t(u32 adv)
24128011cf1SMatt Carlson {
24228011cf1SMatt Carlson 	u32 result = 0;
24328011cf1SMatt Carlson 
24428011cf1SMatt Carlson 	if (adv & ADVERTISE_1000HALF)
24528011cf1SMatt Carlson 		result |= ADVERTISED_1000baseT_Half;
24628011cf1SMatt Carlson 	if (adv & ADVERTISE_1000FULL)
24728011cf1SMatt Carlson 		result |= ADVERTISED_1000baseT_Full;
24828011cf1SMatt Carlson 
24928011cf1SMatt Carlson 	return result;
25028011cf1SMatt Carlson }
25128011cf1SMatt Carlson 
25237f07023SMatt Carlson /**
25337f07023SMatt Carlson  * mii_lpa_to_ethtool_lpa_t
25437f07023SMatt Carlson  * @adv: value of the MII_LPA register
25537f07023SMatt Carlson  *
25637f07023SMatt Carlson  * A small helper function that translates MII_LPA
25737f07023SMatt Carlson  * bits, when in 1000Base-T mode, to ethtool
25837f07023SMatt Carlson  * LP advertisement settings.
25937f07023SMatt Carlson  */
mii_lpa_to_ethtool_lpa_t(u32 lpa)26037f07023SMatt Carlson static inline u32 mii_lpa_to_ethtool_lpa_t(u32 lpa)
26137f07023SMatt Carlson {
26237f07023SMatt Carlson 	u32 result = 0;
26337f07023SMatt Carlson 
26437f07023SMatt Carlson 	if (lpa & LPA_LPACK)
26537f07023SMatt Carlson 		result |= ADVERTISED_Autoneg;
26637f07023SMatt Carlson 
26737f07023SMatt Carlson 	return result | mii_adv_to_ethtool_adv_t(lpa);
26837f07023SMatt Carlson }
26928011cf1SMatt Carlson 
27028011cf1SMatt Carlson /**
27137f07023SMatt Carlson  * mii_stat1000_to_ethtool_lpa_t
27228011cf1SMatt Carlson  * @adv: value of the MII_STAT1000 register
27328011cf1SMatt Carlson  *
27428011cf1SMatt Carlson  * A small helper function that translates MII_STAT1000
27528011cf1SMatt Carlson  * bits, when in 1000Base-T mode, to ethtool
27628011cf1SMatt Carlson  * advertisement settings.
27728011cf1SMatt Carlson  */
mii_stat1000_to_ethtool_lpa_t(u32 lpa)27837f07023SMatt Carlson static inline u32 mii_stat1000_to_ethtool_lpa_t(u32 lpa)
27928011cf1SMatt Carlson {
28028011cf1SMatt Carlson 	u32 result = 0;
28128011cf1SMatt Carlson 
28228011cf1SMatt Carlson 	if (lpa & LPA_1000HALF)
28328011cf1SMatt Carlson 		result |= ADVERTISED_1000baseT_Half;
28428011cf1SMatt Carlson 	if (lpa & LPA_1000FULL)
28528011cf1SMatt Carlson 		result |= ADVERTISED_1000baseT_Full;
28628011cf1SMatt Carlson 
28728011cf1SMatt Carlson 	return result;
28828011cf1SMatt Carlson }
28928011cf1SMatt Carlson 
29028011cf1SMatt Carlson /**
29178a24df3SAndrew Lunn  * mii_stat1000_mod_linkmode_lpa_t
292c0ec3c27SAndrew Lunn  * @advertising: target the linkmode advertisement settings
293c0ec3c27SAndrew Lunn  * @adv: value of the MII_STAT1000 register
294c0ec3c27SAndrew Lunn  *
295c0ec3c27SAndrew Lunn  * A small helper function that translates MII_STAT1000 bits, when in
29678a24df3SAndrew Lunn  * 1000Base-T mode, to linkmode advertisement settings. Other bits in
29778a24df3SAndrew Lunn  * advertising are not changes.
298c0ec3c27SAndrew Lunn  */
mii_stat1000_mod_linkmode_lpa_t(unsigned long * advertising,u32 lpa)29978a24df3SAndrew Lunn static inline void mii_stat1000_mod_linkmode_lpa_t(unsigned long *advertising,
300c0ec3c27SAndrew Lunn 						   u32 lpa)
301c0ec3c27SAndrew Lunn {
30278a24df3SAndrew Lunn 	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
30378a24df3SAndrew Lunn 			 advertising, lpa & LPA_1000HALF);
30478a24df3SAndrew Lunn 
30578a24df3SAndrew Lunn 	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
30678a24df3SAndrew Lunn 			 advertising, lpa & LPA_1000FULL);
307c0ec3c27SAndrew Lunn }
308c0ec3c27SAndrew Lunn 
309c0ec3c27SAndrew Lunn /**
31037f07023SMatt Carlson  * ethtool_adv_to_mii_adv_x
31128011cf1SMatt Carlson  * @ethadv: the ethtool advertisement settings
31228011cf1SMatt Carlson  *
31328011cf1SMatt Carlson  * A small helper function that translates ethtool advertisement
31428011cf1SMatt Carlson  * settings to phy autonegotiation advertisements for the
31528011cf1SMatt Carlson  * MII_CTRL1000 register when in 1000Base-X mode.
31628011cf1SMatt Carlson  */
ethtool_adv_to_mii_adv_x(u32 ethadv)31737f07023SMatt Carlson static inline u32 ethtool_adv_to_mii_adv_x(u32 ethadv)
31828011cf1SMatt Carlson {
31928011cf1SMatt Carlson 	u32 result = 0;
32028011cf1SMatt Carlson 
32128011cf1SMatt Carlson 	if (ethadv & ADVERTISED_1000baseT_Half)
32228011cf1SMatt Carlson 		result |= ADVERTISE_1000XHALF;
32328011cf1SMatt Carlson 	if (ethadv & ADVERTISED_1000baseT_Full)
32428011cf1SMatt Carlson 		result |= ADVERTISE_1000XFULL;
32528011cf1SMatt Carlson 	if (ethadv & ADVERTISED_Pause)
32628011cf1SMatt Carlson 		result |= ADVERTISE_1000XPAUSE;
32728011cf1SMatt Carlson 	if (ethadv & ADVERTISED_Asym_Pause)
32828011cf1SMatt Carlson 		result |= ADVERTISE_1000XPSE_ASYM;
32928011cf1SMatt Carlson 
33028011cf1SMatt Carlson 	return result;
33128011cf1SMatt Carlson }
33228011cf1SMatt Carlson 
33328011cf1SMatt Carlson /**
33437f07023SMatt Carlson  * mii_adv_to_ethtool_adv_x
33528011cf1SMatt Carlson  * @adv: value of the MII_CTRL1000 register
33628011cf1SMatt Carlson  *
33728011cf1SMatt Carlson  * A small helper function that translates MII_CTRL1000
33828011cf1SMatt Carlson  * bits, when in 1000Base-X mode, to ethtool
33928011cf1SMatt Carlson  * advertisement settings.
34028011cf1SMatt Carlson  */
mii_adv_to_ethtool_adv_x(u32 adv)34137f07023SMatt Carlson static inline u32 mii_adv_to_ethtool_adv_x(u32 adv)
34228011cf1SMatt Carlson {
34328011cf1SMatt Carlson 	u32 result = 0;
34428011cf1SMatt Carlson 
34528011cf1SMatt Carlson 	if (adv & ADVERTISE_1000XHALF)
34628011cf1SMatt Carlson 		result |= ADVERTISED_1000baseT_Half;
34728011cf1SMatt Carlson 	if (adv & ADVERTISE_1000XFULL)
34828011cf1SMatt Carlson 		result |= ADVERTISED_1000baseT_Full;
34928011cf1SMatt Carlson 	if (adv & ADVERTISE_1000XPAUSE)
35028011cf1SMatt Carlson 		result |= ADVERTISED_Pause;
35128011cf1SMatt Carlson 	if (adv & ADVERTISE_1000XPSE_ASYM)
35228011cf1SMatt Carlson 		result |= ADVERTISED_Asym_Pause;
35328011cf1SMatt Carlson 
35428011cf1SMatt Carlson 	return result;
35528011cf1SMatt Carlson }
35628011cf1SMatt Carlson 
35728011cf1SMatt Carlson /**
358d3351931SAndrew Lunn  * mii_adv_mod_linkmode_adv_t
359d3351931SAndrew Lunn  * @advertising:pointer to destination link mode.
360d3351931SAndrew Lunn  * @adv: value of the MII_ADVERTISE register
361d3351931SAndrew Lunn  *
362d3351931SAndrew Lunn  * A small helper function that translates MII_ADVERTISE bits to
363d3351931SAndrew Lunn  * linkmode advertisement settings. Leaves other bits unchanged.
364d3351931SAndrew Lunn  */
mii_adv_mod_linkmode_adv_t(unsigned long * advertising,u32 adv)365d3351931SAndrew Lunn static inline void mii_adv_mod_linkmode_adv_t(unsigned long *advertising,
366d3351931SAndrew Lunn 					      u32 adv)
367d3351931SAndrew Lunn {
368d3351931SAndrew Lunn 	linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
369d3351931SAndrew Lunn 			 advertising, adv & ADVERTISE_10HALF);
370d3351931SAndrew Lunn 
371d3351931SAndrew Lunn 	linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
372d3351931SAndrew Lunn 			 advertising, adv & ADVERTISE_10FULL);
373d3351931SAndrew Lunn 
374d3351931SAndrew Lunn 	linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
375d3351931SAndrew Lunn 			 advertising, adv & ADVERTISE_100HALF);
376d3351931SAndrew Lunn 
377d3351931SAndrew Lunn 	linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
378d3351931SAndrew Lunn 			 advertising, adv & ADVERTISE_100FULL);
379d3351931SAndrew Lunn 
380d3351931SAndrew Lunn 	linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising,
381d3351931SAndrew Lunn 			 adv & ADVERTISE_PAUSE_CAP);
382d3351931SAndrew Lunn 
383d3351931SAndrew Lunn 	linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
384d3351931SAndrew Lunn 			 advertising, adv & ADVERTISE_PAUSE_ASYM);
385d3351931SAndrew Lunn }
386d3351931SAndrew Lunn 
387d3351931SAndrew Lunn /**
388edc7ccbbSAndrew Lunn  * mii_adv_to_linkmode_adv_t
389edc7ccbbSAndrew Lunn  * @advertising:pointer to destination link mode.
390edc7ccbbSAndrew Lunn  * @adv: value of the MII_ADVERTISE register
391edc7ccbbSAndrew Lunn  *
392edc7ccbbSAndrew Lunn  * A small helper function that translates MII_ADVERTISE bits
3935f15eed2SAndrew Lunn  * to linkmode advertisement settings. Clears the old value
3945f15eed2SAndrew Lunn  * of advertising.
395edc7ccbbSAndrew Lunn  */
mii_adv_to_linkmode_adv_t(unsigned long * advertising,u32 adv)396edc7ccbbSAndrew Lunn static inline void mii_adv_to_linkmode_adv_t(unsigned long *advertising,
397edc7ccbbSAndrew Lunn 					     u32 adv)
398edc7ccbbSAndrew Lunn {
399edc7ccbbSAndrew Lunn 	linkmode_zero(advertising);
400edc7ccbbSAndrew Lunn 
401d3351931SAndrew Lunn 	mii_adv_mod_linkmode_adv_t(advertising, adv);
402edc7ccbbSAndrew Lunn }
403edc7ccbbSAndrew Lunn 
404edc7ccbbSAndrew Lunn /**
405c0ec3c27SAndrew Lunn  * mii_lpa_to_linkmode_lpa_t
406c0ec3c27SAndrew Lunn  * @adv: value of the MII_LPA register
407c0ec3c27SAndrew Lunn  *
408c0ec3c27SAndrew Lunn  * A small helper function that translates MII_LPA bits, when in
4095f15eed2SAndrew Lunn  * 1000Base-T mode, to linkmode LP advertisement settings. Clears the
4105f15eed2SAndrew Lunn  * old value of advertising
411c0ec3c27SAndrew Lunn  */
mii_lpa_to_linkmode_lpa_t(unsigned long * lp_advertising,u32 lpa)412c0ec3c27SAndrew Lunn static inline void mii_lpa_to_linkmode_lpa_t(unsigned long *lp_advertising,
413c0ec3c27SAndrew Lunn 					     u32 lpa)
414c0ec3c27SAndrew Lunn {
4155f15eed2SAndrew Lunn 	mii_adv_to_linkmode_adv_t(lp_advertising, lpa);
4165f15eed2SAndrew Lunn 
417c0ec3c27SAndrew Lunn 	if (lpa & LPA_LPACK)
418c0ec3c27SAndrew Lunn 		linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
419c0ec3c27SAndrew Lunn 				 lp_advertising);
420c0ec3c27SAndrew Lunn 
421c0ec3c27SAndrew Lunn }
422c0ec3c27SAndrew Lunn 
423c0ec3c27SAndrew Lunn /**
424d3351931SAndrew Lunn  * mii_lpa_mod_linkmode_lpa_t
425d3351931SAndrew Lunn  * @adv: value of the MII_LPA register
426d3351931SAndrew Lunn  *
427d3351931SAndrew Lunn  * A small helper function that translates MII_LPA bits, when in
428d3351931SAndrew Lunn  * 1000Base-T mode, to linkmode LP advertisement settings. Leaves
429d3351931SAndrew Lunn  * other bits unchanged.
430d3351931SAndrew Lunn  */
mii_lpa_mod_linkmode_lpa_t(unsigned long * lp_advertising,u32 lpa)431d3351931SAndrew Lunn static inline void mii_lpa_mod_linkmode_lpa_t(unsigned long *lp_advertising,
432d3351931SAndrew Lunn 					      u32 lpa)
433d3351931SAndrew Lunn {
434d3351931SAndrew Lunn 	mii_adv_mod_linkmode_adv_t(lp_advertising, lpa);
435d3351931SAndrew Lunn 
4366dbd0090SAndrew Lunn 	linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
4376dbd0090SAndrew Lunn 			 lp_advertising, lpa & LPA_LPACK);
438d3351931SAndrew Lunn }
439d3351931SAndrew Lunn 
mii_ctrl1000_mod_linkmode_adv_t(unsigned long * advertising,u32 ctrl1000)4404cf6c57eSRussell King static inline void mii_ctrl1000_mod_linkmode_adv_t(unsigned long *advertising,
4414cf6c57eSRussell King 						   u32 ctrl1000)
4424cf6c57eSRussell King {
4434cf6c57eSRussell King 	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertising,
4444cf6c57eSRussell King 			 ctrl1000 & ADVERTISE_1000HALF);
4454cf6c57eSRussell King 	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertising,
4464cf6c57eSRussell King 			 ctrl1000 & ADVERTISE_1000FULL);
4474cf6c57eSRussell King }
4484cf6c57eSRussell King 
449d3351931SAndrew Lunn /**
4503c1bcc86SAndrew Lunn  * linkmode_adv_to_lcl_adv_t
4513c1bcc86SAndrew Lunn  * @advertising:pointer to linkmode advertising
4525f991f7bSAndrew Lunn  *
4533c1bcc86SAndrew Lunn  * A small helper function that translates linkmode advertising to LVL
4545f991f7bSAndrew Lunn  * pause capabilities.
4555f991f7bSAndrew Lunn  */
linkmode_adv_to_lcl_adv_t(unsigned long * advertising)4563c1bcc86SAndrew Lunn static inline u32 linkmode_adv_to_lcl_adv_t(unsigned long *advertising)
4575f991f7bSAndrew Lunn {
4585f991f7bSAndrew Lunn 	u32 lcl_adv = 0;
4595f991f7bSAndrew Lunn 
4603c1bcc86SAndrew Lunn 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
4613c1bcc86SAndrew Lunn 			      advertising))
4625f991f7bSAndrew Lunn 		lcl_adv |= ADVERTISE_PAUSE_CAP;
4637f07e5f1SClaudiu Manoil 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
4643c1bcc86SAndrew Lunn 			      advertising))
4655f991f7bSAndrew Lunn 		lcl_adv |= ADVERTISE_PAUSE_ASYM;
4665f991f7bSAndrew Lunn 
4675f991f7bSAndrew Lunn 	return lcl_adv;
4685f991f7bSAndrew Lunn }
4695f991f7bSAndrew Lunn 
4705f991f7bSAndrew Lunn /**
471f6554187SRussell King  * mii_lpa_mod_linkmode_x - decode the link partner's config_reg to linkmodes
472f6554187SRussell King  * @linkmodes: link modes array
473f6554187SRussell King  * @lpa: config_reg word from link partner
474f6554187SRussell King  * @fd_bit: link mode for 1000XFULL bit
475f6554187SRussell King  */
mii_lpa_mod_linkmode_x(unsigned long * linkmodes,u16 lpa,int fd_bit)476f6554187SRussell King static inline void mii_lpa_mod_linkmode_x(unsigned long *linkmodes, u16 lpa,
477f6554187SRussell King 					 int fd_bit)
478f6554187SRussell King {
479f6554187SRussell King 	linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, linkmodes,
480f6554187SRussell King 			 lpa & LPA_LPACK);
481f6554187SRussell King 	linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes,
482f6554187SRussell King 			 lpa & LPA_1000XPAUSE);
483f6554187SRussell King 	linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes,
484f6554187SRussell King 			 lpa & LPA_1000XPAUSE_ASYM);
485f6554187SRussell King 	linkmode_mod_bit(fd_bit, linkmodes,
486f6554187SRussell King 			 lpa & LPA_1000XFULL);
487f6554187SRussell King }
488f6554187SRussell King 
489f6554187SRussell King /**
490a9f28ebaSRussell King  * linkmode_adv_to_mii_adv_x - encode a linkmode to config_reg
491a9f28ebaSRussell King  * @linkmodes: linkmodes
492a9f28ebaSRussell King  * @fd_bit: full duplex bit
493a9f28ebaSRussell King  */
linkmode_adv_to_mii_adv_x(const unsigned long * linkmodes,int fd_bit)494a9f28ebaSRussell King static inline u16 linkmode_adv_to_mii_adv_x(const unsigned long *linkmodes,
495a9f28ebaSRussell King 					    int fd_bit)
496a9f28ebaSRussell King {
497a9f28ebaSRussell King 	u16 adv = 0;
498a9f28ebaSRussell King 
499a9f28ebaSRussell King 	if (linkmode_test_bit(fd_bit, linkmodes))
500a9f28ebaSRussell King 		adv |= ADVERTISE_1000XFULL;
501a9f28ebaSRussell King 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes))
502a9f28ebaSRussell King 		adv |= ADVERTISE_1000XPAUSE;
503a9f28ebaSRussell King 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes))
504a9f28ebaSRussell King 		adv |= ADVERTISE_1000XPSE_ASYM;
505a9f28ebaSRussell King 
506a9f28ebaSRussell King 	return adv;
507a9f28ebaSRussell King }
508a9f28ebaSRussell King 
509a9f28ebaSRussell King /**
510a8c30832SBen Hutchings  * mii_advertise_flowctrl - get flow control advertisement flags
511a8c30832SBen Hutchings  * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both)
512a8c30832SBen Hutchings  */
mii_advertise_flowctrl(int cap)513a8c30832SBen Hutchings static inline u16 mii_advertise_flowctrl(int cap)
514a8c30832SBen Hutchings {
515a8c30832SBen Hutchings 	u16 adv = 0;
516a8c30832SBen Hutchings 
517a8c30832SBen Hutchings 	if (cap & FLOW_CTRL_RX)
518a8c30832SBen Hutchings 		adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
519a8c30832SBen Hutchings 	if (cap & FLOW_CTRL_TX)
520a8c30832SBen Hutchings 		adv ^= ADVERTISE_PAUSE_ASYM;
521a8c30832SBen Hutchings 
522a8c30832SBen Hutchings 	return adv;
523a8c30832SBen Hutchings }
524a8c30832SBen Hutchings 
525a8c30832SBen Hutchings /**
526bc02ff95SSteve Glendinning  * mii_resolve_flowctrl_fdx
527bc02ff95SSteve Glendinning  * @lcladv: value of MII ADVERTISE register
528bc02ff95SSteve Glendinning  * @rmtadv: value of MII LPA register
529bc02ff95SSteve Glendinning  *
530bc02ff95SSteve Glendinning  * Resolve full duplex flow control as per IEEE 802.3-2005 table 28B-3
531bc02ff95SSteve Glendinning  */
mii_resolve_flowctrl_fdx(u16 lcladv,u16 rmtadv)532bc02ff95SSteve Glendinning static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv)
533bc02ff95SSteve Glendinning {
534bc02ff95SSteve Glendinning 	u8 cap = 0;
535bc02ff95SSteve Glendinning 
53644c22ee9SBen Hutchings 	if (lcladv & rmtadv & ADVERTISE_PAUSE_CAP) {
537bc02ff95SSteve Glendinning 		cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
53844c22ee9SBen Hutchings 	} else if (lcladv & rmtadv & ADVERTISE_PAUSE_ASYM) {
53944c22ee9SBen Hutchings 		if (lcladv & ADVERTISE_PAUSE_CAP)
540bc02ff95SSteve Glendinning 			cap = FLOW_CTRL_RX;
54144c22ee9SBen Hutchings 		else if (rmtadv & ADVERTISE_PAUSE_CAP)
542bc02ff95SSteve Glendinning 			cap = FLOW_CTRL_TX;
543bc02ff95SSteve Glendinning 	}
544bc02ff95SSteve Glendinning 
545bc02ff95SSteve Glendinning 	return cap;
546bc02ff95SSteve Glendinning }
547bc02ff95SSteve Glendinning 
548*bdb6cfe7SRussell King (Oracle) /**
549*bdb6cfe7SRussell King (Oracle)  * mii_bmcr_encode_fixed - encode fixed speed/duplex settings to a BMCR value
550*bdb6cfe7SRussell King (Oracle)  * @speed: a SPEED_* value
551*bdb6cfe7SRussell King (Oracle)  * @duplex: a DUPLEX_* value
552*bdb6cfe7SRussell King (Oracle)  *
553*bdb6cfe7SRussell King (Oracle)  * Encode the speed and duplex to a BMCR value. 2500, 1000, 100 and 10 Mbps are
554*bdb6cfe7SRussell King (Oracle)  * supported. 2500Mbps is encoded to 1000Mbps. Other speeds are encoded as 10
555*bdb6cfe7SRussell King (Oracle)  * Mbps. Unknown duplex values are encoded to half-duplex.
556*bdb6cfe7SRussell King (Oracle)  */
mii_bmcr_encode_fixed(int speed,int duplex)557*bdb6cfe7SRussell King (Oracle) static inline u16 mii_bmcr_encode_fixed(int speed, int duplex)
558*bdb6cfe7SRussell King (Oracle) {
559*bdb6cfe7SRussell King (Oracle) 	u16 bmcr;
560*bdb6cfe7SRussell King (Oracle) 
561*bdb6cfe7SRussell King (Oracle) 	switch (speed) {
562*bdb6cfe7SRussell King (Oracle) 	case SPEED_2500:
563*bdb6cfe7SRussell King (Oracle) 	case SPEED_1000:
564*bdb6cfe7SRussell King (Oracle) 		bmcr = BMCR_SPEED1000;
565*bdb6cfe7SRussell King (Oracle) 		break;
566*bdb6cfe7SRussell King (Oracle) 
567*bdb6cfe7SRussell King (Oracle) 	case SPEED_100:
568*bdb6cfe7SRussell King (Oracle) 		bmcr = BMCR_SPEED100;
569*bdb6cfe7SRussell King (Oracle) 		break;
570*bdb6cfe7SRussell King (Oracle) 
571*bdb6cfe7SRussell King (Oracle) 	case SPEED_10:
572*bdb6cfe7SRussell King (Oracle) 	default:
573*bdb6cfe7SRussell King (Oracle) 		bmcr = BMCR_SPEED10;
574*bdb6cfe7SRussell King (Oracle) 		break;
575*bdb6cfe7SRussell King (Oracle) 	}
576*bdb6cfe7SRussell King (Oracle) 
577*bdb6cfe7SRussell King (Oracle) 	if (duplex == DUPLEX_FULL)
578*bdb6cfe7SRussell King (Oracle) 		bmcr |= BMCR_FULLDPLX;
579*bdb6cfe7SRussell King (Oracle) 
580*bdb6cfe7SRussell King (Oracle) 	return bmcr;
581*bdb6cfe7SRussell King (Oracle) }
582*bdb6cfe7SRussell King (Oracle) 
5831da177e4SLinus Torvalds #endif /* __LINUX_MII_H__ */
584