* [PATCH RFC net-next 1/8] dt-bindings: ethernet-controller: support multiple PHY connection types
2021-11-10 19:07 [PATCH RFC net-next 0/8] Extend `phy-mode` to string array Marek Behún
@ 2021-11-10 19:07 ` Marek Behún
2021-11-10 19:07 ` [PATCH RFC net-next 2/8] net: Update documentation for *_get_phy_mode() functions Marek Behún
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Marek Behún @ 2021-11-10 19:07 UTC (permalink / raw)
To: Andrew Lunn, netdev
Cc: devicetree, Rob Herring, Russell King, pali, Marek Behún
Sometimes, an ethernet PHY may communicate with ethernet controller with
multiple different PHY connection types, and the software should be able
to choose between them.
Russell King says:
conventionally phy-mode has meant "this is the mode we want to operate
the PHY interface in" which was fine when PHYs didn't change their
mode depending on the media speed
This is no longer the case, since we have PHYs that can change PHY mode.
Existing example is the Marvell 88X3310 PHY, which supports connecting
the MAC with the PHY with `xaui` and `rxaui`. The MAC may also support
both modes, but it is possible that a particular board doesn't have
these modes wired (since they use multiple SerDes lanes).
Another example is one SerDes lane capable of `1000base-x`, `2500base-x`
and `sgmii` when connecting Marvell switches with Marvell ethernet
controller. Currently we mention only one of these modes in device-tree,
and software assumes the other modes are also supported, since they use
the same SerDes lanes. But a board may be able to support `1000base-x`
and not support `2500base-x`, for example due to the higher frequency
not working correctly on a particular board.
In order for the kernel to know which modes are supported on the board,
we need to be able to specify them all in the device-tree.
Change the type of property `phy-connection-type` of an ethernet
controller to be an array of the enumerated strings, instead of just one
string. Require at least one item defined.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
.../bindings/net/ethernet-controller.yaml | 88 ++++++++++---------
1 file changed, 45 insertions(+), 43 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/ethernet-controller.yaml b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
index b0933a8c295a..05a02fdc7ca9 100644
--- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml
+++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml
@@ -56,49 +56,51 @@ properties:
description:
Specifies interface type between the Ethernet device and a physical
layer (PHY) device.
- enum:
- # There is not a standard bus between the MAC and the PHY,
- # something proprietary is being used to embed the PHY in the
- # MAC.
- - internal
- - mii
- - gmii
- - sgmii
- - qsgmii
- - tbi
- - rev-mii
- - rmii
- - rev-rmii
-
- # RX and TX delays are added by the MAC when required
- - rgmii
-
- # RGMII with internal RX and TX delays provided by the PHY,
- # the MAC should not add the RX or TX delays in this case
- - rgmii-id
-
- # RGMII with internal RX delay provided by the PHY, the MAC
- # should not add an RX delay in this case
- - rgmii-rxid
-
- # RGMII with internal TX delay provided by the PHY, the MAC
- # should not add an TX delay in this case
- - rgmii-txid
- - rtbi
- - smii
- - xgmii
- - trgmii
- - 1000base-x
- - 2500base-x
- - 5gbase-r
- - rxaui
- - xaui
-
- # 10GBASE-KR, XFI, SFI
- - 10gbase-kr
- - usxgmii
- - 10gbase-r
- - 25gbase-r
+ minItems: 1
+ items:
+ enum:
+ # There is not a standard bus between the MAC and the PHY,
+ # something proprietary is being used to embed the PHY in the
+ # MAC.
+ - internal
+ - mii
+ - gmii
+ - sgmii
+ - qsgmii
+ - tbi
+ - rev-mii
+ - rmii
+ - rev-rmii
+
+ # RX and TX delays are added by the MAC when required
+ - rgmii
+
+ # RGMII with internal RX and TX delays provided by the PHY,
+ # the MAC should not add the RX or TX delays in this case
+ - rgmii-id
+
+ # RGMII with internal RX delay provided by the PHY, the MAC
+ # should not add an RX delay in this case
+ - rgmii-rxid
+
+ # RGMII with internal TX delay provided by the PHY, the MAC
+ # should not add an TX delay in this case
+ - rgmii-txid
+ - rtbi
+ - smii
+ - xgmii
+ - trgmii
+ - 1000base-x
+ - 2500base-x
+ - 5gbase-r
+ - rxaui
+ - xaui
+
+ # 10GBASE-KR, XFI, SFI
+ - 10gbase-kr
+ - usxgmii
+ - 10gbase-r
+ - 25gbase-r
phy-mode:
$ref: "#/properties/phy-connection-type"
--
2.32.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH RFC net-next 2/8] net: Update documentation for *_get_phy_mode() functions
2021-11-10 19:07 [PATCH RFC net-next 0/8] Extend `phy-mode` to string array Marek Behún
2021-11-10 19:07 ` [PATCH RFC net-next 1/8] dt-bindings: ethernet-controller: support multiple PHY connection types Marek Behún
@ 2021-11-10 19:07 ` Marek Behún
2021-11-10 19:07 ` [PATCH RFC net-next 3/8] device property: add helper function for getting phy mode bitmap Marek Behún
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Marek Behún @ 2021-11-10 19:07 UTC (permalink / raw)
To: Andrew Lunn, netdev
Cc: devicetree, Rob Herring, Russell King, pali, Marek Behún
Now that the `phy-mode` DT property can be an array of strings instead
of just one string, update the documentation for of_get_phy_mode(),
fwnode_get_phy_mode() and device_get_phy_mode() saying that if multiple
strings are present, the first one is returned.
Conventionally the property was used to represent the mode we want the
PHY to operate in, but we extended this to mean the list of all
supported modes by that PHY on that particular board.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/base/property.c | 14 ++++++++------
net/core/of_net.c | 9 +++++----
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index f1f35b48ab8b..e12aef10f7fd 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -893,12 +893,13 @@ enum dev_dma_attr device_get_dma_attr(struct device *dev)
EXPORT_SYMBOL_GPL(device_get_dma_attr);
/**
- * fwnode_get_phy_mode - Get phy mode for given firmware node
+ * fwnode_get_phy_mode - Get first phy mode for given firmware node
* @fwnode: Pointer to the given node
*
* The function gets phy interface string from property 'phy-mode' or
- * 'phy-connection-type', and return its index in phy_modes table, or errno in
- * error case.
+ * 'phy-connection-type', and returns its index in phy_modes table, or errno in
+ * error case. If there are multiple strings in the property, the first one is
+ * used.
*/
int fwnode_get_phy_mode(struct fwnode_handle *fwnode)
{
@@ -921,12 +922,13 @@ int fwnode_get_phy_mode(struct fwnode_handle *fwnode)
EXPORT_SYMBOL_GPL(fwnode_get_phy_mode);
/**
- * device_get_phy_mode - Get phy mode for given device
+ * device_get_phy_mode - Get first phy mode for given device
* @dev: Pointer to the given device
*
* The function gets phy interface string from property 'phy-mode' or
- * 'phy-connection-type', and return its index in phy_modes table, or errno in
- * error case.
+ * 'phy-connection-type', and returns its index in phy_modes table, or errno in
+ * error case. If there are multiple strings in the property, the first one is
+ * used.
*/
int device_get_phy_mode(struct device *dev)
{
diff --git a/net/core/of_net.c b/net/core/of_net.c
index f1a9bf7578e7..7cd10f0ef679 100644
--- a/net/core/of_net.c
+++ b/net/core/of_net.c
@@ -14,14 +14,15 @@
#include <linux/nvmem-consumer.h>
/**
- * of_get_phy_mode - Get phy mode for given device_node
+ * of_get_phy_mode - Get first phy mode for given device_node
* @np: Pointer to the given device_node
* @interface: Pointer to the result
*
* The function gets phy interface string from property 'phy-mode' or
- * 'phy-connection-type'. The index in phy_modes table is set in
- * interface and 0 returned. In case of error interface is set to
- * PHY_INTERFACE_MODE_NA and an errno is returned, e.g. -ENODEV.
+ * 'phy-connection-type'. If there are more string in the property, the first
+ * one is used. The index in phy_modes table is set in interface and 0 returned.
+ * In case of error interface is set to PHY_INTERFACE_MODE_NA and an errno is
+ * returned, e.g. -ENODEV.
*/
int of_get_phy_mode(struct device_node *np, phy_interface_t *interface)
{
--
2.32.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH RFC net-next 3/8] device property: add helper function for getting phy mode bitmap
2021-11-10 19:07 [PATCH RFC net-next 0/8] Extend `phy-mode` to string array Marek Behún
2021-11-10 19:07 ` [PATCH RFC net-next 1/8] dt-bindings: ethernet-controller: support multiple PHY connection types Marek Behún
2021-11-10 19:07 ` [PATCH RFC net-next 2/8] net: Update documentation for *_get_phy_mode() functions Marek Behún
@ 2021-11-10 19:07 ` Marek Behún
2021-11-10 19:07 ` [PATCH RFC net-next 4/8] net: phylink: update supported_interfaces with modes from fwnode Marek Behún
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Marek Behún @ 2021-11-10 19:07 UTC (permalink / raw)
To: Andrew Lunn, netdev
Cc: devicetree, Rob Herring, Russell King, pali, Marek Behún
Now that the 'phy-mode' property can be a string array containing more
PHY modes, add helper function fwnode_get_phy_modes() that reads this
property and fills in PHY interfaces bitmap.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/base/property.c | 34 ++++++++++++++++++++++++++++++++++
include/linux/property.h | 3 +++
2 files changed, 37 insertions(+)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index e12aef10f7fd..9f9dbc2ae386 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -921,6 +921,40 @@ int fwnode_get_phy_mode(struct fwnode_handle *fwnode)
}
EXPORT_SYMBOL_GPL(fwnode_get_phy_mode);
+/**
+ * fwnode_get_phy_modes - Fill in phy modes bitmap for given firmware node
+ * @fwnode: Pointer to the given node
+ * @interfaces: Phy modes bitmask, as declared by DECLARE_PHY_INTERFACE_MASK()
+ *
+ * Reads the strings from property 'phy-mode' or 'phy-connection-type' and fills
+ * interfaces bitmask. Returns 0 on success, or errno on error.
+ */
+int fwnode_get_phy_modes(struct fwnode_handle *fwnode,
+ unsigned long *interfaces)
+{
+ const char *modes[PHY_INTERFACE_MODE_MAX];
+ int len, i, j;
+
+ len = fwnode_property_read_string_array(fwnode, "phy-mode", modes,
+ ARRAY_SIZE(modes));
+ if (len < 0)
+ len = fwnode_property_read_string_array(fwnode,
+ "phy-connection-type",
+ modes,
+ ARRAY_SIZE(modes));
+ if (len < 0)
+ return len;
+
+ phy_interface_zero(interfaces);
+ for (i = 0; i < len; ++i)
+ for (j = 0; j < PHY_INTERFACE_MODE_MAX; j++)
+ if (!strcasecmp(modes[i], phy_modes(j)))
+ __set_bit(j, interfaces);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fwnode_get_phy_modes);
+
/**
* device_get_phy_mode - Get first phy mode for given device
* @dev: Pointer to the given device
diff --git a/include/linux/property.h b/include/linux/property.h
index 88fa726a76df..99a74d524b2b 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -391,6 +391,9 @@ const void *device_get_match_data(struct device *dev);
int device_get_phy_mode(struct device *dev);
int fwnode_get_phy_mode(struct fwnode_handle *fwnode);
+int fwnode_get_phy_modes(struct fwnode_handle *fwnode,
+ unsigned long *interfaces);
+
struct fwnode_handle *fwnode_graph_get_next_endpoint(
const struct fwnode_handle *fwnode, struct fwnode_handle *prev);
struct fwnode_handle *
--
2.32.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH RFC net-next 4/8] net: phylink: update supported_interfaces with modes from fwnode
2021-11-10 19:07 [PATCH RFC net-next 0/8] Extend `phy-mode` to string array Marek Behún
` (2 preceding siblings ...)
2021-11-10 19:07 ` [PATCH RFC net-next 3/8] device property: add helper function for getting phy mode bitmap Marek Behún
@ 2021-11-10 19:07 ` Marek Behún
2021-11-10 19:07 ` [PATCH RFC net-next 5/8] net: phylink: pass supported PHY interface modes to phylib Marek Behún
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Marek Behún @ 2021-11-10 19:07 UTC (permalink / raw)
To: Andrew Lunn, netdev
Cc: devicetree, Rob Herring, Russell King, pali, Marek Behún
Now that the 'phy-mode' property can be a string array containing more
PHY modes (all that are supported by the board), update the bitmap of
interfaces supported by the MAC with this property.
Normally this would be a simple intersection (of interfaces supported by
the current implementation of the driver and interfaces supported by the
board), but we need to keep being backwards compatible with older DTs,
which may only define one mode, since, as Russell King says,
conventionally phy-mode has meant "this is the mode we want to operate
the PHY interface in" which was fine when PHYs didn't change their
mode depending on the media speed
An example is DT defining
phy-mode = "sgmii";
but the board supporting also 1000base-x and 2500base-x.
Add the following logic to keep this backwards compatiblity:
- if more PHY modes are defined, do a simple intersection
- if one PHY mode is defined:
- if it is sgmii, 1000base-x or 2500base-x, add all three and then do
the intersection
- if it is 10gbase-r or usxgmii, add both, and also 5gbase-r,
2500base-x, 1000base-x and sgmii, and then do the intersection
This is simple enough and should work for all boards.
Nonetheless it is possible (although extremely unlikely, in my opinion)
that a board will be found that (for example) defines
phy-mode = "sgmii";
and the MAC drivers supports sgmii, 1000base-x and 2500base-x, but the
board DOESN'T support 2500base-x, because of electrical reasons (since
the frequency is 2.5x of sgmii).
Our code will in this case incorrectly infer also support for
2500base-x. To avoid this, the board maintainer should either change DTS
to
phy-mode = "sgmii", "1000base-x";
and update device tree on all boards, or, if that is impossible, add a
fix into the function we are introducing in this commit.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/net/phy/phylink.c | 63 +++++++++++++++++++++++++++++++++++++++
include/linux/phy.h | 6 ++++
2 files changed, 69 insertions(+)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 3ad7397b8119..4a8a0adf8c6c 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -311,6 +311,67 @@ static int phylink_parse_fixedlink(struct phylink *pl,
return 0;
}
+static void phylink_update_phy_modes(struct phylink *pl,
+ struct fwnode_handle *fwnode)
+{
+ unsigned long *supported = pl->config->supported_interfaces;
+ DECLARE_PHY_INTERFACE_MASK(modes);
+
+ if (fwnode_get_phy_modes(fwnode, modes) < 0)
+ return;
+
+ if (phy_interface_empty(modes))
+ return;
+
+ /* If supported is empty, just copy modes defined in fwnode. */
+ if (phy_interface_empty(supported))
+ return phy_interface_copy(supported, modes);
+
+ /* We want the intersection of given supported modes with those defined
+ * in DT.
+ *
+ * Some older device-trees mention only one of `sgmii`, `1000base-x` or
+ * `2500base-x`, while supporting all three. Other mention `10gbase-r`
+ * or `usxgmii`, while supporting both, and also `sgmii`, `1000base-x`,
+ * `2500base-x` and `5gbase-r`.
+ * For backwards compatibility with these older DTs, make it so that if
+ * one of these modes is mentioned in DT and MAC supports more of them,
+ * keep all that are supported according to the logic above.
+ *
+ * Nonetheless it is possible that a device may support only one mode,
+ * for example 1000base-x, due to strapping pins or some other reasons.
+ * If a specific device supports only the mode mentioned in DT, the
+ * exception should be made here with of_machine_is_compatible().
+ */
+ if (bitmap_weight(modes, PHY_INTERFACE_MODE_MAX) == 1) {
+ bool lower = false;
+
+ if (test_bit(PHY_INTERFACE_MODE_10GBASER, modes) ||
+ test_bit(PHY_INTERFACE_MODE_USXGMII, modes)) {
+ if (test_bit(PHY_INTERFACE_MODE_5GBASER, supported))
+ __set_bit(PHY_INTERFACE_MODE_5GBASER, modes);
+ if (test_bit(PHY_INTERFACE_MODE_10GBASER, supported))
+ __set_bit(PHY_INTERFACE_MODE_10GBASER, modes);
+ if (test_bit(PHY_INTERFACE_MODE_USXGMII, supported))
+ __set_bit(PHY_INTERFACE_MODE_USXGMII, modes);
+ lower = true;
+ }
+
+ if (lower || (test_bit(PHY_INTERFACE_MODE_SGMII, modes) ||
+ test_bit(PHY_INTERFACE_MODE_1000BASEX, modes) ||
+ test_bit(PHY_INTERFACE_MODE_2500BASEX, modes))) {
+ if (test_bit(PHY_INTERFACE_MODE_SGMII, supported))
+ __set_bit(PHY_INTERFACE_MODE_SGMII, modes);
+ if (test_bit(PHY_INTERFACE_MODE_1000BASEX, supported))
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, modes);
+ if (test_bit(PHY_INTERFACE_MODE_2500BASEX, supported))
+ __set_bit(PHY_INTERFACE_MODE_2500BASEX, modes);
+ }
+ }
+
+ phy_interface_and(supported, supported, modes);
+}
+
static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)
{
struct fwnode_handle *dn;
@@ -904,6 +965,8 @@ struct phylink *phylink_create(struct phylink_config *config,
__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
+ phylink_update_phy_modes(pl, fwnode);
+
bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
linkmode_copy(pl->link_config.advertising, pl->supported);
phylink_validate(pl, pl->supported, &pl->link_config);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 96e43fbb2dd8..effa4137f173 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -169,6 +169,12 @@ static inline bool phy_interface_empty(const unsigned long *intf)
return bitmap_empty(intf, PHY_INTERFACE_MODE_MAX);
}
+static inline void phy_interface_copy(unsigned long *dst,
+ const unsigned long *src)
+{
+ bitmap_copy(dst, src, PHY_INTERFACE_MODE_MAX);
+}
+
static inline void phy_interface_and(unsigned long *dst, const unsigned long *a,
const unsigned long *b)
{
--
2.32.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH RFC net-next 5/8] net: phylink: pass supported PHY interface modes to phylib
2021-11-10 19:07 [PATCH RFC net-next 0/8] Extend `phy-mode` to string array Marek Behún
` (3 preceding siblings ...)
2021-11-10 19:07 ` [PATCH RFC net-next 4/8] net: phylink: update supported_interfaces with modes from fwnode Marek Behún
@ 2021-11-10 19:07 ` Marek Behún
2021-11-10 19:07 ` [PATCH RFC net-next 6/8] net: phy: marvell10g: Use generic macro for supported interfaces Marek Behún
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Marek Behún @ 2021-11-10 19:07 UTC (permalink / raw)
To: Andrew Lunn, netdev
Cc: devicetree, Rob Herring, Russell King, pali, Marek Behún
Pass the supported PHY interface types to phylib so that PHY drivers
can select an appropriate host configuration mode for their interface
according to the host capabilities.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/net/phy/phylink.c | 28 ++++++++++++++++++++++++++++
include/linux/phy.h | 4 ++++
2 files changed, 32 insertions(+)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 4a8a0adf8c6c..0697c88227f7 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1178,6 +1178,10 @@ int phylink_connect_phy(struct phylink *pl, struct phy_device *phy)
{
int ret;
+ /* Set the PHY's host supported interfaces */
+ phy_interface_copy(phy->host_interfaces,
+ pl->config->supported_interfaces);
+
/* Use PHY device/driver interface */
if (pl->link_interface == PHY_INTERFACE_MODE_NA) {
pl->link_interface = phy->interface;
@@ -1253,6 +1257,10 @@ int phylink_fwnode_phy_connect(struct phylink *pl,
if (!phy_dev)
return -ENODEV;
+ /* Set the PHY's host supported interfaces */
+ phy_interface_copy(phy_dev->host_interfaces,
+ pl->config->supported_interfaces);
+
ret = phy_attach_direct(pl->netdev, phy_dev, flags,
pl->link_interface);
if (ret) {
@@ -2437,6 +2445,8 @@ static bool phylink_phy_no_inband(struct phy_device *phy)
(phy->c45_ids.device_ids[1] & 0xfffffff0) == 0xae025150;
}
+static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
+
static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
{
struct phylink *pl = upstream;
@@ -2458,6 +2468,10 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
else
mode = MLO_AN_INBAND;
+ /* Set the PHY's host supported interfaces */
+ phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces,
+ pl->config->supported_interfaces);
+
/* Do the initial configuration */
ret = phylink_sfp_config(pl, mode, phy->supported, phy->advertising);
if (ret < 0)
@@ -2819,4 +2833,18 @@ void phylink_mii_c45_pcs_get_state(struct mdio_device *pcs,
}
EXPORT_SYMBOL_GPL(phylink_mii_c45_pcs_get_state);
+static int __init phylink_init(void)
+{
+ __set_bit(PHY_INTERFACE_MODE_USXGMII, phylink_sfp_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_10GBASER, phylink_sfp_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_10GKR, phylink_sfp_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_5GBASER, phylink_sfp_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_2500BASEX, phylink_sfp_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_SGMII, phylink_sfp_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, phylink_sfp_interfaces);
+
+ return 0;
+}
+module_init(phylink_init);
+
MODULE_LICENSE("GPL v2");
diff --git a/include/linux/phy.h b/include/linux/phy.h
index effa4137f173..e05146b383ab 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -569,6 +569,7 @@ struct macsec_ops;
* @advertising: Currently advertised linkmodes
* @adv_old: Saved advertised while power saving for WoL
* @lp_advertising: Current link partner advertised linkmodes
+ * @host_interfaces: PHY interface modes supported by host
* @eee_broken_modes: Energy efficient ethernet modes which should be prohibited
* @autoneg: Flag autoneg being used
* @link: Current link state
@@ -658,6 +659,9 @@ struct phy_device {
/* used with phy_speed_down */
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old);
+ /* host supported PHY interface types */
+ DECLARE_PHY_INTERFACE_MASK(host_interfaces);
+
/* Energy efficient ethernet modes which should be prohibited */
u32 eee_broken_modes;
--
2.32.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH RFC net-next 6/8] net: phy: marvell10g: Use generic macro for supported interfaces
2021-11-10 19:07 [PATCH RFC net-next 0/8] Extend `phy-mode` to string array Marek Behún
` (4 preceding siblings ...)
2021-11-10 19:07 ` [PATCH RFC net-next 5/8] net: phylink: pass supported PHY interface modes to phylib Marek Behún
@ 2021-11-10 19:07 ` Marek Behún
2021-11-10 19:07 ` [PATCH RFC net-next 7/8] net: phy: marvell10g: Use tabs instead of spaces for indentation Marek Behún
2021-11-10 19:07 ` [PATCH RFC net-next 8/8] net: phy: marvell10g: select host interface configuration Marek Behún
7 siblings, 0 replies; 9+ messages in thread
From: Marek Behún @ 2021-11-10 19:07 UTC (permalink / raw)
To: Andrew Lunn, netdev
Cc: devicetree, Rob Herring, Russell King, pali, Marek Behún
Now that phy.h defines macro DECLARE_PHY_INTERFACE_MASK(), use it
instead of DECLARE_BITMAP().
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/net/phy/marvell10g.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index b6fea119fe13..d289641190db 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -148,7 +148,7 @@ struct mv3310_chip {
};
struct mv3310_priv {
- DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX);
+ DECLARE_PHY_INTERFACE_MASK(supported_interfaces);
u32 firmware_ver;
bool has_downshift;
--
2.32.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH RFC net-next 7/8] net: phy: marvell10g: Use tabs instead of spaces for indentation
2021-11-10 19:07 [PATCH RFC net-next 0/8] Extend `phy-mode` to string array Marek Behún
` (5 preceding siblings ...)
2021-11-10 19:07 ` [PATCH RFC net-next 6/8] net: phy: marvell10g: Use generic macro for supported interfaces Marek Behún
@ 2021-11-10 19:07 ` Marek Behún
2021-11-10 19:07 ` [PATCH RFC net-next 8/8] net: phy: marvell10g: select host interface configuration Marek Behún
7 siblings, 0 replies; 9+ messages in thread
From: Marek Behún @ 2021-11-10 19:07 UTC (permalink / raw)
To: Andrew Lunn, netdev
Cc: devicetree, Rob Herring, Russell King, pali, Marek Behún
Some register definitions were defined with spaces used for indentation.
Change them to tabs.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/net/phy/marvell10g.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index d289641190db..0cb9b4ef09c7 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -117,16 +117,16 @@ enum {
MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN = 0x5,
MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH = 0x6,
MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII = 0x7,
- MV_V2_PORT_INTR_STS = 0xf040,
- MV_V2_PORT_INTR_MASK = 0xf043,
- MV_V2_PORT_INTR_STS_WOL_EN = BIT(8),
- MV_V2_MAGIC_PKT_WORD0 = 0xf06b,
- MV_V2_MAGIC_PKT_WORD1 = 0xf06c,
- MV_V2_MAGIC_PKT_WORD2 = 0xf06d,
+ MV_V2_PORT_INTR_STS = 0xf040,
+ MV_V2_PORT_INTR_MASK = 0xf043,
+ MV_V2_PORT_INTR_STS_WOL_EN = BIT(8),
+ MV_V2_MAGIC_PKT_WORD0 = 0xf06b,
+ MV_V2_MAGIC_PKT_WORD1 = 0xf06c,
+ MV_V2_MAGIC_PKT_WORD2 = 0xf06d,
/* Wake on LAN registers */
- MV_V2_WOL_CTRL = 0xf06e,
- MV_V2_WOL_CTRL_CLEAR_STS = BIT(15),
- MV_V2_WOL_CTRL_MAGIC_PKT_EN = BIT(0),
+ MV_V2_WOL_CTRL = 0xf06e,
+ MV_V2_WOL_CTRL_CLEAR_STS = BIT(15),
+ MV_V2_WOL_CTRL_MAGIC_PKT_EN = BIT(0),
/* Temperature control/read registers (88X3310 only) */
MV_V2_TEMP_CTRL = 0xf08a,
MV_V2_TEMP_CTRL_MASK = 0xc000,
--
2.32.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH RFC net-next 8/8] net: phy: marvell10g: select host interface configuration
2021-11-10 19:07 [PATCH RFC net-next 0/8] Extend `phy-mode` to string array Marek Behún
` (6 preceding siblings ...)
2021-11-10 19:07 ` [PATCH RFC net-next 7/8] net: phy: marvell10g: Use tabs instead of spaces for indentation Marek Behún
@ 2021-11-10 19:07 ` Marek Behún
7 siblings, 0 replies; 9+ messages in thread
From: Marek Behún @ 2021-11-10 19:07 UTC (permalink / raw)
To: Andrew Lunn, netdev
Cc: devicetree, Rob Herring, Russell King, pali, Marek Behún
From: Russell King <rmk+kernel@armlinux.org.uk>
Select the host interface configuration according to the capabilities of
the host.
This allows the kernel to:
- support SFP modules with 88X33X0 or 88E21X0 inside them
- switch interface modes when the PHY is used with the mvpp2 MAC
(e.g. on MacchiatoBIN)
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
[ rebase, updated, also added support for 88E21X0 ]
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/net/phy/marvell10g.c | 120 +++++++++++++++++++++++++++++++++--
1 file changed, 115 insertions(+), 5 deletions(-)
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 0cb9b4ef09c7..94bea1bade6f 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -96,6 +96,11 @@ enum {
MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380,
MV_PCS_PORT_INFO_NPORTS_SHIFT = 7,
+ /* SerDes reinitialization 88E21X0 */
+ MV_AN_21X0_SERDES_CTRL2 = 0x800f,
+ MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS = BIT(13),
+ MV_AN_21X0_SERDES_CTRL2_RUN_INIT = BIT(15),
+
/* These registers appear at 0x800X and 0xa00X - the 0xa00X control
* registers appear to set themselves to the 0x800X when AN is
* restarted, but status registers appear readable from either.
@@ -140,6 +145,8 @@ struct mv3310_chip {
bool (*has_downshift)(struct phy_device *phydev);
void (*init_supported_interfaces)(unsigned long *mask);
int (*get_mactype)(struct phy_device *phydev);
+ int (*set_mactype)(struct phy_device *phydev, int mactype);
+ int (*select_mactype)(unsigned long *interfaces);
int (*init_interface)(struct phy_device *phydev, int mactype);
#ifdef CONFIG_HWMON
@@ -593,6 +600,49 @@ static int mv2110_get_mactype(struct phy_device *phydev)
return mactype & MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
}
+static int mv2110_set_mactype(struct phy_device *phydev, int mactype)
+{
+ int err, val;
+
+ mactype &= MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
+ err = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_21X0_PORT_CTRL,
+ MV_PMA_21X0_PORT_CTRL_SWRST |
+ MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK,
+ MV_PMA_21X0_PORT_CTRL_SWRST | mactype);
+ if (err)
+ return err;
+
+ err = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
+ MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS |
+ MV_AN_21X0_SERDES_CTRL2_RUN_INIT);
+ if (err)
+ return err;
+
+ err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_AN,
+ MV_AN_21X0_SERDES_CTRL2, val,
+ !(val &
+ MV_AN_21X0_SERDES_CTRL2_RUN_INIT),
+ 5000, 100000, true);
+ if (err)
+ return err;
+
+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
+ MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS);
+}
+
+static int mv2110_select_mactype(unsigned long *interfaces)
+{
+ if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
+ return MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII;
+ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+ !test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+ return MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER;
+ else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+ return MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
+ else
+ return -1;
+}
+
static int mv3310_get_mactype(struct phy_device *phydev)
{
int mactype;
@@ -604,6 +654,46 @@ static int mv3310_get_mactype(struct phy_device *phydev)
return mactype & MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
}
+static int mv3310_set_mactype(struct phy_device *phydev, int mactype)
+{
+ int ret;
+
+ mactype &= MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
+ MV_V2_33X0_PORT_CTRL_MACTYPE_MASK,
+ mactype);
+ if (ret <= 0)
+ return ret;
+
+ return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
+ MV_V2_33X0_PORT_CTRL_SWRST);
+}
+
+static int mv3310_select_mactype(unsigned long *interfaces)
+{
+ if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
+ return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
+ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+ test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+ return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
+ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+ test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
+ return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
+ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+ test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
+ return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
+ else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+ return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
+ else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
+ return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
+ else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
+ return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
+ else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
+ return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
+ else
+ return -1;
+}
+
static int mv2110_init_interface(struct phy_device *phydev, int mactype)
{
struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
@@ -674,10 +764,16 @@ static int mv3310_config_init(struct phy_device *phydev)
{
struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
const struct mv3310_chip *chip = to_mv3310_chip(phydev);
+ DECLARE_PHY_INTERFACE_MASK(interfaces);
int err, mactype;
- /* Check that the PHY interface type is compatible */
- if (!test_bit(phydev->interface, priv->supported_interfaces))
+ /* In case host didn't provide supported interfaces */
+ __set_bit(phydev->interface, phydev->host_interfaces);
+
+ /* Check that there is at least one compatible PHY interface type */
+ phy_interface_and(interfaces, phydev->host_interfaces,
+ priv->supported_interfaces);
+ if (phy_interface_empty(interfaces))
return -ENODEV;
phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
@@ -687,9 +783,15 @@ static int mv3310_config_init(struct phy_device *phydev)
if (err)
return err;
- mactype = chip->get_mactype(phydev);
- if (mactype < 0)
- return mactype;
+ mactype = chip->select_mactype(interfaces);
+ if (mactype < 0) {
+ mactype = chip->get_mactype(phydev);
+ } else {
+ phydev_info(phydev, "Changing MACTYPE to %i\n", mactype);
+ err = chip->set_mactype(phydev, mactype);
+ if (err)
+ return err;
+ }
err = chip->init_interface(phydev, mactype);
if (err) {
@@ -1049,6 +1151,8 @@ static const struct mv3310_chip mv3310_type = {
.has_downshift = mv3310_has_downshift,
.init_supported_interfaces = mv3310_init_supported_interfaces,
.get_mactype = mv3310_get_mactype,
+ .set_mactype = mv3310_set_mactype,
+ .select_mactype = mv3310_select_mactype,
.init_interface = mv3310_init_interface,
#ifdef CONFIG_HWMON
@@ -1060,6 +1164,8 @@ static const struct mv3310_chip mv3340_type = {
.has_downshift = mv3310_has_downshift,
.init_supported_interfaces = mv3340_init_supported_interfaces,
.get_mactype = mv3310_get_mactype,
+ .set_mactype = mv3310_set_mactype,
+ .select_mactype = mv3310_select_mactype,
.init_interface = mv3340_init_interface,
#ifdef CONFIG_HWMON
@@ -1070,6 +1176,8 @@ static const struct mv3310_chip mv3340_type = {
static const struct mv3310_chip mv2110_type = {
.init_supported_interfaces = mv2110_init_supported_interfaces,
.get_mactype = mv2110_get_mactype,
+ .set_mactype = mv2110_set_mactype,
+ .select_mactype = mv2110_select_mactype,
.init_interface = mv2110_init_interface,
#ifdef CONFIG_HWMON
@@ -1080,6 +1188,8 @@ static const struct mv3310_chip mv2110_type = {
static const struct mv3310_chip mv2111_type = {
.init_supported_interfaces = mv2111_init_supported_interfaces,
.get_mactype = mv2110_get_mactype,
+ .set_mactype = mv2110_set_mactype,
+ .select_mactype = mv2110_select_mactype,
.init_interface = mv2110_init_interface,
#ifdef CONFIG_HWMON
--
2.32.0
^ permalink raw reply related [flat|nested] 9+ messages in thread