From 870dd51117cb901f560ea5a85b9876956e6f35b8 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 7 Oct 2024 18:26:05 +0200 Subject: [PATCH 01/16] selftests: mlxsw: sch_red_ets: Increase required backlog Backlog fluctuates on Spectrum-4 much more than on <4. Increasing the desired backlog seems to help, as the constant fluctuations do not overlap into the territory where packets are marked. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Link: https://patch.msgid.link/0821fb3aa8bb6a6c0d3000baab04995517c9a0cc.1728316370.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/sch_red_ets.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/sch_red_ets.sh b/tools/testing/selftests/drivers/net/mlxsw/sch_red_ets.sh index 8ecddafa79b3..576067b207a8 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/sch_red_ets.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/sch_red_ets.sh @@ -20,8 +20,8 @@ source sch_red_core.sh # $BACKLOG2 are far enough not to overlap, so that we can assume that if we do # see (do not see) marking, it is actually due to the configuration of that one # TC, and not due to configuration of the other TC leaking over. -BACKLOG1=200000 -BACKLOG2=500000 +BACKLOG1=400000 +BACKLOG2=1000000 install_root_qdisc() { @@ -35,7 +35,7 @@ install_qdisc_tc0() tc qdisc add dev $swp3 parent 10:8 handle 108: red \ limit 1000000 min $BACKLOG1 max $((BACKLOG1 + 1)) \ - probability 1.0 avpkt 8000 burst 38 "${args[@]}" + probability 1.0 avpkt 8000 burst 51 "${args[@]}" } install_qdisc_tc1() @@ -44,7 +44,7 @@ install_qdisc_tc1() tc qdisc add dev $swp3 parent 10:7 handle 107: red \ limit 1000000 min $BACKLOG2 max $((BACKLOG2 + 1)) \ - probability 1.0 avpkt 8000 burst 63 "${args[@]}" + probability 1.0 avpkt 8000 burst 126 "${args[@]}" } install_qdisc() -- 2.51.0 From 8fb5b60734564473c72ca85d617cd685738948f0 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 7 Oct 2024 18:26:06 +0200 Subject: [PATCH 02/16] selftests: mlxsw: sch_red_core: Increase backlog size tolerance Backlog fluctuates on Spectrum-4 much more than on <4. In practice we can sample queue depth values going from about -12% to about +7% of the configured RED limit. The test which checks the queue size has a limit of +-10%, and as a result often fails. We attempted to fix the issue by busywaiting for several seconds hoping to get within the bounds, but that still proved to be too noisy (or the wait time would be impractically long). Unfortunately we have to bump the value tolerance from 10% to 15%, which in this patch do. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Link: https://patch.msgid.link/f54950df2a8fcba46c3ddc1053376352fa2e592b.1728316370.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh b/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh index 299e06a5808c..a25a15eb6d31 100644 --- a/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh @@ -532,10 +532,11 @@ do_red_test() check_fail $? "Traffic went into backlog instead of being early-dropped" pct=$(check_marking get_nmarked $vlan "== 0") check_err $? "backlog $backlog / $limit Got $pct% marked packets, expected == 0." + backlog=$(get_qdisc_backlog $vlan) local diff=$((limit - backlog)) pct=$((100 * diff / limit)) - ((-10 <= pct && pct <= 10)) - check_err $? "backlog $backlog / $limit expected <= 10% distance" + ((-15 <= pct && pct <= 15)) + check_err $? "backlog $backlog / $limit expected <= 15% distance" log_test "TC $((vlan - 10)): RED backlog > limit" stop_traffic -- 2.51.0 From 787f148cec340114dc22c49d8b045ff3ff0adad6 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 7 Oct 2024 18:26:07 +0200 Subject: [PATCH 03/16] selftests: mlxsw: sch_red_core: Sleep before querying queue depth The qdisc stats are taken from the port's periodic HW stats, which are updated once a second. We try to accommodate the latency by using busywait in build_backlog(). The issue in that seems to be that when do_mark_test() builds the backlog, it makes the decision whether to send more packets based on the first instance of the queue depth stat exceeding the current value, when in fact more traffic is on the way and the queue depth would increase further. This leads to failures in TC 1 of mark-mirror test, where we see the following failure: TEST: TC 0: marked packets mirror'd [ OK ] TEST: TC 1: marked packets mirror'd [FAIL] Spurious packets (1680 -> 2290) observed without buffer pressure Fix by waiting for the full second before reading the queue depth for the first time, to make sure it reflects all in-flight traffic. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Link: https://patch.msgid.link/321dcf8b3e9a1f0766429c8cf3e3f1746f1bc375.1728316370.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh b/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh index a25a15eb6d31..b1ff395b3880 100644 --- a/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh @@ -372,6 +372,7 @@ build_backlog() local i=0 while :; do + sleep 1 local cur=$(busywait 1100 until_counter_is "> $cur" \ get_qdisc_backlog $vlan) local diff=$((size - cur)) -- 2.51.0 From 7049166e51bc2b854935eda72f7fb8c3f4492f6f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 7 Oct 2024 18:26:08 +0200 Subject: [PATCH 04/16] selftests: mlxsw: sch_red_core: Send more packets for drop tests This test works by injecting into a port with a maxed-out queue a couple packets and checks if a corresponding number of packets were dropped. This has worked well on Spectrum<4, but on Spectrum-4 it has been noisy. This is in line with the observation that on Spectrum-4, queue size tends to fluctuate more. A handful of packets could then still be accepted to the queue even though it was nominally full just recently. In order to accommodate this behavior, send many more packets. The buffer can fit N extra packets, but not N% packets. This therefore allows us to set wider absolute margins, while actually narrowing them relatively. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel Link: https://patch.msgid.link/abc869b9f6003d400d6293ddd5edb2f4517f44d5.1728316370.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../selftests/drivers/net/mlxsw/sch_red_core.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh b/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh index b1ff395b3880..316444389c4e 100644 --- a/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh @@ -653,20 +653,22 @@ do_drop_test() build_backlog $vlan $((3 * limit / 2)) udp >/dev/null base=$($fetch_counter) - send_packets $vlan udp 11 + send_packets $vlan udp 100 - now=$(busywait 1100 until_counter_is ">= $((base + 10))" $fetch_counter) - check_err $? "Dropped packets not observed: 11 expected, $((now - base)) seen" + now=$(busywait 1100 until_counter_is ">= $((base + 95))" $fetch_counter) + check_err $? "${trigger}ped packets not observed: 100 expected, $((now - base)) seen" # When no extra traffic is injected, there should be no mirroring. - busywait 1100 until_counter_is ">= $((base + 20))" $fetch_counter >/dev/null + busywait 1100 until_counter_is ">= $((base + 110))" \ + $fetch_counter >/dev/null check_fail $? "Spurious packets observed" # When the rule is uninstalled, there should be no mirroring. qevent_rule_uninstall_$subtest - send_packets $vlan udp 11 - busywait 1100 until_counter_is ">= $((base + 20))" $fetch_counter >/dev/null - check_fail $? "Spurious packets observed after uninstall" + send_packets $vlan udp 100 + now=$(busywait 1100 until_counter_is ">= $((base + 110))" \ + $fetch_counter) + check_fail $? "$((now - base)) spurious packets observed after uninstall" log_test "TC $((vlan - 10)): ${trigger}ped packets $subtest'd" -- 2.51.0 From 501fa2426b5ffbe08c2571b6f5c3f3afa1970aa2 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 7 Oct 2024 18:26:09 +0200 Subject: [PATCH 05/16] selftests: mlxsw: sch_red_core: Lower TBF rate The RED test uses a pair of TBF shapers. The first to get predictably-sized stream of traffic, and second to get a 100% saturated chokepoint. To this chokepoint it injects individual packets. Because the chokepoint is saturated, these additional packets go straight to the backlog. This allows the test to check RED behavior across various queue sizes. The shapers are rated at 1Gbps, for historical reasons (before mlxsw supported TBF offload, the test used port speed to create the chokepoints). Machines with a low-power CPU may have trouble consistently generating 1Gbps of traffic, and the test then spuriously fails. Instead, drop the rate to 200Mbps (Spectrum has a guaranteed shaper rate granularity of 200Mbps, so anything lower is not guaranteed to work well). Because that means fewer packets will be mirrored in the ECN-mark test, adjust the passing condition accordingly. Signed-off-by: Petr Machata Link: https://patch.msgid.link/c6712f9c5de75ae0bc2ab3d8ea7d92aaaf93af95.1728316370.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh b/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh index 316444389c4e..f4c324957dcc 100644 --- a/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh @@ -137,7 +137,7 @@ h2_create() # Prevent this by adding a shaper which limits the traffic in $h2 to # 1Gbps. - tc qdisc replace dev $h2 root handle 10: tbf rate 1gbit \ + tc qdisc replace dev $h2 root handle 10: tbf rate 200mbit \ burst 128K limit 1G } @@ -199,7 +199,7 @@ switch_create() done for intf in $swp3 $swp4; do - tc qdisc replace dev $intf root handle 1: tbf rate 1gbit \ + tc qdisc replace dev $intf root handle 1: tbf rate 200mbit \ burst 128K limit 1G done @@ -602,7 +602,7 @@ do_mark_test() # Above limit, everything should be mirrored, we should see lots of # packets. build_backlog $vlan $((3 * limit / 2)) tcp tos=0x01 >/dev/null - busywait_for_counter 1100 +10000 \ + busywait_for_counter 1100 +2500 \ $fetch_counter > /dev/null check_err_fail "$should_fail" $? "ECN-marked packets $subtest'd" -- 2.51.0 From 1432965bf5ce0c866924a66be391e478a98e69ee Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 4 Oct 2024 17:18:05 +0100 Subject: [PATCH 06/16] dt-bindings: net: marvell,aquantia: add property to override MDI_CFG Usually the MDI pair order reversal configuration is defined by bootstrap pin MDI_CFG. Some designs, however, require overriding the MDI pair order and force either normal or reverse order. Add property 'marvell,mdi-cfg-order' to allow forcing either normal or reverse order of the MDI pairs. Signed-off-by: Daniel Golle Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/7ccf25d6d7859f1ce9983c81a2051cfdfb0e0a99.1728058550.git.daniel@makrotopia.org Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/marvell,aquantia.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/net/marvell,aquantia.yaml b/Documentation/devicetree/bindings/net/marvell,aquantia.yaml index 9854fab4c4db..f269615126d8 100644 --- a/Documentation/devicetree/bindings/net/marvell,aquantia.yaml +++ b/Documentation/devicetree/bindings/net/marvell,aquantia.yaml @@ -48,6 +48,12 @@ properties: firmware-name: description: specify the name of PHY firmware to load + marvell,mdi-cfg-order: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: + force normal (0) or reverse (1) order of MDI pairs, overriding MDI_CFG bootstrap pin. + nvmem-cells: description: phandle to the firmware nvmem cell maxItems: 1 -- 2.51.0 From a2e1ba275eae96a8171deb19e9c7c2f5978fee7b Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 4 Oct 2024 17:18:16 +0100 Subject: [PATCH 07/16] net: phy: aquantia: allow forcing order of MDI pairs Despite supporting Auto MDI-X, it looks like Aquantia only supports swapping pair (1,2) with pair (3,6) like it used to be for MDI-X on 100MBit/s networks. When all 4 pairs are in use (for 1000MBit/s or faster) the link does not come up with pair order is not configured correctly, either using MDI_CFG pin or using the "PMA Receive Reserved Vendor Provisioning 1" register. Normally, the order of MDI pairs being either ABCD or DCBA is configured by pulling the MDI_CFG pin. However, some hardware designs require overriding the value configured by that bootstrap pin. The PHY allows doing that by setting a bit in "PMA Receive Reserved Vendor Provisioning 1" register which allows ignoring the state of the MDI_CFG pin and another bit configuring whether the order of MDI pairs should be normal (ABCD) or reverse (DCBA). Pair polarity is not affected and remains identical in both settings. Introduce property "marvell,mdi-cfg-order" which allows forcing either normal or reverse order of the MDI pairs from DT. If the property isn't present, the behavior is unchanged and MDI pair order configuration is untouched (ie. either the result of MDI_CFG pin pull-up/pull-down, or pair order override already configured by the bootloader before Linux is started). Forcing normal pair order is required on the Adtran SDG-8733A Wi-Fi 7 residential gateway. Signed-off-by: Daniel Golle Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/9ed760ff87d5fc456f31e407ead548bbb754497d.1728058550.git.daniel@makrotopia.org Signed-off-by: Jakub Kicinski --- drivers/net/phy/aquantia/aquantia_main.c | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 4d156d406bab..dcad3fa1ddc3 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "aquantia.h" @@ -71,6 +72,11 @@ #define MDIO_AN_TX_VEND_INT_MASK2 0xd401 #define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0) +#define PMAPMD_RSVD_VEND_PROV 0xe400 +#define PMAPMD_RSVD_VEND_PROV_MDI_CONF GENMASK(1, 0) +#define PMAPMD_RSVD_VEND_PROV_MDI_REVERSE BIT(0) +#define PMAPMD_RSVD_VEND_PROV_MDI_FORCE BIT(1) + #define MDIO_AN_RX_LP_STAT1 0xe820 #define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15) #define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14) @@ -485,6 +491,29 @@ static void aqr107_chip_info(struct phy_device *phydev) fw_major, fw_minor, build_id, prov_id); } +static int aqr107_config_mdi(struct phy_device *phydev) +{ + struct device_node *np = phydev->mdio.dev.of_node; + u32 mdi_conf; + int ret; + + ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf); + + /* Do nothing in case property "marvell,mdi-cfg-order" is not present */ + if (ret == -ENOENT) + return 0; + + if (ret) + return ret; + + if (mdi_conf & ~PMAPMD_RSVD_VEND_PROV_MDI_REVERSE) + return -EINVAL; + + return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV, + PMAPMD_RSVD_VEND_PROV_MDI_CONF, + mdi_conf | PMAPMD_RSVD_VEND_PROV_MDI_FORCE); +} + static int aqr107_config_init(struct phy_device *phydev) { struct aqr107_priv *priv = phydev->priv; @@ -514,6 +543,10 @@ static int aqr107_config_init(struct phy_device *phydev) if (ret) return ret; + ret = aqr107_config_mdi(phydev); + if (ret) + return ret; + /* Restore LED polarity state after reset */ for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) { ret = aqr_phy_led_active_low_set(phydev, led_active_low, true); -- 2.51.0 From ed1f3b7f1572edd36a4bca86a52adffc76b0ab18 Mon Sep 17 00:00:00 2001 From: Andrew Kreimer Date: Sun, 6 Oct 2024 16:08:29 +0300 Subject: [PATCH 08/16] fsl/fman: Fix a typo Fix a typo in comments: bellow -> below. Reported-by: Matthew Wilcox Signed-off-by: Andrew Kreimer Reviewed-by: Simon Horman Link: https://patch.msgid.link/20241006130829.13967-1-algonell@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/fman/fman_port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c b/drivers/net/ethernet/freescale/fman/fman_port.c index f17a4e511510..e977389f7088 100644 --- a/drivers/net/ethernet/freescale/fman/fman_port.c +++ b/drivers/net/ethernet/freescale/fman/fman_port.c @@ -987,7 +987,7 @@ static int init_low_level_driver(struct fman_port *port) return -ENODEV; } - /* The code bellow is a trick so the FM will not release the buffer + /* The code below is a trick so the FM will not release the buffer * to BM nor will try to enqueue the frame to QM */ if (port->port_type == FMAN_PORT_TYPE_TX) { -- 2.51.0 From 21185019aa9c52d5273eea827f07b3feac811546 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Niklas=20S=C3=B6derlund?= Date: Sat, 5 Oct 2024 13:24:10 +0200 Subject: [PATCH 09/16] net: phy: marvell-88q2xxx: Align soft reset for mv88q2110 and mv88q2220 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The soft reset implementations for mv88q2110 and mv88q2220 differ as the later need to consider that auto negation is supported on mv88q2220 devices. In preparation of enabling auto negotiation on mv88q2110 merge the two rest functions into a device generic one. The mv88q2220 behavior is kept as is but extended to wait for the reset bit to be clears before continuing, as was done previously on mv88q2220. Signed-off-by: Niklas Söderlund Reviewed-by: Andrew Lunn Tested-by: Dimitri Fedrau Tested-by: Stefan Eichenberger Link: https://patch.msgid.link/20241005112412.544360-2-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 60 ++++++++++++++----------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index c812f16eaa3a..850beb4b1722 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -179,15 +179,34 @@ static int mv88q2xxx_soft_reset(struct phy_device *phydev) int ret; int val; - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, - MDIO_PCS_1000BT1_CTRL, MDIO_PCS_1000BT1_CTRL_RESET); + /* Enable RESET of DCL */ + if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) { + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x48); + if (ret < 0) + return ret; + } + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_CTRL, + MDIO_PCS_1000BT1_CTRL_RESET); + if (ret < 0) + return ret; + + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS, + MDIO_PCS_1000BT1_CTRL, val, + !(val & MDIO_PCS_1000BT1_CTRL_RESET), + 50000, 600000, true); if (ret < 0) return ret; - return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS, - MDIO_PCS_1000BT1_CTRL, val, - !(val & MDIO_PCS_1000BT1_CTRL_RESET), - 50000, 600000, true); + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xffe4, 0xc); + if (ret < 0) + return ret; + + /* Disable RESET of DCL */ + if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) + return phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x58); + + return 0; } static int mv88q2xxx_read_link_gbit(struct phy_device *phydev) @@ -705,33 +724,6 @@ static int mv88q2xxx_probe(struct phy_device *phydev) return mv88q2xxx_hwmon_probe(phydev); } -static int mv88q222x_soft_reset(struct phy_device *phydev) -{ - int ret; - - /* Enable RESET of DCL */ - if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) { - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x48); - if (ret < 0) - return ret; - } - - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_CTRL, - MDIO_PCS_1000BT1_CTRL_RESET); - if (ret < 0) - return ret; - - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xffe4, 0xc); - if (ret < 0) - return ret; - - /* Disable RESET of DCL */ - if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) - return phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x58); - - return 0; -} - static int mv88q222x_write_mmd_vals(struct phy_device *phydev, const struct mmd_val *vals, size_t len) { @@ -906,7 +898,7 @@ static struct phy_driver mv88q2xxx_driver[] = { .aneg_done = genphy_c45_aneg_done, .config_init = mv88q222x_config_init, .read_status = mv88q2xxx_read_status, - .soft_reset = mv88q222x_soft_reset, + .soft_reset = mv88q2xxx_soft_reset, .config_intr = mv88q2xxx_config_intr, .handle_interrupt = mv88q2xxx_handle_interrupt, .set_loopback = genphy_c45_loopback, -- 2.51.0 From 0e58c188711d41bd6d3b3db3e57e609f3296e731 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Niklas=20S=C3=B6derlund?= Date: Sat, 5 Oct 2024 13:24:11 +0200 Subject: [PATCH 10/16] net: phy: marvell-88q2xxx: Make register writer function generic MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit In preparation to adding auto negotiation support to mv88q2110 move and rename the helper function used to write an array of register values to the PHY. Just as for mv88q2220 devices this helper will be needed to for the initial configuration of the mv88q2110 to support auto negotiation. The function is moved verbatim, there is no change in behavior. Signed-off-by: Niklas Söderlund Reviewed-by: Andrew Lunn Tested-by: Dimitri Fedrau Tested-by: Stefan Eichenberger Link: https://patch.msgid.link/20241005112412.544360-3-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 40 +++++++++++++++---------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index 850beb4b1722..31f8c976e387 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -174,6 +174,21 @@ static const struct mmd_val mv88q222x_revb1_revb2_init_seq1[] = { { MDIO_MMD_PCS, 0xfe11, 0x1105 }, }; +static int mv88q2xxx_write_mmd_vals(struct phy_device *phydev, + const struct mmd_val *vals, size_t len) +{ + int ret; + + for (; len; vals++, len--) { + ret = phy_write_mmd(phydev, vals->devad, vals->regnum, + vals->val); + if (ret < 0) + return ret; + } + + return 0; +} + static int mv88q2xxx_soft_reset(struct phy_device *phydev) { int ret; @@ -724,33 +739,18 @@ static int mv88q2xxx_probe(struct phy_device *phydev) return mv88q2xxx_hwmon_probe(phydev); } -static int mv88q222x_write_mmd_vals(struct phy_device *phydev, - const struct mmd_val *vals, size_t len) -{ - int ret; - - for (; len; vals++, len--) { - ret = phy_write_mmd(phydev, vals->devad, vals->regnum, - vals->val); - if (ret < 0) - return ret; - } - - return 0; -} - static int mv88q222x_revb0_config_init(struct phy_device *phydev) { int ret; - ret = mv88q222x_write_mmd_vals(phydev, mv88q222x_revb0_init_seq0, + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb0_init_seq0, ARRAY_SIZE(mv88q222x_revb0_init_seq0)); if (ret < 0) return ret; usleep_range(5000, 10000); - ret = mv88q222x_write_mmd_vals(phydev, mv88q222x_revb0_init_seq1, + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb0_init_seq1, ARRAY_SIZE(mv88q222x_revb0_init_seq1)); if (ret < 0) return ret; @@ -764,17 +764,17 @@ static int mv88q222x_revb1_revb2_config_init(struct phy_device *phydev) int ret; if (is_rev_b1) - ret = mv88q222x_write_mmd_vals(phydev, mv88q222x_revb1_init_seq0, + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb1_init_seq0, ARRAY_SIZE(mv88q222x_revb1_init_seq0)); else - ret = mv88q222x_write_mmd_vals(phydev, mv88q222x_revb2_init_seq0, + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb2_init_seq0, ARRAY_SIZE(mv88q222x_revb2_init_seq0)); if (ret < 0) return ret; usleep_range(3000, 5000); - ret = mv88q222x_write_mmd_vals(phydev, mv88q222x_revb1_revb2_init_seq1, + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb1_revb2_init_seq1, ARRAY_SIZE(mv88q222x_revb1_revb2_init_seq1)); if (ret < 0) return ret; -- 2.51.0 From 20c7722a7aa33e5b9de0c0d62b7ec0a2455e6725 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Niklas=20S=C3=B6derlund?= Date: Sat, 5 Oct 2024 13:24:12 +0200 Subject: [PATCH 11/16] net: phy: marvell-88q2xxx: Enable auto negotiation for mv88q2110 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The initial marvell-88q2xxx driver only supported the Marvell 88Q2110 PHY without auto negotiation support. The reason documented states that the provided initialization sequence did not to work. Now a method to enable auto negotiation have been found by comparing the initialization of other supported devices and an out-of-tree PHY driver. Perform the minimal needed initialization of the PHY to get auto negotiation working and remove the limitation that disables the auto negotiation feature for the mv88q2110 device. With this change a 1000Mbps full duplex link is able to be negotiated between two mv88q2110 and the link works perfectly. The other side also reflects the manually configure settings of the master device. # ethtool eth0 Settings for eth0: Supported ports: [ ] Supported link modes: 100baseT1/Full 1000baseT1/Full Supported pause frame use: Symmetric Receive-only Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 100baseT1/Full 1000baseT1/Full Advertised pause frame use: No Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Link partner advertised link modes: 100baseT1/Full 1000baseT1/Full Link partner advertised pause frame use: No Link partner advertised auto-negotiation: Yes Link partner advertised FEC modes: Not reported Speed: 1000Mb/s Duplex: Full Auto-negotiation: on master-slave cfg: preferred master master-slave status: slave Port: Twisted Pair PHYAD: 0 Transceiver: external MDI-X: Unknown Link detected: yes SQI: 15/15 Before this change I was not able to manually configure 1000Mbps link, only a 100Mpps link so this change providers an improvement in performance for this device. [ 5] local 10.1.0.2 port 5201 connected to 10.1.0.1 port 38346 [ ID] Interval Transfer Bitrate Retr Cwnd [ 5] 0.00-1.00 sec 96.8 MBytes 812 Mbits/sec 0 469 KBytes [ 5] 1.00-2.00 sec 94.3 MBytes 791 Mbits/sec 0 469 KBytes [ 5] 2.00-3.00 sec 96.1 MBytes 806 Mbits/sec 0 469 KBytes [ 5] 3.00-4.00 sec 98.3 MBytes 825 Mbits/sec 0 469 KBytes [ 5] 4.00-5.00 sec 98.4 MBytes 825 Mbits/sec 0 469 KBytes [ 5] 5.00-6.00 sec 98.4 MBytes 826 Mbits/sec 0 469 KBytes [ 5] 6.00-7.00 sec 98.9 MBytes 830 Mbits/sec 0 469 KBytes [ 5] 7.00-8.00 sec 91.7 MBytes 769 Mbits/sec 0 469 KBytes [ 5] 8.00-9.00 sec 99.4 MBytes 834 Mbits/sec 0 747 KBytes [ 5] 9.00-10.00 sec 101 MBytes 851 Mbits/sec 0 747 KBytes Signed-off-by: Niklas Söderlund Tested-by: Stefan Eichenberger Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20241005112412.544360-4-niklas.soderlund+renesas@ragnatech.se Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell-88q2xxx.c | 46 ++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index 31f8c976e387..5107f58338af 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -101,6 +101,22 @@ struct mmd_val { u16 val; }; +static const struct mmd_val mv88q2110_init_seq0[] = { + { MDIO_MMD_PCS, 0xffe4, 0x07b5 }, + { MDIO_MMD_PCS, 0xffe4, 0x06b6 }, +}; + +static const struct mmd_val mv88q2110_init_seq1[] = { + { MDIO_MMD_PCS, 0xffde, 0x402f }, + { MDIO_MMD_PCS, 0xfe34, 0x4040 }, + { MDIO_MMD_PCS, 0xfe2a, 0x3c1d }, + { MDIO_MMD_PCS, 0xfe34, 0x0040 }, + { MDIO_MMD_AN, 0x8032, 0x0064 }, + { MDIO_MMD_AN, 0x8031, 0x0a01 }, + { MDIO_MMD_AN, 0x8031, 0x0c01 }, + { MDIO_MMD_PCS, 0xffdb, 0x0010 }, +}; + static const struct mmd_val mv88q222x_revb0_init_seq0[] = { { MDIO_MMD_PCS, 0x8033, 0x6801 }, { MDIO_MMD_AN, MDIO_AN_T1_CTRL, 0x0 }, @@ -424,15 +440,6 @@ static int mv88q2xxx_get_features(struct phy_device *phydev) if (ret) return ret; - /* The PHY signalizes it supports autonegotiation. Unfortunately, so - * far it was not possible to get a link even when following the init - * sequence provided by Marvell. Disable it for now until a proper - * workaround is found or a new PHY revision is released. - */ - if (phydev->drv->phy_id == MARVELL_PHY_ID_88Q2110) - linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - phydev->supported); - return 0; } @@ -739,6 +746,25 @@ static int mv88q2xxx_probe(struct phy_device *phydev) return mv88q2xxx_hwmon_probe(phydev); } +static int mv88q2110_config_init(struct phy_device *phydev) +{ + int ret; + + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q2110_init_seq0, + ARRAY_SIZE(mv88q2110_init_seq0)); + if (ret < 0) + return ret; + + usleep_range(5000, 10000); + + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q2110_init_seq1, + ARRAY_SIZE(mv88q2110_init_seq1)); + if (ret < 0) + return ret; + + return mv88q2xxx_config_init(phydev); +} + static int mv88q222x_revb0_config_init(struct phy_device *phydev) { int ret; @@ -880,7 +906,7 @@ static struct phy_driver mv88q2xxx_driver[] = { .name = "mv88q2110", .get_features = mv88q2xxx_get_features, .config_aneg = mv88q2xxx_config_aneg, - .config_init = mv88q2xxx_config_init, + .config_init = mv88q2110_config_init, .read_status = mv88q2xxx_read_status, .soft_reset = mv88q2xxx_soft_reset, .set_loopback = genphy_c45_loopback, -- 2.51.0 From 36efaca9cb28a893cad98f0448c39a8b698859e2 Mon Sep 17 00:00:00 2001 From: Tarun Alle Date: Mon, 7 Oct 2024 12:09:43 +0530 Subject: [PATCH 12/16] net: phy: microchip_t1: SQI support for LAN887x Add support for measuring Signal Quality Index for LAN887x T1 PHY. Signal Quality Index (SQI) is measure of Link Channel Quality from 0 to 7, with 7 as the best. By default, a link loss event shall indicate an SQI of 0. Signed-off-by: Tarun Alle Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20241007063943.3233-1-tarun.alle@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/microchip_t1.c | 171 +++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/drivers/net/phy/microchip_t1.c b/drivers/net/phy/microchip_t1.c index f99f37634d5e..71d6050b2833 100644 --- a/drivers/net/phy/microchip_t1.c +++ b/drivers/net/phy/microchip_t1.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -238,6 +239,35 @@ #define LAN887X_MX_CHIP_TOP_ALL_MSK (LAN887X_INT_MSK_T1_PHY_INT_MSK |\ LAN887X_MX_CHIP_TOP_LINK_MSK) +#define LAN887X_COEFF_PWR_DN_CONFIG_100 0x0404 +#define LAN887X_COEFF_PWR_DN_CONFIG_100_V 0x16d6 +#define LAN887X_SQI_CONFIG_100 0x042e +#define LAN887X_SQI_CONFIG_100_V 0x9572 +#define LAN887X_SQI_MSE_100 0x483 + +#define LAN887X_POKE_PEEK_100 0x040d +#define LAN887X_POKE_PEEK_100_EN BIT(0) + +#define LAN887X_COEFF_MOD_CONFIG 0x080d +#define LAN887X_COEFF_MOD_CONFIG_DCQ_COEFF_EN BIT(8) + +#define LAN887X_DCQ_SQI_STATUS 0x08b2 + +/* SQI raw samples count */ +#define SQI_SAMPLES 200 + +/* Samples percentage considered for SQI calculation */ +#define SQI_INLINERS_PERCENT 60 + +/* Samples count considered for SQI calculation */ +#define SQI_INLIERS_NUM (SQI_SAMPLES * SQI_INLINERS_PERCENT / 100) + +/* Start offset of samples */ +#define SQI_INLIERS_START ((SQI_SAMPLES - SQI_INLIERS_NUM) / 2) + +/* End offset of samples */ +#define SQI_INLIERS_END (SQI_INLIERS_START + SQI_INLIERS_NUM) + #define DRIVER_AUTHOR "Nisar Sayed " #define DRIVER_DESC "Microchip LAN87XX/LAN937x/LAN887x T1 PHY driver" @@ -1889,6 +1919,145 @@ static int lan887x_cable_test_get_status(struct phy_device *phydev, return lan887x_cable_test_report(phydev); } +/* Compare block to sort in ascending order */ +static int sqi_compare(const void *a, const void *b) +{ + return *(u16 *)a - *(u16 *)b; +} + +static int lan887x_get_sqi_100M(struct phy_device *phydev) +{ + u16 rawtable[SQI_SAMPLES]; + u32 sqiavg = 0; + u8 sqinum = 0; + int rc, i; + + /* Configuration of SQI 100M */ + rc = phy_write_mmd(phydev, MDIO_MMD_VEND1, + LAN887X_COEFF_PWR_DN_CONFIG_100, + LAN887X_COEFF_PWR_DN_CONFIG_100_V); + if (rc < 0) + return rc; + + rc = phy_write_mmd(phydev, MDIO_MMD_VEND1, LAN887X_SQI_CONFIG_100, + LAN887X_SQI_CONFIG_100_V); + if (rc < 0) + return rc; + + rc = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_SQI_CONFIG_100); + if (rc != LAN887X_SQI_CONFIG_100_V) + return -EINVAL; + + rc = phy_modify_mmd(phydev, MDIO_MMD_VEND1, LAN887X_POKE_PEEK_100, + LAN887X_POKE_PEEK_100_EN, + LAN887X_POKE_PEEK_100_EN); + if (rc < 0) + return rc; + + /* Required before reading register + * otherwise it will return high value + */ + msleep(50); + + /* Link check before raw readings */ + rc = genphy_c45_read_link(phydev); + if (rc < 0) + return rc; + + if (!phydev->link) + return -ENETDOWN; + + /* Get 200 SQI raw readings */ + for (i = 0; i < SQI_SAMPLES; i++) { + rc = phy_write_mmd(phydev, MDIO_MMD_VEND1, + LAN887X_POKE_PEEK_100, + LAN887X_POKE_PEEK_100_EN); + if (rc < 0) + return rc; + + rc = phy_read_mmd(phydev, MDIO_MMD_VEND1, + LAN887X_SQI_MSE_100); + if (rc < 0) + return rc; + + rawtable[i] = (u16)rc; + } + + /* Link check after raw readings */ + rc = genphy_c45_read_link(phydev); + if (rc < 0) + return rc; + + if (!phydev->link) + return -ENETDOWN; + + /* Sort SQI raw readings in ascending order */ + sort(rawtable, SQI_SAMPLES, sizeof(u16), sqi_compare, NULL); + + /* Keep inliers and discard outliers */ + for (i = SQI_INLIERS_START; i < SQI_INLIERS_END; i++) + sqiavg += rawtable[i]; + + /* Handle invalid samples */ + if (sqiavg != 0) { + /* Get SQI average */ + sqiavg /= SQI_INLIERS_NUM; + + if (sqiavg < 75) + sqinum = 7; + else if (sqiavg < 94) + sqinum = 6; + else if (sqiavg < 119) + sqinum = 5; + else if (sqiavg < 150) + sqinum = 4; + else if (sqiavg < 189) + sqinum = 3; + else if (sqiavg < 237) + sqinum = 2; + else if (sqiavg < 299) + sqinum = 1; + else + sqinum = 0; + } + + return sqinum; +} + +static int lan887x_get_sqi(struct phy_device *phydev) +{ + int rc, val; + + if (phydev->speed != SPEED_1000 && + phydev->speed != SPEED_100) + return -ENETDOWN; + + if (phydev->speed == SPEED_100) + return lan887x_get_sqi_100M(phydev); + + /* Writing DCQ_COEFF_EN to trigger a SQI read */ + rc = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + LAN887X_COEFF_MOD_CONFIG, + LAN887X_COEFF_MOD_CONFIG_DCQ_COEFF_EN); + if (rc < 0) + return rc; + + /* Wait for DCQ done */ + rc = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, + LAN887X_COEFF_MOD_CONFIG, val, ((val & + LAN887X_COEFF_MOD_CONFIG_DCQ_COEFF_EN) != + LAN887X_COEFF_MOD_CONFIG_DCQ_COEFF_EN), + 10, 200, true); + if (rc < 0) + return rc; + + rc = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_DCQ_SQI_STATUS); + if (rc < 0) + return rc; + + return FIELD_GET(T1_DCQ_SQI_MSK, rc); +} + static struct phy_driver microchip_t1_phy_driver[] = { { PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX), @@ -1942,6 +2111,8 @@ static struct phy_driver microchip_t1_phy_driver[] = { .cable_test_get_status = lan887x_cable_test_get_status, .config_intr = lan887x_config_intr, .handle_interrupt = lan887x_handle_interrupt, + .get_sqi = lan887x_get_sqi, + .get_sqi_max = lan87xx_get_sqi_max, } }; -- 2.51.0 From e30993a9ab00464afebfcc205f00eb8a722799ee Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 4 Oct 2024 11:20:41 +0100 Subject: [PATCH 13/16] net: pcs: xpcs: remove dw_xpcs_compat enum There is no reason for the struct dw_xpcs_compat arrays to be a fixed size other than the way we iterate over them. The index into the array isn't used for anything, and having them fixed size needlessly wastes space. Remove the enum that defines their size, and instead use an empty array entry (with NULL ->supported) to mark the end of the array. Signed-off-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/pcs/pcs-xpcs.c | 69 ++++++++++++++------------------------ 1 file changed, 25 insertions(+), 44 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 0a01c552f591..e1f264039c91 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -135,17 +135,6 @@ static const phy_interface_t xpcs_2500basex_interfaces[] = { PHY_INTERFACE_MODE_2500BASEX, }; -enum { - DW_XPCS_USXGMII, - DW_XPCS_10GKR, - DW_XPCS_XLGMII, - DW_XPCS_10GBASER, - DW_XPCS_SGMII, - DW_XPCS_1000BASEX, - DW_XPCS_2500BASEX, - DW_XPCS_INTERFACE_MAX, -}; - struct dw_xpcs_compat { const int *supported; const phy_interface_t *interface; @@ -163,15 +152,13 @@ struct dw_xpcs_desc { static const struct dw_xpcs_compat * xpcs_find_compat(const struct dw_xpcs_desc *desc, phy_interface_t interface) { - int i, j; - - for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) { - const struct dw_xpcs_compat *compat = &desc->compat[i]; + const struct dw_xpcs_compat *compat; + int j; + for (compat = desc->compat; compat->supported; compat++) for (j = 0; j < compat->num_interfaces; j++) if (compat->interface[j] == interface) return compat; - } return NULL; } @@ -610,14 +597,12 @@ static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported, void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces) { - int i, j; - - for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) { - const struct dw_xpcs_compat *compat = &xpcs->desc->compat[i]; + const struct dw_xpcs_compat *compat; + int j; + for (compat = xpcs->desc->compat; compat->supported; compat++) for (j = 0; j < compat->num_interfaces; j++) __set_bit(compat->interface[j], interfaces); - } } EXPORT_SYMBOL_GPL(xpcs_get_interfaces); @@ -1298,76 +1283,72 @@ static int xpcs_get_id(struct dw_xpcs *xpcs) return 0; } -static const struct dw_xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = { - [DW_XPCS_USXGMII] = { +static const struct dw_xpcs_compat synopsys_xpcs_compat[] = { + { .supported = xpcs_usxgmii_features, .interface = xpcs_usxgmii_interfaces, .num_interfaces = ARRAY_SIZE(xpcs_usxgmii_interfaces), .an_mode = DW_AN_C73, - }, - [DW_XPCS_10GKR] = { + }, { .supported = xpcs_10gkr_features, .interface = xpcs_10gkr_interfaces, .num_interfaces = ARRAY_SIZE(xpcs_10gkr_interfaces), .an_mode = DW_AN_C73, - }, - [DW_XPCS_XLGMII] = { + }, { .supported = xpcs_xlgmii_features, .interface = xpcs_xlgmii_interfaces, .num_interfaces = ARRAY_SIZE(xpcs_xlgmii_interfaces), .an_mode = DW_AN_C73, - }, - [DW_XPCS_10GBASER] = { + }, { .supported = xpcs_10gbaser_features, .interface = xpcs_10gbaser_interfaces, .num_interfaces = ARRAY_SIZE(xpcs_10gbaser_interfaces), .an_mode = DW_10GBASER, - }, - [DW_XPCS_SGMII] = { + }, { .supported = xpcs_sgmii_features, .interface = xpcs_sgmii_interfaces, .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces), .an_mode = DW_AN_C37_SGMII, - }, - [DW_XPCS_1000BASEX] = { + }, { .supported = xpcs_1000basex_features, .interface = xpcs_1000basex_interfaces, .num_interfaces = ARRAY_SIZE(xpcs_1000basex_interfaces), .an_mode = DW_AN_C37_1000BASEX, - }, - [DW_XPCS_2500BASEX] = { + }, { .supported = xpcs_2500basex_features, .interface = xpcs_2500basex_interfaces, .num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces), .an_mode = DW_2500BASEX, - }, + }, { + } }; -static const struct dw_xpcs_compat nxp_sja1105_xpcs_compat[DW_XPCS_INTERFACE_MAX] = { - [DW_XPCS_SGMII] = { +static const struct dw_xpcs_compat nxp_sja1105_xpcs_compat[] = { + { .supported = xpcs_sgmii_features, .interface = xpcs_sgmii_interfaces, .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces), .an_mode = DW_AN_C37_SGMII, .pma_config = nxp_sja1105_sgmii_pma_config, - }, + }, { + } }; -static const struct dw_xpcs_compat nxp_sja1110_xpcs_compat[DW_XPCS_INTERFACE_MAX] = { - [DW_XPCS_SGMII] = { +static const struct dw_xpcs_compat nxp_sja1110_xpcs_compat[] = { + { .supported = xpcs_sgmii_features, .interface = xpcs_sgmii_interfaces, .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces), .an_mode = DW_AN_C37_SGMII, .pma_config = nxp_sja1110_sgmii_pma_config, - }, - [DW_XPCS_2500BASEX] = { + }, { .supported = xpcs_2500basex_features, .interface = xpcs_2500basex_interfaces, .num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces), .an_mode = DW_2500BASEX, .pma_config = nxp_sja1110_2500basex_pma_config, - }, + }, { + } }; static const struct dw_xpcs_desc xpcs_desc_list[] = { -- 2.51.0 From 0397212f930626bd584642454f5c7ad0ba0dca22 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 4 Oct 2024 11:20:46 +0100 Subject: [PATCH 14/16] net: pcs: xpcs: don't use array for interface Currently, xpcs uses an array of interfaces that each "compat" entry supports. When looking up the compat entry for an interface, we iterate over the compat entries and then over each interface. Since each compat entry only has a single interface in its interfaces array, replace the array with a single member in the compat structure. Signed-off-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/pcs/pcs-xpcs.c | 71 ++++++++------------------------------ 1 file changed, 14 insertions(+), 57 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index e1f264039c91..4fbf7c816ed5 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -107,38 +107,9 @@ static const int xpcs_2500basex_features[] = { __ETHTOOL_LINK_MODE_MASK_NBITS, }; -static const phy_interface_t xpcs_usxgmii_interfaces[] = { - PHY_INTERFACE_MODE_USXGMII, -}; - -static const phy_interface_t xpcs_10gkr_interfaces[] = { - PHY_INTERFACE_MODE_10GKR, -}; - -static const phy_interface_t xpcs_xlgmii_interfaces[] = { - PHY_INTERFACE_MODE_XLGMII, -}; - -static const phy_interface_t xpcs_10gbaser_interfaces[] = { - PHY_INTERFACE_MODE_10GBASER, -}; - -static const phy_interface_t xpcs_sgmii_interfaces[] = { - PHY_INTERFACE_MODE_SGMII, -}; - -static const phy_interface_t xpcs_1000basex_interfaces[] = { - PHY_INTERFACE_MODE_1000BASEX, -}; - -static const phy_interface_t xpcs_2500basex_interfaces[] = { - PHY_INTERFACE_MODE_2500BASEX, -}; - struct dw_xpcs_compat { + phy_interface_t interface; const int *supported; - const phy_interface_t *interface; - int num_interfaces; int an_mode; int (*pma_config)(struct dw_xpcs *xpcs); }; @@ -153,12 +124,10 @@ static const struct dw_xpcs_compat * xpcs_find_compat(const struct dw_xpcs_desc *desc, phy_interface_t interface) { const struct dw_xpcs_compat *compat; - int j; for (compat = desc->compat; compat->supported; compat++) - for (j = 0; j < compat->num_interfaces; j++) - if (compat->interface[j] == interface) - return compat; + if (compat->interface == interface) + return compat; return NULL; } @@ -598,11 +567,9 @@ static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported, void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces) { const struct dw_xpcs_compat *compat; - int j; for (compat = xpcs->desc->compat; compat->supported; compat++) - for (j = 0; j < compat->num_interfaces; j++) - __set_bit(compat->interface[j], interfaces); + __set_bit(compat->interface, interfaces); } EXPORT_SYMBOL_GPL(xpcs_get_interfaces); @@ -1285,39 +1252,32 @@ static int xpcs_get_id(struct dw_xpcs *xpcs) static const struct dw_xpcs_compat synopsys_xpcs_compat[] = { { + .interface = PHY_INTERFACE_MODE_USXGMII, .supported = xpcs_usxgmii_features, - .interface = xpcs_usxgmii_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_usxgmii_interfaces), .an_mode = DW_AN_C73, }, { + .interface = PHY_INTERFACE_MODE_10GKR, .supported = xpcs_10gkr_features, - .interface = xpcs_10gkr_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_10gkr_interfaces), .an_mode = DW_AN_C73, }, { + .interface = PHY_INTERFACE_MODE_XLGMII, .supported = xpcs_xlgmii_features, - .interface = xpcs_xlgmii_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_xlgmii_interfaces), .an_mode = DW_AN_C73, }, { + .interface = PHY_INTERFACE_MODE_10GBASER, .supported = xpcs_10gbaser_features, - .interface = xpcs_10gbaser_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_10gbaser_interfaces), .an_mode = DW_10GBASER, }, { + .interface = PHY_INTERFACE_MODE_SGMII, .supported = xpcs_sgmii_features, - .interface = xpcs_sgmii_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces), .an_mode = DW_AN_C37_SGMII, }, { + .interface = PHY_INTERFACE_MODE_1000BASEX, .supported = xpcs_1000basex_features, - .interface = xpcs_1000basex_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_1000basex_interfaces), .an_mode = DW_AN_C37_1000BASEX, }, { + .interface = PHY_INTERFACE_MODE_2500BASEX, .supported = xpcs_2500basex_features, - .interface = xpcs_2500basex_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces), .an_mode = DW_2500BASEX, }, { } @@ -1325,9 +1285,8 @@ static const struct dw_xpcs_compat synopsys_xpcs_compat[] = { static const struct dw_xpcs_compat nxp_sja1105_xpcs_compat[] = { { + .interface = PHY_INTERFACE_MODE_SGMII, .supported = xpcs_sgmii_features, - .interface = xpcs_sgmii_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces), .an_mode = DW_AN_C37_SGMII, .pma_config = nxp_sja1105_sgmii_pma_config, }, { @@ -1336,15 +1295,13 @@ static const struct dw_xpcs_compat nxp_sja1105_xpcs_compat[] = { static const struct dw_xpcs_compat nxp_sja1110_xpcs_compat[] = { { + .interface = PHY_INTERFACE_MODE_SGMII, .supported = xpcs_sgmii_features, - .interface = xpcs_sgmii_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces), .an_mode = DW_AN_C37_SGMII, .pma_config = nxp_sja1110_sgmii_pma_config, }, { + .interface = PHY_INTERFACE_MODE_2500BASEX, .supported = xpcs_2500basex_features, - .interface = xpcs_2500basex_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces), .an_mode = DW_2500BASEX, .pma_config = nxp_sja1110_2500basex_pma_config, }, { -- 2.51.0 From 4490f5669b067359cf149ce1acf5b19c38a5edad Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 4 Oct 2024 11:20:51 +0100 Subject: [PATCH 15/16] net: pcs: xpcs: pass xpcs instead of xpcs->id to xpcs_find_compat() xpcs_find_compat() is now always passed xpcs->id. Rather than always dereferencing this in the caller, move it into xpcs_find_compat(), thus making this function consistent with most of the other xpcs functions in taking an xpcs pointer. Signed-off-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/pcs/pcs-xpcs.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 4fbf7c816ed5..8bde87ab971f 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -121,11 +121,11 @@ struct dw_xpcs_desc { }; static const struct dw_xpcs_compat * -xpcs_find_compat(const struct dw_xpcs_desc *desc, phy_interface_t interface) +xpcs_find_compat(struct dw_xpcs *xpcs, phy_interface_t interface) { const struct dw_xpcs_compat *compat; - for (compat = desc->compat; compat->supported; compat++) + for (compat = xpcs->desc->compat; compat->supported; compat++) if (compat->interface == interface) return compat; @@ -136,7 +136,7 @@ int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface) { const struct dw_xpcs_compat *compat; - compat = xpcs_find_compat(xpcs->desc, interface); + compat = xpcs_find_compat(xpcs, interface); if (!compat) return -ENODEV; @@ -548,7 +548,7 @@ static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported, int i; xpcs = phylink_pcs_to_xpcs(pcs); - compat = xpcs_find_compat(xpcs->desc, state->interface); + compat = xpcs_find_compat(xpcs, state->interface); if (!compat) return -EINVAL; @@ -620,7 +620,7 @@ static void xpcs_pre_config(struct phylink_pcs *pcs, phy_interface_t interface) if (!xpcs->need_reset) return; - compat = xpcs_find_compat(xpcs->desc, interface); + compat = xpcs_find_compat(xpcs, interface); if (!compat) { dev_err(&xpcs->mdiodev->dev, "unsupported interface %s\n", phy_modes(interface)); @@ -810,7 +810,7 @@ static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, const struct dw_xpcs_compat *compat; int ret; - compat = xpcs_find_compat(xpcs->desc, interface); + compat = xpcs_find_compat(xpcs, interface); if (!compat) return -ENODEV; @@ -1074,7 +1074,7 @@ static void xpcs_get_state(struct phylink_pcs *pcs, const struct dw_xpcs_compat *compat; int ret; - compat = xpcs_find_compat(xpcs->desc, state->interface); + compat = xpcs_find_compat(xpcs, state->interface); if (!compat) return; -- 2.51.0 From f042365a26b07006064c2cfa2293e16cad243b0d Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 4 Oct 2024 11:20:56 +0100 Subject: [PATCH 16/16] net: pcs: xpcs: provide a helper to get the phylink pcs given xpcs Provide a helper to provide the pointer to the phylink_pcs struct given a valid xpcs pointer. This will be necessary when we make struct dw_xpcs private to pcs-xpcs.c Signed-off-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c | 2 +- drivers/net/pcs/pcs-xpcs.c | 6 ++++++ include/linux/pcs/pcs-xpcs.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c index 83ad7c7935e3..48acba5eb178 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c @@ -451,7 +451,7 @@ static struct phylink_pcs *intel_mgbe_select_pcs(struct stmmac_priv *priv, * should always be an XPCS. The original code would always * return this if present. */ - return &priv->hw->xpcs->pcs; + return xpcs_to_phylink_pcs(priv->hw->xpcs); } static int intel_mgbe_common_data(struct pci_dev *pdev, diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 8bde87ab971f..a7f6d56183a7 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -132,6 +132,12 @@ xpcs_find_compat(struct dw_xpcs *xpcs, phy_interface_t interface) return NULL; } +struct phylink_pcs *xpcs_to_phylink_pcs(struct dw_xpcs *xpcs) +{ + return &xpcs->pcs; +} +EXPORT_SYMBOL_GPL(xpcs_to_phylink_pcs); + int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface) { const struct dw_xpcs_compat *compat; diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index abda475111d1..868515f3cc88 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -64,6 +64,7 @@ struct dw_xpcs { bool need_reset; }; +struct phylink_pcs *xpcs_to_phylink_pcs(struct dw_xpcs *xpcs); int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface); void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces); int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, -- 2.51.0