@@ -134,6 +134,101 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
134134 return 0 ;
135135}
136136
137+ /**
138+ * mii_ethtool_get_link_ksettings - get settings that are specified in @cmd
139+ * @mii: MII interface
140+ * @cmd: requested ethtool_link_ksettings
141+ *
142+ * The @cmd parameter is expected to have been cleared before calling
143+ * mii_ethtool_get_link_ksettings().
144+ *
145+ * Returns 0 for success, negative on error.
146+ */
147+ int mii_ethtool_get_link_ksettings (struct mii_if_info * mii ,
148+ struct ethtool_link_ksettings * cmd )
149+ {
150+ struct net_device * dev = mii -> dev ;
151+ u16 bmcr , bmsr , ctrl1000 = 0 , stat1000 = 0 ;
152+ u32 nego , supported , advertising , lp_advertising ;
153+
154+ supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
155+ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
156+ SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII );
157+ if (mii -> supports_gmii )
158+ supported |= SUPPORTED_1000baseT_Half |
159+ SUPPORTED_1000baseT_Full ;
160+
161+ /* only supports twisted-pair */
162+ cmd -> base .port = PORT_MII ;
163+
164+ /* this isn't fully supported at higher layers */
165+ cmd -> base .phy_address = mii -> phy_id ;
166+ cmd -> base .mdio_support = ETH_MDIO_SUPPORTS_C22 ;
167+
168+ advertising = ADVERTISED_TP | ADVERTISED_MII ;
169+
170+ bmcr = mii -> mdio_read (dev , mii -> phy_id , MII_BMCR );
171+ bmsr = mii -> mdio_read (dev , mii -> phy_id , MII_BMSR );
172+ if (mii -> supports_gmii ) {
173+ ctrl1000 = mii -> mdio_read (dev , mii -> phy_id , MII_CTRL1000 );
174+ stat1000 = mii -> mdio_read (dev , mii -> phy_id , MII_STAT1000 );
175+ }
176+ if (bmcr & BMCR_ANENABLE ) {
177+ advertising |= ADVERTISED_Autoneg ;
178+ cmd -> base .autoneg = AUTONEG_ENABLE ;
179+
180+ advertising |= mii_get_an (mii , MII_ADVERTISE );
181+ if (mii -> supports_gmii )
182+ advertising |= mii_ctrl1000_to_ethtool_adv_t (ctrl1000 );
183+
184+ if (bmsr & BMSR_ANEGCOMPLETE ) {
185+ lp_advertising = mii_get_an (mii , MII_LPA );
186+ lp_advertising |=
187+ mii_stat1000_to_ethtool_lpa_t (stat1000 );
188+ } else {
189+ lp_advertising = 0 ;
190+ }
191+
192+ nego = advertising & lp_advertising ;
193+
194+ if (nego & (ADVERTISED_1000baseT_Full |
195+ ADVERTISED_1000baseT_Half )) {
196+ cmd -> base .speed = SPEED_1000 ;
197+ cmd -> base .duplex = !!(nego & ADVERTISED_1000baseT_Full );
198+ } else if (nego & (ADVERTISED_100baseT_Full |
199+ ADVERTISED_100baseT_Half )) {
200+ cmd -> base .speed = SPEED_100 ;
201+ cmd -> base .duplex = !!(nego & ADVERTISED_100baseT_Full );
202+ } else {
203+ cmd -> base .speed = SPEED_10 ;
204+ cmd -> base .duplex = !!(nego & ADVERTISED_10baseT_Full );
205+ }
206+ } else {
207+ cmd -> base .autoneg = AUTONEG_DISABLE ;
208+
209+ cmd -> base .speed = ((bmcr & BMCR_SPEED1000 &&
210+ (bmcr & BMCR_SPEED100 ) == 0 ) ?
211+ SPEED_1000 :
212+ ((bmcr & BMCR_SPEED100 ) ?
213+ SPEED_100 : SPEED_10 ));
214+ cmd -> base .duplex = (bmcr & BMCR_FULLDPLX ) ?
215+ DUPLEX_FULL : DUPLEX_HALF ;
216+ }
217+
218+ mii -> full_duplex = cmd -> base .duplex ;
219+
220+ ethtool_convert_legacy_u32_to_link_mode (cmd -> link_modes .supported ,
221+ supported );
222+ ethtool_convert_legacy_u32_to_link_mode (cmd -> link_modes .advertising ,
223+ advertising );
224+ ethtool_convert_legacy_u32_to_link_mode (cmd -> link_modes .lp_advertising ,
225+ lp_advertising );
226+
227+ /* ignore maxtxpkt, maxrxpkt for now */
228+
229+ return 0 ;
230+ }
231+
137232/**
138233 * mii_ethtool_sset - set settings that are specified in @ecmd
139234 * @mii: MII interface
@@ -226,6 +321,104 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
226321 return 0 ;
227322}
228323
324+ /**
325+ * mii_ethtool_set_link_ksettings - set settings that are specified in @cmd
326+ * @mii: MII interfaces
327+ * @cmd: requested ethtool_link_ksettings
328+ *
329+ * Returns 0 for success, negative on error.
330+ */
331+ int mii_ethtool_set_link_ksettings (struct mii_if_info * mii ,
332+ const struct ethtool_link_ksettings * cmd )
333+ {
334+ struct net_device * dev = mii -> dev ;
335+ u32 speed = cmd -> base .speed ;
336+
337+ if (speed != SPEED_10 &&
338+ speed != SPEED_100 &&
339+ speed != SPEED_1000 )
340+ return - EINVAL ;
341+ if (cmd -> base .duplex != DUPLEX_HALF && cmd -> base .duplex != DUPLEX_FULL )
342+ return - EINVAL ;
343+ if (cmd -> base .port != PORT_MII )
344+ return - EINVAL ;
345+ if (cmd -> base .phy_address != mii -> phy_id )
346+ return - EINVAL ;
347+ if (cmd -> base .autoneg != AUTONEG_DISABLE &&
348+ cmd -> base .autoneg != AUTONEG_ENABLE )
349+ return - EINVAL ;
350+ if ((speed == SPEED_1000 ) && (!mii -> supports_gmii ))
351+ return - EINVAL ;
352+
353+ /* ignore supported, maxtxpkt, maxrxpkt */
354+
355+ if (cmd -> base .autoneg == AUTONEG_ENABLE ) {
356+ u32 bmcr , advert , tmp ;
357+ u32 advert2 = 0 , tmp2 = 0 ;
358+ u32 advertising ;
359+
360+ ethtool_convert_link_mode_to_legacy_u32 (
361+ & advertising , cmd -> link_modes .advertising );
362+
363+ if ((advertising & (ADVERTISED_10baseT_Half |
364+ ADVERTISED_10baseT_Full |
365+ ADVERTISED_100baseT_Half |
366+ ADVERTISED_100baseT_Full |
367+ ADVERTISED_1000baseT_Half |
368+ ADVERTISED_1000baseT_Full )) == 0 )
369+ return - EINVAL ;
370+
371+ /* advertise only what has been requested */
372+ advert = mii -> mdio_read (dev , mii -> phy_id , MII_ADVERTISE );
373+ tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4 );
374+ if (mii -> supports_gmii ) {
375+ advert2 = mii -> mdio_read (dev , mii -> phy_id ,
376+ MII_CTRL1000 );
377+ tmp2 = advert2 &
378+ ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL );
379+ }
380+ tmp |= ethtool_adv_to_mii_adv_t (advertising );
381+
382+ if (mii -> supports_gmii )
383+ tmp2 |= ethtool_adv_to_mii_ctrl1000_t (advertising );
384+ if (advert != tmp ) {
385+ mii -> mdio_write (dev , mii -> phy_id , MII_ADVERTISE , tmp );
386+ mii -> advertising = tmp ;
387+ }
388+ if ((mii -> supports_gmii ) && (advert2 != tmp2 ))
389+ mii -> mdio_write (dev , mii -> phy_id , MII_CTRL1000 , tmp2 );
390+
391+ /* turn on autonegotiation, and force a renegotiate */
392+ bmcr = mii -> mdio_read (dev , mii -> phy_id , MII_BMCR );
393+ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART );
394+ mii -> mdio_write (dev , mii -> phy_id , MII_BMCR , bmcr );
395+
396+ mii -> force_media = 0 ;
397+ } else {
398+ u32 bmcr , tmp ;
399+
400+ /* turn off auto negotiation, set speed and duplexity */
401+ bmcr = mii -> mdio_read (dev , mii -> phy_id , MII_BMCR );
402+ tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
403+ BMCR_SPEED1000 | BMCR_FULLDPLX );
404+ if (speed == SPEED_1000 )
405+ tmp |= BMCR_SPEED1000 ;
406+ else if (speed == SPEED_100 )
407+ tmp |= BMCR_SPEED100 ;
408+ if (cmd -> base .duplex == DUPLEX_FULL ) {
409+ tmp |= BMCR_FULLDPLX ;
410+ mii -> full_duplex = 1 ;
411+ } else {
412+ mii -> full_duplex = 0 ;
413+ }
414+ if (bmcr != tmp )
415+ mii -> mdio_write (dev , mii -> phy_id , MII_BMCR , tmp );
416+
417+ mii -> force_media = 1 ;
418+ }
419+ return 0 ;
420+ }
421+
229422/**
230423 * mii_check_gmii_support - check if the MII supports Gb interfaces
231424 * @mii: the MII interface
@@ -466,7 +659,9 @@ MODULE_LICENSE("GPL");
466659EXPORT_SYMBOL (mii_link_ok );
467660EXPORT_SYMBOL (mii_nway_restart );
468661EXPORT_SYMBOL (mii_ethtool_gset );
662+ EXPORT_SYMBOL (mii_ethtool_get_link_ksettings );
469663EXPORT_SYMBOL (mii_ethtool_sset );
664+ EXPORT_SYMBOL (mii_ethtool_set_link_ksettings );
470665EXPORT_SYMBOL (mii_check_link );
471666EXPORT_SYMBOL (mii_check_media );
472667EXPORT_SYMBOL (mii_check_gmii_support );
0 commit comments