summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/marvell/pxa168_eth.c4
-rw-r--r--drivers/net/phy/aquantia.c12
-rw-r--r--drivers/net/phy/bcm63xx.c9
-rw-r--r--drivers/net/phy/marvell.c2
-rw-r--r--drivers/net/phy/marvell10g.c11
-rw-r--r--drivers/net/phy/microchip_t1.c2
-rw-r--r--drivers/net/phy/phy_device.c164
-rw-r--r--include/linux/linkmode.h9
-rw-r--r--include/linux/phy.h24
9 files changed, 198 insertions, 39 deletions
diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index ff2fea0f8b75..0bd4351b2a49 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..d95bffdec4c1 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 */
+ 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,
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 8872a430d74a..cbec296107bd 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -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,
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index f214834819dd..1c9d039eec63 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 35102e17bbeb..f53ce65f45c5 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,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;
diff --git a/include/linux/linkmode.h b/include/linux/linkmode.h
index 014fb86c7114..22443d7fb5cd 100644
--- a/include/linux/linkmode.h
+++ b/include/linux/linkmode.h
@@ -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);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 0f6e7bf5e9c5..dff51dd36e52 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 __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;