mirror of https://github.com/hak5/openwrt.git
kernel: add SFP support for Methode DM7052 NBASE-T module
Add support for Methode DM7052 NBASE-T module to OpenWRT. These patches are taken from my "phy" branch, and will be sent for the next kernel merge window. Signed-off-by: Russell King <linux@armlinux.org.uk> [jonas.gorski: move patches to pending, refresh patches] Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>master
parent
1c16b574c4
commit
a1358fc7ae
|
@ -192,6 +192,23 @@ endef
|
|||
$(eval $(call KernelPackage,phy-broadcom))
|
||||
|
||||
|
||||
define KernelPackage/phy-bcm84881
|
||||
SUBMENU:=$(NETWORK_DEVICES_MENU)
|
||||
TITLE:=Broadcom BCM84881 PHY driver
|
||||
KCONFIG:=CONFIG_BCM84881_PHY
|
||||
DEPENDS:=+kmod-libphy
|
||||
FILES:=$(LINUX_DIR)/drivers/net/phy/bcm84881.ko
|
||||
AUTOLOAD:=$(call AutoLoad,18,bcm84881,1)
|
||||
endef
|
||||
|
||||
define KernelPackage/phy-bcm84881/description
|
||||
Supports the Broadcom 84881 PHY.
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,phy-bcm84881))
|
||||
|
||||
|
||||
|
||||
define KernelPackage/phy-realtek
|
||||
SUBMENU:=$(NETWORK_DEVICES_MENU)
|
||||
TITLE:=Realtek Ethernet PHY driver
|
||||
|
|
|
@ -479,6 +479,7 @@ CONFIG_BASE_SMALL=0
|
|||
# CONFIG_BCM63XX_PHY is not set
|
||||
# CONFIG_BCM7038_WDT is not set
|
||||
# CONFIG_BCM7XXX_PHY is not set
|
||||
# CONFIG_BCM84881_PHY is not set
|
||||
# CONFIG_BCM87XX_PHY is not set
|
||||
# CONFIG_BCMA is not set
|
||||
# CONFIG_BCMA_DRIVER_GPIO is not set
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -548,6 +548,12 @@ struct phy_driver {
|
||||
@@ -555,6 +555,12 @@ struct phy_driver {
|
||||
/* Determines the negotiated speed and duplex */
|
||||
int (*read_status)(struct phy_device *phydev);
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
|||
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -1512,6 +1512,9 @@ int genphy_update_link(struct phy_device
|
||||
@@ -1576,6 +1576,9 @@ int genphy_update_link(struct phy_device
|
||||
{
|
||||
int status;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
|||
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -1136,6 +1136,9 @@ void phy_detach(struct phy_device *phyde
|
||||
@@ -1200,6 +1200,9 @@ void phy_detach(struct phy_device *phyde
|
||||
struct module *ndev_owner = dev->dev.parent->driver->owner;
|
||||
struct mii_bus *bus;
|
||||
|
||||
|
@ -23,7 +23,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
|||
sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev");
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -560,6 +560,12 @@ struct phy_driver {
|
||||
@@ -567,6 +567,12 @@ struct phy_driver {
|
||||
*/
|
||||
int (*did_interrupt)(struct phy_device *phydev);
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
From 29cd215aaf6c2050c43e4de03aee436c16f90b96 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Thu, 21 Nov 2019 17:27:14 +0000
|
||||
Subject: [PATCH 643/660] net: sfp: remove incomplete 100BASE-FX and 100BASE-LX
|
||||
support
|
||||
|
||||
The 100BASE-FX and 100BASE-LX support assumes a PHY is present; this
|
||||
is probably an incorrect assumption. In any case, sfp_parse_support()
|
||||
will fail such a module. Let's stop pretending we support these
|
||||
modules.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp-bus.c | 4 +---
|
||||
drivers/net/phy/sfp.c | 13 +------------
|
||||
2 files changed, 2 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -341,9 +341,7 @@ phy_interface_t sfp_select_interface(str
|
||||
if (phylink_test(link_modes, 2500baseX_Full))
|
||||
return PHY_INTERFACE_MODE_2500BASEX;
|
||||
|
||||
- if (id->base.e1000_base_t ||
|
||||
- id->base.e100_base_lx ||
|
||||
- id->base.e100_base_fx)
|
||||
+ if (id->base.e1000_base_t)
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
|
||||
if (phylink_test(link_modes, 1000baseX_Full))
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -1413,18 +1413,7 @@ static void sfp_sm_fault(struct sfp *sfp
|
||||
|
||||
static void sfp_sm_probe_for_phy(struct sfp *sfp)
|
||||
{
|
||||
- /* Setting the serdes link mode is guesswork: there's no
|
||||
- * field in the EEPROM which indicates what mode should
|
||||
- * be used.
|
||||
- *
|
||||
- * If it's a gigabit-only fiber module, it probably does
|
||||
- * not have a PHY, so switch to 802.3z negotiation mode.
|
||||
- * Otherwise, switch to SGMII mode (which is required to
|
||||
- * support non-gigabit speeds) and probe for a PHY.
|
||||
- */
|
||||
- if (sfp->id.base.e1000_base_t ||
|
||||
- sfp->id.base.e100_base_lx ||
|
||||
- sfp->id.base.e100_base_fx)
|
||||
+ if (sfp->id.base.e1000_base_t)
|
||||
sfp_sm_probe_phy(sfp);
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
From dc45d9e04572b5cd6d32f51cdf9f62b18022e6dd Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Thu, 21 Nov 2019 17:32:59 +0000
|
||||
Subject: [PATCH 644/660] net: sfp: derive interface mode from ethtool link
|
||||
modes
|
||||
|
||||
We don't need the EEPROM ID to derive the phy interface mode as we can
|
||||
derive it merely from the ethtool link modes. Remove the EEPROM ID
|
||||
argument to sfp_select_interface().
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/marvell10g.c | 2 +-
|
||||
drivers/net/phy/phylink.c | 2 +-
|
||||
drivers/net/phy/sfp-bus.c | 11 ++++-------
|
||||
include/linux/sfp.h | 2 --
|
||||
4 files changed, 6 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/marvell10g.c
|
||||
+++ b/drivers/net/phy/marvell10g.c
|
||||
@@ -227,7 +227,7 @@ static int mv3310_sfp_insert(void *upstr
|
||||
phy_interface_t iface;
|
||||
|
||||
sfp_parse_support(phydev->sfp_bus, id, support);
|
||||
- iface = sfp_select_interface(phydev->sfp_bus, id, support);
|
||||
+ iface = sfp_select_interface(phydev->sfp_bus, support);
|
||||
|
||||
if (iface != PHY_INTERFACE_MODE_10GKR) {
|
||||
dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -1663,7 +1663,7 @@ static int phylink_sfp_module_insert(voi
|
||||
|
||||
linkmode_copy(support1, support);
|
||||
|
||||
- iface = sfp_select_interface(pl->sfp_bus, id, config.advertising);
|
||||
+ iface = sfp_select_interface(pl->sfp_bus, config.advertising);
|
||||
if (iface == PHY_INTERFACE_MODE_NA) {
|
||||
netdev_err(pl->netdev,
|
||||
"selection of interface failed, advertisement %*pb\n",
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -319,16 +319,12 @@ EXPORT_SYMBOL_GPL(sfp_parse_support);
|
||||
/**
|
||||
* sfp_select_interface() - Select appropriate phy_interface_t mode
|
||||
* @bus: a pointer to the &struct sfp_bus structure for the sfp module
|
||||
- * @id: a pointer to the module's &struct sfp_eeprom_id
|
||||
* @link_modes: ethtool link modes mask
|
||||
*
|
||||
- * Derive the phy_interface_t mode for the information found in the
|
||||
- * module's identifying EEPROM and the link modes mask. There is no
|
||||
- * standard or defined way to derive this information, so we decide
|
||||
- * based upon the link mode mask.
|
||||
+ * Derive the phy_interface_t mode for the SFP module from the link
|
||||
+ * modes mask.
|
||||
*/
|
||||
phy_interface_t sfp_select_interface(struct sfp_bus *bus,
|
||||
- const struct sfp_eeprom_id *id,
|
||||
unsigned long *link_modes)
|
||||
{
|
||||
if (phylink_test(link_modes, 10000baseCR_Full) ||
|
||||
@@ -341,7 +337,8 @@ phy_interface_t sfp_select_interface(str
|
||||
if (phylink_test(link_modes, 2500baseX_Full))
|
||||
return PHY_INTERFACE_MODE_2500BASEX;
|
||||
|
||||
- if (id->base.e1000_base_t)
|
||||
+ if (phylink_test(link_modes, 1000baseT_Half) ||
|
||||
+ phylink_test(link_modes, 1000baseT_Full))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
|
||||
if (phylink_test(link_modes, 1000baseX_Full))
|
||||
--- a/include/linux/sfp.h
|
||||
+++ b/include/linux/sfp.h
|
||||
@@ -504,7 +504,6 @@ int sfp_parse_port(struct sfp_bus *bus,
|
||||
void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
|
||||
unsigned long *support);
|
||||
phy_interface_t sfp_select_interface(struct sfp_bus *bus,
|
||||
- const struct sfp_eeprom_id *id,
|
||||
unsigned long *link_modes);
|
||||
|
||||
int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo);
|
||||
@@ -532,7 +531,6 @@ static inline void sfp_parse_support(str
|
||||
}
|
||||
|
||||
static inline phy_interface_t sfp_select_interface(struct sfp_bus *bus,
|
||||
- const struct sfp_eeprom_id *id,
|
||||
unsigned long *link_modes)
|
||||
{
|
||||
return PHY_INTERFACE_MODE_NA;
|
|
@ -0,0 +1,251 @@
|
|||
From c66a4e76c8554c84e64b9315314576ac403c6641 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Thu, 26 Sep 2019 15:14:18 +0100
|
||||
Subject: [PATCH 645/660] net: sfp: add more extended compliance codes
|
||||
|
||||
SFF-8024 is used to define various constants re-used in several SFF
|
||||
SFP-related specifications. Split these constants from the enum, and
|
||||
rename them to indicate that they're defined by SFF-8024.
|
||||
|
||||
Add and use updated SFF-8024 extended compliance code definitions for
|
||||
10GBASE-T, 5GBASE-T and 2.5GBASE-T modules.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp-bus.c | 60 ++++++++++++++++------------
|
||||
drivers/net/phy/sfp.c | 4 +-
|
||||
include/linux/sfp.h | 82 ++++++++++++++++++++++++++-------------
|
||||
3 files changed, 93 insertions(+), 53 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -123,35 +123,35 @@ int sfp_parse_port(struct sfp_bus *bus,
|
||||
|
||||
/* port is the physical connector, set this from the connector field. */
|
||||
switch (id->base.connector) {
|
||||
- case SFP_CONNECTOR_SC:
|
||||
- case SFP_CONNECTOR_FIBERJACK:
|
||||
- case SFP_CONNECTOR_LC:
|
||||
- case SFP_CONNECTOR_MT_RJ:
|
||||
- case SFP_CONNECTOR_MU:
|
||||
- case SFP_CONNECTOR_OPTICAL_PIGTAIL:
|
||||
+ case SFF8024_CONNECTOR_SC:
|
||||
+ case SFF8024_CONNECTOR_FIBERJACK:
|
||||
+ case SFF8024_CONNECTOR_LC:
|
||||
+ case SFF8024_CONNECTOR_MT_RJ:
|
||||
+ case SFF8024_CONNECTOR_MU:
|
||||
+ case SFF8024_CONNECTOR_OPTICAL_PIGTAIL:
|
||||
+ case SFF8024_CONNECTOR_MPO_1X12:
|
||||
+ case SFF8024_CONNECTOR_MPO_2X16:
|
||||
port = PORT_FIBRE;
|
||||
break;
|
||||
|
||||
- case SFP_CONNECTOR_RJ45:
|
||||
+ case SFF8024_CONNECTOR_RJ45:
|
||||
port = PORT_TP;
|
||||
break;
|
||||
|
||||
- case SFP_CONNECTOR_COPPER_PIGTAIL:
|
||||
+ case SFF8024_CONNECTOR_COPPER_PIGTAIL:
|
||||
port = PORT_DA;
|
||||
break;
|
||||
|
||||
- case SFP_CONNECTOR_UNSPEC:
|
||||
+ case SFF8024_CONNECTOR_UNSPEC:
|
||||
if (id->base.e1000_base_t) {
|
||||
port = PORT_TP;
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
- case SFP_CONNECTOR_SG: /* guess */
|
||||
- case SFP_CONNECTOR_MPO_1X12:
|
||||
- case SFP_CONNECTOR_MPO_2X16:
|
||||
- case SFP_CONNECTOR_HSSDC_II:
|
||||
- case SFP_CONNECTOR_NOSEPARATE:
|
||||
- case SFP_CONNECTOR_MXC_2X16:
|
||||
+ case SFF8024_CONNECTOR_SG: /* guess */
|
||||
+ case SFF8024_CONNECTOR_HSSDC_II:
|
||||
+ case SFF8024_CONNECTOR_NOSEPARATE:
|
||||
+ case SFF8024_CONNECTOR_MXC_2X16:
|
||||
port = PORT_OTHER;
|
||||
break;
|
||||
default:
|
||||
@@ -260,22 +260,33 @@ void sfp_parse_support(struct sfp_bus *b
|
||||
}
|
||||
|
||||
switch (id->base.extended_cc) {
|
||||
- case 0x00: /* Unspecified */
|
||||
+ case SFF8024_ECC_UNSPEC:
|
||||
break;
|
||||
- case 0x02: /* 100Gbase-SR4 or 25Gbase-SR */
|
||||
+ case SFF8024_ECC_100GBASE_SR4_25GBASE_SR:
|
||||
phylink_set(modes, 100000baseSR4_Full);
|
||||
phylink_set(modes, 25000baseSR_Full);
|
||||
break;
|
||||
- case 0x03: /* 100Gbase-LR4 or 25Gbase-LR */
|
||||
- case 0x04: /* 100Gbase-ER4 or 25Gbase-ER */
|
||||
+ case SFF8024_ECC_100GBASE_LR4_25GBASE_LR:
|
||||
+ case SFF8024_ECC_100GBASE_ER4_25GBASE_ER:
|
||||
phylink_set(modes, 100000baseLR4_ER4_Full);
|
||||
break;
|
||||
- case 0x0b: /* 100Gbase-CR4 or 25Gbase-CR CA-L */
|
||||
- case 0x0c: /* 25Gbase-CR CA-S */
|
||||
- case 0x0d: /* 25Gbase-CR CA-N */
|
||||
+ case SFF8024_ECC_100GBASE_CR4:
|
||||
phylink_set(modes, 100000baseCR4_Full);
|
||||
+ /* fallthrough */
|
||||
+ case SFF8024_ECC_25GBASE_CR_S:
|
||||
+ case SFF8024_ECC_25GBASE_CR_N:
|
||||
phylink_set(modes, 25000baseCR_Full);
|
||||
break;
|
||||
+ case SFF8024_ECC_10GBASE_T_SFI:
|
||||
+ case SFF8024_ECC_10GBASE_T_SR:
|
||||
+ phylink_set(modes, 10000baseT_Full);
|
||||
+ break;
|
||||
+ case SFF8024_ECC_5GBASE_T:
|
||||
+ phylink_set(modes, 5000baseT_Full);
|
||||
+ break;
|
||||
+ case SFF8024_ECC_2_5GBASE_T:
|
||||
+ phylink_set(modes, 2500baseT_Full);
|
||||
+ break;
|
||||
default:
|
||||
dev_warn(bus->sfp_dev,
|
||||
"Unknown/unsupported extended compliance code: 0x%02x\n",
|
||||
@@ -300,7 +311,7 @@ void sfp_parse_support(struct sfp_bus *b
|
||||
*/
|
||||
if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS)) {
|
||||
/* If the encoding and bit rate allows 1000baseX */
|
||||
- if (id->base.encoding == SFP_ENCODING_8B10B && br_nom &&
|
||||
+ if (id->base.encoding == SFF8024_ENCODING_8B10B && br_nom &&
|
||||
br_min <= 1300 && br_max >= 1200)
|
||||
phylink_set(modes, 1000baseX_Full);
|
||||
}
|
||||
@@ -331,7 +342,8 @@ phy_interface_t sfp_select_interface(str
|
||||
phylink_test(link_modes, 10000baseSR_Full) ||
|
||||
phylink_test(link_modes, 10000baseLR_Full) ||
|
||||
phylink_test(link_modes, 10000baseLRM_Full) ||
|
||||
- phylink_test(link_modes, 10000baseER_Full))
|
||||
+ phylink_test(link_modes, 10000baseER_Full) ||
|
||||
+ phylink_test(link_modes, 10000baseT_Full))
|
||||
return PHY_INTERFACE_MODE_10GKR;
|
||||
|
||||
if (phylink_test(link_modes, 2500baseX_Full))
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -229,7 +229,7 @@ struct sfp {
|
||||
|
||||
static bool sff_module_supported(const struct sfp_eeprom_id *id)
|
||||
{
|
||||
- return id->base.phys_id == SFP_PHYS_ID_SFF &&
|
||||
+ return id->base.phys_id == SFF8024_ID_SFF_8472 &&
|
||||
id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP;
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ static const struct sff_data sff_data =
|
||||
|
||||
static bool sfp_module_supported(const struct sfp_eeprom_id *id)
|
||||
{
|
||||
- return id->base.phys_id == SFP_PHYS_ID_SFP &&
|
||||
+ return id->base.phys_id == SFF8024_ID_SFP &&
|
||||
id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP;
|
||||
}
|
||||
|
||||
--- a/include/linux/sfp.h
|
||||
+++ b/include/linux/sfp.h
|
||||
@@ -275,6 +275,61 @@ struct sfp_diag {
|
||||
__be16 cal_v_offset;
|
||||
} __packed;
|
||||
|
||||
+/* SFF8024 defined constants */
|
||||
+enum {
|
||||
+ SFF8024_ID_UNK = 0x00,
|
||||
+ SFF8024_ID_SFF_8472 = 0x02,
|
||||
+ SFF8024_ID_SFP = 0x03,
|
||||
+ SFF8024_ID_DWDM_SFP = 0x0b,
|
||||
+ SFF8024_ID_QSFP_8438 = 0x0c,
|
||||
+ SFF8024_ID_QSFP_8436_8636 = 0x0d,
|
||||
+ SFF8024_ID_QSFP28_8636 = 0x11,
|
||||
+
|
||||
+ SFF8024_ENCODING_UNSPEC = 0x00,
|
||||
+ SFF8024_ENCODING_8B10B = 0x01,
|
||||
+ SFF8024_ENCODING_4B5B = 0x02,
|
||||
+ SFF8024_ENCODING_NRZ = 0x03,
|
||||
+ SFF8024_ENCODING_8472_MANCHESTER= 0x04,
|
||||
+ SFF8024_ENCODING_8472_SONET = 0x05,
|
||||
+ SFF8024_ENCODING_8472_64B66B = 0x06,
|
||||
+ SFF8024_ENCODING_8436_MANCHESTER= 0x06,
|
||||
+ SFF8024_ENCODING_8436_SONET = 0x04,
|
||||
+ SFF8024_ENCODING_8436_64B66B = 0x05,
|
||||
+ SFF8024_ENCODING_256B257B = 0x07,
|
||||
+ SFF8024_ENCODING_PAM4 = 0x08,
|
||||
+
|
||||
+ SFF8024_CONNECTOR_UNSPEC = 0x00,
|
||||
+ /* codes 01-05 not supportable on SFP, but some modules have single SC */
|
||||
+ SFF8024_CONNECTOR_SC = 0x01,
|
||||
+ SFF8024_CONNECTOR_FIBERJACK = 0x06,
|
||||
+ SFF8024_CONNECTOR_LC = 0x07,
|
||||
+ SFF8024_CONNECTOR_MT_RJ = 0x08,
|
||||
+ SFF8024_CONNECTOR_MU = 0x09,
|
||||
+ SFF8024_CONNECTOR_SG = 0x0a,
|
||||
+ SFF8024_CONNECTOR_OPTICAL_PIGTAIL= 0x0b,
|
||||
+ SFF8024_CONNECTOR_MPO_1X12 = 0x0c,
|
||||
+ SFF8024_CONNECTOR_MPO_2X16 = 0x0d,
|
||||
+ SFF8024_CONNECTOR_HSSDC_II = 0x20,
|
||||
+ SFF8024_CONNECTOR_COPPER_PIGTAIL= 0x21,
|
||||
+ SFF8024_CONNECTOR_RJ45 = 0x22,
|
||||
+ SFF8024_CONNECTOR_NOSEPARATE = 0x23,
|
||||
+ SFF8024_CONNECTOR_MXC_2X16 = 0x24,
|
||||
+
|
||||
+ SFF8024_ECC_UNSPEC = 0x00,
|
||||
+ SFF8024_ECC_100G_25GAUI_C2M_AOC = 0x01,
|
||||
+ SFF8024_ECC_100GBASE_SR4_25GBASE_SR = 0x02,
|
||||
+ SFF8024_ECC_100GBASE_LR4_25GBASE_LR = 0x03,
|
||||
+ SFF8024_ECC_100GBASE_ER4_25GBASE_ER = 0x04,
|
||||
+ SFF8024_ECC_100GBASE_SR10 = 0x05,
|
||||
+ SFF8024_ECC_100GBASE_CR4 = 0x0b,
|
||||
+ SFF8024_ECC_25GBASE_CR_S = 0x0c,
|
||||
+ SFF8024_ECC_25GBASE_CR_N = 0x0d,
|
||||
+ SFF8024_ECC_10GBASE_T_SFI = 0x16,
|
||||
+ SFF8024_ECC_10GBASE_T_SR = 0x1c,
|
||||
+ SFF8024_ECC_5GBASE_T = 0x1d,
|
||||
+ SFF8024_ECC_2_5GBASE_T = 0x1e,
|
||||
+};
|
||||
+
|
||||
/* SFP EEPROM registers */
|
||||
enum {
|
||||
SFP_PHYS_ID = 0x00,
|
||||
@@ -309,34 +364,7 @@ enum {
|
||||
SFP_SFF8472_COMPLIANCE = 0x5e,
|
||||
SFP_CC_EXT = 0x5f,
|
||||
|
||||
- SFP_PHYS_ID_SFF = 0x02,
|
||||
- SFP_PHYS_ID_SFP = 0x03,
|
||||
SFP_PHYS_EXT_ID_SFP = 0x04,
|
||||
- SFP_CONNECTOR_UNSPEC = 0x00,
|
||||
- /* codes 01-05 not supportable on SFP, but some modules have single SC */
|
||||
- SFP_CONNECTOR_SC = 0x01,
|
||||
- SFP_CONNECTOR_FIBERJACK = 0x06,
|
||||
- SFP_CONNECTOR_LC = 0x07,
|
||||
- SFP_CONNECTOR_MT_RJ = 0x08,
|
||||
- SFP_CONNECTOR_MU = 0x09,
|
||||
- SFP_CONNECTOR_SG = 0x0a,
|
||||
- SFP_CONNECTOR_OPTICAL_PIGTAIL = 0x0b,
|
||||
- SFP_CONNECTOR_MPO_1X12 = 0x0c,
|
||||
- SFP_CONNECTOR_MPO_2X16 = 0x0d,
|
||||
- SFP_CONNECTOR_HSSDC_II = 0x20,
|
||||
- SFP_CONNECTOR_COPPER_PIGTAIL = 0x21,
|
||||
- SFP_CONNECTOR_RJ45 = 0x22,
|
||||
- SFP_CONNECTOR_NOSEPARATE = 0x23,
|
||||
- SFP_CONNECTOR_MXC_2X16 = 0x24,
|
||||
- SFP_ENCODING_UNSPEC = 0x00,
|
||||
- SFP_ENCODING_8B10B = 0x01,
|
||||
- SFP_ENCODING_4B5B = 0x02,
|
||||
- SFP_ENCODING_NRZ = 0x03,
|
||||
- SFP_ENCODING_8472_MANCHESTER = 0x04,
|
||||
- SFP_ENCODING_8472_SONET = 0x05,
|
||||
- SFP_ENCODING_8472_64B66B = 0x06,
|
||||
- SFP_ENCODING_256B257B = 0x07,
|
||||
- SFP_ENCODING_PAM4 = 0x08,
|
||||
SFP_OPTIONS_HIGH_POWER_LEVEL = BIT(13),
|
||||
SFP_OPTIONS_PAGING_A2 = BIT(12),
|
||||
SFP_OPTIONS_RETIMER = BIT(11),
|
|
@ -0,0 +1,131 @@
|
|||
From f9a5a54b59cb904b37bf7409a43635ab195d0214 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 19 Nov 2019 10:13:25 +0000
|
||||
Subject: [PATCH 646/660] net: sfp: add module start/stop upstream
|
||||
notifications
|
||||
|
||||
When dealing with some copper modules, we can't positively know the
|
||||
module capabilities are until we have probed the PHY. Without the full
|
||||
capabilities, we may end up failing a module that we could otherwise
|
||||
drive with a restricted set of capabilities.
|
||||
|
||||
An example of this would be a module with a NBASE-T PHY plugged into
|
||||
a host that supports phy interface modes 2500BASE-X and SGMII. The
|
||||
PHY supports 10GBASE-R, 5000BASE-X, 2500BASE-X, SGMII interface modes,
|
||||
which means a subset of the capabilities are compatible with the host.
|
||||
|
||||
However, reading the module EEPROM leads us to believe that the module
|
||||
only supports ethtool link mode 10GBASE-T, which is incompatible with
|
||||
the host - and thus results in the module being rejected.
|
||||
|
||||
This patch adds an extra notification which are triggered after the
|
||||
SFP module's PHY probe, and a corresponding notification just before
|
||||
the PHY is removed.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp-bus.c | 21 +++++++++++++++++++++
|
||||
drivers/net/phy/sfp.c | 8 ++++++++
|
||||
drivers/net/phy/sfp.h | 2 ++
|
||||
include/linux/sfp.h | 4 ++++
|
||||
4 files changed, 35 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -711,6 +711,27 @@ void sfp_module_remove(struct sfp_bus *b
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sfp_module_remove);
|
||||
|
||||
+int sfp_module_start(struct sfp_bus *bus)
|
||||
+{
|
||||
+ const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (ops && ops->module_start)
|
||||
+ ret = ops->module_start(bus->upstream);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(sfp_module_start);
|
||||
+
|
||||
+void sfp_module_stop(struct sfp_bus *bus)
|
||||
+{
|
||||
+ const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
|
||||
+
|
||||
+ if (ops && ops->module_stop)
|
||||
+ ops->module_stop(bus->upstream);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(sfp_module_stop);
|
||||
+
|
||||
static void sfp_socket_clear(struct sfp_bus *bus)
|
||||
{
|
||||
bus->sfp_dev = NULL;
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -57,6 +57,7 @@ enum {
|
||||
SFP_DEV_UP,
|
||||
|
||||
SFP_S_DOWN = 0,
|
||||
+ SFP_S_FAIL,
|
||||
SFP_S_WAIT,
|
||||
SFP_S_INIT,
|
||||
SFP_S_INIT_TX_FAULT,
|
||||
@@ -120,6 +121,7 @@ static const char *event_to_str(unsigned
|
||||
|
||||
static const char * const sm_state_strings[] = {
|
||||
[SFP_S_DOWN] = "down",
|
||||
+ [SFP_S_FAIL] = "fail",
|
||||
[SFP_S_WAIT] = "wait",
|
||||
[SFP_S_INIT] = "init",
|
||||
[SFP_S_INIT_TX_FAULT] = "init_tx_fault",
|
||||
@@ -1749,6 +1751,8 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
if (sfp->sm_state == SFP_S_LINK_UP &&
|
||||
sfp->sm_dev_state == SFP_DEV_UP)
|
||||
sfp_sm_link_down(sfp);
|
||||
+ if (sfp->sm_state > SFP_S_INIT)
|
||||
+ sfp_module_stop(sfp->sfp_bus);
|
||||
if (sfp->mod_phy)
|
||||
sfp_sm_phy_detach(sfp);
|
||||
sfp_module_tx_disable(sfp);
|
||||
@@ -1815,6 +1819,10 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
* clear. Probe for the PHY and check the LOS state.
|
||||
*/
|
||||
sfp_sm_probe_for_phy(sfp);
|
||||
+ if (sfp_module_start(sfp->sfp_bus)) {
|
||||
+ sfp_sm_next(sfp, SFP_S_FAIL, 0);
|
||||
+ break;
|
||||
+ }
|
||||
sfp_sm_link_check_los(sfp);
|
||||
|
||||
/* Reset the fault retry count */
|
||||
--- a/drivers/net/phy/sfp.h
|
||||
+++ b/drivers/net/phy/sfp.h
|
||||
@@ -22,6 +22,8 @@ void sfp_link_up(struct sfp_bus *bus);
|
||||
void sfp_link_down(struct sfp_bus *bus);
|
||||
int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
|
||||
void sfp_module_remove(struct sfp_bus *bus);
|
||||
+int sfp_module_start(struct sfp_bus *bus);
|
||||
+void sfp_module_stop(struct sfp_bus *bus);
|
||||
int sfp_link_configure(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
|
||||
struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
|
||||
const struct sfp_socket_ops *ops);
|
||||
--- a/include/linux/sfp.h
|
||||
+++ b/include/linux/sfp.h
|
||||
@@ -507,6 +507,8 @@ struct sfp_bus;
|
||||
* @module_insert: called after a module has been detected to determine
|
||||
* whether the module is supported for the upstream device.
|
||||
* @module_remove: called after the module has been removed.
|
||||
+ * @module_start: called after the PHY probe step
|
||||
+ * @module_stop: called before the PHY is removed
|
||||
* @link_down: called when the link is non-operational for whatever
|
||||
* reason.
|
||||
* @link_up: called when the link is operational.
|
||||
@@ -520,6 +522,8 @@ struct sfp_upstream_ops {
|
||||
void (*detach)(void *priv, struct sfp_bus *bus);
|
||||
int (*module_insert)(void *priv, const struct sfp_eeprom_id *id);
|
||||
void (*module_remove)(void *priv);
|
||||
+ int (*module_start)(void *priv);
|
||||
+ void (*module_stop)(void *priv);
|
||||
void (*link_down)(void *priv);
|
||||
void (*link_up)(void *priv);
|
||||
int (*connect_phy)(void *priv, struct phy_device *);
|
|
@ -0,0 +1,72 @@
|
|||
From e2dc261b872a92a055eb2e86ac136baf9b20f2f2 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Thu, 21 Nov 2019 17:21:33 +0000
|
||||
Subject: [PATCH 647/660] net: sfp: move phy_start()/phy_stop() to phylink
|
||||
|
||||
Move phy_start() and phy_stop() into the module_start and module_stop
|
||||
notifications in phylink, rather than having them in the SFP code.
|
||||
This gives phylink responsibility for controlling the PHY, rather
|
||||
than having SFP start and stop the PHY state machine.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 22 ++++++++++++++++++++++
|
||||
drivers/net/phy/sfp.c | 2 --
|
||||
2 files changed, 22 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -1717,6 +1717,26 @@ static int phylink_sfp_module_insert(voi
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int phylink_sfp_module_start(void *upstream)
|
||||
+{
|
||||
+ struct phylink *pl = upstream;
|
||||
+
|
||||
+ /* If this SFP module has a PHY, start the PHY now. */
|
||||
+ if (pl->phydev)
|
||||
+ phy_start(pl->phydev);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void phylink_sfp_module_stop(void *upstream)
|
||||
+{
|
||||
+ struct phylink *pl = upstream;
|
||||
+
|
||||
+ /* If this SFP module has a PHY, stop it. */
|
||||
+ if (pl->phydev)
|
||||
+ phy_stop(pl->phydev);
|
||||
+}
|
||||
+
|
||||
static void phylink_sfp_link_down(void *upstream)
|
||||
{
|
||||
struct phylink *pl = upstream;
|
||||
@@ -1752,6 +1772,8 @@ static const struct sfp_upstream_ops sfp
|
||||
.attach = phylink_sfp_attach,
|
||||
.detach = phylink_sfp_detach,
|
||||
.module_insert = phylink_sfp_module_insert,
|
||||
+ .module_start = phylink_sfp_module_start,
|
||||
+ .module_stop = phylink_sfp_module_stop,
|
||||
.link_up = phylink_sfp_link_up,
|
||||
.link_down = phylink_sfp_link_down,
|
||||
.connect_phy = phylink_sfp_connect_phy,
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -1320,7 +1320,6 @@ static void sfp_sm_mod_next(struct sfp *
|
||||
|
||||
static void sfp_sm_phy_detach(struct sfp *sfp)
|
||||
{
|
||||
- phy_stop(sfp->mod_phy);
|
||||
sfp_remove_phy(sfp->sfp_bus);
|
||||
phy_device_remove(sfp->mod_phy);
|
||||
phy_device_free(sfp->mod_phy);
|
||||
@@ -1351,7 +1350,6 @@ static void sfp_sm_probe_phy(struct sfp
|
||||
}
|
||||
|
||||
sfp->mod_phy = phy;
|
||||
- phy_start(phy);
|
||||
}
|
||||
|
||||
static void sfp_sm_link_up(struct sfp *sfp)
|
|
@ -0,0 +1,74 @@
|
|||
From c9de73988a35c6c85810a992954ac568cca503e5 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Wed, 2 Oct 2019 10:31:10 +0100
|
||||
Subject: [PATCH 648/660] net: mdio-i2c: add support for Clause 45 accesses
|
||||
|
||||
Some SFP+ modules have PHYs on them just like SFP modules do, except
|
||||
they are Clause 45 PHYs. The I2C protocol used to access them is
|
||||
modified slightly in order to send the device address and 16-bit
|
||||
register index.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/mdio-i2c.c | 28 ++++++++++++++++++++--------
|
||||
1 file changed, 20 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/mdio-i2c.c
|
||||
+++ b/drivers/net/phy/mdio-i2c.c
|
||||
@@ -36,17 +36,24 @@ static int i2c_mii_read(struct mii_bus *
|
||||
{
|
||||
struct i2c_adapter *i2c = bus->priv;
|
||||
struct i2c_msg msgs[2];
|
||||
- u8 data[2], dev_addr = reg;
|
||||
+ u8 addr[3], data[2], *p;
|
||||
int bus_addr, ret;
|
||||
|
||||
if (!i2c_mii_valid_phy_id(phy_id))
|
||||
return 0xffff;
|
||||
|
||||
+ p = addr;
|
||||
+ if (reg & MII_ADDR_C45) {
|
||||
+ *p++ = 0x20 | ((reg >> 16) & 31);
|
||||
+ *p++ = reg >> 8;
|
||||
+ }
|
||||
+ *p++ = reg;
|
||||
+
|
||||
bus_addr = i2c_mii_phy_addr(phy_id);
|
||||
msgs[0].addr = bus_addr;
|
||||
msgs[0].flags = 0;
|
||||
- msgs[0].len = 1;
|
||||
- msgs[0].buf = &dev_addr;
|
||||
+ msgs[0].len = p - addr;
|
||||
+ msgs[0].buf = addr;
|
||||
msgs[1].addr = bus_addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(data);
|
||||
@@ -64,18 +71,23 @@ static int i2c_mii_write(struct mii_bus
|
||||
struct i2c_adapter *i2c = bus->priv;
|
||||
struct i2c_msg msg;
|
||||
int ret;
|
||||
- u8 data[3];
|
||||
+ u8 data[5], *p;
|
||||
|
||||
if (!i2c_mii_valid_phy_id(phy_id))
|
||||
return 0;
|
||||
|
||||
- data[0] = reg;
|
||||
- data[1] = val >> 8;
|
||||
- data[2] = val;
|
||||
+ p = data;
|
||||
+ if (reg & MII_ADDR_C45) {
|
||||
+ *p++ = (reg >> 16) & 31;
|
||||
+ *p++ = reg >> 8;
|
||||
+ }
|
||||
+ *p++ = reg;
|
||||
+ *p++ = val >> 8;
|
||||
+ *p++ = val;
|
||||
|
||||
msg.addr = i2c_mii_phy_addr(phy_id);
|
||||
msg.flags = 0;
|
||||
- msg.len = 3;
|
||||
+ msg.len = p - data;
|
||||
msg.buf = data;
|
||||
|
||||
ret = i2c_transfer(i2c, &msg, 1);
|
|
@ -0,0 +1,93 @@
|
|||
From 0db7fba746b5608c30d4e2ba1c99a2a309e2d288 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 8 Nov 2019 15:22:48 +0000
|
||||
Subject: [PATCH 649/660] net: phylink: re-split __phylink_connect_phy()
|
||||
|
||||
In order to support Clause 45 PHYs on SFP+ modules, which have an
|
||||
indeterminant phy interface mode, we need to be able to call
|
||||
phylink_bringup_phy() with a different interface mode to that used when
|
||||
binding the PHY. Reduce __phylink_connect_phy() to an attach operation,
|
||||
and move the call to phylink_bringup_phy() to its call sites.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 39 ++++++++++++++++++++++++---------------
|
||||
1 file changed, 24 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -728,11 +728,9 @@ static int phylink_bringup_phy(struct ph
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int __phylink_connect_phy(struct phylink *pl, struct phy_device *phy,
|
||||
- phy_interface_t interface)
|
||||
+static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy,
|
||||
+ phy_interface_t interface)
|
||||
{
|
||||
- int ret;
|
||||
-
|
||||
if (WARN_ON(pl->link_an_mode == MLO_AN_FIXED ||
|
||||
(pl->link_an_mode == MLO_AN_INBAND &&
|
||||
phy_interface_mode_is_8023z(interface))))
|
||||
@@ -741,15 +739,7 @@ static int __phylink_connect_phy(struct
|
||||
if (pl->phydev)
|
||||
return -EBUSY;
|
||||
|
||||
- ret = phy_attach_direct(pl->netdev, phy, 0, interface);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- ret = phylink_bringup_phy(pl, phy);
|
||||
- if (ret)
|
||||
- phy_detach(phy);
|
||||
-
|
||||
- return ret;
|
||||
+ return phy_attach_direct(pl->netdev, phy, 0, interface);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -769,13 +759,23 @@ static int __phylink_connect_phy(struct
|
||||
*/
|
||||
int phylink_connect_phy(struct phylink *pl, struct phy_device *phy)
|
||||
{
|
||||
+ int ret;
|
||||
+
|
||||
/* Use PHY device/driver interface */
|
||||
if (pl->link_interface == PHY_INTERFACE_MODE_NA) {
|
||||
pl->link_interface = phy->interface;
|
||||
pl->link_config.interface = pl->link_interface;
|
||||
}
|
||||
|
||||
- return __phylink_connect_phy(pl, phy, pl->link_interface);
|
||||
+ ret = phylink_attach_phy(pl, phy, pl->link_interface);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = phylink_bringup_phy(pl, phy);
|
||||
+ if (ret)
|
||||
+ phy_detach(phy);
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phylink_connect_phy);
|
||||
|
||||
@@ -1759,8 +1759,17 @@ static void phylink_sfp_link_up(void *up
|
||||
static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
|
||||
{
|
||||
struct phylink *pl = upstream;
|
||||
+ int ret;
|
||||
|
||||
- return __phylink_connect_phy(upstream, phy, pl->link_config.interface);
|
||||
+ ret = phylink_attach_phy(pl, phy, pl->link_config.interface);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = phylink_bringup_phy(pl, phy);
|
||||
+ if (ret)
|
||||
+ phy_detach(phy);
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static void phylink_sfp_disconnect_phy(void *upstream)
|
|
@ -0,0 +1,89 @@
|
|||
From caf32f96f13df7d3ae6cb8bf8001c88ae22025ca Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 8 Nov 2019 15:28:22 +0000
|
||||
Subject: [PATCH 650/660] net: phylink: support Clause 45 PHYs on SFP+ modules
|
||||
|
||||
Some SFP+ modules have Clause 45 PHYs embedded on them, which need a
|
||||
little more handling in order to ensure that they are correctly setup,
|
||||
as they switch the PHY link mode according to the negotiated speed.
|
||||
|
||||
With Clause 22 PHYs, we assumed that they would operate in SGMII mode,
|
||||
but this assumption is now false. Adapt phylink to support Clause 45
|
||||
PHYs on SFP+ modules.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 21 ++++++++++++++++-----
|
||||
1 file changed, 16 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -671,7 +671,8 @@ static void phylink_phy_change(struct ph
|
||||
phy_duplex_to_str(phydev->duplex));
|
||||
}
|
||||
|
||||
-static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy)
|
||||
+static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
|
||||
+ phy_interface_t interface)
|
||||
{
|
||||
struct phylink_link_state config;
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
|
||||
@@ -691,7 +692,7 @@ static int phylink_bringup_phy(struct ph
|
||||
ethtool_convert_legacy_u32_to_link_mode(supported, phy->supported);
|
||||
ethtool_convert_legacy_u32_to_link_mode(config.advertising,
|
||||
phy->advertising);
|
||||
- config.interface = pl->link_config.interface;
|
||||
+ config.interface = interface;
|
||||
|
||||
ret = phylink_validate(pl, supported, &config);
|
||||
if (ret)
|
||||
@@ -707,6 +708,7 @@ static int phylink_bringup_phy(struct ph
|
||||
mutex_lock(&phy->lock);
|
||||
mutex_lock(&pl->state_mutex);
|
||||
pl->phydev = phy;
|
||||
+ pl->phy_state.interface = interface;
|
||||
linkmode_copy(pl->supported, supported);
|
||||
linkmode_copy(pl->link_config.advertising, config.advertising);
|
||||
|
||||
@@ -771,7 +773,7 @@ int phylink_connect_phy(struct phylink *
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- ret = phylink_bringup_phy(pl, phy);
|
||||
+ ret = phylink_bringup_phy(pl, phy, pl->link_config.interface);
|
||||
if (ret)
|
||||
phy_detach(phy);
|
||||
|
||||
@@ -824,7 +826,7 @@ int phylink_of_phy_connect(struct phylin
|
||||
if (!phy_dev)
|
||||
return -ENODEV;
|
||||
|
||||
- ret = phylink_bringup_phy(pl, phy_dev);
|
||||
+ ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface);
|
||||
if (ret)
|
||||
phy_detach(phy_dev);
|
||||
|
||||
@@ -1759,13 +1761,22 @@ static void phylink_sfp_link_up(void *up
|
||||
static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
|
||||
{
|
||||
struct phylink *pl = upstream;
|
||||
+ phy_interface_t interface = pl->link_config.interface;
|
||||
int ret;
|
||||
|
||||
ret = phylink_attach_phy(pl, phy, pl->link_config.interface);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- ret = phylink_bringup_phy(pl, phy);
|
||||
+ /* Clause 45 PHYs switch their Serdes lane between several different
|
||||
+ * modes, normally 10GBASE-R, SGMII. Some use 2500BASE-X for 2.5G
|
||||
+ * speeds. We really need to know which interface modes the PHY and
|
||||
+ * MAC supports to properly work out which linkmodes can be supported.
|
||||
+ */
|
||||
+ if (phy->is_c45)
|
||||
+ interface = PHY_INTERFACE_MODE_NA;
|
||||
+
|
||||
+ ret = phylink_bringup_phy(pl, phy, interface);
|
||||
if (ret)
|
||||
phy_detach(phy);
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
From d1339d6956f0255b6ce2412328a98945be8cc3ca Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Sat, 16 Nov 2019 11:30:18 +0000
|
||||
Subject: [PATCH 651/660] net: phylink: split link_an_mode configured and
|
||||
current settings
|
||||
|
||||
Split link_an_mode between the configured setting and the current
|
||||
operating setting. This is an important distinction to make when we
|
||||
need to configure PHY mode for a plugged SFP+ module that does not
|
||||
use in-band signalling.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 59 ++++++++++++++++++++-------------------
|
||||
1 file changed, 31 insertions(+), 28 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -48,7 +48,8 @@ struct phylink {
|
||||
unsigned long phylink_disable_state; /* bitmask of disables */
|
||||
struct phy_device *phydev;
|
||||
phy_interface_t link_interface; /* PHY_INTERFACE_xxx */
|
||||
- u8 link_an_mode; /* MLO_AN_xxx */
|
||||
+ u8 cfg_link_an_mode; /* MLO_AN_xxx */
|
||||
+ u8 cur_link_an_mode;
|
||||
u8 link_port; /* The current non-phy ethtool port */
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
|
||||
|
||||
@@ -253,12 +254,12 @@ static int phylink_parse_mode(struct phy
|
||||
|
||||
dn = fwnode_get_named_child_node(fwnode, "fixed-link");
|
||||
if (dn || fwnode_property_present(fwnode, "fixed-link"))
|
||||
- pl->link_an_mode = MLO_AN_FIXED;
|
||||
+ pl->cfg_link_an_mode = MLO_AN_FIXED;
|
||||
fwnode_handle_put(dn);
|
||||
|
||||
if (fwnode_property_read_string(fwnode, "managed", &managed) == 0 &&
|
||||
strcmp(managed, "in-band-status") == 0) {
|
||||
- if (pl->link_an_mode == MLO_AN_FIXED) {
|
||||
+ if (pl->cfg_link_an_mode == MLO_AN_FIXED) {
|
||||
netdev_err(pl->netdev,
|
||||
"can't use both fixed-link and in-band-status\n");
|
||||
return -EINVAL;
|
||||
@@ -270,7 +271,7 @@ static int phylink_parse_mode(struct phy
|
||||
phylink_set(pl->supported, Asym_Pause);
|
||||
phylink_set(pl->supported, Pause);
|
||||
pl->link_config.an_enabled = true;
|
||||
- pl->link_an_mode = MLO_AN_INBAND;
|
||||
+ pl->cfg_link_an_mode = MLO_AN_INBAND;
|
||||
|
||||
switch (pl->link_config.interface) {
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
@@ -330,14 +331,14 @@ static void phylink_mac_config(struct ph
|
||||
{
|
||||
netdev_dbg(pl->netdev,
|
||||
"%s: mode=%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n",
|
||||
- __func__, phylink_an_mode_str(pl->link_an_mode),
|
||||
+ __func__, phylink_an_mode_str(pl->cur_link_an_mode),
|
||||
phy_modes(state->interface),
|
||||
phy_speed_to_str(state->speed),
|
||||
phy_duplex_to_str(state->duplex),
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
|
||||
state->pause, state->link, state->an_enabled);
|
||||
|
||||
- pl->ops->mac_config(pl->netdev, pl->link_an_mode, state);
|
||||
+ pl->ops->mac_config(pl->netdev, pl->cur_link_an_mode, state);
|
||||
}
|
||||
|
||||
static void phylink_mac_config_up(struct phylink *pl,
|
||||
@@ -446,7 +447,7 @@ static void phylink_resolve(struct work_
|
||||
} else if (pl->mac_link_dropped) {
|
||||
link_state.link = false;
|
||||
} else {
|
||||
- switch (pl->link_an_mode) {
|
||||
+ switch (pl->cur_link_an_mode) {
|
||||
case MLO_AN_PHY:
|
||||
link_state = pl->phy_state;
|
||||
phylink_resolve_flow(pl, &link_state);
|
||||
@@ -483,12 +484,12 @@ static void phylink_resolve(struct work_
|
||||
if (link_state.link != netif_carrier_ok(ndev)) {
|
||||
if (!link_state.link) {
|
||||
netif_carrier_off(ndev);
|
||||
- pl->ops->mac_link_down(ndev, pl->link_an_mode,
|
||||
+ pl->ops->mac_link_down(ndev, pl->cur_link_an_mode,
|
||||
pl->cur_interface);
|
||||
netdev_info(ndev, "Link is Down\n");
|
||||
} else {
|
||||
pl->cur_interface = link_state.interface;
|
||||
- pl->ops->mac_link_up(ndev, pl->link_an_mode,
|
||||
+ pl->ops->mac_link_up(ndev, pl->cur_link_an_mode,
|
||||
pl->cur_interface, pl->phydev);
|
||||
|
||||
netif_carrier_on(ndev);
|
||||
@@ -610,7 +611,7 @@ struct phylink *phylink_create(struct ne
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
- if (pl->link_an_mode == MLO_AN_FIXED) {
|
||||
+ if (pl->cfg_link_an_mode == MLO_AN_FIXED) {
|
||||
ret = phylink_parse_fixedlink(pl, fwnode);
|
||||
if (ret < 0) {
|
||||
kfree(pl);
|
||||
@@ -618,6 +619,8 @@ struct phylink *phylink_create(struct ne
|
||||
}
|
||||
}
|
||||
|
||||
+ pl->cur_link_an_mode = pl->cfg_link_an_mode;
|
||||
+
|
||||
ret = phylink_register_sfp(pl, fwnode);
|
||||
if (ret < 0) {
|
||||
kfree(pl);
|
||||
@@ -733,8 +736,8 @@ static int phylink_bringup_phy(struct ph
|
||||
static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
- if (WARN_ON(pl->link_an_mode == MLO_AN_FIXED ||
|
||||
- (pl->link_an_mode == MLO_AN_INBAND &&
|
||||
+ if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED ||
|
||||
+ (pl->cfg_link_an_mode == MLO_AN_INBAND &&
|
||||
phy_interface_mode_is_8023z(interface))))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -801,8 +804,8 @@ int phylink_of_phy_connect(struct phylin
|
||||
int ret;
|
||||
|
||||
/* Fixed links and 802.3z are handled without needing a PHY */
|
||||
- if (pl->link_an_mode == MLO_AN_FIXED ||
|
||||
- (pl->link_an_mode == MLO_AN_INBAND &&
|
||||
+ if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
|
||||
+ (pl->cfg_link_an_mode == MLO_AN_INBAND &&
|
||||
phy_interface_mode_is_8023z(pl->link_interface)))
|
||||
return 0;
|
||||
|
||||
@@ -813,7 +816,7 @@ int phylink_of_phy_connect(struct phylin
|
||||
phy_node = of_parse_phandle(dn, "phy-device", 0);
|
||||
|
||||
if (!phy_node) {
|
||||
- if (pl->link_an_mode == MLO_AN_PHY)
|
||||
+ if (pl->cfg_link_an_mode == MLO_AN_PHY)
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
@@ -876,7 +879,7 @@ int phylink_fixed_state_cb(struct phylin
|
||||
/* It does not make sense to let the link be overriden unless we use
|
||||
* MLO_AN_FIXED
|
||||
*/
|
||||
- if (pl->link_an_mode != MLO_AN_FIXED)
|
||||
+ if (pl->cfg_link_an_mode != MLO_AN_FIXED)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&pl->state_mutex);
|
||||
@@ -926,7 +929,7 @@ void phylink_start(struct phylink *pl)
|
||||
ASSERT_RTNL();
|
||||
|
||||
netdev_info(pl->netdev, "configuring for %s/%s link mode\n",
|
||||
- phylink_an_mode_str(pl->link_an_mode),
|
||||
+ phylink_an_mode_str(pl->cur_link_an_mode),
|
||||
phy_modes(pl->link_config.interface));
|
||||
|
||||
/* Always set the carrier off */
|
||||
@@ -948,7 +951,7 @@ void phylink_start(struct phylink *pl)
|
||||
clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
|
||||
phylink_run_resolve(pl);
|
||||
|
||||
- if (pl->link_an_mode == MLO_AN_FIXED && pl->link_gpio) {
|
||||
+ if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->link_gpio) {
|
||||
int irq = gpiod_to_irq(pl->link_gpio);
|
||||
|
||||
if (irq > 0) {
|
||||
@@ -963,7 +966,7 @@ void phylink_start(struct phylink *pl)
|
||||
if (irq <= 0)
|
||||
mod_timer(&pl->link_poll, jiffies + HZ);
|
||||
}
|
||||
- if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
|
||||
+ if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
|
||||
mod_timer(&pl->link_poll, jiffies + HZ);
|
||||
if (pl->phydev)
|
||||
phy_start(pl->phydev);
|
||||
@@ -1090,7 +1093,7 @@ int phylink_ethtool_ksettings_get(struct
|
||||
|
||||
linkmode_copy(kset->link_modes.supported, pl->supported);
|
||||
|
||||
- switch (pl->link_an_mode) {
|
||||
+ switch (pl->cur_link_an_mode) {
|
||||
case MLO_AN_FIXED:
|
||||
/* We are using fixed settings. Report these as the
|
||||
* current link settings - and note that these also
|
||||
@@ -1163,7 +1166,7 @@ int phylink_ethtool_ksettings_set(struct
|
||||
/* If we have a fixed link (as specified by firmware), refuse
|
||||
* to change link parameters.
|
||||
*/
|
||||
- if (pl->link_an_mode == MLO_AN_FIXED &&
|
||||
+ if (pl->cur_link_an_mode == MLO_AN_FIXED &&
|
||||
(s->speed != pl->link_config.speed ||
|
||||
s->duplex != pl->link_config.duplex))
|
||||
return -EINVAL;
|
||||
@@ -1175,7 +1178,7 @@ int phylink_ethtool_ksettings_set(struct
|
||||
__clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising);
|
||||
} else {
|
||||
/* If we have a fixed link, refuse to enable autonegotiation */
|
||||
- if (pl->link_an_mode == MLO_AN_FIXED)
|
||||
+ if (pl->cur_link_an_mode == MLO_AN_FIXED)
|
||||
return -EINVAL;
|
||||
|
||||
config.speed = SPEED_UNKNOWN;
|
||||
@@ -1217,7 +1220,7 @@ int phylink_ethtool_ksettings_set(struct
|
||||
* configuration. For a fixed link, this isn't able to change any
|
||||
* parameters, which just leaves inband mode.
|
||||
*/
|
||||
- if (pl->link_an_mode == MLO_AN_INBAND &&
|
||||
+ if (pl->cur_link_an_mode == MLO_AN_INBAND &&
|
||||
!test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) {
|
||||
phylink_mac_config(pl, &pl->link_config);
|
||||
phylink_mac_an_restart(pl);
|
||||
@@ -1307,7 +1310,7 @@ int phylink_ethtool_set_pauseparam(struc
|
||||
pause->tx_pause);
|
||||
} else if (!test_bit(PHYLINK_DISABLE_STOPPED,
|
||||
&pl->phylink_disable_state)) {
|
||||
- switch (pl->link_an_mode) {
|
||||
+ switch (pl->cur_link_an_mode) {
|
||||
case MLO_AN_FIXED:
|
||||
/* Should we allow fixed links to change against the config? */
|
||||
phylink_resolve_flow(pl, config);
|
||||
@@ -1496,7 +1499,7 @@ static int phylink_mii_read(struct phyli
|
||||
struct phylink_link_state state;
|
||||
int val = 0xffff;
|
||||
|
||||
- switch (pl->link_an_mode) {
|
||||
+ switch (pl->cur_link_an_mode) {
|
||||
case MLO_AN_FIXED:
|
||||
if (phy_id == 0) {
|
||||
phylink_get_fixed_state(pl, &state);
|
||||
@@ -1524,7 +1527,7 @@ static int phylink_mii_read(struct phyli
|
||||
static int phylink_mii_write(struct phylink *pl, unsigned int phy_id,
|
||||
unsigned int reg, unsigned int val)
|
||||
{
|
||||
- switch (pl->link_an_mode) {
|
||||
+ switch (pl->cur_link_an_mode) {
|
||||
case MLO_AN_FIXED:
|
||||
break;
|
||||
|
||||
@@ -1698,10 +1701,10 @@ static int phylink_sfp_module_insert(voi
|
||||
linkmode_copy(pl->link_config.advertising, config.advertising);
|
||||
}
|
||||
|
||||
- if (pl->link_an_mode != MLO_AN_INBAND ||
|
||||
+ if (pl->cur_link_an_mode != MLO_AN_INBAND ||
|
||||
pl->link_config.interface != config.interface) {
|
||||
pl->link_config.interface = config.interface;
|
||||
- pl->link_an_mode = MLO_AN_INBAND;
|
||||
+ pl->cur_link_an_mode = MLO_AN_INBAND;
|
||||
|
||||
changed = true;
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
From 36569971241ae6b81376da4937d2c8760122d10b Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Thu, 21 Nov 2019 17:58:58 +0000
|
||||
Subject: [PATCH 652/660] net: phylink: split phylink_sfp_module_insert()
|
||||
|
||||
Split out the configuration step from phylink_sfp_module_insert() so
|
||||
we can re-use this later.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 47 +++++++++++++++++++++++----------------
|
||||
1 file changed, 28 insertions(+), 19 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -1633,25 +1633,21 @@ static void phylink_sfp_detach(void *ups
|
||||
pl->netdev->sfp_bus = NULL;
|
||||
}
|
||||
|
||||
-static int phylink_sfp_module_insert(void *upstream,
|
||||
- const struct sfp_eeprom_id *id)
|
||||
+static int phylink_sfp_config(struct phylink *pl, u8 mode, u8 port,
|
||||
+ const unsigned long *supported,
|
||||
+ const unsigned long *advertising)
|
||||
{
|
||||
- struct phylink *pl = upstream;
|
||||
- __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(support1);
|
||||
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(support);
|
||||
struct phylink_link_state config;
|
||||
phy_interface_t iface;
|
||||
- int ret = 0;
|
||||
bool changed;
|
||||
- u8 port;
|
||||
+ int ret;
|
||||
|
||||
- ASSERT_RTNL();
|
||||
-
|
||||
- sfp_parse_support(pl->sfp_bus, id, support);
|
||||
- port = sfp_parse_port(pl->sfp_bus, id, support);
|
||||
+ linkmode_copy(support, supported);
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
- linkmode_copy(config.advertising, support);
|
||||
+ linkmode_copy(config.advertising, advertising);
|
||||
config.interface = PHY_INTERFACE_MODE_NA;
|
||||
config.speed = SPEED_UNKNOWN;
|
||||
config.duplex = DUPLEX_UNKNOWN;
|
||||
@@ -1666,8 +1662,6 @@ static int phylink_sfp_module_insert(voi
|
||||
return ret;
|
||||
}
|
||||
|
||||
- linkmode_copy(support1, support);
|
||||
-
|
||||
iface = sfp_select_interface(pl->sfp_bus, config.advertising);
|
||||
if (iface == PHY_INTERFACE_MODE_NA) {
|
||||
netdev_err(pl->netdev,
|
||||
@@ -1677,18 +1671,18 @@ static int phylink_sfp_module_insert(voi
|
||||
}
|
||||
|
||||
config.interface = iface;
|
||||
+ linkmode_copy(support1, support);
|
||||
ret = phylink_validate(pl, support1, &config);
|
||||
if (ret) {
|
||||
netdev_err(pl->netdev, "validation of %s/%s with support %*pb failed: %d\n",
|
||||
- phylink_an_mode_str(MLO_AN_INBAND),
|
||||
+ phylink_an_mode_str(mode),
|
||||
phy_modes(config.interface),
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
netdev_dbg(pl->netdev, "requesting link mode %s/%s with support %*pb\n",
|
||||
- phylink_an_mode_str(MLO_AN_INBAND),
|
||||
- phy_modes(config.interface),
|
||||
+ phylink_an_mode_str(mode), phy_modes(config.interface),
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS, support);
|
||||
|
||||
if (phy_interface_mode_is_8023z(iface) && pl->phydev)
|
||||
@@ -1701,15 +1695,15 @@ static int phylink_sfp_module_insert(voi
|
||||
linkmode_copy(pl->link_config.advertising, config.advertising);
|
||||
}
|
||||
|
||||
- if (pl->cur_link_an_mode != MLO_AN_INBAND ||
|
||||
+ if (pl->cur_link_an_mode != mode ||
|
||||
pl->link_config.interface != config.interface) {
|
||||
pl->link_config.interface = config.interface;
|
||||
- pl->cur_link_an_mode = MLO_AN_INBAND;
|
||||
+ pl->cur_link_an_mode = mode;
|
||||
|
||||
changed = true;
|
||||
|
||||
netdev_info(pl->netdev, "switched to %s/%s link mode\n",
|
||||
- phylink_an_mode_str(MLO_AN_INBAND),
|
||||
+ phylink_an_mode_str(mode),
|
||||
phy_modes(config.interface));
|
||||
}
|
||||
|
||||
@@ -1722,6 +1716,21 @@ static int phylink_sfp_module_insert(voi
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int phylink_sfp_module_insert(void *upstream,
|
||||
+ const struct sfp_eeprom_id *id)
|
||||
+{
|
||||
+ struct phylink *pl = upstream;
|
||||
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
|
||||
+ u8 port;
|
||||
+
|
||||
+ ASSERT_RTNL();
|
||||
+
|
||||
+ sfp_parse_support(pl->sfp_bus, id, support);
|
||||
+ port = sfp_parse_port(pl->sfp_bus, id, support);
|
||||
+
|
||||
+ return phylink_sfp_config(pl, MLO_AN_INBAND, port, support, support);
|
||||
+}
|
||||
+
|
||||
static int phylink_sfp_module_start(void *upstream)
|
||||
{
|
||||
struct phylink *pl = upstream;
|
|
@ -0,0 +1,204 @@
|
|||
From eb514428f75bc67d12ff019c44a8f8ca9f33c54c Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Thu, 21 Nov 2019 17:42:49 +0000
|
||||
Subject: [PATCH 653/660] net: phylink: delay MAC configuration for copper SFP
|
||||
modules
|
||||
|
||||
Knowing whether we need to delay the MAC configuration because a module
|
||||
may have a PHY is useful to phylink to allow NBASE-T modules to work on
|
||||
systems supporting no more than 2.5G speeds.
|
||||
|
||||
This commit allows us to delay such configuration until after the PHY
|
||||
has been probed by recording the parsed capabilities, and if the module
|
||||
may have a PHY, doing no more until the module_start() notification is
|
||||
called. At that point, we either have a PHY, or we don't.
|
||||
|
||||
We move the PHY-based setup a little later, and use the PHYs support
|
||||
capabilities rather than the EEPROM parsed capabilities to determine
|
||||
whether we can support the PHY.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 59 +++++++++++++++++++++++++++++++--------
|
||||
drivers/net/phy/sfp-bus.c | 28 +++++++++++++++++++
|
||||
include/linux/sfp.h | 7 +++++
|
||||
3 files changed, 83 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -72,6 +72,9 @@ struct phylink {
|
||||
bool mac_link_dropped;
|
||||
|
||||
struct sfp_bus *sfp_bus;
|
||||
+ bool sfp_may_have_phy;
|
||||
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
|
||||
+ u8 sfp_port;
|
||||
};
|
||||
|
||||
static inline void linkmode_zero(unsigned long *dst)
|
||||
@@ -1633,7 +1636,7 @@ static void phylink_sfp_detach(void *ups
|
||||
pl->netdev->sfp_bus = NULL;
|
||||
}
|
||||
|
||||
-static int phylink_sfp_config(struct phylink *pl, u8 mode, u8 port,
|
||||
+static int phylink_sfp_config(struct phylink *pl, u8 mode,
|
||||
const unsigned long *supported,
|
||||
const unsigned long *advertising)
|
||||
{
|
||||
@@ -1707,7 +1710,7 @@ static int phylink_sfp_config(struct phy
|
||||
phy_modes(config.interface));
|
||||
}
|
||||
|
||||
- pl->link_port = port;
|
||||
+ pl->link_port = pl->sfp_port;
|
||||
|
||||
if (changed && !test_bit(PHYLINK_DISABLE_STOPPED,
|
||||
&pl->phylink_disable_state))
|
||||
@@ -1720,15 +1723,20 @@ static int phylink_sfp_module_insert(voi
|
||||
const struct sfp_eeprom_id *id)
|
||||
{
|
||||
struct phylink *pl = upstream;
|
||||
- __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
|
||||
- u8 port;
|
||||
+ unsigned long *support = pl->sfp_support;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
+ linkmode_zero(support);
|
||||
sfp_parse_support(pl->sfp_bus, id, support);
|
||||
- port = sfp_parse_port(pl->sfp_bus, id, support);
|
||||
+ pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support);
|
||||
|
||||
- return phylink_sfp_config(pl, MLO_AN_INBAND, port, support, support);
|
||||
+ /* If this module may have a PHY connecting later, defer until later */
|
||||
+ pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id);
|
||||
+ if (pl->sfp_may_have_phy)
|
||||
+ return 0;
|
||||
+
|
||||
+ return phylink_sfp_config(pl, MLO_AN_INBAND, support, support);
|
||||
}
|
||||
|
||||
static int phylink_sfp_module_start(void *upstream)
|
||||
@@ -1736,10 +1744,19 @@ static int phylink_sfp_module_start(void
|
||||
struct phylink *pl = upstream;
|
||||
|
||||
/* If this SFP module has a PHY, start the PHY now. */
|
||||
- if (pl->phydev)
|
||||
+ if (pl->phydev) {
|
||||
phy_start(pl->phydev);
|
||||
-
|
||||
- return 0;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ /* If the module may have a PHY but we didn't detect one we
|
||||
+ * need to configure the MAC here.
|
||||
+ */
|
||||
+ if (!pl->sfp_may_have_phy)
|
||||
+ return 0;
|
||||
+
|
||||
+ return phylink_sfp_config(pl, MLO_AN_INBAND,
|
||||
+ pl->sfp_support, pl->sfp_support);
|
||||
}
|
||||
|
||||
static void phylink_sfp_module_stop(void *upstream)
|
||||
@@ -1773,10 +1790,30 @@ static void phylink_sfp_link_up(void *up
|
||||
static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
|
||||
{
|
||||
struct phylink *pl = upstream;
|
||||
- phy_interface_t interface = pl->link_config.interface;
|
||||
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
|
||||
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
|
||||
+ phy_interface_t interface;
|
||||
int ret;
|
||||
|
||||
- ret = phylink_attach_phy(pl, phy, pl->link_config.interface);
|
||||
+ /*
|
||||
+ * This is the new way of dealing with flow control for PHYs,
|
||||
+ * as described by Timur Tabi in commit 529ed1275263 ("net: phy:
|
||||
+ * phy drivers should not set SUPPORTED_[Asym_]Pause") except
|
||||
+ * using our validate call to the MAC, we rely upon the MAC
|
||||
+ * clearing the bits from both supported and advertising fields.
|
||||
+ */
|
||||
+ phy_support_asym_pause(phy);
|
||||
+
|
||||
+ ethtool_convert_legacy_u32_to_link_mode(supported, phy->supported);
|
||||
+ ethtool_convert_legacy_u32_to_link_mode(advertising, phy->advertising);
|
||||
+
|
||||
+ /* Do the initial configuration */
|
||||
+ ret = phylink_sfp_config(pl, ML_AN_INBAND, supported, advertising);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ interface = pl->link_config.interface;
|
||||
+ ret = phylink_attach_phy(pl, phy, interface);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -102,6 +102,7 @@ static const struct sfp_quirk *sfp_looku
|
||||
|
||||
return NULL;
|
||||
}
|
||||
+
|
||||
/**
|
||||
* sfp_parse_port() - Parse the EEPROM base ID, setting the port type
|
||||
* @bus: a pointer to the &struct sfp_bus structure for the sfp module
|
||||
@@ -178,6 +179,33 @@ int sfp_parse_port(struct sfp_bus *bus,
|
||||
EXPORT_SYMBOL_GPL(sfp_parse_port);
|
||||
|
||||
/**
|
||||
+ * sfp_may_have_phy() - indicate whether the module may have a PHY
|
||||
+ * @bus: a pointer to the &struct sfp_bus structure for the sfp module
|
||||
+ * @id: a pointer to the module's &struct sfp_eeprom_id
|
||||
+ *
|
||||
+ * Parse the EEPROM identification given in @id, and return whether
|
||||
+ * this module may have a PHY.
|
||||
+ */
|
||||
+bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id)
|
||||
+{
|
||||
+ if (id->base.e1000_base_t)
|
||||
+ return true;
|
||||
+
|
||||
+ if (id->base.phys_id != SFF8024_ID_DWDM_SFP) {
|
||||
+ switch (id->base.extended_cc) {
|
||||
+ case SFF8024_ECC_10GBASE_T_SFI:
|
||||
+ case SFF8024_ECC_10GBASE_T_SR:
|
||||
+ case SFF8024_ECC_5GBASE_T:
|
||||
+ case SFF8024_ECC_2_5GBASE_T:
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(sfp_may_have_phy);
|
||||
+
|
||||
+/**
|
||||
* sfp_parse_support() - Parse the eeprom id for supported link modes
|
||||
* @bus: a pointer to the &struct sfp_bus structure for the sfp module
|
||||
* @id: a pointer to the module's &struct sfp_eeprom_id
|
||||
--- a/include/linux/sfp.h
|
||||
+++ b/include/linux/sfp.h
|
||||
@@ -533,6 +533,7 @@ struct sfp_upstream_ops {
|
||||
#if IS_ENABLED(CONFIG_SFP)
|
||||
int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
|
||||
unsigned long *support);
|
||||
+bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
|
||||
void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
|
||||
unsigned long *support);
|
||||
phy_interface_t sfp_select_interface(struct sfp_bus *bus,
|
||||
@@ -556,6 +557,12 @@ static inline int sfp_parse_port(struct
|
||||
return PORT_OTHER;
|
||||
}
|
||||
|
||||
+static inline bool sfp_may_have_phy(struct sfp_bus *bus,
|
||||
+ const struct sfp_eeprom_id *id)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static inline void sfp_parse_support(struct sfp_bus *bus,
|
||||
const struct sfp_eeprom_id *id,
|
||||
unsigned long *support)
|
|
@ -0,0 +1,58 @@
|
|||
From 3d8592a23dd67fb78ad85ddf711a059d3880fcb4 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 8 Nov 2019 17:19:16 +0000
|
||||
Subject: [PATCH 654/660] net: phylink: make Broadcom BCM84881 based SFPs work
|
||||
|
||||
The Broadcom BCM84881 does not appear to send the SGMII control word
|
||||
when operating in SGMII mode, which causes network adapters to fail
|
||||
to link with the PHY, or decide to operate at fixed 1G speed, even if
|
||||
the PHY negotiated 100M.
|
||||
|
||||
Work around this by detecting the Broadcom BCM84881 and switch to phy
|
||||
mode rather than inband mode.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 17 ++++++++++++++++-
|
||||
1 file changed, 16 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -1787,12 +1787,22 @@ static void phylink_sfp_link_up(void *up
|
||||
phylink_run_resolve(pl);
|
||||
}
|
||||
|
||||
+/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
|
||||
+ * or 802.3z control word, so inband will not work.
|
||||
+ */
|
||||
+static bool phylink_phy_no_inband(struct phy_device *phy)
|
||||
+{
|
||||
+ return phy->is_c45 &&
|
||||
+ (phy->c45_ids.device_ids[1] & 0xfffffff0) == 0xae025150;
|
||||
+}
|
||||
+
|
||||
static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
|
||||
{
|
||||
struct phylink *pl = upstream;
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
|
||||
phy_interface_t interface;
|
||||
+ u8 mode;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@@ -1807,8 +1817,13 @@ static int phylink_sfp_connect_phy(void
|
||||
ethtool_convert_legacy_u32_to_link_mode(supported, phy->supported);
|
||||
ethtool_convert_legacy_u32_to_link_mode(advertising, phy->advertising);
|
||||
|
||||
+ if (phylink_phy_no_inband(phy))
|
||||
+ mode = MLO_AN_PHY;
|
||||
+ else
|
||||
+ mode = MLO_AN_INBAND;
|
||||
+
|
||||
/* Do the initial configuration */
|
||||
- ret = phylink_sfp_config(pl, ML_AN_INBAND, supported, advertising);
|
||||
+ ret = phylink_sfp_config(pl, mode, supported, advertising);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
From 0f669e10ede7f06bb998373de6a9d169f47fcc66 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 5 Nov 2019 11:54:30 +0000
|
||||
Subject: [PATCH 655/660] net: phy: add Broadcom BCM84881 PHY driver
|
||||
|
||||
Add a rudimentary Clause 45 driver for the BCM84881 PHY, found on
|
||||
Methode DM7052 SFPs.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/Kconfig | 5 +
|
||||
drivers/net/phy/Makefile | 1 +
|
||||
drivers/net/phy/bcm84881.c | 290 +++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 296 insertions(+)
|
||||
create mode 100644 drivers/net/phy/bcm84881.c
|
||||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -280,6 +280,11 @@ config BROADCOM_PHY
|
||||
Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
|
||||
BCM5481, BCM54810 and BCM5482 PHYs.
|
||||
|
||||
+config BCM84881_PHY
|
||||
+ tristate "Broadcom BCM84881 PHY"
|
||||
+ ---help---
|
||||
+ Support the Broadcom BCM84881 PHY.
|
||||
+
|
||||
config CICADA_PHY
|
||||
tristate "Cicada PHYs"
|
||||
---help---
|
||||
--- a/drivers/net/phy/Makefile
|
||||
+++ b/drivers/net/phy/Makefile
|
||||
@@ -54,6 +54,7 @@ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o
|
||||
obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o
|
||||
obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o
|
||||
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
|
||||
+obj-$(CONFIG_BCM84881_PHY) += bcm84881.o
|
||||
obj-$(CONFIG_CICADA_PHY) += cicada.o
|
||||
obj-$(CONFIG_CORTINA_PHY) += cortina.o
|
||||
obj-$(CONFIG_DAVICOM_PHY) += davicom.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/phy/bcm84881.c
|
||||
@@ -0,0 +1,290 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+// Broadcom BCM84881 NBASE-T PHY driver, as found on a SFP+ module.
|
||||
+// Copyright (C) 2019 Russell King, Deep Blue Solutions Ltd.
|
||||
+//
|
||||
+// Like the Marvell 88x3310, the Broadcom 84881 changes its host-side
|
||||
+// interface according to the operating speed between 10GBASE-R,
|
||||
+// 2500BASE-X and SGMII (but unlike the 88x3310, without the control
|
||||
+// word).
|
||||
+//
|
||||
+// This driver only supports those aspects of the PHY that I'm able to
|
||||
+// observe and test with the SFP+ module, which is an incomplete subset
|
||||
+// of what this PHY is able to support. For example, I only assume it
|
||||
+// supports a single lane Serdes connection, but it may be that the PHY
|
||||
+// is able to support more than that.
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/phy.h>
|
||||
+
|
||||
+enum {
|
||||
+ MDIO_AN_C22 = 0xffe0,
|
||||
+};
|
||||
+
|
||||
+static int bcm84881_wait_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ unsigned int tries = 20;
|
||||
+ int ret, val;
|
||||
+
|
||||
+ do {
|
||||
+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
|
||||
+ if (val < 0) {
|
||||
+ ret = val;
|
||||
+ break;
|
||||
+ }
|
||||
+ if (!(val & MDIO_CTRL1_RESET)) {
|
||||
+ ret = 0;
|
||||
+ break;
|
||||
+ }
|
||||
+ if (!--tries) {
|
||||
+ ret = -ETIMEDOUT;
|
||||
+ break;
|
||||
+ }
|
||||
+ msleep(100);
|
||||
+ } while (1);
|
||||
+
|
||||
+ if (ret)
|
||||
+ phydev_err(phydev, "%s failed: %d\n", __func__, ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int bcm84881_config_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ switch (phydev->interface) {
|
||||
+ case PHY_INTERFACE_MODE_SGMII:
|
||||
+ case PHY_INTERFACE_MODE_2500BASEX:
|
||||
+ case PHY_INTERFACE_MODE_10GKR:
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bcm84881_probe(struct phy_device *phydev)
|
||||
+{
|
||||
+ /* This driver requires PMAPMD and AN blocks */
|
||||
+ const u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
|
||||
+
|
||||
+ if (!phydev->is_c45 ||
|
||||
+ (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int genphy_c45_an_config_aneg(struct phy_device *phydev)
|
||||
+{
|
||||
+ bool changed = false;
|
||||
+ u32 advertising;
|
||||
+ int ret;
|
||||
+
|
||||
+ phydev->advertising &= phydev->supported;
|
||||
+ advertising = phydev->advertising;
|
||||
+
|
||||
+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE,
|
||||
+ ADVERTISE_ALL | ADVERTISE_100BASE4 |
|
||||
+ ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
|
||||
+ ethtool_adv_to_mii_adv_t(advertising));
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ if (ret > 0)
|
||||
+ changed = true;
|
||||
+
|
||||
+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
|
||||
+ MDIO_AN_10GBT_CTRL_ADV10G,
|
||||
+ advertising & ADVERTISED_10000baseT_Full ?
|
||||
+ MDIO_AN_10GBT_CTRL_ADV10G : 0);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ if (ret > 0)
|
||||
+ changed = true;
|
||||
+
|
||||
+ return genphy_c45_check_and_restart_aneg(phydev, changed);
|
||||
+}
|
||||
+
|
||||
+static int bcm84881_config_aneg(struct phy_device *phydev)
|
||||
+{
|
||||
+ bool changed = false;
|
||||
+ u32 adv;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Wait for the PHY to finish initialising, otherwise our
|
||||
+ * advertisement may be overwritten.
|
||||
+ */
|
||||
+ ret = bcm84881_wait_init(phydev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* We don't support manual MDI control */
|
||||
+ phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
|
||||
+
|
||||
+ /* disabled autoneg doesn't seem to work with this PHY */
|
||||
+ if (phydev->autoneg == AUTONEG_DISABLE)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ ret = genphy_c45_an_config_aneg(phydev);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ if (ret > 0)
|
||||
+ changed = true;
|
||||
+
|
||||
+ adv = ethtool_adv_to_mii_ctrl1000_t(phydev->advertising);
|
||||
+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN,
|
||||
+ MDIO_AN_C22 + MII_CTRL1000,
|
||||
+ ADVERTISE_1000FULL | ADVERTISE_1000HALF,
|
||||
+ adv);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ if (ret > 0)
|
||||
+ changed = true;
|
||||
+
|
||||
+ return genphy_c45_check_and_restart_aneg(phydev, changed);
|
||||
+}
|
||||
+
|
||||
+static int bcm84881_aneg_done(struct phy_device *phydev)
|
||||
+{
|
||||
+ int bmsr, val;
|
||||
+
|
||||
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
|
||||
+ if (val < 0)
|
||||
+ return val;
|
||||
+
|
||||
+ bmsr = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_C22 + MII_BMSR);
|
||||
+ if (bmsr < 0)
|
||||
+ return val;
|
||||
+
|
||||
+ return !!(val & MDIO_AN_STAT1_COMPLETE) &&
|
||||
+ !!(bmsr & BMSR_ANEGCOMPLETE);
|
||||
+}
|
||||
+
|
||||
+static int bcm84881_read_status(struct phy_device *phydev)
|
||||
+{
|
||||
+ bool autoneg_complete;
|
||||
+ unsigned int mode;
|
||||
+ int bmsr, val;
|
||||
+
|
||||
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
|
||||
+ if (val < 0)
|
||||
+ return val;
|
||||
+
|
||||
+ if (val & MDIO_AN_CTRL1_RESTART) {
|
||||
+ phydev->link = 0;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
|
||||
+ if (val < 0)
|
||||
+ return val;
|
||||
+
|
||||
+ bmsr = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_C22 + MII_BMSR);
|
||||
+ if (bmsr < 0)
|
||||
+ return val;
|
||||
+
|
||||
+ autoneg_complete = !!(val & MDIO_AN_STAT1_COMPLETE) &&
|
||||
+ !!(bmsr & BMSR_ANEGCOMPLETE);
|
||||
+ phydev->link = !!(val & MDIO_STAT1_LSTATUS) &&
|
||||
+ !!(bmsr & BMSR_LSTATUS);
|
||||
+ if (phydev->autoneg == AUTONEG_ENABLE && !autoneg_complete)
|
||||
+ phydev->link = false;
|
||||
+
|
||||
+ if (!phydev->link)
|
||||
+ return 0;
|
||||
+
|
||||
+ phydev->lp_advertising = 0;
|
||||
+ phydev->speed = SPEED_UNKNOWN;
|
||||
+ phydev->duplex = DUPLEX_UNKNOWN;
|
||||
+ phydev->pause = 0;
|
||||
+ phydev->asym_pause = 0;
|
||||
+ phydev->mdix = 0;
|
||||
+
|
||||
+ if (autoneg_complete) {
|
||||
+ val = genphy_c45_read_lpa(phydev);
|
||||
+ if (val < 0)
|
||||
+ return val;
|
||||
+
|
||||
+ val = phy_read_mmd(phydev, MDIO_MMD_AN,
|
||||
+ MDIO_AN_C22 + MII_STAT1000);
|
||||
+ if (val < 0)
|
||||
+ return val;
|
||||
+
|
||||
+ phydev->lp_advertising |= mii_stat1000_to_ethtool_lpa_t(val);
|
||||
+
|
||||
+ if (phydev->autoneg == AUTONEG_ENABLE)
|
||||
+ phy_resolve_aneg_linkmode(phydev);
|
||||
+ }
|
||||
+
|
||||
+ if (phydev->autoneg == AUTONEG_DISABLE) {
|
||||
+ /* disabled autoneg doesn't seem to work, so force the link
|
||||
+ * down.
|
||||
+ */
|
||||
+ phydev->link = 0;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ /* Set the host link mode - we set the phy interface mode and
|
||||
+ * the speed according to this register so that downshift works.
|
||||
+ * We leave the duplex setting as per the resolution from the
|
||||
+ * above.
|
||||
+ */
|
||||
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x4011);
|
||||
+ mode = (val & 0x1e) >> 1;
|
||||
+ if (mode == 1 || mode == 2)
|
||||
+ phydev->interface = PHY_INTERFACE_MODE_SGMII;
|
||||
+ else if (mode == 3)
|
||||
+ phydev->interface = PHY_INTERFACE_MODE_10GKR;
|
||||
+ else if (mode == 4)
|
||||
+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
|
||||
+ switch (mode & 7) {
|
||||
+ case 1:
|
||||
+ phydev->speed = SPEED_100;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ phydev->speed = SPEED_1000;
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ phydev->speed = SPEED_10000;
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ phydev->speed = SPEED_2500;
|
||||
+ break;
|
||||
+ case 5:
|
||||
+ phydev->speed = SPEED_5000;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return genphy_c45_read_mdix(phydev);
|
||||
+}
|
||||
+
|
||||
+static struct phy_driver bcm84881_drivers[] = {
|
||||
+ {
|
||||
+ .phy_id = 0xae025150,
|
||||
+ .phy_id_mask = 0xfffffff0,
|
||||
+ .name = "Broadcom BCM84881",
|
||||
+ .features = SUPPORTED_100baseT_Full |
|
||||
+ SUPPORTED_100baseT_Half |
|
||||
+ SUPPORTED_1000baseT_Full |
|
||||
+ SUPPORTED_Autoneg |
|
||||
+ SUPPORTED_TP |
|
||||
+ SUPPORTED_FIBRE |
|
||||
+ SUPPORTED_10000baseT_Full |
|
||||
+ SUPPORTED_Backplane,
|
||||
+ .config_init = bcm84881_config_init,
|
||||
+ .probe = bcm84881_probe,
|
||||
+ .config_aneg = bcm84881_config_aneg,
|
||||
+ .aneg_done = bcm84881_aneg_done,
|
||||
+ .read_status = bcm84881_read_status,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_phy_driver(bcm84881_drivers);
|
||||
+
|
||||
+/* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */
|
||||
+static struct mdio_device_id __maybe_unused bcm84881_tbl[] = {
|
||||
+ { 0xae025150, 0xfffffff0 },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_AUTHOR("Russell King");
|
||||
+MODULE_DESCRIPTION("Broadcom BCM84881 PHY driver");
|
||||
+MODULE_DEVICE_TABLE(mdio, bcm84881_tbl);
|
||||
+MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,94 @@
|
|||
From 6df6709dc3d00e0bc948d45dfa8d8f18ba379c48 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 5 Nov 2019 11:56:18 +0000
|
||||
Subject: [PATCH 656/660] net: sfp: add support for Clause 45 PHYs
|
||||
|
||||
Some SFP+ modules have a Clause 45 PHY onboard, which is accessible via
|
||||
the normal I2C address. Detect 10G BASE-T PHYs which may have an
|
||||
accessible PHY and probe for it.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 44 +++++++++++++++++++++++++++++++++++++++----
|
||||
1 file changed, 40 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -1326,12 +1326,12 @@ static void sfp_sm_phy_detach(struct sfp
|
||||
sfp->mod_phy = NULL;
|
||||
}
|
||||
|
||||
-static void sfp_sm_probe_phy(struct sfp *sfp)
|
||||
+static void sfp_sm_probe_phy(struct sfp *sfp, bool is_c45)
|
||||
{
|
||||
struct phy_device *phy;
|
||||
int err;
|
||||
|
||||
- phy = mdiobus_scan(sfp->i2c_mii, SFP_PHY_ADDR);
|
||||
+ phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45);
|
||||
if (phy == ERR_PTR(-ENODEV)) {
|
||||
dev_info(sfp->dev, "no PHY detected\n");
|
||||
return;
|
||||
@@ -1341,6 +1341,13 @@ static void sfp_sm_probe_phy(struct sfp
|
||||
return;
|
||||
}
|
||||
|
||||
+ err = phy_device_register(phy);
|
||||
+ if (err) {
|
||||
+ phy_device_free(phy);
|
||||
+ dev_err(sfp->dev, "phy_device_register failed: %d\n", err);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
err = sfp_add_phy(sfp->sfp_bus, phy);
|
||||
if (err) {
|
||||
phy_device_remove(phy);
|
||||
@@ -1411,10 +1418,32 @@ static void sfp_sm_fault(struct sfp *sfp
|
||||
}
|
||||
}
|
||||
|
||||
+/* Probe a SFP for a PHY device if the module supports copper - the PHY
|
||||
+ * normally sits at I2C bus address 0x56, and may either be a clause 22
|
||||
+ * or clause 45 PHY.
|
||||
+ *
|
||||
+ * Clause 22 copper SFP modules normally operate in Cisco SGMII mode with
|
||||
+ * negotiation enabled, but some may be in 1000base-X - which is for the
|
||||
+ * PHY driver to determine.
|
||||
+ *
|
||||
+ * Clause 45 copper SFP+ modules (10G) appear to switch their interface
|
||||
+ * mode according to the negotiated line speed.
|
||||
+ */
|
||||
static void sfp_sm_probe_for_phy(struct sfp *sfp)
|
||||
{
|
||||
- if (sfp->id.base.e1000_base_t)
|
||||
- sfp_sm_probe_phy(sfp);
|
||||
+ switch (sfp->id.base.extended_cc) {
|
||||
+ case SFF8024_ECC_10GBASE_T_SFI:
|
||||
+ case SFF8024_ECC_10GBASE_T_SR:
|
||||
+ case SFF8024_ECC_5GBASE_T:
|
||||
+ case SFF8024_ECC_2_5GBASE_T:
|
||||
+ sfp_sm_probe_phy(sfp, true);
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ if (sfp->id.base.e1000_base_t)
|
||||
+ sfp_sm_probe_phy(sfp, false);
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
|
||||
static int sfp_module_parse_power(struct sfp *sfp)
|
||||
@@ -1474,6 +1503,13 @@ static int sfp_sm_mod_hpower(struct sfp
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
+ /* DM7052 reports as a high power module, responds to reads (with
|
||||
+ * all bytes 0xff) at 0x51 but does not accept writes. In any case,
|
||||
+ * if the bit is already set, we're already in high power mode.
|
||||
+ */
|
||||
+ if (!!(val & BIT(0)) == enable)
|
||||
+ return 0;
|
||||
+
|
||||
if (enable)
|
||||
val |= BIT(0);
|
||||
else
|
Loading…
Reference in New Issue