diff mbox series

[PATH,RFC,net-next,7/8] net: phy: Replace phy driver features u32 with link_mode bitmap

Message ID 1536961136-30453-8-git-send-email-andrew@lunn.ch
State RFC, archived
Delegated to: David Miller
Headers show
Series Continue towards using linkmode in phylib | expand

Commit Message

Andrew Lunn Sept. 14, 2018, 9:38 p.m. UTC
This is one step in allowing phylib to make use of link_mode bitmaps,
instead of u32 for supported and advertised features. Convert the phy
drivers to use bitmaps to indicates the features they support. This
requires some macro magic in order to construct constant bitmaps used
to initialise the driver structures.

Some new PHY_*_FEATURES are added, to indicate FIBRE is supported, and
that all media ports are supported. This is done since bitmaps cannot
be ORed together at compile time.

Within phylib, the features bitmap is currently turned back into a
u32.  The MAC API to phylib needs to be cleaned up before the core of
phylib can be converted to using bitmaps instead of u32.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/marvell/pxa168_eth.c |   4 +-
 drivers/net/phy/aquantia.c                |  12 +-
 drivers/net/phy/bcm63xx.c                 |   9 +-
 drivers/net/phy/marvell.c                 |   2 +-
 drivers/net/phy/marvell10g.c              |  11 +-
 drivers/net/phy/microchip_t1.c            |   2 +-
 drivers/net/phy/phy_device.c              | 204 +++++++++++++++++++++-
 include/linux/phy.h                       |  24 ++-
 8 files changed, 229 insertions(+), 39 deletions(-)

Comments

Florian Fainelli Sept. 15, 2018, 9:31 p.m. UTC | #1
On 09/14/18 14:38, Andrew Lunn wrote:
> This is one step in allowing phylib to make use of link_mode bitmaps,
> instead of u32 for supported and advertised features. Convert the phy
> drivers to use bitmaps to indicates the features they support. This
> requires some macro magic in order to construct constant bitmaps used
> to initialise the driver structures.
> 
> Some new PHY_*_FEATURES are added, to indicate FIBRE is supported, and
> that all media ports are supported. This is done since bitmaps cannot
> be ORed together at compile time.
> 
> Within phylib, the features bitmap is currently turned back into a
> u32.  The MAC API to phylib needs to be cleaned up before the core of
> phylib can be converted to using bitmaps instead of u32.

Nice!

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Andrew Lunn Sept. 15, 2018, 10:30 p.m. UTC | #2
On Sat, Sep 15, 2018 at 02:31:14PM -0700, Florian Fainelli wrote:
> 
> 
> On 09/14/18 14:38, Andrew Lunn wrote:
> > This is one step in allowing phylib to make use of link_mode bitmaps,
> > instead of u32 for supported and advertised features. Convert the phy
> > drivers to use bitmaps to indicates the features they support. This
> > requires some macro magic in order to construct constant bitmaps used
> > to initialise the driver structures.
> > 
> > Some new PHY_*_FEATURES are added, to indicate FIBRE is supported, and
> > that all media ports are supported. This is done since bitmaps cannot
> > be ORed together at compile time.
> > 
> > Within phylib, the features bitmap is currently turned back into a
> > u32.  The MAC API to phylib needs to be cleaned up before the core of
> > phylib can be converted to using bitmaps instead of u32.
> 
> Nice!

Hi Florian

This is the patch i don't like. I'm hoping somebody can think of a
better way to initialise a bitmap.

       Andrew
Florian Fainelli Sept. 16, 2018, 4:20 p.m. UTC | #3
Hi Andrew,

On September 15, 2018 3:30:53 PM PDT, Andrew Lunn <andrew@lunn.ch> wrote:
>On Sat, Sep 15, 2018 at 02:31:14PM -0700, Florian Fainelli wrote:
>> 
>> 
>> On 09/14/18 14:38, Andrew Lunn wrote:
>> > This is one step in allowing phylib to make use of link_mode
>bitmaps,
>> > instead of u32 for supported and advertised features. Convert the
>phy
>> > drivers to use bitmaps to indicates the features they support. This
>> > requires some macro magic in order to construct constant bitmaps
>used
>> > to initialise the driver structures.
>> > 
>> > Some new PHY_*_FEATURES are added, to indicate FIBRE is supported,
>and
>> > that all media ports are supported. This is done since bitmaps
>cannot
>> > be ORed together at compile time.
>> > 
>> > Within phylib, the features bitmap is currently turned back into a
>> > u32.  The MAC API to phylib needs to be cleaned up before the core
>of
>> > phylib can be converted to using bitmaps instead of u32.
>> 
>> Nice!
>
>Hi Florian
>
>This is the patch i don't like. I'm hoping somebody can think of a
>better way to initialise a bitmap.

