net: phy: Replace phy driver features u32 with link_mode bitmap
authorAndrew Lunn <andrew@lunn.ch>
Sat, 29 Sep 2018 21:04:16 +0000 (23:04 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 2 Oct 2018 05:55:36 +0000 (22:55 -0700)
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.

Build bitmap equivalents of the u32 values at runtime, and have the
drivers point to the appropriate bitmap. These bitmaps are shared, and
we don't want a driver to modify them. So mark them __ro_after_init.

Within phylib, the features bitmap is currently turned back into a
u32. This will be removed once the whole of phylib, and the drivers
are converted to use bitmaps.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/pxa168_eth.c
drivers/net/phy/aquantia.c
drivers/net/phy/bcm63xx.c
drivers/net/phy/marvell.c
drivers/net/phy/marvell10g.c
drivers/net/phy/microchip_t1.c
drivers/net/phy/phy_device.c
include/linux/linkmode.h
include/linux/phy.h

index ff2fea0f8b75181eba81fd62d08194537116391e..0bd4351b2a49075fb6760034b44cad557e08192e 100644 (file)
@@ -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)
index 319edc9c8ec7f04c533c1d61d3bb959ca2d445e9..632472cab3bbb4094187ba2d01d836b8fd2d8285 100644 (file)
@@ -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,
index cf14613745c976068ab26323ab858ad95f37cdfe..d95bffdec4c14fe0e57a7920c21d673b13536eec 100644 (file)
@@ -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 */
+       phydev->supported |= SUPPORTED_Pause;
+
        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,