By that you mean having to determine whether you overflow the capacity of an unsigned long storage type and having to put the bits in either unsigned long [0] or [1]? Being able to eliminate the duplication would also be nice, but I cannot think about a smart solution at compile time that would avoid doing that.
Andrew Lunn Sept. 16, 2018, 5:59 p.m. UTC | #4
> By that you mean having to determine whether you overflow the
> capacity of an unsigned long storage type and having to put the bits
> in either unsigned long [0] or [1]? Being able to eliminate the
> duplication would also be nice, but I cannot think about a smart
> solution at compile time that would avoid doing that.

Hi Florian

I've given up on doing it at compile time. I'm working on a run-time
solution at the moment, which i think looks better. I will probably
split the patchset. Post for merging all but the last two patches, and
then an RFC for replacing this patch.

    Andrew
diff mbox series

Patch

diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index 3a9730612a70..b406395bbb37 100644
--- a/drivers/net/ethernet/marvell/pxa168_eth.c
+++ b/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -988,8 +988,8 @@  static int pxa168_init_phy(struct net_device *dev)
 	cmd.base.phy_address = pep->phy_addr;
 	cmd.base.speed = pep->phy_speed;
 	cmd.base.duplex = pep->phy_duplex;
-	ethtool_convert_legacy_u32_to_link_mode(cmd.link_modes.advertising,
-						PHY_BASIC_FEATURES);
+	bitmap_copy(cmd.link_modes.advertising, PHY_BASIC_FEATURES,
+		    __ETHTOOL_LINK_MODE_MASK_NBITS);
 	cmd.base.autoneg = AUTONEG_ENABLE;
 
 	if (cmd.base.speed != 0)
diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c
index 319edc9c8ec7..632472cab3bb 100644
--- a/drivers/net/phy/aquantia.c
+++ b/drivers/net/phy/aquantia.c
@@ -115,7 +115,7 @@  static struct phy_driver aquantia_driver[] = {
 	.phy_id		= PHY_ID_AQ1202,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Aquantia AQ1202",
-	.features	= PHY_AQUANTIA_FEATURES,
+	.features	= PHY_10GBIT_FULL_FEATURES,
 	.flags		= PHY_HAS_INTERRUPT,
 	.aneg_done	= genphy_c45_aneg_done,
 	.config_aneg    = aquantia_config_aneg,
@@ -127,7 +127,7 @@  static struct phy_driver aquantia_driver[] = {
 	.phy_id		= PHY_ID_AQ2104,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Aquantia AQ2104",
-	.features	= PHY_AQUANTIA_FEATURES,
+	.features	= PHY_10GBIT_FULL_FEATURES,
 	.flags		= PHY_HAS_INTERRUPT,
 	.aneg_done	= genphy_c45_aneg_done,
 	.config_aneg    = aquantia_config_aneg,
@@ -139,7 +139,7 @@  static struct phy_driver aquantia_driver[] = {
 	.phy_id		= PHY_ID_AQR105,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Aquantia AQR105",
-	.features	= PHY_AQUANTIA_FEATURES,
+	.features	= PHY_10GBIT_FULL_FEATURES,
 	.flags		= PHY_HAS_INTERRUPT,
 	.aneg_done	= genphy_c45_aneg_done,
 	.config_aneg    = aquantia_config_aneg,
@@ -151,7 +151,7 @@  static struct phy_driver aquantia_driver[] = {
 	.phy_id		= PHY_ID_AQR106,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Aquantia AQR106",
-	.features	= PHY_AQUANTIA_FEATURES,
+	.features	= PHY_10GBIT_FULL_FEATURES,
 	.flags		= PHY_HAS_INTERRUPT,
 	.aneg_done	= genphy_c45_aneg_done,
 	.config_aneg    = aquantia_config_aneg,
@@ -163,7 +163,7 @@  static struct phy_driver aquantia_driver[] = {
 	.phy_id		= PHY_ID_AQR107,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Aquantia AQR107",
-	.features	= PHY_AQUANTIA_FEATURES,
+	.features	= PHY_10GBIT_FULL_FEATURES,
 	.flags		= PHY_HAS_INTERRUPT,
 	.aneg_done	= genphy_c45_aneg_done,
 	.config_aneg    = aquantia_config_aneg,
@@ -175,7 +175,7 @@  static struct phy_driver aquantia_driver[] = {
 	.phy_id		= PHY_ID_AQR405,
 	.phy_id_mask	= 0xfffffff0,
 	.name		= "Aquantia AQR405",
-	.features	= PHY_AQUANTIA_FEATURES,
+	.features	= PHY_10GBIT_FULL_FEATURES,
 	.flags		= PHY_HAS_INTERRUPT,
 	.aneg_done	= genphy_c45_aneg_done,
 	.config_aneg    = aquantia_config_aneg,
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
index cf14613745c9..ff5acf01b877 100644
--- a/drivers/net/phy/bcm63xx.c
+++ b/drivers/net/phy/bcm63xx.c
@@ -42,6 +42,9 @@  static int bcm63xx_config_init(struct phy_device *phydev)
 {
 	int reg, err;
 
+	/* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
+	linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported),
+
 	reg = phy_read(phydev, MII_BCM63XX_IR);
 	if (reg < 0)
 		return reg;
@@ -65,8 +68,7 @@  static struct phy_driver bcm63xx_driver[] = {
 	.phy_id		= 0x00406000,
 	.phy_id_mask	= 0xfffffc00,
 	.name		= "Broadcom BCM63XX (1)",
-	/* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
-	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.features	= PHY_BASIC_FEATURES,
 	.flags		= PHY_HAS_INTERRUPT | PHY_IS_INTERNAL,
 	.config_init	= bcm63xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
@@ -75,8 +77,7 @@  static struct phy_driver bcm63xx_driver[] = {
 	/* same phy as above, with just a different OUI */
 	.phy_id		= 0x002bdc00,
 	.phy_id_mask	= 0xfffffc00,
-	.name		= "Broadcom BCM63XX (2)",
-	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+	.features	= PHY_BASIC_FEATURES,
 	.flags		= PHY_HAS_INTERRUPT | PHY_IS_INTERNAL,
 	.config_init	= bcm63xx_config_init,
 	.ack_interrupt	= bcm_phy_ack_intr,
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index f7c69ca34056..de1e900f7253 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2222,7 +2222,7 @@  static struct phy_driver marvell_drivers[] = {
 		.phy_id = MARVELL_PHY_ID_88E1510,
 		.phy_id_mask = MARVELL_PHY_ID_MASK,
 		.name = "Marvell 88E1510",
-		.features = PHY_GBIT_FEATURES | SUPPORTED_FIBRE,
+		.features = PHY_GBIT_FIBRE_FEATURES,
 		.flags = PHY_HAS_INTERRUPT,
 		.probe = &m88e1510_probe,
 		.config_init = &m88e1510_config_init,
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index f77a2d9e7f9d..7f4a43c65da6 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -535,16 +535,7 @@  static struct phy_driver mv3310_drivers[] = {
 		.phy_id		= 0x002b09aa,
 		.phy_id_mask	= MARVELL_PHY_ID_MASK,
 		.name		= "mv88x3310",
-		.features	= SUPPORTED_10baseT_Full |
-				  SUPPORTED_10baseT_Half |
-				  SUPPORTED_100baseT_Full |
-				  SUPPORTED_100baseT_Half |
-				  SUPPORTED_1000baseT_Full |
-				  SUPPORTED_Autoneg |
-				  SUPPORTED_TP |
-				  SUPPORTED_FIBRE |
-				  SUPPORTED_10000baseT_Full |
-				  SUPPORTED_Backplane,
+		.features	= PHY_10GBIT_FEATURES,
 		.soft_reset	= gen10g_no_soft_reset,
 		.config_init	= mv3310_config_init,
 		.probe		= mv3310_probe,
diff --git a/drivers/net/phy/microchip_t1.c b/drivers/net/phy/microchip_t1.c
index b1917dd1978a..c600a8509d60 100644
--- a/drivers/net/phy/microchip_t1.c
+++ b/drivers/net/phy/microchip_t1.c
@@ -46,7 +46,7 @@  static struct phy_driver microchip_t1_phy_driver[] = {
 		.phy_id_mask    = 0xfffffff0,
 		.name           = "Microchip LAN87xx T1",
 
-		.features       = SUPPORTED_100baseT_Full,
+		.features       = PHY_BASIC_T1_FEATURES,
 		.flags          = PHY_HAS_INTERRUPT,
 
 		.config_init    = genphy_config_init,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index af64a9320fb0..eed61ee1d394 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -29,6 +29,7 @@ 
 #include <linux/module.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/bitmap.h>
 #include <linux/phy.h>
 #include <linux/phy_led_triggers.h>
 #include <linux/mdio.h>
@@ -42,6 +43,191 @@  MODULE_DESCRIPTION("PHY library");
 MODULE_AUTHOR("Andy Fleming");
 MODULE_LICENSE("GPL");
 
+#define BIT_IN_RANGE(bit, lower, upper)			\
+	((bit) < (lower) ? 0 : ((bit) > (upper) ? 0 :	\
+				 BIT((bit) - (lower))))
+
+#define BIT_IN_LONG_ARRAY(bit, index)				\
+	BIT_IN_RANGE(bit, (BITS_PER_LONG * (index)),		\
+		     (BITS_PER_LONG * ((index) + 1)) - 1)
+
+#define BIT_IN_LONG_ARRAY_0(bit) BIT_IN_LONG_ARRAY(bit, 0)
+#define BIT_IN_LONG_ARRAY_1(bit) BIT_IN_LONG_ARRAY(bit, 1)
+#define BIT_IN_LONG_ARRAY_2(bit) BIT_IN_LONG_ARRAY(bit, 2)
+
+const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_features) = {
+	[0] = (BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_Autoneg_BIT)	|
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_TP_BIT)		|
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_MII_BIT)		|
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10baseT_Half_BIT)	|
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	|
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Half_BIT)	|
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Full_BIT)),
+#if BITS_PER_LONG == 32
+	[1] = (BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_Autoneg_BIT)	|
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_TP_BIT)		|
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_MII_BIT)		|
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10baseT_Half_BIT)	|
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	|
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Half_BIT)	|
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Full_BIT)),
+#endif
+};
+EXPORT_SYMBOL_GPL(phy_basic_features);
+
+const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1_features) = {
+	[0] = (BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_TP_BIT)		|
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Full_BIT)),
+#if BITS_PER_LONG == 32
+	[1] = (BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_TP_BIT)		|
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Full_BIT)),
+#endif
+};
+EXPORT_SYMBOL_GPL(phy_basic_t1_features);
+
+const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features) = {
+	[0] = (BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_Autoneg_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_TP_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_MII_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_1000baseT_Half_BIT) |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_1000baseT_Full_BIT)),
+#if BITS_PER_LONG == 32
+	[1] = (BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_Autoneg_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_TP_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_MII_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_1000baseT_Half_BIT) |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_1000baseT_Full_BIT)),
+#endif
+};
+EXPORT_SYMBOL_GPL(phy_gbit_features);
+
+const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_fibre_features) = {
+	[0] = (BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_Autoneg_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_TP_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_MII_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_FIBRE_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_1000baseT_Half_BIT) |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_1000baseT_Full_BIT)),
+#if BITS_PER_LONG == 32
+	[1] = (BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_Autoneg_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_TP_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_MII_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_FIBRE_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_1000baseT_Half_BIT) |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_1000baseT_Full_BIT)),
+#endif
+};
+EXPORT_SYMBOL_GPL(phy_gbit_fibre_features);
+
+const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_all_ports_features) = {
+	[0] = (BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_Autoneg_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_TP_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_MII_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_FIBRE_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_AUI_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_BNC_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_Backplane_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_1000baseT_Half_BIT) |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_1000baseT_Full_BIT)),
+#if BITS_PER_LONG == 32
+	[1] = (BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_Autoneg_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_TP_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_MII_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_FIBRE_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_AUI_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_BNC_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_Backplane_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_1000baseT_Half_BIT) |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_1000baseT_Full_BIT)),
+#endif
+};
+EXPORT_SYMBOL_GPL(phy_gbit_all_ports_features);
+
+const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_features) = {
+	[0] = (BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_Autoneg_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_TP_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_MII_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_FIBRE_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_AUI_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_BNC_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_Backplane_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_1000baseT_Half_BIT) |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_1000baseT_Full_BIT) |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10000baseT_Full_BIT)),
+#if BITS_PER_LONG == 32
+	[1] = (BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_Autoneg_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_TP_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_MII_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_FIBRE_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_Backplane_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Half_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_1000baseT_Half_BIT) |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_1000baseT_Full_BIT) |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10000baseT_Full_BIT)),
+#endif
+};
+EXPORT_SYMBOL_GPL(phy_10gbit_features);
+
+/* No half duplex support */
+const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) = {
+	[0] = (BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_Autoneg_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_TP_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_MII_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_FIBRE_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_AUI_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_BNC_BIT)		 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_Backplane_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_100baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_1000baseT_Full_BIT) |
+	       BIT_IN_LONG_ARRAY_0(ETHTOOL_LINK_MODE_10000baseT_Full_BIT)),
+#if BITS_PER_LONG == 32
+	[1] = (BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_Autoneg_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_TP_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_MII_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_AUI_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_BNC_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_FIBRE_BIT)		 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_Backplane_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_100baseT_Full_BIT)	 |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_1000baseT_Full_BIT) |
+	       BIT_IN_LONG_ARRAY_1(ETHTOOL_LINK_MODE_10000baseT_Full_BIT)),
+#endif
+};
+EXPORT_SYMBOL_GPL(phy_10gbit_full_features);
+
 void phy_device_free(struct phy_device *phydev)
 {
 	put_device(&phydev->mdio.dev);
@@ -1938,6 +2124,7 @@  static int phy_probe(struct device *dev)
 	struct phy_device *phydev = to_phy_device(dev);
 	struct device_driver *drv = phydev->mdio.dev.driver;
 	struct phy_driver *phydrv = to_phy_driver(drv);
+	u32 features;
 	int err = 0;
 
 	phydev->drv = phydrv;
@@ -1958,7 +2145,8 @@  static int phy_probe(struct device *dev)
 	 * a controller will attach, and may modify one
 	 * or both of these values
 	 */
-	phydev->supported = phydrv->features;
+	ethtool_convert_link_mode_to_legacy_u32(&features, phydrv->features);
+	phydev->supported = features;
 	of_set_phy_supported(phydev);
 	phydev->advertising = phydev->supported;
 
@@ -1978,10 +2166,14 @@  static int phy_probe(struct device *dev)
 	 * (e.g. hardware erratum) where the driver wants to set only one
 	 * of these bits.
 	 */
-	if (phydrv->features & (SUPPORTED_Pause | SUPPORTED_Asym_Pause)) {
+	if (test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydrv->features) ||
+	    test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydrv->features)) {
 		phydev->supported &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause);