index 8872a430d74ab815ef5a81d7395de72667f96dbe..cbec296107bdd72b677ff60b8800650489087312 100644 (file)
@@ -2201,7 +2201,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,
index f214834819ddaff856b00fc4371703d9054d0463..1c9d039eec63d97b9dc1bd05209e8d225703e166 100644 (file)
@@ -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,
index b1917dd1978a12e3568e296ab099058160c74c11..c600a8509d606258a9daa6efc216fbaccaa4b3bb 100644 (file)
@@ -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,
index 35102e17bbeb80b40aafdd9f149e3e32e0e79002..f53ce65f45c536e6c4bab2a83990d591b198b83a 100644 (file)
@@ -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,149 @@ MODULE_DESCRIPTION("PHY library");
 MODULE_AUTHOR("Andy Fleming");
 MODULE_LICENSE("GPL");
 
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_basic_features);
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_basic_t1_features);
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_gbit_features);
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_fibre_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_gbit_fibre_features);
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_all_ports_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_gbit_all_ports_features);
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_10gbit_features);
+
+static const int phy_basic_ports_array[] = {
+       ETHTOOL_LINK_MODE_Autoneg_BIT,
+       ETHTOOL_LINK_MODE_TP_BIT,
+       ETHTOOL_LINK_MODE_MII_BIT,
+};
+
+static const int phy_fibre_port_array[] = {
+       ETHTOOL_LINK_MODE_FIBRE_BIT,
+};
+
+static const int phy_all_ports_features_array[] = {
+       ETHTOOL_LINK_MODE_Autoneg_BIT,
+       ETHTOOL_LINK_MODE_TP_BIT,
+       ETHTOOL_LINK_MODE_MII_BIT,
+       ETHTOOL_LINK_MODE_FIBRE_BIT,
+       ETHTOOL_LINK_MODE_AUI_BIT,
+       ETHTOOL_LINK_MODE_BNC_BIT,
+       ETHTOOL_LINK_MODE_Backplane_BIT,
+};
+
+static const int phy_10_100_features_array[] = {
+       ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+       ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+       ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+       ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+};
+
+static const int phy_basic_t1_features_array[] = {
+       ETHTOOL_LINK_MODE_TP_BIT,
+       ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+};
+
+static const int phy_gbit_features_array[] = {
+       ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+       ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+};
+
+static const int phy_10gbit_features_array[] = {
+       ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+};
+
+__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) __ro_after_init;
+EXPORT_SYMBOL_GPL(phy_10gbit_full_features);
+
+static const int phy_10gbit_full_features_array[] = {
+       ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+       ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+       ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+       ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+};
+
+static void features_init(void)
+{
+       /* 10/100 half/full*/
+       linkmode_set_bit_array(phy_basic_ports_array,
+                              ARRAY_SIZE(phy_basic_ports_array),
+                              phy_basic_features);
+       linkmode_set_bit_array(phy_10_100_features_array,
+                              ARRAY_SIZE(phy_10_100_features_array),
+                              phy_basic_features);
+
+       /* 100 full, TP */
+       linkmode_set_bit_array(phy_basic_t1_features_array,
+                              ARRAY_SIZE(phy_basic_t1_features_array),
+                              phy_basic_t1_features);
+
+       /* 10/100 half/full + 1000 half/full */
+       linkmode_set_bit_array(phy_basic_ports_array,
+                              ARRAY_SIZE(phy_basic_ports_array),
+                              phy_gbit_features);
+       linkmode_set_bit_array(phy_10_100_features_array,
+                              ARRAY_SIZE(phy_10_100_features_array),
+                              phy_gbit_features);
+       linkmode_set_bit_array(phy_gbit_features_array,
+                              ARRAY_SIZE(phy_gbit_features_array),
+                              phy_gbit_features);
+
+       /* 10/100 half/full + 1000 half/full + fibre*/
+       linkmode_set_bit_array(phy_basic_ports_array,
+                              ARRAY_SIZE(phy_basic_ports_array),
+                              phy_gbit_fibre_features);
+       linkmode_set_bit_array(phy_10_100_features_array,
+                              ARRAY_SIZE(phy_10_100_features_array),
+                              phy_gbit_fibre_features);
+       linkmode_set_bit_array(phy_gbit_features_array,
+                              ARRAY_SIZE(phy_gbit_features_array),
+                              phy_gbit_fibre_features);
+       linkmode_set_bit_array(phy_fibre_port_array,
+                              ARRAY_SIZE(phy_fibre_port_array),
+                              phy_gbit_fibre_features);
+
+       /* 10/100 half/full + 1000 half/full + TP/MII/FIBRE/AUI/BNC/Backplane*/
+       linkmode_set_bit_array(phy_all_ports_features_array,
+                              ARRAY_SIZE(phy_all_ports_features_array),
+                              phy_gbit_all_ports_features);
+       linkmode_set_bit_array(phy_10_100_features_array,
+                              ARRAY_SIZE(phy_10_100_features_array),
+                              phy_gbit_all_ports_features);
+       linkmode_set_bit_array(phy_gbit_features_array,
+                              ARRAY_SIZE(phy_gbit_features_array),
+                              phy_gbit_all_ports_features);
+
+       /* 10/100 half/full + 1000 half/full + 10G full*/
+       linkmode_set_bit_array(phy_all_ports_features_array,
+                              ARRAY_SIZE(phy_all_ports_features_array),
+                              phy_10gbit_features);
+       linkmode_set_bit_array(phy_10_100_features_array,
+                              ARRAY_SIZE(phy_10_100_features_array),
+                              phy_10gbit_features);
+       linkmode_set_bit_array(phy_gbit_features_array,
+                              ARRAY_SIZE(phy_gbit_features_array),
+                              phy_10gbit_features);
+       linkmode_set_bit_array(phy_10gbit_features_array,
+                              ARRAY_SIZE(phy_10gbit_features_array),
+                              phy_10gbit_features);
+
+       /* 10/100/1000/10G full */
+       linkmode_set_bit_array(phy_all_ports_features_array,
+                              ARRAY_SIZE(phy_all_ports_features_array),
+                              phy_10gbit_full_features);
+       linkmode_set_bit_array(phy_10gbit_full_features_array,
+                              ARRAY_SIZE(phy_10gbit_full_features_array),
+                              phy_10gbit_full_features);
+}
+
 void phy_device_free(struct phy_device *phydev)
 {
        put_device(&phydev->mdio.dev);
@@ -1936,6 +2080,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;
@@ -1956,7 +2101,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;
 
@@ -1976,10 +2122,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;
        }
@@ -2092,9 +2242,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,
@@ -2109,6 +2257,8 @@ static int __init phy_init(void)
        if (rc)
                return rc;
 
+       features_init();
+
        rc = phy_driver_register(&genphy_10g_driver, THIS_MODULE);
        if (rc)
                goto err_10g;
index 014fb86c71146f67372c0a5bfdfc8eb4e3d000de..22443d7fb5cd617dacb30e10348a4749c24aebb8 100644 (file)
@@ -43,6 +43,15 @@ static inline void linkmode_set_bit(int nr, volatile unsigned long *addr)
        __set_bit(nr, addr);
 }
 
+static inline void linkmode_set_bit_array(const int *array, int array_size,
+                                         unsigned long *addr)
+{
+       int i;
+
+       for (i = 0; i < array_size; i++)
+               linkmode_set_bit(array[i], addr);
+}
+
 static inline void linkmode_clear_bit(int nr, volatile unsigned long *addr)
 {
        __clear_bit(nr, addr);
index 0f6e7bf5e9c5e973231ed5f5bd843fa992a2929d..dff51dd36e52fb5dd3e96c3c99b450abb733c88b 100644 (file)
 #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 __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_features) __ro_after_init;
+extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1_features) __ro_after_init;
+extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features) __ro_after_init;
+extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_fibre_features) __ro_after_init;
+extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_all_ports_features) __ro_after_init;
+extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_features) __ro_after_init;
+extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) __ro_after_init;
+
+#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;