-		phydev->supported |= phydrv->features &
-				     (SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+		if (test_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydrv->features))
+			phydev->supported |= SUPPORTED_Pause;
+		if (test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+			     phydrv->features))
+			phydev->supported |= SUPPORTED_Asym_Pause;
 	} else {
 		phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
 	}
@@ -2094,9 +2286,7 @@  static struct phy_driver genphy_driver = {
 	.name		= "Generic PHY",
 	.soft_reset	= genphy_no_soft_reset,
 	.config_init	= genphy_config_init,
-	.features	= PHY_GBIT_FEATURES | SUPPORTED_MII |
-			  SUPPORTED_AUI | SUPPORTED_FIBRE |
-			  SUPPORTED_BNC,
+	.features	= PHY_GBIT_ALL_PORTS_FEATURES,
 	.aneg_done	= genphy_aneg_done,
 	.suspend	= genphy_suspend,
 	.resume		= genphy_resume,
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 0ab9f89773fd..8343a1999e1b 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -42,13 +42,21 @@ 
 #define PHY_1000BT_FEATURES	(SUPPORTED_1000baseT_Half | \
 				 SUPPORTED_1000baseT_Full)
 
-#define PHY_BASIC_FEATURES	(PHY_10BT_FEATURES | \
-				 PHY_100BT_FEATURES | \
-				 PHY_DEFAULT_FEATURES)
-
-#define PHY_GBIT_FEATURES	(PHY_BASIC_FEATURES | \
-				 PHY_1000BT_FEATURES)
-
+extern const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_features);
+extern const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1_features);
+extern const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features);
+extern const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_fibre_features);
+extern const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_all_ports_features);
+extern const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_features);
+extern const __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features);
+
+#define PHY_BASIC_FEATURES ((unsigned long *)&phy_basic_features)
+#define PHY_BASIC_T1_FEATURES ((unsigned long *)&phy_basic_t1_features)
+#define PHY_GBIT_FEATURES ((unsigned long *)&phy_gbit_features)
+#define PHY_GBIT_FIBRE_FEATURES ((unsigned long *)&phy_gbit_fibre_features)
+#define PHY_GBIT_ALL_PORTS_FEATURES ((unsigned long *)&phy_gbit_all_ports_features)
+#define PHY_10GBIT_FEATURES ((unsigned long *)&phy_10gbit_features)
+#define PHY_10GBIT_FULL_FEATURES ((unsigned long *)&phy_10gbit_full_features)
 
 /*
  * Set phydev->irq to PHY_POLL if interrupts are not supported,
@@ -510,7 +518,7 @@  struct phy_driver {
 	u32 phy_id;
 	char *name;
 	u32 phy_id_mask;
-	u32 features;
+	const unsigned long * const features;
 	u32 flags;
 	const void *driver_data;